node.js - Jest + Mongoose: Have to run find twice to get results
问题描述
I am building tests for my node/express controller methods and using @shelf/jest-mongodb
. I am creating a document first, and then when I try to find that I have to run find twice from model in order to get the results. It should get the results in the first find instead.
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}`);
}
};
The schemaModel file essentially contains the schema and exports model. Everything seems to work fine if I would do all the operations in the test file (schema+model+controller module)which defeats the purpose of testing my modules but not if I am importing. In this case I would have to run find()
twice to get the results.
I have been trying multiple things from what I could find from googling, but no luck! Any help or lead would be appreciated. Also let me know if you need any other details. Thank you!!
解决方案
The only problem that posted code contains is that Mongoose promise API is mixed with legacy callback API. It appears that save
results in race condition that is has been circumvented by random delay that extra find
provides.
Although Mongoose documentation mentions that methods unconditionally return promises, a common pattern for JavaScript APIs that support both promises and callbacks is to enable promise control flow by omitting callback argument, and vice versa. This is most likely what happens here.
A way to avoid race conditions in such cases is to stick to promise control flow, e.g.:
beforeAll(async () => {
try {
await mongoose.connect(
process.env.MONGO_URL,
{ useNewUrlParser: true, useUnifiedTopology: true },
)
} catch (err) {
console.error(err);
process.exit(1);
}
});
推荐阅读
- excel - 如何将数据验证放在excel中重复值的列中?
- kotlin - KotlinTest jUnit 报告不包含 BehaviorSpec 步骤
- google-analytics - SQL for GA 会话(来自 BigQuery),页面包含特定时间范围内的事件
- python - 带有 setuptools 模块的 Python 包没有属性
- java - Servlet 3.0 web-fragment 提供静态内容
- php - Laravel ManyToMany withPivot 试图获取非对象的属性“started_at”
- python - tkinter:多个列表框不会触发向上/向下箭头键
- android - 使用另一个密钥库生成签名的 apk
- python - AttributeError: 'NoneType' 对象没有 Flask Web App 的属性 'drivername'
- hyperledger-fabric - 在fabric-ca中可以撤销吗?