47
Testing with AngularJS Raissa Ferreira [email protected]

Angular testing

Embed Size (px)

Citation preview

Testing with AngularJSRaissa Ferreira

[email protected]

Testing Tools

● Testing Frameworks○ Jasmine

● Karma (Unit Test)● Grunt● Protractor (E2E Test)● Bower● NVM

Testing Frameworks

● QUnit ● Jasmine● Mocha

QUnitExample 1test('test', function() {

equals( {}, {}, 'fails, these are different objects');

});

Example 2module('Module A');

test('a test',function() {});

test('an another test',

function() {});

module('Module B');

test('a test',

function() {});

test('an another test',

function() {});

JasmineExample

describe("A spec", function() {

var foo;

beforeEach(function() {

foo = 0;

foo += 1;

});

it("is just a function, so it can contain any code",function(){

expect(foo).toEqual(1);

});

});

Jasmine X QUnit

● Nested describes ● Less vulnerable to

changes, less setup

● Modules(can’t be nested)

● Massive amount of setup to cover all different paths

MochaExamplevar assert = require("assert")

describe('Array', function(){

describe('#indexOf()', function(){

it('should return -1 when the value is not present',

function(){

assert.equal(-1, [1,2,3].indexOf(5));

assert.equal(-1, [1,2,3].indexOf(0));

});

});

});

Jasmine X Mocha

● Runner● Nested describes● Built-in:

○ Assertion library○ Mocking library

● Runner● Nested describes● You can choose:

○ Assertion library (eg. Chai)

○ Mocking library(eg. Sinon)

● Pick syntax

Jasmine

● Behavior Driven Development testing framework for

JavaScript

● Does not depend on any other JavaScript frameworks

● Does not require a DOM

● Clean syntax

Suites● Begins with global Jasmine function describe

○ Takes two parameters:

■ string - a name or title for a spec suite, what is being

tested

■ function - Block of code that implements the suite

Jasmine

Specs● Begins with global Jasmine function it.

○ Takes two parameters:

■ string - title of the spec

■ function - the spec, or test

○ Can contains one or more expectations

■ Expectation - assertion that is either true or false

○ Passing spec - all true expectations

○ Failing spec - one or more false expectations

Jasmine

Expectations● Built with function expect

○ Takes the actual value

● Chained with a matcher function

○ Takes the expected value

Eg. expect(actualValue).toEqual(expectedValue);

Jasmine

Matchers

● Implement boolean comparison between actual and expected

value

● Responsible for reporting to Jasmine if expectation is true or

false

○ Based on this, Jasmine will pass or fail the spec

● Matcher can evaluate to a negative assertion by chaining the

call to expect with a not

Eg. expect(a).not.toBe(null);

Jasmine

Matchers

● Included Matchers

○ toBe(===), toEqual, toBeNull, toBeDefined, toBeUndefined

○ Boolean Casting - toBeFalsy, toBeTruthy

○ String/Regex - toMatch

○ Array - toContain

○ Math - toBeLessThen, toBeGreaterThan

○ Precision Math - toBeClose

○ Check if function throws exception - toThrow

Jasmine

Spies● Test double functions

● Can stub any function

● Tracks calls to it and all arguments

● Only exists in describe and it blocks it is defined

■ Will be removed after each spec

● Matchers

■ toHaveBeenCalled - if the spy was called

■ toHaveBeenCalledWith - if argument list matches any of

the recorded calls to the spy

Jasmine

JasmineAsynchronous Support

● beforeEach, it and afterEach can take optional single

argument to be called when the async work is complete

JasmineAsynchronous Support

describe("Asynchronous specs", function() { var value;

beforeEach(function(done) { setTimeout(function() { value=0;

done(); }, 1);});

it("should support async execution of test preparation and expectations", function(done) { value++; expect(value).toBeGreaterThan(0); done(); });});

ngMockFunctions (declared ONLY in jasmine or mocha)

● angular.mock.module○ Registers a module configuration code

○ Collects configuration information to be used when the injector

is created by inject

● angular.mock.inject○ Wraps a function into an injectable function

○ Creates new instance of $injector per test to be used for

resolving references

○ $injector is used to retrieve object instances as defined by

provider, instantiate types, invoke methods, and load modules

Unit Test (Service)

