I'm trying to create some tests for my Mongoose models, and I can't figure out how to get the Jest/Mockgoose test to pass for a shorthand query/aggregation pipeline (see below in first code block) that I created to retrieve a random document from one collection that isn't referenced in another collection.
activitySchema.query.getUnused = function() {
return Activity.aggregate()
.lookup({
from: 'userActivity',
localField: '_id',
foreignField: 'activity',
as: 'matched_docs',
})
.match({ matched_docs: { $eq: [] } })
.sample(1)
.project({ matched_docs: 0, __v: 0 })
.exec()
}
Jest test
describe('Activity methods', () => {
test('Activity unused query executes', (done) => {
function createActivity() {
return Activity
.create({ activity: 'running' })
.then(activity => {
console.log('Activity is generated')
return Promise.resolve(true)
})
}
async function retrieveActivity() {
await createActivity()
Activity
.find()
.getUnused()
.then(unused => {
console.log(unused);
expect(unused).toHaveLength(1)
done()
})
.catch(x => {
console.log(x)
})
}
return retrieveActivity()
})
})
Sandbox Node JS code:
Activity.find().getUnused()
.then((x) => {
console.log(x);
})
When I try it in a sandbox node file, wit works normally and retrieves a typical queryset like:
[ { _id: 58f3dee3b0346910a69e6e5d, activity: 'running', __v: 0 } ]
When I run the test, I get this MongoError:
The 'cursor' option is required, except for aggregation explain
How do I fix this with a universal manner that works in both contexts? I'd like for the method to return a promise if possible. I've tried both the chained aggregate methods (see above) and the more native Mongo aggregate array for pipelines, but both return errors. My mongo version is 3.4.2 if that's relevant.
I have faced similar kind of problem and after researching a lot I found that that it was due to older version of mongoose as earlier versions are not compatible with breaking changes in MongoDB 3.6 and above.
I upgraded mongoose version one by one and I found that it works perfectly fine with mongoose version 4.12.2
or above ([email protected]).
You can upgrade your mongoose version by running following command:
npm install [email protected]
Finally figured this out: I had to add a cursor call to the aggregation pipeline, and translate it into a stream. To maintain the Promise I had the query method return a Promise that resolves with data once the stream has ended, as below:
activitySchema.query.getUnused = function() {
return new Promise((res, rej) => {
let data = []
return Activity.aggregate()
.lookup({
from: 'userActivity',
localField: '_id',
foreignField: 'activity',
as: 'matched_docs',
})
.match({ matched_docs: { $eq: [] } })
.sample(1)
.project({ matched_docs: 0, __v: 0 })
.cursor({})
.exec()
.on('data', doc => data.push(doc))
.on('end', () => res(data))
})
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With