Tim Smart Tim Smart - 11 days ago 4
Javascript Question

Jasmine does not Resolve Angular Promise

I am new to Jasmine. I am trying to get my factory promise to resolve but it never seems to.

Here is my factory which will retuirn a list of companies

angular.module('commercial.factories').factory('companyFactory', companyFactory);

function companyFactory($http, $location, sessionStorage, config) {
function getCompanies() {
//call service and include company identifier in the service url
return $http.get(wunUtils.constants.serviceBaseUrl + 'myCompanyService.svc/companies')
.then(function(response) {
return response.data;
}, function(err){
console.log(err);
});
}
});


and my spec

describe('company', function() {
beforeEach(module('mockedCommercial'));

var $httpBackend, companyFactory, $rootScope

beforeEach(function() {

inject(function(_$httpBackend_, _$rootScope_, _companyFactory_) {
$rootScope = _$rootScope_;
$httpBackend = _$httpBackend_;
companyFactory = _companyFactory_;
});
})


it('should return available languages asynchronously', function() {


$httpBackend.expectGET(/https:\/\/myDomain.com\/myCompanyService.svc\/companies+/)

.respond(function(method, url, data, headers, params) {

var response = {
"data": [{
"address1": "Portsmouth",
"address2": null,
"city": "Portsmouth",
"contactEmail": "mocks@mocks.com",
"contactFirstName": "Mock",
"contactLastName": "Data",
"contactPhone": null,
"contactTitle": "Mr",
"country": "UK",
"fax": null,
"identifier": "c1xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"location": "Portsmouth, UK",
"name": "Mock Company 1",
"phone": null,
"state": "Hampshire",
"zipCode": "PO19 3 EN"
}, {
"address1": "Portsmouth",
"address2": null,
"city": "Portsmouth",
"contactEmail": "mocks@mocks.com",
"contactFirstName": "Test",
"contactLastName": "Test",
"contactPhone": null,
"contactTitle": "Mrs",
"country": "UK",
"fax": null,
"identifier": "c2xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"location": "Portsmouth, UK",
"name": "Mock Company 2",
"phone": null,
"state": "Hampshire",
"zipCode": "Po9 3EN"
}],
"total": 2
}

});


//--------------------------

$rootScope.$digest();

companyFactory.GetCompanies().then(function(result) {
expect(result.hasOwnProperty('total')).toBe(true);
})
});
});


As you can see i am using $rootScope.$digest to run the promise, however my expect is never hit so the test always passes.

I have read loads of different posts about this who all say this should work. Am i doing something wrong here or have i missed some step?

Edited - Simplified approach



So i simplified my question somewhat after looking at some more posts

Here is my new controller call...

$scope.companies = [];
var GetCompanies = function(options) {
companyFactory.GetCompanies().then(function(response) {
options.success(response);
$scope.companies = response
});
}
$scope.GetCompanies = GetCompanies


my factory...

function getCompanies() {
//call service and include company identifier in the service url
return $http.get(wunUtils.constants.serviceBaseUrl + 'CompanyService.svc/companies')
.then(function(response) {
return response.data;
}, function(err){
console.log(err);
});
}
var service = {
AddCompany: addCompany,
GetCompany: getCompany,
GetCompanies: getCompanies,
GetUserCompanyFleets: getUserCompanyFleets,
EditCompany: editCompany
};


and my new spec

describe('company', function() {
beforeEach(module('mockedCommercial'));

var $httpBackend, companyFactory, $rootScope, createController, scope

beforeEach(function() {

inject(function($controller, _$httpBackend_, _$rootScope_, _companyFactory_) {
$rootScope = _$rootScope_;
$httpBackend = _$httpBackend_;
scope = _$rootScope_.$new();
companyFactory = _companyFactory_;
createController = function() {
return $controller('ManageCompaniesController', {
'$scope': scope
});
};
});
})


it('should return available languages asynchronously', function(done) {

$httpBackend.whenGET(/https:\/\/myDomain.com\/V3_Fleet\/CompanyService.svc\/companies+/)

.respond(function(method, url, data, headers, params) {
return [{ 'id': 1 }];
}
});

//--------------------------
var dummy = [{ 'id': 1 }];

createController();

scope.GetCompanies()

$httpBackend.flush()


expect(scope.companies).toEqual(dummy)


scope.$digest(); done()

});


});

Answer

So after much reading i found the answer by simplifying everything down. I think my issues came from mixing $httpBackend.flush() and the done() function

What seems to happen is the the done() function triggers its own digest, so when trying to use the flush() function there is a conflict.

Here is my working factory. Its a little different from my original purly as this was a more simple function to work with (less things to go wrong)

        function getUser(userId) {
        //call service and include user identifier in the service url
        return $http.get(wunUtils.constants.serviceBaseUrl + 'myService.svc/fleetusers/' + userId)
            .then(function(response) {
                return response.data;
            });
         }

        var service = {
        GetMe: getMe,
        GetUser: getUser,
        AddUser: addUser,
        EditUser: editUser,
        ActivateUser: activateUser
    };

and here is my simplified spec call the $httpBackend.Flush()

describe('Testing httpBackend', function() {

var $httpBackend;

beforeEach(module('mockedCommercial'));


beforeEach(inject(function(_$httpBackend_) {
    $httpBackend = _$httpBackend_;
}))

it('should behave...', function() {

    inject(function(userFactory, $rootScope) {

        var mockData = [];

        $httpBackend.expectGET(wunUtils.constants.serviceBaseUrl + 'FleetUserService.svc/fleetusers/10').respond(mockData);

        var promise = userFactory.GetUser(10);

        $httpBackend.flush();

        promise.then(function(result) {
            expect(result).toEqual(mockData);
        });

        });

});
});
Comments