Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fetch never returns data when msw (Mock Service Worker) intercepts request

I am currently using next/jest to setup my environment, with msw and @testing@library/react. My test looks like:

import { TestComponent } from '../../../components/TestComponent'
import React from 'react'
import { render } from '@testing-library/react'

test('Test TestComponent', function () {
  const wrap = render(<TestComponent />)
  expect(wrap.container.childElementCount).toBe(2)
})

My jest.config.js looks like:

const nextJest = require('next/jest')

const createJestConfig = nextJest({
  dir: './',
})

const customJestConfig = {
  setupFilesAfterEnv: ['<rootDir>/test_utils/setup-env.js'],
  moduleDirectories: ['node_modules', '<rootDir>/'],
  testEnvironment: 'jest-environment-jsdom',
}

module.exports = createJestConfig(customJestConfig)

My setup-env.js looks like this:

import '@testing-library/jest-dom'
import { server } from './server.js'

beforeAll(() => server.listen())
afterEach(() => server.resetHandlers())
afterAll(() => server.close())

My component looks something like this...

import React, { useEffect, useState } from 'react'

import { useSWRFetch } from '../../../hooks'

export const TestComponent = (): JSX.Element => {
  const [data, setData] = useState([])
  const dataInfo = useSWRFetch({
    endpoint: `${process.env.NEXT_PUBLIC_API_URL}/v1/endpoint`,
  })

  useEffect(() => {
    if (dataInfo) {
      setDomains(dataInfo.data)
    }
  }, [dataInfo])
  return (
    <>
        {data &&
          data.map((item, idx) => (
                  <div>
                    <p>{item.count | 0}</p>
                    <p>Job</p>
                  </div>
          ))}
    </>
  )
}

When I run my test however I get the following error...

ReferenceError: fetch is not defined

However when I value of dataInfo.data it is always undefined.

I have a fetcher function which SWR uses that looks like the following:

async function fetcher(...args) {
  console.log("BEFORE REQUEST")
  const url = args[0]
  const token = args[1]
  const method = args.length > 2 ? args[2] : 'GET'
  const body = args.length > 3 ? { body: JSON.stringify(args[3]) } : {}
  const res = await fetch(url, {
    method: method,

    headers:
      method != 'GET'
        ? {
            Authorization: `bearer ${token}`,
            'Content-Type': 'application/json',
          }
        : {
            Authorization: `Bearer ${token}`,
          },
    ...body,
  })

  console.log("AFTER REQUEST")

  if (!res.ok) {
    const error = new Error('An error occurred while fetching the data.')
    // Attach extra info to the error object.
    error.info = await res.json()
    error.status = res.status
    throw error
  }

  return res.json()
}

function useSWRFetch({ endpoint, token, options = null, condition=true }) {
  const { data, error, mutate } = useSWR(token && condition ? [endpoint, token] : null, fetcher, options)

  return {
    mutate: mutate,
    data: data,
    isLoading: !error && !data,
    error: error,
  }
}

However it never reaches the second console, AFTER REQUEST when the request is intercepted.

like image 656
Kalimantan Avatar asked Oct 19 '25 02:10

Kalimantan


1 Answers

Taken from React Jest tests failing with MSW the answer is probably the same:

You need to make sure that your tests are waiting for things to unwrap. If you're not awaiting something to happen, your test-suite will not execute properly.

Try implementing a loading-state and then:

await waitForElementToBeRemoved(screen.getByText("Loading ..."))

As this might be considered "bad practice" you can also do the opposite which would be waiting for something to appear:

await screen.findByText('The text you are waiting for');

I'd also like to point out that @kettanaito 's answer helped me a lot to find a good polyfill for vitest. Thanks!

like image 83
bastianwegge Avatar answered Oct 20 '25 16:10

bastianwegge