javascript - AngularJs - testing

AngularJS - testing

tools

unit testing

best articles

best lib (ng-describe)

Articles de l'auteur de la lib :

intégration jasmine dans webstorm

http://stackoverflow.com/questions/8108461/how-can-i-get-webstorm-to-recognize-jasmine-methods

Selection jasmine definitly typed : http://stackoverflow.com/a/36864225

examples

repos examples

tests avec $http

tests de services

tests de directives

Dependencies mocking

Testing a throw exception :

it('throws exception when args are undefined or null', inject(function (HistoryLRindexService) {
  expect(function(){HistoryLRindexService.addIndexElement(undefined, 'toto');})
    .toThrowError('HistoryLRindexValueFactory.addIndexElement(key, data) error : key null or undefined');
}));
  • use anonymous function for the call
  • use toThrowError(exceptionMsg) matcher from Jasmine

  • your impl should be something like that :

    if(!key) {
    throw new Error('HistoryLRindexValueFactory.addIndexElement(key, data) error : key null or undefined');
    }
    

Testing a directive :

(function () {
    'use strict';

    angular
        .module('app')
        .directive('exampleDirective', exampleDirective);

    function exampleDirective() {
        return {
            restrict: 'E',
            scope: {
                stroke: "@",
                fill: "@"
            },
            template: '<svg ng-attr-height="{{values.canvas}}" ng-attr-width="{{values.canvas}}" class="gray">' +
            '<circle ng-attr-cx="{{values.center}}" ng-attr-cy="{{values.center}}"' +
            'ng-attr-r="{{values.radius}}" stroke="{{stroke}}"' +
            'stroke-width="3" fill="{{fill}}" />' +
            '</svg>',
            link: function(scope, element, attrs) {
                var calculateValues = function(size) {
                    var canvasSize = size * 2.5;

                    scope.values = {
                        canvas: canvasSize,
                        radius: size,
                        center: canvasSize / 2
                    };
                };

                attrs.$observe('size', function(newSize) {
                    calculateValues(parseInt(newSize, 10));
                });
            }
        };
    }

}());
(function () {
    'use strict';

    describe('directive: example', function() {
        var element, scope;

        beforeEach(module('app'));

        beforeEach(inject(function($rootScope, $compile) {
            scope = $rootScope.$new();

            element =
                '<example-directive size="{{size}}" stroke="black" fill="blue"></example-directive>';

            scope.size = 100;

            element = $compile(element)(scope);
            scope.$digest();
        }));

        describe('with the first given value', function() {
            it("should compute the size to create other values", function() {
                var isolated = element.isolateScope();
                expect(isolated.values.canvas).toBe(250);
                expect(isolated.values.center).toBe(125);
                expect(isolated.values.radius).toBe(100);
            });

            it("should contain a svg tag with proper size", function() {
                expect(element.find('svg').attr('height')).toBe('250');
                expect(element.find('svg').attr('width')).toBe('250');
            });

            it("should contain a circle with proper attributes", function() {
                expect(element.find('circle').attr('cx')).toBe('125');
                expect(element.find('circle').attr('cy')).toBe('125');
                expect(element.find('circle').attr('r')).toBe('100');
                expect(element.find('circle').attr('stroke')).toBe('black');
                expect(element.find('circle').attr('fill')).toBe('blue');
            });
        });

        describe('when changing the initial value to a different one', function() {

            beforeEach(function() {
                scope.size = 160;
                scope.$digest();
            });

            it("should compute the size to create other values", function() {
                var isolated = element.isolateScope();
                expect(isolated.values.canvas).toBe(400);
                expect(isolated.values.center).toBe(200);
                expect(isolated.values.radius).toBe(160);
            });

            it("should contain a svg tag with proper size", function() {
                expect(element.find('svg').attr('height')).toBe('400');
                expect(element.find('svg').attr('width')).toBe('400');
            });

            it("should contain a circle with proper attributes", function() {
                expect(element.find('circle').attr('cx')).toBe('200');
                expect(element.find('circle').attr('cy')).toBe('200');
                expect(element.find('circle').attr('r')).toBe('160');
                expect(element.find('circle').attr('stroke')).toBe('black');
                expect(element.find('circle').attr('fill')).toBe('blue');
            });
        });

    });

}());

