简体   繁体   English

mocha done() 和 async await 的矛盾问题

[英]Paradoxical issue with mocha done() and async await

I have the following test case:我有以下测试用例:

it("should pass the test", async function (done) {
        await asyncFunction();
        true.should.eq(true);
        done();
    });

Running it asserts:运行它断言:

Error: Resolution method is overspecified.错误:解析方法被过度指定。 Specify a callback or return a Promise;指定回调返回 Promise; not both.不是都。

And if I remove the done();如果我删除done(); statement, it asserts:声明,它断言:

Error: Timeout of 2000ms exceeded.错误:超过 2000 毫秒超时。 For async tests and hooks, ensure "done()" is called;对于异步测试和钩子,确保调用“done()”; if returning a Promise, ensure it resolves.如果返回 Promise,请确保它已解决。

How to solve this paradox?如何解决这个悖论?

You need to remove the done parameter as well, not just the call to it.您还需要删除done参数,而不仅仅是对它的调用。 Testing frameworks like Mocha look at the function's parameter list (or at least its arity) to know whether you're using done or similar.像 Mocha 这样的测试框架会查看函数的参数列表(或至少是它的 arity),以了解您使用的done还是类似的。

Using Mocha 3.5.3, this works for me (had to change true.should.be(true) to assert.ok(true) as the former threw an error):使用 Mocha 3.5.3,这对我true.should.be(true) (必须将true.should.be(true)更改为assert.ok(true)因为前者抛出错误):

const assert = require('assert');

function asyncFunction() {
    return new Promise(resolve => {
        setTimeout(resolve, 10);
    });
}

describe('Container', function() {
  describe('Foo', function() {
    it("should pass the test", async function () {
        await asyncFunction();
        assert.ok(true);
    });
  });
});

But if I add done :但如果我添加done

describe('Container', function() {
  describe('Foo', function() {
    it("should pass the test", async function (done) {  // <==== Here
        await asyncFunction();
        assert.ok(true);
    });
  });
});

...then I get ...然后我得到

Error: Timeout of 2000ms exceeded.错误:超过 2000 毫秒超时。 For async tests and hooks, ensure "done()" is called;对于异步测试和钩子,确保调用“done()”; if returning a Promise, ensure it resolves.如果返回 Promise,请确保它已解决。

Removing done as a param from it worked for me!从它的参数中删除 done 对我有用! Instead only use expect/should.而是只使用期望/应该。 Example is as follows:示例如下:

getResponse(unitData, function callBack(unit, error, data){ try {
    return request.post(unit, function (err, resp) {
        if (!err && resp.statusCode === 200) {
            if (resp.body.error) {
                return callback(obj, JSON.stringify(resp.body.error), null); 
            }
            return callback(obj, null, resp); 
        } else {
            if (err == null) {  
                err = { statusCode: resp.statusCode, error: 'Error occured.' };
            }
            return callback(obj, err, null); 
        }
    });
} catch (err) {
    return callback(obj, err, null);
}}

BEFORE:前:

it('receives successful response', async (done) => { 
const getSomeData = await getResponse(unitData, function callBack(unit, error, data){ 
    expect(data.statusCode).to.be.equal(200); 
    done(); 
}) })

AFTER (works):之后(作品):

it('receives successful response', async () => { 
const getSomeData = await getResponse(unitData, function callBack(unit, error, data){
     expect(data.statusCode).to.be.equal(200); 
}) })

Sometimes there are cases you need to use async/await + done function in mocha.有时候有些情况你需要在 mocha 中使用async/await + done函数。

For example, in one of my socket.io unit test cases, I have to call db functions with async functions and test socket event handlers which are callback functions:例如,在我的socket.io单元测试用例之一中,我必须使用异步函数和测试套接字事件处理程序调用 db 函数,这些函数是回调函数:

context("on INIT_CHAT", ()=> {
  it("should create a room", async (done) => {
    const user = await factory.create("User");
    socket.emit("INIT_CHAT", user);
    
    socket.on("JOIN_CHAT", async (roomId) => {
       const room = await ChatRoom.findByPk(roomId);
       expect(room).to.exist;
       // then I need to close a test case here
       done();
    });
  });
});

This will causes the exact same error as in the OP:这将导致与 OP 完全相同的错误:

Error: Resolution method is overspecified.错误:解析方法被过度指定。 Specify a callback or return a Promise;指定回调或返回 Promise; not both.不是都。

My Workaround:我的解决方法:

I just wrapped the entire test code in a promise generator:我只是将整个测试代码包装在一个 Promise 生成器中:

context("on INIT_CHAT", ()=> {
  it("should create a room", async () => {
    const asyncWrapper = () => {
      return new Promise(async (resolve) => {
        const user = await factory.create("User");
        socket.emit("INIT_CHAT", user);
        socket.on("JOIN_CHAT", async (roomId) => {
          const room = await ChatRoom.findByPk(roomId);
          expect(room).to.exist;
          resolve(true);
        });
      });
    });
    await asyncWrapper();
  });
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM