Jasmine: How can I declare an "it" loop instead of a "wait" loop for testing angular factory?

This is the angular factory I want to test:

var myApp = angular.module('myApp', []);

myApp.factory('factoryTest',function(){
    return [
        {number: 1, name: 'one'},
        {number: 2, name: 'two'},
        {number: 3, name: 'three'}
    ];
});

      

And this is the jasmine way of testing it:

beforeEach(inject(function (_factoryTest_) {
    factoryTest = _factoryTest_;
}));

it('verifies every item has a number', function(){
    for(var i=0;i < factoryTest.length; i++){
        expect(factoryTest[i].number).toEqual(jasmine.any(Number));
    }
});

      

the above test works, however in case of failure, you don't know which item is failing.

To make an error meaningful, it would have to be rebuilt in the "her" loop:

beforeEach(inject(function (_factoryTest_) {
    factoryTest = _factoryTest_;
}));

for(var i=0;i < factoryTest.length; i++){
    it('verifies ' + factoryTest[i].name + ' has a number', function(){
        expect(factoryTest[i].number).toEqual(jasmine.any(Number));
    });
}

      

However, this fails because the factoryTest is not injected into the described context. How can I inject an angular factory to make it work?

I made a fiddle: http://jsfiddle.net/rodhom/woq9fhg9/

I first found the idea of ​​looping "him" here: http://tosbourn.com/using-loops-in-jasmine/

+3


source to share


1 answer


See my previous comment as I believe you have an XY problem .

jasmine evaluates test definitions in stages. At the point at which it is evaluated describe

, beforeEach

by assigning factoryTest

, it has not been evaluated. I can't seem to find a link as to what the order is at the moment.

To have an error message indicating which object the wait occurred on, create a custom connector and repeat the wait in the phase it

.

Define custom matches as shown below:

beforeEach(function () {
    var customMatchers = {
        toHaveNumericProperty: function (property) {
            var instance = this.actual;
            var description = instance.name || instance.toString();
            var isNumeric = typeof instance[property] === 'number';

            this.message = function() {
                return isNumeric ? '' : 'Expected \'' + description + '.' + property + '\' to be numeric';
            };

            return isNumeric;
        }
    };

    this.addMatchers(customMatchers);
});

      

Then use it in your tests like this:



it('verifies each object has a number',
function () {
    for (var i = 0; i < factoryTest.length; i++) {
        expect(factoryTest[i]).toHaveNumericProperty('number');
    }
})

      

I have forked your script to use this solution

The solution to your asked question is to make a closure to contain the variable factoryTest

.

beforeEach(inject(function (_factoryTest_) {
    factoryTest = _factoryTest_;
}));

for(var i=0;i < factoryTest.length; i++){
    it('verifies ' + factoryTest[i].name + ' has a number', 
        createFactoryTestClosure(factoryTest[i]));
}

function createFactoryTestClosure(factoryElement) {
    return function() {
        expect(factoryElement.number.toEqual(jasmine.any(Number));
    };
}

      

Strike>

+2


source







All Articles