javascript - AngularJS 在事件处理程序(Jasmine)之后使用异步请求测试 Controller

标签 javascript angularjs asynchronous jasmine

我有一个 Controller :

myApp.controller('someCtrl', function ($scope, myAsyncService, $routeParams) {

    var foo_id = $routeParams.foo_id;

    $scope.foo = 0;
    $scope.bar = false;

    $scope.$on('that_happened',
        function (event, plan) {
            myAsyncService.save({id: foo_id}).$promise.then(function (res) {
                $scope.bar = true;
                $location.path('/foo/' + res.id);
            });
        }
    );

});

发出“that_hapend”事件后,服务调用异步方法,我想测试执行回调后更改的 $scope 和位置:

describe('my module', function () {
    var res_mock = 2,

        myAsyncService_mock = {
            save: function () {}
        };


    describe('someCtrl', function(){
        var $location,
            $scope,
            $subscope,
            deferred,
            promise_mock,
            ctrl,
            $q;

        beforeEach(
            inject(function ($rootScope, _$location_, _$q_) {
                $q = _$q_;

                $location = _$location_;
                $scope = $rootScope.$new();
                $subscope = $scope.$new();

                deferred = $q.defer();
                promise_mock = {
                    $promise: deferred.promise
                };


                spyOn(myAsyncService_mock, 'save').andReturn(promise_mock);

                ctrl = $controller('someCtrl',
                    {
                        $scope: $scope,
                        $location: $location,
                        myAsyncService: myAsyncService_mock
                    }
                );

            })
        );


        it('should call save method of service and set bar to true and goto /foo/:saved_foo.id ', function () {

            var saved_foo_mock = {
                    id: 3
                }

            $scope.foo = 11;
            $scope.bar = false;

            $subscope.$emit('that_happened');
            deferred.resolve(saved_foo_mock);

            expect(myAsyncService_mock.save).toHaveBeenCalled();
            expect($scope.bar).toBe(true);
            expect($location.path()).toBe('/foo/' + saved_foo_mock.id);

        });

    });

});

但是测试失败并出现错误“预期 false 为 true”。看起来promise回调没有执行或者是在expect()之后执行的;

我尝试以异步方式测试它,但结果是相同的 - 测试失败并超时:

runs(function () {
    $scope.bar = false;
    $subscope.$emit('that_happened');
});

waitsFor(function () {
    deferred.resolve(saved_foo_mock);
    return $scope.bar;
}, 'bar should be true', 500);

runs(function () {
    expect(myAsyncService_mock.save).toHaveBeenCalled();
    expect($location.path()).toBe('/foo/' + saved_foo_mock.id);                
});

发生什么事了?为什么$scope和位置路径没有改变?

最佳答案

这个问题帮助了我:How to test with Jasmine an AngularJS controller that calls service method that returns promise

将 myAsyncService_mock 移至 beforeEach block 并添加 $scope.$digest 调用,最后它起作用了:

beforeEach(
    inject(function ($rootScope, _$location_, _$q_) {
        .
        .
        .

        myAsyncService_mock = {
            save: function () {
                deferred = $q.defer();
                promise_mock = {
                    $promise: deferred.promise
                };    

                return promise_mock;
            }
        };

        .
        .
        .
    })
);


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

    $subscope.$emit('that_happened');
    deferred.resolve(saved_foo_mock);    

    $scope.$digest();

    .
    .
    .
})

关于javascript - AngularJS 在事件处理程序(Jasmine)之后使用异步请求测试 Controller ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19930261/

相关文章:

angularjs - 如何找到 ng-repeat 中的最小值?

javascript - Three.js 渲染器是否克隆对象位置?

javascript - 使用 splice 在 Angular JS 中“取消编辑”

javascript - 使用 Emscripten 将 JavaScript 字符串数组传递给 C 函数

javascript - 带有复杂 JSON 对象的嵌套 ngRepeat

c# - 在异步操作中锁定对象

javascript - Selenium:如何在 javascript 比较中使用存储值

javascript - AngularJS 禁用 2 路绑定(bind)

c# - 异步/等待执行差异

c# - 在 MVC3 应用程序中为异步处理程序保留依赖注入(inject)对象