e2e testing

installation des drivers pour webdrivers

ATTENTION CHROME & FIREFOX, need dl update de webdriver.

Derrière un proxy il faut config envvar HTTP_PROXY & HTTPS_PROXY sur fiddler (http://localhost:8888) et set ignore_ssl à true si le magasin de certificat du réseau est fucké. Pour le moment on sait le faire que en dur dans le source de webdriver-manager ( .\node_modules\gulp-protractor\node_modules\protractor\bin\webdriver-manager ) ligne 93 (default('ignore_ssl', false).)

ATTENTION IE : pour exécution sur IE [need drivers spécifiques] (http://selenium-release.storage.googleapis.com/index.html). (dépendent de la plateforme, sur win x64 : IEDriverServer_x64_2.47.0.zip) Config à faire ensuite dans protractor.conf.js pour lancer sur ce server (géré au niveau du generator)

lancer la suite de test sur chaque browser

multiCapabilities: [{
    'browserName': 'firefox'
  }, {
    'browserName': 'chrome'
  }, {
    'browserName': 'ie'
  }],

tests pour ie fail

UnknownError: The path to the driver executable must be set by the webdriver.ie.driver system property; for more information, see http://code.google.com/p/selenium/wiki/InternetExplorerDriver. The latest version can be downloaded from http://selenium-release.storage.googleapis.com/index.html

IE nécessite un driver spécifique et une config spécifique. Dans gulp-protractor les drivers webdriver de IE ne sont pas DL, cf [issue 38] (https://github.com/mllrsohn/gulp-protractor/issues/38) Télécharger les drivers IE manuellement [ici] (http://selenium-release.storage.googleapis.com/index.html). Doc du driver [ici] (https://code.google.com/p/selenium/wiki/InternetExplorerDriver).

Installer l'exe dans la partie exécutable du disque dur.

Ajouter de la config à protractor.conf.js :

 seleniumArgs: [
    '-Dwebdriver.ie.driver=C:\\Produits\\dev\\ws-js\\webdriver-ie\\IEDriverServer.exe'
  ],

Ajouter la capability à la config de protractor.conf.js :

 multiCapabilities: [{
    'browserName': 'firefox'
  }, {
    'browserName': 'chrome'
  }, {
    'browserName': 'internet explorer',
    'platform': 'ANY',
    'version': '11'
  }],

exporter les résultats

resultJsonOutputFile: 'e2e.results.json',

Nécessite que jasmineNodeOpts.isVerbose soit à true.

reporter

installation :

npm install jasmine-reporters@^2.0.7 --save-dev

Dans protractor.conf.js, ajouter :

var jasmineReporters = require('jasmine-reporters');
exports.config = {
    // ...
    framework: 'jasmine2',
    // ...
    onPrepare: function () {
    jasmine.getEnv().addReporter(new jasmineReporters.JUnitXmlReporter({
      savePath: paths.e2e + '/reports/',
      consolidateAll: true,
      filePrefix: 'e2e.chrome.results.' + _currentTimestampToString()
    }));
    // ...
    // Options to be passed to Jasmine-node.
  jasmineNodeOpts: {
    showColors: true,
    defaultTimeoutInterval: 60000,
    print: function() {}
  }
  },
};

Va créer le rapport dans ../e2e/reports/

Le rapport est un fichier au format xml qui nécessite une mise en forme. [Cette xslt] (https://github.com/niedbalski/nosetest-xunit-xslt/blob/master/nosetests.xslt) peut être utilisée pour mettre en forme le xml d'output mais manque un moyen pour linker automatiquement le xml de sortie avec la xsl. (pas prévu par le module)

results for ""

    No results matching ""