有没有办法让Chai与asynchronous摩卡testing一起工作?

我正在Mocha使用Browser Runner运行一些asynchronoustesting,我试图使用Chai的expect风格断言:

window.expect = chai.expect; describe('my test', function() { it('should do something', function (done) { setTimeout(function () { expect(true).to.equal(false); }, 100); } } 

这不会给我正常的失败的断言信息,而是我得到:

 Error: the string "Uncaught AssertionError: expected true to equal false" was thrown, throw an Error :) at Runner.fail (http://localhost:8000/tests/integration/mocha/vendor/mocha.js:3475:11) at Runner.uncaught (http://localhost:8000/tests/integration/mocha/vendor/mocha.js:3748:8) at uncaught (http://localhost:8000/tests/integration/mocha/vendor/mocha.js:3778:10) 

所以很明显,这个错误只是显示不正确。 任何想法如何做到这一点? 我想我可以用一个错误对象来调用“完成”,但是随后我失去了所有类似Chai的优雅,并且变得非常笨重。

你的asynchronoustesting会在expect()失败的时候产生一个exception, it()不能被it()捕获,因为这个exception被抛出it()的范围之外。

您看到显示的捕获exception使用process.on('uncaughtException')或在浏览器中使用window.onerror() process.on('uncaughtException')

为了解决这个问题,你需要在由setTimeout()调用的asynchronous函数中捕获exception,以便以exception作为第一个参数调用done() 。 你也需要调用done()而不用参数来指示成功,否则mocha会报告一个超时错误,因为你的testing函数永远不会发出已经完成的信号:

 window.expect = chai.expect; describe( 'my test', function() { it( 'should do something', function ( done ) { // done() is provided by it() to indicate asynchronous completion // call done() with no parameter to indicate that it() is done() and successful // or with an error to indicate that it() failed setTimeout( function () { // Called from the event loop, not it() // So only the event loop could capture uncaught exceptions from here try { expect( true ).to.equal( false ); done(); // success: call done with no parameter to indicate that it() is done() } catch( e ) { done( e ); // failure: call done with an error Object to indicate that it() failed } }, 100 ); // returns immediately after setting timeout // so it() can no longer catch exception happening asynchronously } } 

在所有的testing用例上这样做是烦人的,而不是干,所以你可能想提供一个函数来为你做这个。 我们来调用这个函数check()

 function check( done, f ) { try { f(); done(); } catch( e ) { done( e ); } } 

使用check()你现在可以重写你的asynchronoustesting,如下所示:

 window.expect = chai.expect; describe( 'my test', function() { it( 'should do something', function( done ) { setTimeout( function () { check( done, function() { expect( true ).to.equal( false ); } ); }, 100 ); } } 

如果你喜欢承诺,尝试柴作为承诺 + Q ,这允许这样的事情:

 doSomethingAsync().should.eventually.equal("foo").notify(done); 

这是我通过的testingES6 / ES2015承诺和ES7 / ES2016asynchronous/等待。 希望这为任何研究这个主题的人提供了一个很好的更新的答案:

 import { expect } from 'chai' describe('Mocha', () => { it('works synchronously', () => { expect(true).to.equal(true) }) it('works ansyncronously', done => { setTimeout(() => { expect(true).to.equal(true) done() }, 4) }) it('throws errors synchronously', () => { return true throw new Error('it works') }) it('throws errors ansyncronously', done => { setTimeout(() => { return done() done(new Error('it works')) }, 4) }) it('uses promises', () => { var testPromise = new Promise((resolve, reject) => { setTimeout(() => { resolve('Hello') }, 4) }) testPromise.then(result => { expect(result).to.equal('Hello') }, reason => { throw new Error(reason) }) }) it('uses es7 async/await', async (done) => { const testPromise = new Promise((resolve, reject) => { setTimeout(() => { resolve('Hello') }, 4) }) try { const result = await testPromise expect(result).to.equal('Hello') done() } catch(err) { done(err) } }) /* * Higher-order function for use with async/await (last test) */ const mochaAsync = fn => { return async (done) => { try { await fn() done() } catch (err) { done(err) } } } it('uses a higher order function wrap around async', mochaAsync(async () => { const testPromise = new Promise((resolve, reject) => { setTimeout(() => { resolve('Hello') }, 4) }) expect(await testPromise).to.equal('Hello') })) }) 

我在Mocha的邮件列表中询问了同样的事情。 他们基本上是这样告诉我的:用摩卡和柴编写asynchronoustesting:

  • 总是用if (err) done(err);开始testingif (err) done(err);
  • 总是用done()结束testing。

它解决了我的问题,并没有改变我的代码之间的单行(柴期望等)。 setTimout不是做asynchronoustesting的方法。

这里是邮件列表中讨论的链接 。

我已经发布了一个解决这个问题的包。

首先安装check-chai包:

npm install --save check-chai

然后在你的testing中,使用chai.use(checkChai); 然后使用chai.check帮助函数,如下所示:

 var chai = require('chai'); var dirtyChai = require('dirty-chai'); var checkChai = require('check-chai'); var expect = chai.expect; chai.use(dirtyChai); chai.use(checkChai); describe('test', function() { it('should do something', function(done) { // imagine you have some API call here // and it returns (err, res, body) var err = null; var res = {}; var body = {}; chai.check(done, function() { expect(err).to.be.a('null'); expect(res).to.be.an('object'); expect(body).to.be.an('object'); }); }); }); 

Per 有没有办法让Chai和asynchronous摩卡testing一起工作? 我把它作为NPM包发布。

有关更多信息,请参阅https://github.com/niftylettuce/check-chai

与Jean Vincent的回答非常相关,我们采用了类似于他的checkfunction的帮助函数,但是我们eventually调用它(这有助于它与chai-as-promised的命名约定匹配)。 它返回一个函数,它接受任意数量的参数并将它们传递给原始的callback函数。 这有助于消除testing中的额外嵌套function块,并允许您处理任何types的asynchronouscallback。 这里是在ES2015中写的:

 function eventually(done, fn) { return (...args) => { try { fn(...args); done(); } catch (err) { done(err); } }; }; 

用法示例:

 describe("my async test", function() { it("should fail", function(done) { setTimeout(eventually(done, (param1, param2) => { assert.equal(param1, "foo"); // this should pass assert.equal(param2, "bogus"); // this should fail }), 100, "foo", "bar"); }); }); 

基于@richardforrester http://staxmanade.com/2015/11/testing-asyncronous-code-with-mochajs-and-es7-async-await/提供的链接,如果您省略完成,describe可以使用返回的Promise参数。;

唯一的缺点是必须有一个承诺,没有任何asynchronousfunction(你可以包装一个承诺,你)。 但在这种情况下,代码可以被极大地减less。

它考虑到来自最初的funcThatReturnsAPromise函数或期望的失败:

 it('should test Promises', function () { // <= done removed return testee.funcThatReturnsAPromise({'name': 'value'}) // <= return added .then(response => expect(response).to.have.property('ok', 1)); }); 

我解决了它提取try/catch函数。

 function asyncExpect(test, done){ try{ test(); done(); } catch(error){ done(error); } } 

然后在it()我打电话:

 it('shall update a host', function (done) { testee.insertHost({_id: 'host_id'}) .then(response => { asyncExpect(() => { expect(response).to.have.property('ok', 1); expect(response).to.have.property('nModified', 1); }, done); }); }); 

这也是可debugging的。

尝试chaiAsPromised! 除了出色的命名,你可以使用像这样的语句:

expect(asyncToResultingValue()).to.eventually.equal(true)

可以确认 ,摩卡+柴的效果非常好。

https://github.com/domenic/chai-as-promised

对我来说非常好的工作icm Mocha / Chai是来自Sinon图书馆的假定时器。 只要有必要就在testing中提前计时器。

 var sinon = require('sinon'); clock = sinon.useFakeTimers(); // Do whatever. clock.tick( 30000 ); // Advances the JS clock 30 seconds. 

有更多的testing完成更快的奖金。

你也可以使用域模块。 例如:

 var domain = require('domain').create(); domain.run(function() { // place you code here }); domain.on('error',function(error){ // do something with error or simply print it });