Copyright 2013-2014 by Object Computing, Inc. (OCI). All rights reserved. AngularJS Testing



Similar documents
ANGULAR JS SOFTWARE ENGINEERING FOR WEB SERVICES HASAN FAIZAL K APRIL,2014

Grunt, Gulp & fabs. Build-System and Development-Workflow for modern Web-Applications

Web Development CSE2WD Final Examination June (a) Which organisation is primarily responsible for HTML, CSS and DOM standards?

Appendix for Tx5xx and P85x1 manuals

Visualizing a Neo4j Graph Database with KeyLines

JavaScript By: A. Mousavi & P. Broomhead SERG, School of Engineering Design, Brunel University, UK

Abusing HTML5. DEF CON 19 Ming Chow Lecturer, Department of Computer Science TuCs University Medford, MA

MASTERTAG DEVELOPER GUIDE

MAGENTO THEME SHOE STORE

MODERN WEB APPLICATION DEVELOPMENT WORKFLOW

Visualizing an OrientDB Graph Database with KeyLines

Website Login Integration

PLAYER DEVELOPER GUIDE

Introduction to PhoneGap

Using HTML5 Pack for ADOBE ILLUSTRATOR CS5

Develop a Native App (ios and Android) for a Drupal Website without Learning Objective-C or Java. Drupaldelphia 2014 By Joe Roberts

Tutorial: Building a Dojo Application using IBM Rational Application Developer Loan Payment Calculator

Bazaarvoice for Magento Extension Implementation Guide v6.3.4

Web Design Basics. Cindy Royal, Ph.D. Associate Professor Texas State University

Dashboard Skin Tutorial. For ETS2 HTML5 Mobile Dashboard v3.0.2

Test Automation Integration with Test Management QAComplete

ipad Set Up Guide: Staff! 1 of! 20

Drupal CMS for marketing sites

Certified Selenium Professional VS-1083

Magento Theme EM0006 for Computer store

React+d3.js. Build data visualizations with React and d3.js. Swizec Teller. This book is for sale at

Making Web Application using Tizen Web UI Framework. Koeun Choi

PISA 2015 MS Online School Questionnaire: User s Manual

Installation Guide. Before We Begin: Please verify your practice management system is compatible with Dental Collect Enterprise.

Citrix Receiver for Mobile Devices Troubleshooting Guide

Table of Contents. Overview Supported Platforms Demos/Downloads Known Issues Note Included Files...

Chapter 22 How to send and access other web sites

Selenium An Effective Weapon In The Open Source Armory

Intell-a-Keeper Reporting System Technical Programming Guide. Tracking your Bookings without going Nuts!

ResPAK Internet Module

Connection. to SECON-Server

the intro for RPG programmers Making mobile app development easier... of KrengelTech by Aaron Bartell

Getting Started with AWS. Hosting a Static Website

vtiger Customer Portal 4.2 User Manual

Quick Start Guide Mobile Entrée 4

Dashboard Builder TM for Microsoft Access

Installation and Setup Guide

Automated testing of CS UI using Selenium and Python

Implementing Specialized Data Capture Applications with InVision Development Tools (Part 2)

VPN: Virtual Private Network Setup Instructions

Partek Flow Installation Guide

Load testing with. WAPT Cloud. Quick Start Guide

CREATE A CUSTOM THEME WEBSPHERE PORTAL

Automation using Selenium

Cloud Administration Guide for Service Cloud. August 2015 E

Write a Web Application for Free Edition 2

Laravel + AngularJS - Contact Manager

Getting Started Guide

Selenium 1.0 Testing Tools

If you examine a typical data exchange on the command connection between an FTP client and server, it would probably look something like this:

WIRIS quizzes web services Getting started with PHP and Java

Selenium Automation set up with TestNG and Eclipse- A Beginners Guide

Spectrum Technology Platform

ACCEPT THE SECURITY CERTIFICATE FOR THE WEB FILTER

WNMS Mobile Application

Instructions for Configuring Your Browser Settings and Online Security FAQ s. ios8 Settings for iphone and ipad app

Student BYOD - Olathe Public Schools

EVALUATION ONLY. WA2088 WebSphere Application Server 8.5 Administration on Windows. Student Labs. Web Age Solutions Inc.

Accessing UniSIM MyMail For Students and Associates Via Microsoft Office 365. UniSIM - Restricted

DNS REBINDING DENIS BARANOV, POSITIVE TECHNOLOGIES

CIS 467/602-01: Data Visualization

Local Caching Servers (LCS): User Manual

