Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

jest-mock-axios incompatible with CRA 4 / resetMocks: true #63

Open
alyssaruth opened this issue Nov 30, 2020 · 10 comments
Open

jest-mock-axios incompatible with CRA 4 / resetMocks: true #63

alyssaruth opened this issue Nov 30, 2020 · 10 comments
Labels

Comments

@alyssaruth
Copy link

alyssaruth commented Nov 30, 2020

Hi!

We're using this library in a project built with Create React App, and have followed the async / await testing pattern outlined in #28.

I'm trying to upgrade us to CRA 4, but doing so is breaking all of these tests with Error: No request to respond to!. Bumping major CRA version bumps a load of sub-dependencies, so guessing one of these is the actual cause (jest seems most likely) - I'm happy to check other package versions before/after the upgrade if there are any in particular you think will be relevant!

We were using version 2.3.0 of this library, but can also reproduce the issue on the latest version (4.2.1). I've put together a SRE of three files to demonstrate what's happening.

Our axios instance, defined in axiosInstance.ts

import axios from 'axios'

export const axiosInstance = axios.create({
  baseURL: '/api',
  timeout: 20000,
  withCredentials: true,
  headers: { 'X-Csrf-Prevention': 'true' },
})

A fake API to test in sreApi.ts

import { AxiosResponse } from 'axios'
import { axiosInstance } from './axiosInstance'

export const callEndpoint = async (data: string): Promise<AxiosResponse> => {
  return axiosInstance.post('/endpoint', data)
}

The test that fails after the upgrade, but passes before in sreApi.test.ts

import { callEndpoint } from './sreApi'
import mockAxios from 'jest-mock-axios'

it('should call the correct endpoint', async () => {
  const promise = callEndpoint('some-data')
  mockAxios.mockResponse({ data: 'response' }) <-- blows up here
  const result = await promise

  expect(mockAxios.post).toHaveBeenCalledWith('/endpoint', 'some-data')
  expect(result.data).toBe('response')
})

In the above example, the mockResponse line blows up with:

Error: No request to respond to!
    at Function.mockResponse (/home/me/sre-package/node_modules/jest-mock-axios/lib/mock-axios.ts:170:15)
    at Object.<anonymous> (/home/me/sre-package/src/sre/sreApi.test.ts:6:13)
    at Promise.then.completed (/home/me/sre-package/node_modules/jest-circus/build/utils.js:276:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/home/me/sre-package/node_modules/jest-circus/build/utils.js:216:10)
    at _callCircusTest (/home/me/sre-package/node_modules/jest-circus/build/run.js:212:40)
    at processTicksAndRejections (internal/process/task_queues.js:85:5)
    at _runTest (/home/me/sre-package/node_modules/jest-circus/build/run.js:149:3)
    at _runTestsForDescribeBlock (/home/me/sre-package/node_modules/jest-circus/build/run.js:63:9)
    at run (/home/me/sre-package/node_modules/jest-circus/build/run.js:25:3)
    at runAndTransformResultsToJestFormat (/home/me/sre-package/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:176:21)

Interestingly, reordering the test like this still fails but does pass the call assertion, so mockAxios.post is definitely still being called:

it('should call the correct endpoint', async () => {
  const promise = callEndpoint('some-data')
  expect(mockAxios.post).toHaveBeenCalledWith('/endpoint', 'some-data')
  mockAxios.mockResponse({ data: 'response' }) <-- still blows up here
  const result = await promise

  expect(result.data).toBe('response')
})

Versions that work:

jest: 24.9.0
react-scripts: 3.4.4
axios: 0.18.1
jest-mock-axios: 4.2.1

Versions that don't work (after upgrade):

jest: 26.6.0
react-scripts: 4.0.1
axios: 0.18.1
jest-mock-axios: 4.2.1

@kingjan1999
Copy link
Collaborator

Hi,

thanks for reporting - I was able to reproduce this with the latest version of create-react-app / react-scripts. It looks like this is related to react-scripts defaulting jest's resetMocks to true since v4. Consequently you can workaround this bug by adding:

  "jest": {
    "resetMocks": false
  }

in your package.json while I am further investigating this issue.

@kingjan1999 kingjan1999 changed the title async / await testing pattern broken when upgrading Jest version - No request to respond to! jest-mock-axios incompatible with CRA 4 / restMocks: true Dec 2, 2020
@kingjan1999 kingjan1999 changed the title jest-mock-axios incompatible with CRA 4 / restMocks: true jest-mock-axios incompatible with CRA 4 / resetMocks: true Dec 2, 2020
@alyssaruth
Copy link
Author

Thanks for looking into this and responding so quickly with a workaround! 🎉

@Chris-Thompson-bnsf
Copy link
Contributor

I also ran into this issue after the CRA 4.0 upgrade, and I can confirm that the resetMocks: false workaround worked for our project as well.

@alyssaruth
Copy link
Author

Hmm, the resetMocks: false workaround doesn't seem to be working here - I'm still seeing Error: No request to respond to!

@kingjan1999
Copy link
Collaborator

Hi,

there are several upstream issues for the resetMocks behavior breaking existing test behavior (e.g. facebook/create-react-app#9935). I'm still looking for a feasible solution except for the aforementioned workaround.

@alexburlton-sonocent I created a repro-repo using the example code you provided at kingjan1999/jest-mock-axios-cra-repo. Can you try if this works for you and look for differences between this repo and your project?

@alyssaruth
Copy link
Author

Sorry for going AWOL, the create-react-app upgrade dropped off our radar for a bit so I've not been looking at this for a while.

Dug into this a bit more today and have concluded that it's our use of react-app-rewired which is breaking the workaround. If I change our test command to go via vanilla react-scripts rather than react-app-rewired, I can indeed see that specifying the resetMocks option fixes the problem.

So now I need to figure out if we can drop react-app-rewired for running tests, or failing that how to make it respect the resetMocks option. Have you made any progress on a feasible solution for making these tests work with resetMocks set to true?

@doutatsu
Copy link

doutatsu commented Jun 1, 2022

Not sure if related, but I am getting Cannot set properties of undefined (setting 'Authorization') after upgrading to Jest 28. This comes from my custom axios configuration that sets the auth token:

const setAuthConfig = (config) => {
  const token = localStorage.getItem('access');

  if (token) { config.headers.Authorization = `Bearer ${token}`; }

  return config;
};
    TypeError: Cannot set properties of undefined (setting 'Authorization')

      18 |   const token = localStorage.getItem('access');
      19 |
    > 20 |   if (token) { config.headers.Authorization = `Bearer ${token}`; }
         |                ^
      21 |
      22 |   return config;
      23 | };

Setting resetMocks: false doesn't help with this issue for me though

@kingjan1999
Copy link
Collaborator

kingjan1999 commented Jun 1, 2022

@doutatsu Can you post a more complete example that shows how you invoke setAuthConfig / axios? (maybe in a separate issue?)

@EmlynB23
Copy link

EmlynB23 commented Sep 9, 2024

@doutatsu did you ever resolve this issue? I'm facing the exact same problem

@doutatsu
Copy link

I don't use Jest anymore, I've switched to Vitest

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants