我正在为我的 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()
两次才能获得结果。
我一直在尝试从谷歌搜索中找到的多种方法,但没有运气!任何帮助或领导将不胜感激。如果您需要任何其他详细信息,也请告诉我。 谢谢!!
答案 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);
}
});