Configuring. Moodle. Chapter 82

Bazaarvoice for Magento

Agile Web Application Testing

ICON UK 2015 node.js for Domino developers. Presenter: Matt White Company: LDC Via

Adobe Summit 2015 Lab 712: Building Mobile Apps: A PhoneGap Enterprise Introduction for Developers

Windmill. Automated Testing for Web Applications

BlackBerry Universal Device Service. Demo Access. AUTHOR: System4u

2X Cloud Portal v10.5

Install and Config For IBM BPM 8.5.5

You need to be assigned and logged in to the system by the Records Management Service in order to use it.

Citrix StoreFront. Customizing the Receiver for Web User Interface Citrix. All rights reserved.

Sophos Mobile Control Installation guide. Product version: 3.5

Website Planning Checklist

Web App Development Session 1 - Getting Started. Presented by Charles Armour and Ryan Knee for Coder Dojo Pensacola

Insight Student for Chromebooks - Auto Configuration

The goal with this tutorial is to show how to implement and use the Selenium testing framework.

Actualtests.C questions

Lab 1: Windows Azure Virtual Machines

Web Development 1 A4 Project Description Web Architecture

Git - Working with Remote Repositories

Support Portal User Guide. Version 3.0

How to code, test, and validate a web page

Install and End User Reference Guide for Direct Access to Citrix Applications

Continuous Integration

Drupal Automated Testing: Using Behat and Gherkin

Transcription:

Testing The most popular tool for running automated tests for AngularJS applications is Karma runs unit tests and end-to-end tests in real browsers and PhantomJS can use many testing frameworks, but Jasmine seems to supported best Create test directory with subdirectories unit and e2e in unit directory, create subdirectories controllers and services 2

Installing Karma To install Karma npm install -g karma cd to top directory of project karma init (answer questions; creates karma.config.js) in Windows, this didn t work from Cygwin but did from a Command Prompt edit karma.config.js maybe because node and npm for Windows don t work in Cygwin add to files array passed to config.set the paths to angular.min.js, angular-mocks.js and the JavaScript files being tested 3

Browser Support To use Google Chrome karma-chrome-launcher is installed automatically when karma is installed on Windows, set CHROME_BIN environment variable to point to chrome.exe To use Firefox karma-firefox-launcher is installed automatically when karma is installed on Windows, set FIREFOX_BIN environment variable to point to firefox.exe To use IE (Windows-only) npm install -g karma-ie-launcher To use Safari (Mac-only) npm install -g karma-safari-launcher To use PhantomJS karma-phantomjs-launcher is installed automatically when karma is installed; includes PhantomJS set PHANTOMJS_BIN environment variable to point to phantomjs executable (not needed on Windows) executable is in `npm root -g`/karma-phantomjs-launcher/node_modules/phantomjs/bin 4

Sample Application We will walk through writing tests for a simple application The application has one service three controllers one custom filter one custom directive routing Pressing the Increment button increments the number the controller calls a service method to increment it - keeping things simple! A filter formats the numbers 1, 2 and 3 as words A directive applies different CSS classes to the number based on whether it is even or odd Routes cause different footers to be displayed based on whether the number is even or odd 5

HTML and CSS <!DOCTYPE html> index.html <html ng-app="karmademo"> <head> <link rel="stylesheet" href="karma-demo.css"/> <script src="lib/angular.min.js"></script> <script src="scripts/karma-demo.js"></script> </head> <body> <h1>karma Demo</h1> <div ng-controller="democtrl"> <div> Number: <span even-odd-class="foo,bar">{{number asword}}</span> </div> <button ng-click="increment()">increment</button> </div> <div ng-view="footer"></div> </body> </html> body { font-family: sans-serif; }.foo { color: green; }.bar { color: red; } karma-demo.css 6

