3

I have a simple React application with the following App.js, App.test.js, and utils.js files:

App.js

import React from 'react';
import { randomNameGenerator } from './utils.js';
import './App.css';

function App() {
  return (
    <div>
      {randomNameGenerator()}
    </div>
  );
}

export default App;

App.test.js

import React from 'react';
import { render } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect'
import App from './App';

it('allows Jest method mocking', () => {
  const { getByText } = render(<App />);
  expect(getByText("Craig")).toBeInTheDocument()
});

utils.js

export function randomNameGenerator() {
    return Math.floor((Math.random() * 2) + 1) == 1 ? 'Steve' : 'Bill';
}

This is a simple example, but what I'm trying to accomplish is a Jest mock of the randomNameGenerator() function to only return "Craig" for that specific Jest test.

I've followed a wide variety of tutorials/guides, but can't find anything that works - the closest (by "feel") that I've gotten was this (in App.test.js), which had no effect:

jest.doMock('./utils', () => {
  const originalUtils = jest.requireActual('./utils');
  return {
    __esModule: true,
    ...originalUtils,
    randomNameGenerator: jest.fn(() => {
      console.log('## Returning mocked typing duration!');
      return 'Craig';
    }),
  };
})

The way it fails is expected:

Unable to find an element with the text: Craig. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.

    <body>
      <div>
        <div>
          Steve
        </div>
      </div>
    </body>

       6 | it('allows Jest method mocking', () => {
       7 |   const { getByText } = render(<App />);
    >  8 |   expect(getByText("Craig")).toBeInTheDocument()
         |          ^
       9 | });

1 Answer 1

9

You can mock the module by calling jest.mock, and then import it, then inside your tests you call mockImplementation to setup the right return value.

import React from 'react';
import { render } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect'
import App from './App';

import { randomNameGenerator } from "./utils";

jest.mock('./utils.js', () => ({ 
  randomNameGenerator: jest.fn()
}));

describe('test', () => {
  it('allows Jest method mocking 1', () => {
    randomNameGenerator.mockImplementation(() => "Craig");
    const { getByText } = render(<App />);
    expect(getByText("Craig")).toBeInTheDocument()
  });

  it('allows Jest method mocking 2', () => {
    randomNameGenerator.mockImplementation(() => "Not Craig");
    const { getByText } = render(<App />);
    expect(getByText("Not Craig")).toBeInTheDocument()
  });
});
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, this seems to mostly work, with one caveat. It requires every test method to provide a mock implementation of the randomNameGenerator method - there's no 'default' which falls back to the original implementation in the case where a mock has not been defined. I tried a few attempts at setting this up in the jest.mock() using requireActual but encountered scope access issues (not allowed to reference any out-of-scope variables)
Yes, unfortunately looks like there isn't any official way of doing this, you may wanna check this on github: github.com/facebook/jest/issues/2649

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.