title: Testing with Jest while using MSW and RTK Query leads to strange error in test
body: <p>I have been spending most of the day trying to sort out this insanely annoying bug.</p>
  <p>I am using redux-toolkit, MSW, RTK query, and React Testing Libary and am currently busy writing an integration test that tests a simple login flow.</p>
  <p>The problem I have is that I am testing two different scenarios in one test suite, one is a successful login and one is a failed one.</p>
  <p>When I run one at a time, I get no problems, but when when I run both, I get the following error for the failed scenario.</p>
  <pre><code>TypeError: Cannot convert undefined or null to object
          at Function.values (&lt;anonymous&gt;)
  
        59 |       (state, action) =&gt; {
        60 |         const { payload } = action;
      &gt; 61 |         adapter.upsertMany(state, payload);
           |                 ^
        62 |       }
        63 |     );
        64 |   },
  
        at ensureEntitiesArray (node_modules/@reduxjs/toolkit/dist/redux-toolkit.cjs.development.js:794:27)
        at splitAddedUpdatedEntities (node_modules/@reduxjs/toolkit/dist/redux-toolkit.cjs.development.js:799:19)
        at upsertManyMutably (node_modules/@reduxjs/toolkit/dist/redux-toolkit.cjs.development.js:911:18)
        at runMutator (node_modules/@reduxjs/toolkit/dist/redux-toolkit.cjs.development.js:772:17)
        at Object.upsertMany (node_modules/@reduxjs/toolkit/dist/redux-toolkit.cjs.development.js:776:13)
        at src/features/customers/store/customersSlice.ts:61:17
        at recipe (node_modules/@reduxjs/toolkit/dist/redux-toolkit.cjs.development.js:663:32)
        at Immer.produce (node_modules/immer/src/core/immerClass.ts:94:14)
        at node_modules/@reduxjs/toolkit/dist/redux-toolkit.cjs.development.js:662:54
            at Array.reduce (&lt;anonymous&gt;)
        at node_modules/@reduxjs/toolkit/dist/redux-toolkit.cjs.development.js:641:29
        at combination (node_modules/redux/lib/redux.js:536:29)
        at dispatch (node_modules/redux/lib/redux.js:296:22)
        at node_modules/@reduxjs/toolkit/dist/query/rtk-query.cjs.development.js:1366:26
        at node_modules/@reduxjs/toolkit/dist/query/rtk-query.cjs.development.js:1264:26
        at node_modules/@reduxjs/toolkit/dist/query/rtk-query.cjs.development.js:1224:22
        at node_modules/@reduxjs/toolkit/dist/query/rtk-query.cjs.development.js:1138:26
        at node_modules/@reduxjs/toolkit/dist/query/rtk-query.cjs.development.js:1087:22
        at node_modules/@reduxjs/toolkit/dist/query/rtk-query.cjs.development.js:1049:26
        at node_modules/@reduxjs/toolkit/dist/query/rtk-query.cjs.development.js:1424:26
        at node_modules/@reduxjs/toolkit/dist/query/rtk-query.cjs.development.js:1458:24
        at node_modules/@reduxjs/toolkit/dist/redux-toolkit.cjs.development.js:446:22
        at node_modules/redux-thunk/lib/index.js:14:16
        at node_modules/@reduxjs/toolkit/dist/redux-toolkit.cjs.development.js:374:36
        at dispatch (node_modules/redux/lib/redux.js:667:28)
        at node_modules/@reduxjs/toolkit/dist/redux-toolkit.cjs.development.js:1204:37
        at step (node_modules/@reduxjs/toolkit/dist/redux-toolkit.cjs.development.js:38:23)
        at Object.next (node_modules/@reduxjs/toolkit/dist/redux-toolkit.cjs.development.js:19:53)
        at fulfilled (node_modules/@reduxjs/toolkit/dist/redux-toolkit.cjs.development.js:97:32)
  </code></pre>
  <p>What makes this strange is that the failed scenario isn't supposed to get to the page that calls the API call that results in this extra reducer matcher, hence why there is no payload and the error happens.</p>
  <p>This doesn't happen when I test in the browser, only when testing with Jest.</p>
  <p>Below are my tests:</p>
  <pre><code>import React from &quot;react&quot;;
  import { render, screen, waitFor, cleanup } from &quot;./test-utils&quot;;
  import App from &quot;../App&quot;;
  import userEvent from &quot;@testing-library/user-event&quot;;
  import { waitForElementToBeRemoved } from &quot;@testing-library/react&quot;;
  import { configureStore } from &quot;@reduxjs/toolkit&quot;;
  import { api } from &quot;../services/api/api&quot;;
  import counterReducer from &quot;../features/counter/counterSlice&quot;;
  import customersReducer from &quot;../features/customers/store/customersSlice&quot;;
  import subscriptionsReducer from &quot;../features/subscriptions/store/subscriptionsSlice&quot;;
  import uiReducer from &quot;../features/common/store/uiSlice&quot;;
  import authReducer from &quot;../features/auth/store/authSlice&quot;;
  
  describe(&quot;LoginIntegrationTests&quot;, () =&gt; {
    afterEach(() =&gt; {
      cleanup();
    });
  
    it(&quot;should render the correct initial state&quot;, function () {
      render(&lt;App /&gt;);
  
      // it doesnt render an appbar
      let navbar = screen.queryByRole(&quot;heading&quot;, {
        name: /fincon admin console/i,
      });
      expect(navbar).not.toBeInTheDocument();
  
      // it renders an empty email address field
      const emailField = screen.getByLabelText(/email address/i);
      expect(emailField).toHaveTextContent(&quot;&quot;);
  
      // it renders an empty password password field and hides the input
      const passwordField = screen.getByLabelText(/password/i);
      expect(passwordField).toHaveTextContent(&quot;&quot;);
      expect(passwordField).toHaveAttribute(&quot;type&quot;, &quot;password&quot;);
  
      // it renders a disabled login button
      const loginButton = screen.getByRole(&quot;button&quot;, { name: /login/i });
      emailField.focus();
      expect(loginButton).toBeDisabled();
    });
  
    it(&quot;should complete a successful login flow&quot;, async function () {
      render(&lt;App /&gt;);
  
      // it fills out the email address and password
      const emailField = screen.getByLabelText(/email address/i);
      const passwordField = screen.getByLabelText(/password/i);
  
      await userEvent.type(emailField, &quot;joe@soap.co.za&quot;);
      await userEvent.type(passwordField, &quot;blabla&quot;);
  
      // it clicks the login button
      const loginButton = screen.getByRole(&quot;button&quot;);
      expect(loginButton).toHaveTextContent(/login/i);
  
      userEvent.click(loginButton);
  
      // it sets the loading state
      expect(loginButton).toBeDisabled();
      expect(loginButton).toHaveTextContent(/loading .../i);
  
      const loadingSpinner = document.querySelector(&quot;.k-loading-mask&quot;);
      expect(loadingSpinner).toBeInTheDocument();
  
      // it removes the previous page's components
      await waitFor(() =&gt; {
        expect(emailField).not.toBeInTheDocument();
        expect(passwordField).not.toBeInTheDocument();
        expect(loginButton).not.toBeInTheDocument();
        expect(loadingSpinner).not.toBeInTheDocument();
      });
  
      // it navigates to the customers page
      const accountsPage = screen.getByRole(&quot;heading&quot;, { name: /accounts/i });
      expect(accountsPage).toBeInTheDocument();
  
      // it displays the appbar
      const navbar = screen.getByRole(&quot;heading&quot;, {
        name: /fincon admin console/i,
      });
  
      expect(navbar).toBeInTheDocument();
    });
  
    it(&quot;should present an error when invalid credentials are entered&quot;, async function () {
      render(&lt;App /&gt;);
  
      // it fills in invalid credentials
      const emailField = screen.getByLabelText(/email address/i);
      const passwordField = screen.getByLabelText(/password/i);
  
      await userEvent.type(emailField, &quot;error@error.co.za&quot;);
      await userEvent.type(passwordField, &quot;blabla1&quot;);
  
      // it clicks the login button
      const loginButton = screen.getByRole(&quot;button&quot;);
      expect(loginButton).toHaveTextContent(/login/i);
  
      userEvent.click(loginButton);
  
      // it sets the loading state
      expect(loginButton).toBeDisabled();
      expect(loginButton).toHaveTextContent(/loading .../i);
  
      const loadingSpinner = document.querySelector(&quot;.k-loading-mask&quot;);
      expect(loadingSpinner).toBeInTheDocument();
  
      // it removes the loading spinner
      await waitForElementToBeRemoved(loadingSpinner);
  
      // it displays the error
      const errors = await screen.findByText(
        /the provided credentials are invalid/i
      );
      expect(errors).toBeInTheDocument();
  
      // it stays on the same page
      expect(screen.getByText(/log into the admin console/i)).toBeInTheDocument();
  
      // it retains the input of the fields
      expect(emailField).toHaveValue(&quot;error@error.co.za&quot;);
      expect(passwordField).toHaveValue(&quot;blabla1&quot;);
    });
  });
  </code></pre>
  <p>Below is my redux setup for the tests:</p>
  <pre><code>import React from &quot;react&quot;;
  import { render as rtlRender } from &quot;@testing-library/react&quot;;
  import { configureStore } from &quot;@reduxjs/toolkit&quot;;
  import { Provider, useDispatch } from &quot;react-redux&quot;;
  import { Router } from &quot;react-router-dom&quot;;
  import { createMemoryHistory } from &quot;history&quot;;
  import { reducer, store } from &quot;../app/store&quot;;
  import { api } from &quot;../services/api/api&quot;;
  import { setupListeners } from &quot;@reduxjs/toolkit/query&quot;;
  import { renderHook } from &quot;@testing-library/react-hooks&quot;;
  import counterReducer from &quot;../features/counter/counterSlice&quot;;
  import customersReducer from &quot;../features/customers/store/customersSlice&quot;;
  import subscriptionsReducer from &quot;../features/subscriptions/store/subscriptionsSlice&quot;;
  import uiReducer from &quot;../features/common/store/uiSlice&quot;;
  import authReducer from &quot;../features/auth/store/authSlice&quot;;
  // import { useAppDispatch } from &quot;../app/hooks&quot;;
  
  function render(
    ui,
    {
      preloadedState,
      store = configureStore({
        reducer: {
          [api.reducerPath]: api.reducer,
          counter: counterReducer,
          customers: customersReducer,
          subscriptions: subscriptionsReducer,
          ui: uiReducer,
          auth: authReducer,
        },
        preloadedState,
        middleware: (getDefaultMiddleware) =&gt;
          getDefaultMiddleware().concat(api.middleware),
      }),
      ...renderOptions
    } = {}
  ) {
    setupListeners(store.dispatch);
  
    function Wrapper({ children }) {
      const history = createMemoryHistory();
  
      return (
        &lt;Provider store={store}&gt;
          &lt;Router history={history}&gt;{children}&lt;/Router&gt;
        &lt;/Provider&gt;
      );
    }
  
    // function useAppDispatch() {
    //     return useDispatch();
    // }
  
    // type AppDispatch = typeof store.dispatch;
    // const useAppDispatch = () =&gt; useDispatch&lt;AppDispatch&gt;();
  
    store.dispatch(api.util.resetApiState());
  
    return rtlRender(ui, { wrapper: Wrapper, ...renderOptions });
  }
  
  export * from &quot;@testing-library/react&quot;;
  export { render };
  </code></pre>
  <p>Below is my <code>setupTests.ts</code> file.</p>
  <pre><code>import &quot;@testing-library/jest-dom/extend-expect&quot;;
  import { server } from &quot;./mocks/server&quot;;
  
  beforeAll(() =&gt; server.listen());
  
  afterAll(() =&gt; server.close());
  
  afterEach(() =&gt; {
    server.resetHandlers();
  });
  </code></pre>
  <p>And finally my MSW files.</p>
  <p>handlers</p>
  <pre><code>import { rest } from &quot;msw&quot;;
  import { authResponse } from &quot;./data&quot;;
  import { customers } from &quot;../utils/dummyData&quot;;
  import { LoginRequest } from &quot;../app/types/users&quot;;
  import { ApiFailResponse } from &quot;../app/types/api&quot;;
  
  export const handlers = [
    rest.post(&quot;/login&quot;, (req, res, ctx) =&gt; {
      const body = req.body as LoginRequest;
  
      if (body.emailAddress === &quot;error@error.co.za&quot;) {
        const response: ApiFailResponse = {
          errors: [&quot;The provided credentials are invalid&quot;],
        };
  
        return res(ctx.status(400), ctx.json(response));
      } else {
        return res(ctx.json(authResponse));
      }
    }),
    rest.get(&quot;/customers&quot;, (req, res, ctx) =&gt; {
      return res(ctx.json(customers));
    }),
  ];
  </code></pre>
  <p>server</p>
  <pre><code>import { setupServer } from &quot;msw/node&quot;;
  import { handlers } from &quot;./handlers&quot;;
  
  export const server = setupServer(...handlers);
  </code></pre>
  <p>Any ideas?</p>
  <p>Thanks for all your help!</p>