Promises with $q and angular in karma, mocha & chai

南笙酒味 提交于 2019-12-13 02:12:53

问题


So i tried to get the promises to work in my angular app tests, can anyone figure out what im doing wrong here it keeps returning:

Error: timeout of 2000ms exceeded. Ensure the done() callback is being called in this test.

I don't know if it's $q.

FYI i also tried the it('test', function(done){... done();})

Controller

(function() {
    'use strict';

    angular
        .module('controller.editor', [])
        .controller('EditorController', EditorController);

    function EditorController($scope, $q) {
        var vm = this;

        angular.extend(vm, {
            hack: hack
        });

        function hack(bool) {
            return $q(function(resolve, reject) {
                if (bool) {
                    resolve(true);
                }

                reject(false);
            });
        }
    }
});

Test

describe('EditorController', function() {
    var vm, scope, $controller, $rootScope, $injector;

    beforeEach(function() {
        module('app');

        //Inject
        inject(function(_$injector_) {
            $injector = _$injector_;
            $controller = $injector.get('$controller');
            $rootScope = $injector.get('$rootScope');

            // Create new scope object
            scope = $rootScope.$new();

            // Bind the controller
            vm = $controller('EditorController', {
                $scope: scope
            });
        });
    });

    describe('#addCustom', function() {
        it('test', function(done) {
            var aHack = vm.hack(true);

            aHack.then(function(bool){
                // Resolve
                expect(bool).to.be.eq(true);
                done();
            }, function() {
                // Reject
                expect(bool).to.be.eq(false);
                done();
            });
        });
    });
});

回答1:


When testing promises in angular, it's a best practice to depend on angular machinery to do its job to resolve promises synchronously instead of asynchronously.

This makes the code easier to read and maintain.

It's also less error prone; doing assertions in .then() is an anti-pattern because if the callback is never called, your assertions will never run.

To use the angular way of testing, you should:

  1. remove done
  2. do $rootScope.$digest() in the test to resolve promises
  3. do your assertions

Applying this to your code would be:

describe('#addCustom', function() {
    it('test', function() {
        var __bool = false;
        var aHack = vm.hack(true).then(function(bool) {
            __bool = bool;
        });

        $rootScope.$digest();

        expect(__bool).to.be.eq(true);
    });
});

But it's tricky, because $rootScope.$digest resolves only $q promises, not all promises, particularly not the promises created via Promise() constructor from various es5 shims, see this:

Promise resolved too late in angularjs jasmine test

See also:

http://brianmcd.com/2014/03/27/a-tip-for-angular-unit-tests-with-promises.html




回答2:


The problem is that your Promise is resolved before you setup your 'then' behavior.

Take a look at these examples that all use a setTimeout.



来源:https://stackoverflow.com/questions/35180958/promises-with-q-and-angular-in-karma-mocha-chai

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!