在调用 beforeEach() 之前异步 beforeAll() 未完成

Async beforeAll() does not finish before beforeEach() is called

在 Jest 中,beforeAll() 应该在 beforeEach() 之前 运行。

问题是,当我为 beforeAll() 使用异步回调时,Jest 在继续 beforeEach().

之前不会等待回调完成

如何强制 Jest 在继续 beforeEach() 之前等待异步 beforeAll() 回调完成?

最小的可重现示例

tests/myTest.test.js

const connectToMongo = require('../my_async_callback')    

// This uses an async callback.
beforeAll(connectToMongo) 

// This is entered before the beforeAll block finishes. =,(
beforeEach(() => { 
  console.log('entered body of beforeEach')  
}

test('t1'), () => {
  expect(1).toBe(1)
}
test('t2'), () => {
  expect(2+2).toBe(4)
}
test('t3'), () => {
  expect(3+3+3).toBe(9)
}

my_async_callback.js

const connectToMongo = async () => {
  try {
    await mongoose.connect(config.MONGODB_URI, { 
      useNewUrlParser: true, 
      useUnifiedTopology: true, 
      useFindAndModify: false, 
      useCreateIndex: true 
    })
    console.log('Connected to MongoDB')
  } catch (err) {
    console.log(`Error connecting to MongoDB: ${err.message}`)
  }
}

module.exports = connectToMongo

更新: 正如已接受的答案有用地指出的那样,Jest 实际上会等待 beforeAll 首先完成,除非 Promise 链损坏或暂停。所以,我的问题的前提是错误的。我的 connectToMongo 函数超时,只需增加 Jest 超时即可解决问题。

connectToMongo函数是一个async函数,不是async callback(有一个函数作为参数的async函数???)

beforeEach 将在 beforeAll 完成时调用,它仍然有效。

beforeAll(connectToMongo) 将在您调用后立即完成,这意味着它不会等到数据库连接成功。

等到 connectToMongo 完成并继续:

beforeAll(async () => { // async function
    await connectToMongo() // wait until connected to db
}) 

如果有异步函数和回调你可以调用完成。如果你想在异步函数中传递回调你是免费的!

让我告诉你;

beforeAll(async (done) => {
  await connectToMongo().catch(done) // if there is error it finish with error payload
  done(); // it says i am finish. also you can use it on your callback function to say i am done.
})

The problem is that when I use an async callback for beforeAll(), Jest doesn't wait for the callback to finish before going on to beforeEach().

How can I force Jest to wait for an async beforeAll() callback to finish before proceeding to beforeEach()?

TLDR

简短的回答是 Jest 确实 等待异步 beforeAll() 回调完成,然后再继续 beforeEach()

这意味着如果 beforeEach()beforeAll() 中应该 运行 的东西之前 运行ning 那么 Promise 链必须被打破或者 beforeAll功能超时。


Jest 中的队列运行器

与测试相关的所有 beforeAllbeforeEachtestafterEachafterAll 函数都收集在 queueableFns 中并链接 on these lines in queueRunner.ts:

  const result = options.queueableFns.reduce(
    (promise, fn) => promise.then(() => mapper(fn)),
    Promise.resolve(),
  );

所以 Jest 从一个已解决的 Promise 开始,并按顺序将每个函数链接到具有 .then 的 Promise 链。


可以通过以下测试看到此行为:

const order = [];

// first beforeAll with async function
beforeAll(async () => {
  order.push(1);
  await new Promise((resolve) => { setTimeout(resolve, 1000); });
  order.push(2);
});

// first beforeEach with done callback
beforeEach(done => {
  order.push(4);
  setTimeout(() => {
    order.push(6);
    done();
  }, 1000);
  order.push(5);
});

// second beforeEach
beforeEach(() => {
  order.push(7);
});

// second beforeAll
beforeAll(() => {
  order.push(3);
});

it("should run in order", () => {
  expect(order).toEqual([1, 2, 3, 4, 5, 6, 7]);  // SUCCESS!
});


破碎的承诺链

如果 beforeEachbeforeAll 中应该 运行 的东西之前 运行ning 那么 Promise 链可能被破坏了:

const order = [];

// does not return Promise and will break the Promise chain
const func = () => {
  setTimeout(() => { order.push(2); }, 1000);
}

const asyncFunc = async () => {
  order.push(1);
  await func();  // doesn't actually wait for 2 to be pushed
  order.push(3);
}

beforeAll(asyncFunc);

beforeEach(() => {
  order.push(4);
});

it("should run in order", () => {
  expect(order).toEqual([1, 2, 3, 4]);  // FAIL: [1, 3, 4]
});

超时

...或者超时(注意Jest会在输出中报告超时):

const order = [];

jest.setTimeout(100);  // 100ms timeout

const asyncFunc = async () => {
  order.push(1);
  await new Promise(resolve => { setTimeout(resolve, 1000); });  // times out
  order.push(2);
}

beforeAll(asyncFunc);

beforeEach(() => {
  order.push(3);
});

it("should run in order", () => {
  expect(order).toEqual([1, 2, 3]);  // FAIL: [1, 3] and Timeout error
});