How to use jest to spy on Schema.virtual of mongoose?

Viewed 206

I have defined a mongoose Schema, how to spy on Schema and make sure the virtual method is called in my unit test.

const UserSchema = new Schema(
  {
    username: SchemaTypes.String,
    password: SchemaTypes.String,
    email: SchemaTypes.String,
    firstName: { type: SchemaTypes.String, required: false },
    lastName: { type: SchemaTypes.String, required: false },
    roles: [
      { type: SchemaTypes.String, enum: ['ADMIN', 'USER'], required: false },
    ],
    //   createdAt: { type: SchemaTypes.Date, required: false },
    //   updatedAt: { type: SchemaTypes.Date, required: false },
  },
  {
    timestamps: true,
    toJSON: {
      virtuals: true
    }
  },
);

UserSchema.virtual('name').get(function () {
  return `${this.firstName} ${this.lastName}`;
});

UserSchema.virtual('posts', {
  ref: 'Post',
  localField: '_id',
  foreignField: 'createdBy',
});

1 Answers

I found a simple solution to resolve this problem, but I have to refactor my codes.

Extract the virtual method into a standalone function.

function nameGetHook() {
  return `${this.firstName} ${this.lastName}`;
}

UserSchema.virtual('name').get(nameGetHook);

And set a mock context to run the function in jest.

const getMock = jest.fn().mockImplementationOnce(cb => cb)
const virtualMock = jest.fn().mockImplementationOnce(
    (name: string) => ({
        get: getMock
    })
);

describe('UserSchema', () => {

    it('should called Schame.virtual ', () => {
        expect(UserSchema).toBeDefined()

        expect(getMock).toBeCalled()
        expect(getMock).toBeCalledWith(anyFunction())
        expect(virtualMock).toBeCalled()
        expect(virtualMock).toHaveBeenNthCalledWith(1, "name")
        expect(virtualMock).toHaveBeenNthCalledWith(2, "posts", { "foreignField": "createdBy", "localField": "_id", "ref": "Post" })
        expect(virtualMock).toBeCalledTimes(2)
    });

});
...

Check my complete example codes here.

Related