角度测试:我如何用ajax测试角度承诺?

时间:2016-01-24 06:02:29

标签: javascript angularjs promise karma-jasmine

如何用ajax测试角度承诺呢?

代码是通过ajax调用父代,然后通过ajax调用其子代的休息。

代码,

app.controller('MyController', ['$scope', '$http', '$timeout', '$q', function($scope, $http, $timeout, $q) {

    $scope.myParen = function(url) {
        var deferred = $q.defer();

        setTimeout(function() {
        $http({
            method: 'GET',
            url: url
        })
        .success(function(data, status, headers, config) {
            deferred.resolve([data]);
        })
        .error(function(data, status, headers, config) {
            deferred.reject(data);
        });
        }, 1000);

        return deferred.promise;
    }

    $scope.submit = function() {
        $scope.commentCollection = '';

        var promise = $scope.myParen('https://example.com/parents/1');

        promise.then(function(success) {
            var list = success;

            $http({
                method: 'GET',
                url: 'https://example.com/parents/1/children'
            })
            .success(function(data, status, headers, config) {
                $scope.commentCollection = list.concat(data);
            })
            .error(function(data, status, headers, config) {
                $scope.error = data;
            });
        }, function(error) {
            $scope.error = error;
        });
    };

}]);

测试,

describe('MyController Test', function() {

    beforeEach(module('RepoApp'));

    var controller, $scope, $http, $httpBackend, $q;
    var deferred;

    beforeEach(inject(function ($rootScope, $controller, $http, $httpBackend, $q) {

        $scope = $rootScope.$new();

        deferred = $q.defer();

        // Create the controller.
        controller = $controller;
        controller("MyController", {$scope, $http, $httpBackend, $q});
    }));

    it('should demonstrate using when (200 status)', inject(function($rootScope, $http, $httpBackend, $q) {

        var $scope = {};

        /* Code Under Test */
        $scope.myParen = function(url) {
            ...
        }

        $scope.submit = function() {
            ...
        };
        /* End */

        $scope.submit();

        deferred.promise.then(function (value) {

            $httpBackend.whenGET('https://example.com/parents/1/children', undefined, {})
            .respond(function(){ return [200,{foo: 'bar'}]});

            expect(value).toBe(4);
        });
        deferred.resolve(4);
        $rootScope.$apply();

        expect($scope.commentCollection).toEqual({foo: 'bar'});
    }));
});

结果失败,

Expected '' to equal { foo: 'bar' }.

有什么想法吗?

修改

....
deferred.resolve(4);
$rootScope.$apply();

$timeout.flush();
expect($scope.commentCollection).toEqual({foo: 'bar'});

2 个答案:

答案 0 :(得分:2)

1)在控制器中的setTimeout上切换$timeout

2)替换$httpBackend函数

中的所有beforeEach

3)使用.flush()函数

describe('MyController Test', function() {

beforeEach(module('app'));

var controller, $scope, $http, httpBackend, $q;
var deferred;

beforeEach(inject(function ($rootScope, $controller, $http, $httpBackend, $q) {

    $httpBackend
        .whenGET('https://example.com/parents/1', undefined, {})
        .respond(function(){ return [200, {parents: []}]});

    $httpBackend
        .whenGET('https://example.com/parents/1/children', undefined, {})
        .respond(function(){ return [200, {foo: 'bar'}]});

    $scope = $rootScope.$new();

    deferred = $q.defer();

    // Create the controller.
    controller = $controller;
    controller("MyController", {$scope: $scope, $http: $http, $httpBackend: $httpBackend, $q: $q});
}));

it('should demonstrate using when (200 status)', inject(function($httpBackend, $timeout) {

    // var $scope = {}; // don't write it, becouse you rewrite a scope which defined at beforeEach function
    $scope.submit();   
    //$httpBackend.flush(); // wait when backend return parents
    $timeout.flush(); // wait timeout in $scope.myParen 
    $httpBackend.flush(); // wait when backend return children

    expect($scope.commentCollection[0]).toEqual({parents: []});
    expect($scope.commentCollection[1]).toEqual({foo: 'bar'});
}));

});

答案 1 :(得分:1)

重新编写$scope.myParen函数以使用$timeout代替setTimeout

$scope.myParen = function(url) {

    var promise = $http({
        method: 'GET',
        url: url
    })
    .then (function(response) {
        var data = response.data;
        return $timeout(function(){return data;}, 1000);
    })
    .catch(function(response) {
        var data = response.data;
        return 
            ($timeout(angular.noop, 1000)
            ).then (function () {
                 throw data;
            });
    });

    return promise;
}

然后在测试中,您可以使用$timeout.flush()来同步刷新延迟函数的队列。

  

弃用通知

     

$ http遗留承诺方法successerror已被弃用。改为使用标准then方法。

     

- AngularJS $http Service API Reference -- deprecation notice