Luis
Luis

Reputation: 2133

Jest: Does not allow mocked method to be overwritten

Given the following test code:

import { MyParentClass } from "MyParentClass";
import { MyClass } from "MyClass";

MyClass.prototype.post = jest.fn(() => Promise.resolve({token: '12345'}));

it('first test: this test will be successful tested ✓', async() => {
    const myParentClass = new MyParentClass();
    await expect(myParentClass.run()).toEqual({token: '12345'});
})

it('second test: this test will fail ×', async () => {
    MyClass.prototype.post = jest.fn(() => Promise.reject({message: 'An error ocurred'}));
    const myParentClass = new MyParentClass();
    await expect(myParentClass.run()).rejects.toEqual({message: 'success'});
})

The "run" method internally makes use of the 'MyClass' class and its "post" method. When I run a code like this, for my second test, I get a message like the following:

"Received promise resolved instead of rejected"

I understand that when the answer for the "post" method is globally defined, it will always take that value, but I also understand that in the second test I am overwriting the behavior of that method, why don't you take it into account?

I know I can also use jest.doMock, but I don't understand the documentation well, could someone help me understand it to apply it to my example?

Upvotes: 0

Views: 375

Answers (2)

Iku-turso
Iku-turso

Reputation: 21

Using asyncFn as so will solve the problem, and additionally simplify the test by making it read in chronological order.

import asyncFn from '@asyncFn/jest';

describe('myParentClass', () => {
  let parentClass;
  let runPromise;

  beforeEach(() => {
    parentClass = new MyParentClass();
    parentClass.post = asyncFn();
    runPromise = myParentClass.run();
  });      

  it('first test: this test will be successful tested ✓', () => {
    parentClass.post.resolve({ token: '12345' });

    return expect(runPromise).resolves.toEqual({ token: '12345' });
  })

  it('second test: this test will fail ×', () => {
    parentClass.post.reject({ message: 'An error occured'} );

    return expect(runPromise).rejects.toEqual({ message: 'An error occured' });
  });
});

Upvotes: 1

josholiveros
josholiveros

Reputation: 81

You can use mockImplementationOnce or mockReturnValueOnce since you've already converted post to a jest mock function. So you could do something like this on your 2nd test:

it('second test: this test will fail ×', async () => {
  MyClass.prototype.post.mockReturnValueOnce(Promise.reject({message: 'An error ocurred'}));
  const myParentClass = new MyParentClass();
  await expect(myParentClass.run()).rejects.toEqual({message: 'An error ocurred'});
})

Upvotes: 0

Related Questions