typescriptjestjsnestjs

Nestjs + Jest: expect().toHaveReturnedWith() returning empty object


I'm trying out nestjs and jest on a personal project. And I'm having issues figuring out how to properly use the expect().toHaveReturnedWith() methods.

Or maybe the problem is with the way I define the resolved value: jest.spyOn(subscriptionsHistoryRepository, 'findAll').mockResolvedValue([mockRecords, 2])? Although, debugging the test I can see that the .findAll() returns the mockRecords as I expected.

This is the bit of the code that I'm implementing:

describe('SubscriptionsModule', () => {
  describe('GetSubscriptionHistoryService', () => {
    let service: GetSubscriptionHistoryService;
    let subscriptionsHistoryRepository: SubscriptionsHistoryRepository;

    beforeAll(async () => {
      const moduleRef: TestingModule = await Test.createTestingModule({
        providers: [
          GetSubscriptionHistoryService,
          {
            provide: SubscriptionsHistoryRepository,
            useValue: {
              findAll: jest.fn(),
            },
          },
        ],
      }).compile();

      service = moduleRef.get<GetSubscriptionHistoryService>(GetSubscriptionHistoryService);
      subscriptionsHistoryRepository = moduleRef.get<SubscriptionsHistoryRepository>(
        SubscriptionsHistoryRepository,
      );
    });

    afterEach(() => {
      jest.resetAllMocks();
    });

    it('Should hava all class instances defined', () => {
      expect(service).toBeDefined();
      expect(subscriptionsHistoryRepository).toBeDefined();
    });

    it("Should return the subscription's status history", async () => {
      jest.spyOn(subscriptionsHistoryRepository, 'findAll').mockResolvedValue([mockRecords, 2]);

      await service.execute(CUSTOMER_ID, SUBSCRIPTION_ID, 1);

      expect(subscriptionsHistoryRepository.findAll).toHaveBeenCalledTimes(1);
      expect(subscriptionsHistoryRepository.findAll).toHaveBeenCalledWith({
        where: {
          customerId: CUSTOMER_ID,
          subscriptionId: SUBSCRIPTION_ID,
        },
        take: 5,
        skip: 0,
        order: {
          createdAt: 'DESC',
        },
      });
      expect(subscriptionsHistoryRepository.findAll).toHaveReturnedWith([mockRecords, 2]);
    });
  });
});

Test Results:

expect(jest.fn()).toHaveReturnedWith(expected)

Expected: [[{"createdAt": 2023-11-30T02:02:51.982Z, "customerId": "f1e8fc48-4780-45e4-858b-9e15b3382db5", "deletedAt": null, "extProviderStatus": "trialing", "id": "2e4c42b1-3d46-4438-bc68-64de46aa16d0", "status": "started", "subscriptionId": "2e4c42b1-3d46-4438-bc68-64de46aa16d5", "updatedAt": 2023-11-30T02:02:51.982Z}, {"createdAt": 2023-11-30T02:02:51.982Z, "customerId": "f1e8fc48-4780-45e4-858b-9e15b3382db5", "deletedAt": null, "extProviderStatus": "active", "id": "2e4c42b1-3d46-4438-bc68-64de46aa16d1", "status": "active", "subscriptionId": "2e4c42b1-3d46-4438-bc68-64de46aa16d5", "updatedAt": 2023-11-30T02:02:51.982Z}], 2]

Received: {}

All the other assertions work nice, but the expect(subscriptionsHistoryRepository.findAll).toHaveReturnedWith([mockRecords, 2]) line returns a empty object {}.

I've debugged the test run and I can see that the spyOn.mockResolved worked fine, though. Not sure of what am I missing and why this assertion is failing.


Solution

  • The problem is that subscriptionsHistoryRepository.findAll returns a promise.

    So the expectation is comparing a promise with the array. Also bear in mind that toHaveReturnedWith uses strict equality (===), so you must have the exact same result.

    expect(subscriptionsHistoryRepository.findAll).toHaveReturnedWith([mockRecords, 2]);
    

    You can fix this with something like

    const expectedPromise = Promise.resolve([mockRecords, 2]);
    jest.spyOn(subscriptionsHistoryRepository, 'findAll').mockValue(expectedPromise);
    [...]
    expect(subscriptionsHistoryRepository.findAll).toHaveReturnedWith(expectedPromise);
        
    

    I have to say that I never had to use something like toHaveReturnedWith in a unit test. In this case in particular, I don't think that expectation adds anything to the test. The assertion expect(subscriptionsHistoryRepository.findAll).toHaveBeenCalledWith([...]) is all you need.