异步 beforeAll() 在 beforeEach() 被调用之前没有完成

Ask*_*ker 5 asynchronous control-flow node.js promise jestjs

在 Jest 中,beforeAll()应该在beforeEach().

问题是,当我对 使用异步回调时beforeAll(),Jest 在继续之前不会等待回调完成beforeEach()

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

最小的可重复示例

测试/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)
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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

Bri*_*ams 14

问题是,当我使用异步回调时beforeAll(),Jest 不会等待回调完成后再继续beforeEach()

如何强制 Jest 等待异步beforeAll()回调完成后再继续beforeEach()

总长DR

简短的回答是,Jest在继续之前等待异步beforeAll()回调完成beforeEach()

这意味着如果在beforeEach()应该运行的东西之前运行,beforeAll()那么 Promise 链必须被破坏或者beforeAll函数超时。


笑话中的队列跑者

与测试相关的所有beforeAll, beforeEach, test, afterEach,函数都收集在queueRunner.ts中的这些行中并链接在其中:afterAllqueueableFns

  const result = options.queueableFns.reduce(
    (promise, fn) => promise.then(() => mapper(fn)),
    Promise.resolve(),
  );
Run Code Online (Sandbox Code Playgroud)

因此,Jest 从一个已解决的 Promise 开始,并按顺序将每个函数链接到带有 的 Promise 链.then


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

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!
});

Run Code Online (Sandbox Code Playgroud)

破碎的承诺链

如果beforeEach在应该运行的东西之前运行,beforeAll那么 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]
});
Run Code Online (Sandbox Code Playgroud)

暂停

...或者存在超时(请注意,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
});
Run Code Online (Sandbox Code Playgroud)