0

I'm using Mockingoose to mock my mongoose calls when running tests with Jest. I tried this but I get an error

mockingoose.Account.toReturn(
    ["593cebebebe11c1b06efff0372","593cebebebe11c1b06efff0373"],
    "distinct"
);

Error:

ObjectParameterError: Parameter "obj" to Document() must be an object, got 593cebebebe11c1b06efff0372

So then I try passing it an array of document objects but it just returns the documents. How di I get it to return just an array or strings?

Here's the code inside the function I'm testing:

const accountIDs = await Account.find({
    userID: "test",
    lastLoginAttemptSuccessful: true
}).distinct("_id");

I'm open to other ways of mocking my mongoose calls if someone knows of a better way. Thanks!

skyboyer
  • 22,209
  • 7
  • 57
  • 64
Dev01
  • 13,292
  • 19
  • 70
  • 124

2 Answers2

1

You can't.

My bad. I looked into mockingoose implementation and realized, it kind of "supports" distinct by implementing a mock, but it actually returned just the given documents, as for the other operations.

Opened a pull request for this issue and added a test, so you're example should be valid and working.

naeramarth7
  • 6,030
  • 1
  • 22
  • 26
  • but `await Account.find({}).distinct("_id");` will return an array of strings. Are you saying it won't? – Dev01 Oct 05 '18 at 20:39
  • I'm saying, the `toReturn` part (what mongoose actually returns) must contain an array of objects as the first parameter. That's why you get the error in the first place. – naeramarth7 Oct 06 '18 at 06:48
  • Seems like an issue in mongoose to me. It "supports" distinct by allowing to use it, but the mock lacks of an implementation and simply returns. Created an pull request for that. – naeramarth7 Oct 06 '18 at 08:54
0

I think the answer is to not use mockingoose. You can do it pretty easily with jest alone.

You can use jest.spyOn() and then mockImplementation() to mock the first call like find() and update(). Here's an example of findOneAndUpdate() where we're checking to make sure the correct object is passed:

// TESTING:
// await Timeline.findOneAndUpdate(query, obj);
//

const Timeline = require("./models/user.timeline");
...
const TimelineFindOneAndUpdateMock = jest.spyOn(Timeline, "findOneAndUpdate");
const TimelineFindOneAndUpdate = jest.fn((query, obj) => {
    expect(obj.sendDateHasPassed).toBeFalsy();
    expect(moment(obj.sendDate).format()).toBe(moment("2018-11-05T23:00:00.000Z").format());
});
TimelineFindOneAndUpdateMock.mockImplementation(TimelineFindOneAndUpdate);

If you want to mock a chained function you can have it return an object with the next chained function you want to call. Here's an example of how to mock a chained distinct() call.

// TESTING:
// let accountIDs = await Account.find(query).distinct("_id");
//
// WILL RETURN:
// ["124512341234","124512341234","124512341234"]
//

const Account = require("./models/user.account");
...
const AccountFindMock = jest.spyOn(Account, "find");
const AccountFindDistinctResult = ["124512341234","124512341234","124512341234"];
const AccountFindDistinctResult = jest.fn(() => AccountFindDistinctResult);
const AccountFindResult = {
    distinct: AccountFindDistinct
};
const AccountFind = jest.fn(() => AccountFindResult);
AccountFindMock.mockImplementation(AccountFind);

And after your test runs, if you want to check how many times a function is called like how many times distinct() was called you can add this:

expect(AccountFindDistinct).toHaveBeenCalledTimes(0);
Dev01
  • 13,292
  • 19
  • 70
  • 124