我使用的浏览器Runner在摩卡运行一些异步测试,我试图用柴的期待风格断言:
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)
所以,这显然抓住了错误,它只是不正确显示它。 任何想法如何做到这一点? 我想我可以就叫“做”一个错误的对象,但后来我失去的东西像柴所有的优雅和它变得非常笨重...
Answer 1:
您的异步测试产生异常,对失败的expect()
ations,这是不能被捕捉it()
因为抛出异常之外it()
的范围。
你看到显示的捕获异常使用所拍摄的process.on('uncaughtException')
下的节点或使用window.onerror()
在浏览器中。
要解决这个问题,你需要捕捉称为异步函数中的异常setTimeout()
以调用done()
不同之处作为第一个参数。 您还需要调用done()
不带参数来表示成功,否则,因为你的测试功能绝不会暗示有人做过摩卡将报告超时错误:
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
}
}
在所有的测试用例这样做是烦人,不干燥,所以你可能想提供一个函数来为你做这个。 让我们把这个功能check()
function check( done, f ) {
try {
f();
done();
} catch( e ) {
done( e );
}
}
随着check()
你现在可以重写你的异步测试,如下所示:
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 );
}
}
Answer 2:
这里是我的ES6 / ES2015承诺和ES7 / ES2016异步通过的测试/等待。 希望这提供了人研究这个主题一个很好的更新答案:
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')
}))
})
Answer 3:
如果你喜欢许诺,尝试柴如许 + Q ,它允许这样的事情:
doSomethingAsync().should.eventually.equal("foo").notify(done);
Answer 4:
我问同样的事情在摩卡邮件列表。 他们基本上告诉我:写有摩卡和柴异步测试:
- 总是先从测试
if (err) done(err);
- 最终总是与测试
done()
。
它解决了我的问题,并没有改变我在中间代码(柴预期除其他)一行。 该setTimout
不进行异步测试的方式。
下面是在邮件列表链接的讨论 。
Answer 5:
我已经公布了解决此问题的一揽子。
首先安装check-chai
包:
npm install --save check-chai
然后在您的测试中,使用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');
});
});
});
每有没有办法让柴异步摩卡测试工作? 我发表以此为NPM包。
请参阅https://github.com/niftylettuce/check-chai以获取更多信息。
Answer 6:
尝试chaiAsPromised! 除了被命名为出色,你可以用这样的语句:
expect(asyncToResultingValue()).to.eventually.equal(true)
可以确认 ,都非常好,摩卡+柴。
https://github.com/domenic/chai-as-promised
Answer 7:
有很大关系和灵感让·文森特的回答 ,我们采用类似于他的一个辅助功能check
功能,但我们把它称为eventually
代替(这有助于它匹配了的命名约定柴作为-承诺)。 它返回一个函数,它接受任何数量的参数,并将其传递到原来的回调。 这有助于消除你的测试一个额外的嵌套功能块,并允许您处理任何类型的异步回调。 这是写在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");
});
});
Answer 8:
我知道有很多重复的答案和建议的软件包来解决这个,但是我还没有看到上面提供简单的解决方案,为两个用例的简明模式。 我张贴此作为其他一个统一的答案谁愿意复制面食:
事件回调
function expectEventCallback(done, fn) {
return function() {
try { fn(...arguments); }
catch(error) { return done(error); }
done();
};
}
节点样式的回调
function expectNodeCallback(done, fn) {
return function(err, ...args) {
if (err) { return done(err); }
try { fn(...args); }
catch(error) { return done(error); }
done();
};
}
例如使用
it('handles event callbacks', function(done) {
something.on('event', expectEventCallback(done, (payload) => {
expect(payload).to.have.propertry('foo');
}));
});
it('handles node callbacks', function(done) {
doSomething(expectNodeCallback(done, (payload) => {
expect(payload).to.have.propertry('foo');
}));
});
Answer 9:
基于由@richardforrester提供此链接http://staxmanade.com/2015/11/testing-asyncronous-code-with-mochajs-and-es7-async-await/ ,描述如果省略DONE可以使用返回无极参数。
唯一的缺点,必须有一个承诺在那里,没有任何异步功能(你可以用一个承诺,你把它包)。 但是,在这种情况下,代码可以极大地减小。
它考虑到失败从无论是在初始funcThatReturnsAPromise功能或期望:
it('should test Promises', function () { // <= done removed
return testee.funcThatReturnsAPromise({'name': 'value'}) // <= return added
.then(response => expect(response).to.have.property('ok', 1));
});
Answer 10:
我解决了它提取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);
});
});
它也可调试。
Answer 11:
在测试和异步定时器听起来很粗糙。 有一种方法并承诺为基础的方法来做到这一点。
const sendFormResp = async (obj) => {
const result = await web.chat.postMessage({
text: 'Hello world!',
});
return result
}
这个异步函数使用一个Web客户端(在这种情况下,西裤SDK)。 该SDK采用的API调用的异步性照顾,并返回一个有效载荷。 然后,我们可以通过运行测试寨内的有效载荷expect
侵害的对象在异步承诺返回。
describe("Slack Logic For Working Demo Environment", function (done) {
it("Should return an object", () => {
return sdkLogic.sendFormResp(testModels.workingModel).then(res => {
expect(res).to.be.a("Object");
})
})
});
Answer 12:
什么工作对我非常好ICM摩卡/柴来自兴农图书馆的fakeTimer。 只是在必要时提前计时器测试。
var sinon = require('sinon');
clock = sinon.useFakeTimers();
// Do whatever.
clock.tick( 30000 ); // Advances the JS clock 30 seconds.
具有测试完成更快的额外的奖励。
Answer 13:
您还可以使用域模块。 例如:
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
});
文章来源: Is there a way to get Chai working with asynchronous Mocha tests?