JavaScript... (function () { 'use strict'; scripts/karma-demo.js // Create a module just to use for testing module dependencies. angular.module('othermodule', []); var app = angular.module('karmademo', ['OtherModule']); app.factory('demosvc', function () { var svc = {}; svc.increment = function (number) { return number + 1; }; return svc; app.controller('democtrl', function ($scope, $location, demosvc) { $scope.number = 1; $scope.increment = function () { $scope.number = demosvc.increment($scope.number); var iseven = $scope.number % 2 === 0; $location.path('/' + (iseven? 'even' : 'odd')); }; // These empty controllers are only used to test that routes // associated the correct controller with a view. app.controller('evenfooterctrl', function () { app.controller('oddfooterctrl', function () { 7

... JavaScript... app.directive('evenoddclass', function () { var evenclass, oddclass; function evaluate(number, element) { if (number % 2 === 0) { element.removeclass(oddclass); element.addclass(evenclass); } else { element.removeclass(evenclass); element.addclass(oddclass); } } scripts/ karma-demo.js app.filter('asword', function () { return function (number) { return number === 1? 'one' : number === 2? 'two' : number === 3? 'three' : number; }; return { restrict: 'A', link: function (scope, element, attrs) { var classnames = attrs.evenoddclass.split(','); evenclass = classnames[0]; oddclass = classnames[1]; scope.$watch('number', function (newvalue, oldvalue) { evaluate(newvalue, element); evaluate(scope.number, element); } }; 8

... JavaScript app.config(function ($routeprovider) { $routeprovider.when('/even', { 'controller': 'EvenFooterCtrl', 'templateurl': 'views/evenfooter.html', 'view': 'footer' }).when('/odd', { 'controller': 'OddFooterCtrl', 'templateurl': 'views/oddfooter.html', 'view': 'footer' }).otherwise({ redirectto: '/odd' })(); 9

Module Tests describe('karmademo module', function () { var module = angular.module('karmademo'); it('should exist', function () { expect(module).not.tobenull(); it('should have one dependency', function () { expect(module.requires.length).tobe(1); expect(module.requires).tocontain('othermodule'); 10

Service Tests describe('demosvc service', function () { var svc; beforeeach(module('karmademo')); The method angular.mock.module is added to window as module. it('should have demosvc service', inject(function ($injector) { svc = $injector.get('demosvc'); expect(svc).not.tobenull(); })); it('should increment properly', function () { expect(svc.increment(2)).tobe(3); 11

Controller Tests describe('democtrl controller', function () { var scope; beforeeach(function () { module('karmademo'); inject(function ($rootscope, $controller) { scope = $rootscope.$new(); // create a scope for DemoCtrl to use $controller('democtrl', {$scope: scope // give scope to DemoCtrl it('should have number in scope', function () { expect(scope.number).not.tobenull(); expect(scope.number).tobe(1); it('should increment properly', function () { scope.increment(); expect(scope.number).tobe(2); scope.increment(); expect(scope.number).tobe(3); The method angular.mock.inject is added to window as inject. 12

Filter Tests describe('asword filter', function () { var filter; beforeeach(module('karmademo')); it('should have asword filter', inject(function ($filter) { filter = $filter('asword'); expect(filter).not.tobenull(); })); it('should translate 2', function () { expect(filter(2)).tobe('two'); 13

Directive Tests describe('evenoddclass directive', function () { var directive; beforeeach(module('karmademo')); // TODO: Is there a way to test that a directive with a given name // TODO: exists in a module? it('should add the correct CSS class to an element', inject(function ($compile, $rootscope) { $rootscope.number = 1; // The directive should add the CSS class "bar" // to the element because number is odd. var element = $compile('<span even-odd-class="foo,bar"></span>')($rootscope); expect(element.hasclass('bar')).tobe(true); $rootscope.number = 2; // The directive should add the CSS class "foo" // to the element because number is even. element = $compile('<span even-odd-class="foo,bar"></span>')($rootscope); expect(element.hasclass('foo')).tobe(true); })); 14

Route Tests describe('footer routes', function () { it('should change path', function () { module('karmademo'); // must do before inject inject(function ($route) { var route = $route.routes['/even']; expect(route.controller).tobe('evenfooterctrl'); expect(route.templateurl).tobe('views/evenfooter.html'); expect(route.view).tobe('footer'); route = $route.routes['/odd']; expect(route.controller).tobe('oddfooterctrl'); expect(route.templateurl).tobe('views/oddfooter.html'); expect(route.view).tobe('footer'); 15

karma.conf.js module.exports = function (config) { config.set({ basepath: '', // used to resolve relative file paths frameworks: ['jasmine'], files: [ 'lib/angular.min.js', 'lib/angular-mocks.js', 'scripts/*.js', 'test/unit/*spec.js' ], exclude: [], // options: 'dots', 'progress', 'junit', 'growl', 'coverage' reporters: ['progress'], port: 9876, // web server port colors: true, // in output of reporters and logs loglevel: config.log_info, autowatch: true, // watch files and execute tests when any change // options: Chrome, ChromeCanary, Firefox, Opera, // Safari (Mac-only), IE (Windows-only), PhantomJS browsers: ['Chrome'], // if browser doesn t capture output in given timeout(ms), kill it capturetimeout: 60000, // if true, it capture browsers, runs tests and exits singlerun: false }; for running unit tests, not e2e tests 16

Running Unit Tests For a single run edit karma.conf.js and verify that in the object passed to config.set auto-watch is false and singlerun is true For repeated runs every time a watched file is modified edit karma.conf.js and verify that in the object passed to config.set auto-watch is true and singlerun is false To run unit tests karma start starts its own server and configured browsers runs tests exits if configured for a single run 17

Mock Dependency Injection In unit test code, mock implementations of services can be used in place of real implementations One way to do this create an object that has all the methods of the service register that object under the name of the service to be replaced app.value(svcname, mocksvcobject); Other ways? 18

End-to-End Tests Old approach - Angular Scenario Runner used with Karma npm install -g karma-ng-scenario must start a server that serves all static content can use Grunt with the connect plugin must do a local npm install of grunt, grunt-contrib-connect and grunt-karma (takes a LONG time!) being phased out in favor of Protractor New approach - Protractor https://github.com/angular/protractor based on Selenium WebDriverJS designed for AngularJS, but not restricted to that can use Jasmine or Mocha test frameworks a test runner; doesn t require using Karma can use Selenium Grid to test in multiple browsers simultaneously and run mulitple instances of the same browser for load testing 19

Protractor... To install npm install -g protractor cd to top project directory determine directory where global node modules are installed by running npm root -g install standalone Selenium server./that-dir/protractor/bin/install_selenium_standalone on Windows, node /that-dir/protractor/bin/install_selenium_standalone copy /that-dir/protractor/referenceconf.js to protractor.conf.js Edit protractor.conf.js modify specs property to include directory where tests will be stored (ex. test/e2e) modify capabilities.browsername property to the name of the browser to be used common choices are android, chrome, firefox, internet explorer, iphone, ipad and safari modify baseurl property to to be URL where web app is served for a detailed description of options, see https://code.google.com/ p.selenium/wiki/desiredcapabilities not needed if using an existing Selenium server 20

... Protractor To run tests cd to top project directory start Web server that servers static files and processes Ajax calls protractor protractor.conf.js starts Selenium server, runs tests, reports results, shuts down Selenium server, and exits console.log output in tests will go to stdout 21

Working With Page Elements Get Protractor instance and load a page var ptor; beforeeach(function () { ptor = protractor.getinstance(); ptor.get('some-url'); Get element objects by calling ptor.findelement or ptor.findelements with a locator findelement returns the first matching element findelements returns an array of all matching elements. locators are protractor.by.x('some-string') where x is one of classname, css, id, linktext, partiallinktext, name, tagname or xpath AngularJS-specific values for x include binding, select, selectedoption, input and repeater throws if no matching elements are found, causing test to fail 22

Element Methods Can call many methods on these element objects clear(), click(), getattribute(name), getcssvalue(propertyname), getlocation(), getsize(), gettagname(), gettext(), isdisplayed(), isenabled(), isselected(), sendkeys(text) Typically want to call clear() on input elements before calling sendkeys(text) Methods that return data such as gettext actually return a promise When a promise is passed to expect, it waits until the promise is resolved or rejected to evaluate it 23

Protractor Sugar Directly using Protractor methods can be verbose Here are some utility methods to make Protractor tests less verbose This is used in the example test on the next slide module.exports = function (ptor) { var obj = {}; obj.click = function (id) { this.getelementbyid(id).click(); }; protractorsugar.js obj.getelementbyid = function (id) { return ptor.findelement(protractor.by.id(id)); }; obj.gettext = function (id) { return this.getelementbyid(id).gettext(); }; obj.setinputvalue = function (id, value) { var input = this.getelementbyid(id); input.clear(); input.sendkeys(value); }; return obj; }; 24

Example Protractor Test var protractorsugar = require('./protractorsugar'); describe('login', function () { var ps, ptor; beforeeach(function () { ptor = protractor.getinstance(); ps = protractorsugar(ptor); ptor.get('/'); loginspec.js it('should fail on bad username/password', function () { ps.setinputvalue('userid', 'foo'); ps.setinputvalue('password', 'bar'); ps.click('login'); expect(ps.gettext('loginerror')).tobe( 'The user id or password is incorrect.'); }, 5000); // five second timeout it('should get password hint', function () { ps.setinputvalue('userid', 'gumby'); ps.click('passwordhintlink'); expect(ps.gettext('passwordhint')).tobe('my horse'); }, 5000); // five second timeout 25