简体   繁体   中英

Testing angular $http inside promise chain with mocha

I have jsdom/mocha/chai set up for backend angular testing.

I have a service that essentially does this (intentionally no post data):

app.service('testService', ['config', '$http', function(config, $http) {
    function getSpecificConfig(type) {
        return config.getConfig()
        .then(function(config) {
            // config is coming back defined;
            // $http timesout
            return $http({method: 'post', url: 'http://localhost:2222/some/path', withCredentials: true});
        })
        .then(function(res) {
            return res.data.config[type];
        })
        .catch(function(err) {
            //handles err
        });
    };

    return {
        getConfig: getConfig
    }
}]);

my test is:

/* jshint node: true */
/* jshint esversion: 6 */

let helpers = require(bootstrapTest),
    inject = helpers.inject,
    config,
    specificConfig,
    mockResponse,
    $httpBackend,
    $rootScope;

//config service
require('config.js');

//testService I'm testing
require('testService');

beforeEach(inject(function($injector, _$httpBackend_) {
    config = $injector.get('config');
    specificConfig = $injector.get('testService');
    $rootScope = $injector.get('$rootScope');
    $httpBackend = _$httpBackend_;

    $httpBackend.when('POST', 'http://localhost:2222/some/path')
    .response(function(data) {
        //would like this to fire
        console.log('something happened');
        mockResponse = {data: 'some data'};
        return mockResponse;
    });
}));   

afterEach(function() {
    $httpBackend.verifyNoOutstandingExpectations();
    $httpBackend.verifyNoOutstandingRequest();
});

describe ('this service', function() {
    beforeEach(function() {
        $httpBackend.expect('POST', 'http://localhost:2222/some/path');
        $rootScope.$apply(function() {
            return specificConfig('something');
        });
    });

    it ('returns the specific config', function() {
        expect(mockResponse).to.equal('some data');
    })
});

Problem: When the test is run, the config.getConfig() is resolving properly but the $http leads to a mocha timeout (2000ms) and the afterEach hook throws an Unsatisfied request.

My understanding of this may be completely incorrect so please feel free to educate me on the correct approach (here was my approach):

1) require all necessary dependencies.

2)inject them and set up a $httpBackend listener which fires the test response when the real http is fired.

3) $rootScope.$apply() any promises as the resolution of them is tied to the angular lifecycle.

4) the first before each sets the listener, the second before each fires the service which fires the $http allowing $httpBackend to fire and set the mockResponse.

5) test mock response.

If you need to return promises in your mocked HTTP requests you can use angular-mocks-async like so:

var app = ng.module( 'mockApp', [
    'ngMockE2E',
    'ngMockE2EAsync'
]);

app.run( [ '$httpBackend', '$q', function( $httpBackend, $q ) {

    $httpBackend.whenAsync(
        'GET',
        new RegExp( 'http://api.example.com/user/.+$' )
    ).respond( function( method, url, data, config ) {

        var re = /.*\/user\/(\w+)/;
        var userId = parseInt(url.replace(re, '$1'), 10);

        var response = $q.defer();

        setTimeout( function() {

            var data = {
                userId: userId
            };
            response.resolve( [ 200, "mock response", data ] );

        }, 1000 );

        return response.promise;

    });

}]);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM