【问题标题】:Asynchronous Issues with JEST and MongoDBJEST 和 MongoDB 的异步问题
【发布时间】:2019-03-28 02:16:56
【问题描述】:

当我尝试使用 beforeEach() Hook 从 MongoDB 集合中删除项目时,我得到的结果与 JEST 不一致。

我的 Mongoose 架构和模型定义为:

// Define Mongoose wafer sort schema
const waferSchema = new mongoose.Schema({
  productType: {
    type: String,
    required: true,
    enum: ['A', 'B'],
  },
  updated: {
    type: Date,
    default: Date.now,
    index: true,
  },
  waferId: {
    type: String,
    required: true,
    trim: true,
    minlength: 7,
  },
  sublotId: {
    type: String,
    required: true,
    trim: true,
    minlength: 7,
  },
}

// Define unique key for the schema
const Wafer = mongoose.model('Wafer', waferSchema);
module.exports.Wafer = Wafer;

我的 JEST 测试:

describe('API: /WT', () => {
  // Happy Path for Posting Object
  let wtEntry = {};

  beforeEach(async () => {
    wtEntry = {
      productType: 'A',
      waferId: 'A01A001.3',
      sublotId: 'A01A001.1',
    };
    await Wafer.deleteMany({});
    // I also tried to pass in done and then call done() after the delete
  });

  describe('GET /:id', () => {
    it('Return Wafer Sort Entry with specified ID', async () => {
      // Create a new wafer Entry and Save it to the DB
      const wafer = new Wafer(wtEntry);
      await wafer.save();

      const res = await request(apiServer).get(`/WT/${wafer.id}`);
      expect(res.status).toBe(200);
      expect(res.body).toHaveProperty('productType', 'A');
      expect(res.body).toHaveProperty('waferId', 'A01A001.3');
      expect(res.body).toHaveProperty('sublotId', 'A01A001.1');
    });
}

所以当我多次运行测试时,我总是得到的错误与重复键有关: MongoError: E11000 重复键错误集合:promis_tests.promiswts 索引:waferId_1_sublotId_1 dup key: { : "A01A001.3", : "A01A001.1" }

但我不明白如果 beforeEach() 正确触发,我怎么会得到这个重复的键错误。我是否试图不正确地清除集合?我尝试将 done 元素传递给每个回调之前,并在 delete 命令之后调用它。我还尝试在 beforeAll()、afterEach() 和 afterAll() 中实现删除,但仍然得到不一致的结果。我对这个很困惑。我可能只是一起删除了模式键,但我想了解 beforeEach() 发生了什么。提前感谢您的任何建议。

【问题讨论】:

  • Using mongoose.connection.collections.wafers.drop(() => { // 准备运行下一个测试!done(); });代替 await Wafer.deleteMany({}) 似乎更可靠,但仍然经常抛出重复键错误。

标签: mongodb express mongoose jestjs


【解决方案1】:

这可能是因为您实际上并没有使用 mongoose 提供的 promise API。默认情况下,像 deleteMany() 这样的猫鼬函数不返回承诺。您必须在函数链的末尾调用.exec() 才能返回一个承诺e.g. await collection.deleteMany({}).exec()。所以你遇到了竞争条件。 deleteMany() 也接受回调,所以你总是可以将它包装在一个 Promise 中。我会这样做:

describe('API: /WT', () => {
  // Happy Path for Posting Object
  const wtEntry = {
    productType: 'A',
    waferId: 'A01A001.3',
    sublotId: 'A01A001.1',
  };

  beforeEach(async () => {
    await Wafer.deleteMany({}).exec();
  });

  describe('GET /:id', () => {
    it('Return Wafer Sort Entry with specified ID', async () => {
      expect.assertions(4);
      // Create a new wafer Entry and Save it to the DB
      const wafer = await Wafer.create(wtEntry);

      const res = await request(apiServer).get(`/WT/${wafer.id}`);
      expect(res.status).toBe(200);
      expect(res.body).toHaveProperty('productType', 'A');
      expect(res.body).toHaveProperty('waferId', 'A01A001.3');
      expect(res.body).toHaveProperty('sublotId', 'A01A001.1');
    });
}

另外,总是期待带有异步代码的断言 https://jestjs.io/docs/en/asynchronous.html

您可以在此处阅读有关 mongoose 承诺和查询对象的更多信息 https://mongoosejs.com/docs/promises.html

【讨论】:

  • 是的,deletemany() 没有返回承诺是问题所在。我想我只是假设它像许多其他猫鼬方法一样返回了一个承诺。该死。再次感谢!我很高兴知道这里发生了什么。
  • 你打赌!我很高兴能帮上忙
【解决方案2】:

在不删除架构索引的情况下,这似乎是最可靠的解决方案。不是 100% 确定为什么它可以通过异步 await Wafer.deleteMany({});

beforeEach((done) => {
    wtEntry = {
      productType: 'A',
      waferId: 'A01A001.3',
      sublotId: 'A01A001.1',
    };
    mongoose.connection.collections.promiswts.drop(() => {
      // Run the next test!
      done();
    });
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-26
    • 1970-01-01
    • 2018-04-30
    • 2019-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多