I'm trying to test a service that I build which uses Angular's $q implementation of Promises. I'm using a combination of Karma, Mocha, Chai, Sinon, Sinon Chai and Chai as Promised.
我正在尝试测试我构建的服务,该服务使用Angular的$ q Promise实现。我正在使用Karma,Mocha,Chai,Sinon,Sinon Chai和Chai的组合作为承诺。
All the tests that I wrote and return promises are passing but the ones that reject or uses $q.all([ ... ])
. I have tried all I could think of but I cannot seem to find where the issue is.
我写的所有测试和返回的承诺都是通过但拒绝或使用$ q.all([...])的那些。我已经尝试了所有我能想到的但是我似乎无法找到问题所在。
The following is a slim version of what I am testing:
以下是我正在测试的超薄版本:
"use strict";
describe("Promise", function () {
var $rootScope,
$scope,
$q;
beforeEach(angular.mock.inject(function (_$rootScope_, _$q_) {
$rootScope = _$rootScope_;
$q = _$q_;
$scope = $rootScope.$new();
}));
afterEach(function () {
$scope.$apply();
});
it("should resolve promise and eventually return", function () {
var defer = $q.defer();
defer.resolve("incredible, this doesn't work at all");
return defer.promise.should.eventually.deep.equal("incredible, this doesn't work at all");
});
it("should resolve promises as expected", function () {
var fst = $q.defer(),
snd = $q.defer();
fst
.promise
.then(function (value) {
value.should.eql("phew, this works");
});
snd
.promise
.then(function (value) {
value.should.eql("wow, this works as well");
});
fst.resolve("phew, this works");
snd.resolve("wow, this works as well");
var all = $q.all([
fst.promise,
snd.promise
]);
return all.should.be.fullfiled;
});
it("should reject promise and eventually return", function () {
return $q.reject("no way, this doesn't work either?").should.eventually.deep.equal("no way, this doesn't work either?");
});
it("should reject promises as expected", function () {
var promise = $q.reject("sadly I failed for some stupid reason");
promise
["catch"](function (reason) {
reason.should.eql("sadly I failed for some stupid reason");
});
var all = $q.all([
promise
]);
return all.should.be.rejected;
});
});
The 3rd, last and the first test are the ones that fail. Actually it does not fail, it just resolves after the timeout is exceeded and I get a Error: timeout of 2000ms exceeded
.
第3次,最后一次和第一次测试是失败的。实际上它没有失败,它只是在超过超时后才解决,我得到一个错误:超过2000ms的超时。
EDIT: I have just tried to test with Kris Kowal's implementation of the promises and it works just fine with that.
编辑:我刚刚尝试用Kris Kowal的承诺进行测试,它的工作原理很好。
P.S. I actually found that there is some time spent somewhere in the bowls of either Mocha, Chai or Chai As Promised and the afterEach
hook gets called later than the timeout.
附:我实际上发现在Mocha,Chai或Chai As Promised的碗里花了一些时间,并且afterMach钩子在超时之后被调用。
2 个解决方案
#1
13
afterEach()
is used for cleanup, not for executing code after your preparations but before your tests. $scope.$apply()
is not cleanup either.
afterEach()用于清理,而不是在准备之后但在测试之前执行代码。 $ scope。$ apply()也不是清理。
You need to be doing the following:
您需要执行以下操作:
// setup async behavior
var all = $q.all(x.promise, y.promise)
// resolve your deferreds/promises
x.reject(); y.reject();
// call $scope.$apply() to 'digest' all the promises
$scope.$apply();
// test the results
return all.should.be.rejected;
You're doing an $apply()
AFTER your tests are done, not in between setup and evaluation.
您在测试完成后进行$ apply(),而不是在设置和评估之间。
#2
3
I've tried to find out why the tests are not passing even though at first glance they should. Of course I would have to move the $scope.$apply();
from afterEach
since that is not the place to call as @proloser mentioned.
我试图找出为什么测试没有通过,即使乍一看他们应该。当然我必须移动$ scope。$ apply();来自afterEach,因为那不是@proloser提到的地方。
Even though I have done that, the tests are still not passing. I've also opened issues on chai-as-promised and angular to see if I get any input/feedback and I've actually been told that it's most likely not to work. The reason is probably because of Angular $q
's dependency on the digest phase which is not accounted for in the chai-as-promsied library.
即使我已经这样做了,测试仍然没有通过。我还开了关于chai-as-promise和angular的问题,看看我是否得到任何输入/反馈,我实际上被告知它最有可能不起作用。原因可能是因为Angular $ q依赖于摘要阶段,这在chai-as-promsied库中没有考虑到。
Therefore I've checked the tests with Q instead of $q and it worked just fine, thus strengthening my hypothesis that the fault was not in the chai-as-promised library.
因此,我用Q而不是$ q检查了测试,它运行得很好,从而加强了我的假设,即故障不在chai-as-promise库中。
I've eventually dropped chai-as-promised and I've rewritten my test using Mocha's done
callback instead (even though behind the scenes, chai-as-promised does the same):
我最终放弃了chai-as-promise,我用摩卡的完成回调改写了我的测试(即使在幕后,chai-as-promise也是如此):
"use strict";
describe("Promise", function () {
var $rootScope,
$scope,
$q;
beforeEach(angular.mock.inject(function (_$rootScope_, _$q_) {
$rootScope = _$rootScope_;
$q = _$q_;
$scope = $rootScope.$new();
}));
it("should resolve promise and eventually return", function (done) {
var defer = $q.defer();
defer
.promise
.then(function (value) {
value.should.eql("incredible, this doesn't work at all");
done();
});
defer.resolve("incredible, this doesn't work at all");
$scope.$apply();
});
it("should resolve promises as expected", function (done) {
var fst = $q.defer(),
snd = $q.defer();
fst
.promise
.then(function (value) {
value.should.eql("phew, this works");
});
snd
.promise
.then(function (value) {
value.should.eql("wow, this works as well");
});
fst.resolve("phew, this works");
snd.resolve("wow, this works as well");
var all = $q.all([
fst.promise,
snd.promise
]);
all
.then(function () {
done();
});
$scope.$apply();
});
it("should reject promise and eventually return", function (done) {
$q
.reject("no way, this doesn't work either?")
.catch(function (value) {
value.should.eql("no way, this doesn't work either?");
done();
});
$scope.$apply();
});
it("should reject promises as expected", function (done) {
var promise = $q.reject("sadly I failed for some stupid reason");
promise
["catch"](function (reason) {
reason.should.eql("sadly I failed for some stupid reason");
});
var all = $q.all([
promise
]);
all
.catch(function () {
done();
});
$scope.$apply();
});
});
The above tests will all pass as expected. There might be other ways to do it, but I could not figure out how else, so if anyone else does, it would be great to have it posted so others can benefit from it.
上述测试将按预期通过。可能还有其他方法可以做到这一点,但我无法弄清楚其他方面,所以如果其他人这样做,那么将其发布以便其他人可以从中受益将会很棒。
#1
13
afterEach()
is used for cleanup, not for executing code after your preparations but before your tests. $scope.$apply()
is not cleanup either.
afterEach()用于清理,而不是在准备之后但在测试之前执行代码。 $ scope。$ apply()也不是清理。
You need to be doing the following:
您需要执行以下操作:
// setup async behavior
var all = $q.all(x.promise, y.promise)
// resolve your deferreds/promises
x.reject(); y.reject();
// call $scope.$apply() to 'digest' all the promises
$scope.$apply();
// test the results
return all.should.be.rejected;
You're doing an $apply()
AFTER your tests are done, not in between setup and evaluation.
您在测试完成后进行$ apply(),而不是在设置和评估之间。
#2
3
I've tried to find out why the tests are not passing even though at first glance they should. Of course I would have to move the $scope.$apply();
from afterEach
since that is not the place to call as @proloser mentioned.
我试图找出为什么测试没有通过,即使乍一看他们应该。当然我必须移动$ scope。$ apply();来自afterEach,因为那不是@proloser提到的地方。
Even though I have done that, the tests are still not passing. I've also opened issues on chai-as-promised and angular to see if I get any input/feedback and I've actually been told that it's most likely not to work. The reason is probably because of Angular $q
's dependency on the digest phase which is not accounted for in the chai-as-promsied library.
即使我已经这样做了,测试仍然没有通过。我还开了关于chai-as-promise和angular的问题,看看我是否得到任何输入/反馈,我实际上被告知它最有可能不起作用。原因可能是因为Angular $ q依赖于摘要阶段,这在chai-as-promsied库中没有考虑到。
Therefore I've checked the tests with Q instead of $q and it worked just fine, thus strengthening my hypothesis that the fault was not in the chai-as-promised library.
因此,我用Q而不是$ q检查了测试,它运行得很好,从而加强了我的假设,即故障不在chai-as-promise库中。
I've eventually dropped chai-as-promised and I've rewritten my test using Mocha's done
callback instead (even though behind the scenes, chai-as-promised does the same):
我最终放弃了chai-as-promise,我用摩卡的完成回调改写了我的测试(即使在幕后,chai-as-promise也是如此):
"use strict";
describe("Promise", function () {
var $rootScope,
$scope,
$q;
beforeEach(angular.mock.inject(function (_$rootScope_, _$q_) {
$rootScope = _$rootScope_;
$q = _$q_;
$scope = $rootScope.$new();
}));
it("should resolve promise and eventually return", function (done) {
var defer = $q.defer();
defer
.promise
.then(function (value) {
value.should.eql("incredible, this doesn't work at all");
done();
});
defer.resolve("incredible, this doesn't work at all");
$scope.$apply();
});
it("should resolve promises as expected", function (done) {
var fst = $q.defer(),
snd = $q.defer();
fst
.promise
.then(function (value) {
value.should.eql("phew, this works");
});
snd
.promise
.then(function (value) {
value.should.eql("wow, this works as well");
});
fst.resolve("phew, this works");
snd.resolve("wow, this works as well");
var all = $q.all([
fst.promise,
snd.promise
]);
all
.then(function () {
done();
});
$scope.$apply();
});
it("should reject promise and eventually return", function (done) {
$q
.reject("no way, this doesn't work either?")
.catch(function (value) {
value.should.eql("no way, this doesn't work either?");
done();
});
$scope.$apply();
});
it("should reject promises as expected", function (done) {
var promise = $q.reject("sadly I failed for some stupid reason");
promise
["catch"](function (reason) {
reason.should.eql("sadly I failed for some stupid reason");
});
var all = $q.all([
promise
]);
all
.catch(function () {
done();
});
$scope.$apply();
});
});
The above tests will all pass as expected. There might be other ways to do it, but I could not figure out how else, so if anyone else does, it would be great to have it posted so others can benefit from it.
上述测试将按预期通过。可能还有其他方法可以做到这一点,但我无法弄清楚其他方面,所以如果其他人这样做,那么将其发布以便其他人可以从中受益将会很棒。