describe("Auth", function() {

beforeEach(module("app"));

var Auth, $httpBackend;

beforeEach(inject(function(_Auth_, _$httpBackend_) {

Auth = _Auth_;

$httpBackend = _$httpBackend_;

}));

afterEach(function() {

$httpBackend.verifyNoOutstandingRequest();

});

Unit Test (Service)describe(".logout", function() {

describe("given a valid token", function() {

var Session, token = "9664bbf375";

beforeEach(inject(function(_Session_) {

Session = _Session_;

$httpBackend.

whenGET("api/auth/logout.json?token="+token).

respond(200, { invalid: true });

spyOn(Session, "clear");

}));

it("should erase user’s token", function() {

Auth.logout(token);

$httpBackend.flush();/* explicitly flush pending requests */

expect(Session.clear).toHaveBeenCalled();

});

}); });

Unit Test (Controller)describe("AuthController", function() {

beforeEach(module("app"));

var $scope, controller, $httpBackend;

beforeEach(inject(

function($controller, $injector, _$httpBackend_) {

$httpBackend = _$httpBackend_;

$scope = $injector.get("$rootScope").$new();

controller = $controller("AuthController",

{ $scope: $scope });

}));

afterEach(function() {

$httpBackend.verifyNoOutstandingRequest();

});

Unit Test (Controller)describe(".login", function() {

var $state, httpBackend;

describe("given valid user"s credentials", function() {

beforeEach(inject(function(_$state_) {

$state = _$state_;

$httpBackend.whenPOST("api/auth/login.json").respond(200,{});

spyOn($state, "go");

$scope.login();

$httpBackend.flush();

}));

it("should go to role selection state", function() {

expect($state.go).toHaveBeenCalledWith("role_selection");

});

});

}); });

Karma● Testing Engine

○ Launches a HTTP server and generates the test

runner HTML file

■ Runs in browser

■ Can run in multiple real browsers (can also

run in a headless one - PhantomJS)

■ Show output in command line■ Developed by the AngularJS team

Karma● Instalation

# Install Karma:

$ npm install karma karma-cli --save-dev

# Install plugins that your project needs:

$ npm install karma-jasmine karma-phantomjs-launcher karma-

coverage karma-mocha-reporter --save-dev

● Configuration

# Initialize a config file:

$ node ./node_modules/karma-cli/bin/karma init [<configFile>]

Karma● Configuration file ( karma.conf.js )

module.exports = function(config) { config.set({ frameworks: ["jasmine"], files: ["src/*.js","test/*.js"], plugins: ["karma-jasmine","karma-phantomjs-launcher",

"karma-coverage","karma-mocha-reporter"], browsers: ["PhantomJS"], reporters: ["mocha","coverage"], preprocessors: {"src/*.js": "coverage"}, coverageReporter: { type : "html", dir : "coverage"}, display: "full", isVerbose: true, showColors: true, includeStackTrace: true });};

● Javascript Task Runner● Automation of repetitive tasks:

○ Minification○ Compilation○ Unit Testing

...● Instalation# install Grunt

$ npm install grunt

# install Grunt’s command line interface globally

$ npm install -g grunt-cli

Grunt

● Gruntfilegrunt.initConfig({

...

unit: {

configFile: "karma.conf.js",

singleRun: true,

browsers: ["PhantomJS"]

}

});

...

grunt.loadNpmTasks("grunt-karma");

grunt.registerTask("unit", "Run unit test",["karma"]);

Grunt Task for Karma

Protractor● Acceptance tests

● Integration Tests

● Main paths

● Takes longer to run(compared to unit testing)

● WebdriverJS (Binding for Selenium Webdriver)

● Works better with Jasmine

● Currently does not support PhantomJS

ProtractorAPI (Most Common functions)

● element Eg. element(locator)

○ isPresent

● element.all

● browser

○ waitForAngular

○ get

○ pause

○ debugger

API (Most Common functions)

● Protractor’s locators○ by

■ binding■ model■ css■ cssContainingText■ buttonText

● getText● sendKeys● clear● getAttribute

Protractor

Protractor● Example

describe("angularjs homepage", function() { it("should add one and two", function() {

browser.get("http://juliemr.github.io/protractor-demo/");element(by.model("first")).sendKeys(1);element(by.model("second")).sendKeys(2);element(by.id("gobutton")).click();expect(element(by.binding("latest")).getText()). toEqual("3"); });

});

});

ngMockE2E● Fake HTTP backend implementation suitable for end-to-end testing

○ $httpBackend● Can be used via:

● when API - when(<HTTPMETHOD>, url, params).respond

(statusCode, data)

○ shortcuts (whenGET, whenPOST,..)

● Can pass through requests to the real $httpBackend (passThrough

function)

● Flushes mocked out requests automatically

● Instalation (via Bower)

$ bower install angular-mocks --save-dev

● Instalation

# Install Protractor:

$ npm install protractor --save-dev

# Install webdriver-manager, helper tool to get an instance of a

Selenium Server running:

$ node node_modules/protractor/bin/webdriver-manager update

# Install Grunt Protractor Task

$ npm install grunt-protractor-runner --save-dev

# Install Rails Server Task

$ npm install grunt-rails-server--save-dev

Protractor

Protractor● Configuration file(protractor.conf.js):

exports.config = {

capabilities: {

"browserName": "chrome"

},

directConnect: true, /* bypass selenium webdriver */

specs: ["spec/javascripts/e2e/**/*.js"],

baseUrl: "http://local.ntp.uff.br:4000",

framework: "jasmine"

}

● Gruntfile grunt.initConfig({

... rails: { /* Backend Task */

options: {

port: 4000,

environment: "test",

keepAlive: false

},

your_target: {

}

}

...

Grunt Task for Protractor

● Gruntfileprotractor: {

options: {

configFile: "node_modules/protractor/referenceConf.js",

keepAlive: false,

noColor: false,

},

your_target: {

options: {

configFile: "protractor.conf.js",

args: {}

}

}

}

Grunt Task for Protractor

● Gruntfile ... grunt.loadNpmTasks("grunt-rails-server");

grunt.loadNpmTasks("grunt-protractor-runner");

...

grunt.registerTask("e2e", "Run e2e test",

["rails", "protractor"]);

Grunt Task for Protractor

NVM

● Instalation# Install nvm (Node Version Manager)$ curl https://raw.githubusercontent.com/creationix/nvm/v0.23.3/install.sh | bash

# To source it from your shell, this line can be added to ~/.bashrc, ~/.profile, or ~/.zshrc

$ source ~/.nvm/nvm.sh

# To install a node version

$ nvm install 0.10

# In your project folder, you can include a .nvmrc file to choose the desired node version

$ nvm use 0.10

Bower

Package Manager for Web● Instalation# Install Bower globally

$ npm install -g bower

# Interactively create a bower.json file

$ bower init

# Install a package

$ bower install <package-name>

# List all installed packages and check for new versions$ bower list

# Clean local unused packages

$ bower prune

Bower

● Configuration bower.json

{

"name": "assets",

"dependencies": {

"jquery": "latest",

"bootstrap": "latest",

"angular": "1.3.4"

...

}

.bowerrc

{

"directory": "vendor/assets/bower_components"

}

ResourcesTesting Frameworks● QUnit

http://qunitjs.com/

● Jasmine

http://jasmine.github.io/2.2/introduction.html

● Mocha

http://mochajs.org/

Assertion library● Chai

http://chaijs.com/

Mocking library● Sinon

http://sinonjs.org/

ResourcesUnit Testing

● Unit Testinghttps://docs.angularjs.org/guide/unit-testing

● Jasminehttp://jasmine.github.io/2.2/introduction.html

● ngMockhttps://docs.angularjs.org/api/ngMock

ResourcesTest Runner● Karma

http://karma-runner.github.io/

● Karma Jasmine

https://www.npmjs.com/package/karma-jasmine

● Karma PhantomJS Launcher

https://github.com/karma-runner/karma-phantomjs-launcher

● Karma Mocha Reporter

https://www.npmjs.com/package/karma-mocha-reporter

● Karma Coverage

https://github.com/karma-runner/karma-coverage

● PhantomJS

https://github.com/ariya/phantomjs

E2E Testing

● E2E Testhttps://docs.angularjs.org/guide/e2e-testing

● Protractorhttp://angular.github.io/protractor

● ngMockE2Ehttps://docs.angularjs.org/api/ngMockE2E

● HTTP Backend Proxyhttps://www.npmjs.com/package/http-backend-proxy

Resources

Automate Tasks

● Grunthttp://gruntjs.com/

● Grunt Karmahttps://github.com/karma-runner/grunt-karma

● Grunt Protractor Runnerhttps://www.npmjs.com/package/grunt-protractor-runner

Resources