4

I have a controller which used rxjs' lastValueFrom method, and I want to mock the method so that the actual method won't be called. My code for the controller is:

async doSomething(request) {
  ...
  const data = await lastValueFrom(
    ...
  );
  ...
}

For the test, I've tried multiple ways, which is:

import rxjs from 'rxjs';

jest.spyOn(rxjs, 'lastValueFrom').mockReturnValueOnce(
  new Promise((resolve, reject) => {
    resolve(true);
  }),
);
// This gives me error: Cannot spyOn on a primitive value; undefined given
import { lastValueFrom } from 'rxjs';

lastValueFrom = jest.fn().mockReturnValueOnce(
  new Promise((resolve, reject) => {
    resolve(true),
);
// This gives me error: Cannot assign to 'lastValueFrom' because it is an import.
import rxjs from 'rxjs';

rxjs.lastValueFrom = jest.fn().mockReturnValue(
  new Promise((resolve, reject) => {
    resolve(true);
  }),
);
// This gives me error: Cannot set property 'lastValueFrom' of undefined
felixbmmm
  • 362
  • 3
  • 13
  • Looks pretty clear to me that rxjs is undefined which is why it is throwing all those errors. Are you sure you have all the typings for it? You may need to delete rxjs and reinstall it or install the @types/rxjs library. – ScarpMetal Mar 26 '22 at 02:34
  • @ScarpMetal I have been considering using @types/rxjs, but since the code is already there, I wonder if I can write the test using the same code, thanks for the advice. – felixbmmm Mar 26 '22 at 03:03
  • What are you `lastValueFrom`ing? Could you mock that to return an observable with data you expect, so that `lastValueFrom` just returns that value as a promise, instead of mocking the method directly? – Jay McDoniel Mar 26 '22 at 18:09
  • @JayMcDoniel I tried that the first time but also didn't work, that's why I thought that maybe it's the right way to mock the `lastValueFrom` itself. Inside that `lastValueFrom`, I called an API route using axios that connect me to a websocket-ish. – felixbmmm Mar 28 '22 at 01:15

1 Answers1

6

If you're using TypeScript I'm afraid the only way is mocking the import 'rxjs'.

jest.mock('rxjs', () => {
  const original = jest.requireActual('rxjs');

  return {
    ...original,
    lastValueFrom: () =>
      new Promise((resolve, reject) => {
        resolve(true);
      }),
  };
});

import { of, lastValueFrom } from 'rxjs';

test('test', () => {
  lastValueFrom(of(1)).then((val) => {
    expect(val).toStrictEqual(true);
  });
});

Live demo: https://stackblitz.com/edit/node-6vjbxb?file=index.spec.ts

With just ES* seems like you could do: How to spy on a default exported function with Jest?

martin
  • 93,354
  • 25
  • 191
  • 226