Angularjs Mocha在没有$ rootScope的情况下测试$ q承诺。$ apply

时间:2016-07-29 15:56:26

标签: angularjs mocha angular-promise chai karma-mocha

我有这项服务:

    angular.module('domeeApp')
        .factory('streamWidget', streamWidgetFactory);

    function streamWidgetFactory($q) {
        return {
            loadContent: function() { 
                return $q(function(resolve, reject) {
                    resolve('test');
                }) 
            }
        }
    }

我用karma / mocha / chai测试它:

describe('streamWidget', function() {
    beforeEach(module('domeeApp'));
    var streamWidget;
    var $timeout;

    beforeEach(inject(function(_$timeout_, _streamWidget_) {
        streamWidget = _streamWidget_;
        $timeout = _$timeout_;
    }));


    it('should load new content', function(done) {        
        streamWidget.loadContent()
        .then(function(res) {
            expect(res).to.equal('test');
            done();
        })
        .catch(function(){})
        $timeout.flush();
    });    
});

由于$ q承诺在跟随this answer之后不能与mocha一起使用,{{3}}表示添加$timeout.flush()以强制承诺的.then方法被执行。

问题是,在调用.flush()之后,我的所有应用程序都醒来了,我开始从角度模拟中得到这个错误:

Error: Unexpected request: GET /partials/page/view/index

我知道$ httpBackend,但是疯狂来模拟我的应用在启动时发出的所有请求。

有没有办法让$q承诺可以在不调用$timeout.flush()$rootScope.$apply()的情况下使用mocha?

2 个答案:

答案 0 :(得分:1)

如图here所示,chai-as-promised可用于声明$q承诺。 使用此设置

chaiAsPromised.transferPromiseness = function (assertion, promise) {
  assertion.then = promise.then.bind(promise);

  if (!('$$state' in promise))
    return;

  inject(function ($rootScope) {
    if (!$rootScope.$$phase)
      $rootScope.$digest();
  });
};

摘要周期将在promise断言上自动触发,执行整个promise链。

在这种情况下,规范

it('...', () => {
  ...
  expect(...).to.eventually...;
  expect(...).to.eventually...;
  $rootScope.$digest();
});

可以省略$digest()来电并成为

it('...', () => {
  ...
  expect(...).to.eventually...;
  expect(...).to.eventually...;
});

请注意,$q承诺是同步的,不应该从Mocha规范返回,也不应调用done回调。

答案 1 :(得分:0)

这是我们使用的另一种策略,因为我们从不实际上需要$httpBackend,但它有时(随机)无法对指令使用的模板进行请求(即使这些模板在$templateCache)中可用:

beforeEach(function() {
  module('app', function($provide) {
    // This is using jasmine, but the idea is the same with mocha.
    // Basically just replace $httpBackend with a function that does nothing.
    $provide.constant('$httpBackend', jasmine.createSpy('$httpBackend'));
  });
});

当然,如果您在其他情况下实际使用 $httpBackend,那么这将无法正常工作,因为您需要它来模拟响应对象。