Jest + Mongoose:必须运行 find 两次才能获得结果

时间:2021-04-12 21:07:18

标签: node.js mongodb express mongoose jestjs

我正在为我的 node/express 控制器方法构建测试并使用 @shelf/jest-mongodb。我首先创建一个文档,然后当我尝试发现我必须从模型中运行 find 两次才能获得结果。它应该在第一个查找中获得结果。

test.js

const { Subscription } = require('../src/models/subscription.schemaModel'); // model
const {
  createSubscription,
} = require('../src/controllers/subscription.controller');

const subData = {...};

beforeAll(async () => {
  await mongoose.connect(

    process.env.MONGO_URL,
    { useNewUrlParser: true, useUnifiedTopology: true },
    (err) => {
      if (err) {
        console.error(err);
        process.exit(1);
      }
    }
  );
});

afterAll(async () => {
  await mongoose.connection.close();
});

describe('creates a subscription ', () => {
  it('can be created correctly', async () => {
    const sub = await createSubscription(subData);
    await Subscription.find(); // if I comment out this line, I would get 0 results.
    const subs = await Subscription.find();
    expect(subs[0].items[0].sku).toBe(233234);
  });
});

subscription.controller.js

const Mongoose = require('mongoose');
const { Subscription } = require('../models/subscription.schemaModel');
const isTestEnv = process.env.NODE_ENV === 'test';

module.exports.createSubscription = async (data) => {
  try {
    let error = null;
    const doc = new Subscription(data);
    doc.accountId = Mongoose.Types.ObjectId(doc.accountId);

    await doc.save(function (err) {
      if (err) {
        logger.error(`createSubscription saving ${err}`);
        error = err;
      }
    });

    if (!error) {
      logger.info(
        `Subscription created =>  id: ${doc._id} store: ${doc.store}`
      );
      return doc;
    } else {
      return error;
    }
  } catch (err) {
    logger.error(`createSubscription ${err}`);
  }
};

schemaModel 文件主要包含架构和导出模型。如果我在测试文件(模式+模型+控制器模块)中执行所有操作,一切似乎都正常,这违背了测试我的模块的目的,但如果我正在导入,则不会。在这种情况下,我必须运行 find() 两次才能获得结果。

我一直在尝试从谷歌搜索中找到的多种方法,但没有运气!任何帮助或领导将不胜感激。如果您需要任何其他详细信息,也请告诉我。 谢谢!!

1 个答案:

答案 0 :(得分:1)

发布的代码包含的唯一问题是 Mongoose 承诺 API 与遗留回调 API 混合。看来 save 会导致竞争条件,该条件已被额外的 find 提供的随机延迟所规避。

虽然 Mongoose 文档提到方法无条件返回承诺,但支持承诺和回调的 JavaScript API 的常见模式是通过省略回调参数来启用承诺控制流,反之亦然。这很可能就是这里发生的情况。

在这种情况下避免竞争条件的一种方法是坚持承诺控制流,例如:

beforeAll(async () => {
 try {
  await mongoose.connect(
    process.env.MONGO_URL,
    { useNewUrlParser: true, useUnifiedTopology: true },
  )
 } catch (err) {
   console.error(err);
   process.exit(1);
 }
});