简体   繁体   中英

Asynchronous Issues with JEST and MongoDB

I am getting inconsistent results with JEST when I try to remove items from a MongoDB Collection using the beforeEach() Hook.

My Mongoose schema and model defined as:

// 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;

My JEST tests:

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

So the error I always get is related to duplicate keys when I run my tests more than once: MongoError: E11000 duplicate key error collection: promis_tests.promiswts index: waferId_1_sublotId_1 dup key: { : "A01A001.3", : "A01A001.1" }

But I do not understand how I can get this duplicate key error if the beforeEach() were firing properly. Am I trying to clear the collection improperly? I've tried passing in a done element to the before each callback and invoking it after delete command. I've also tried implementing the delete in beforeAll(), afterEach(), and afterAll() but still get inconsistent results. I'm pretty stumped on this one. I might just removed the schema key all together but I would like to understand what is going on here with the beforeEach(). Thanks in advance for any advice.

Without deleting the schema index this seems to be the most reliable solution. Not 100% sure why it works over async await Wafer.deleteMany({});

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

It might be because you are not actually using the promise API that mongoose has to offer. By default, mongooses functions like deleteMany() do not return a promise. You will have to call .exec() at the end of the function chain to return a promise eg await collection.deleteMany({}).exec() . So you are running into a race condition. deleteMany() also accepts a callback, so you could always wrap it in a promise. I would do something like this:

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

Also, always expect the assertions with asynchronous code https://jestjs.io/docs/en/asynchronous.html

You can read more about mongoose promises and query objects here https://mongoosejs.com/docs/promises.html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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