'How to test custom hook to and mock request api with react testing library

I'm trying to test custom hook that contains fetching api request

this is the code in useReportDownload.ts hook

import { useEffect, useState } from 'react'
import { useParams } from 'react-router'
import { fetchdownload } from '~/services'

export default function useReportDownload() {
  const { id } = useParams()
  const [list, setList] = useState<Array<any>>([])

  const getList = async () => {
    try {
      if (id) {
        const data = await fetchdownload(Number(id))
        setList(data)
      }
    } catch (error) {
      // eslint-disable-next-line no-console
      console.debug('error', error)
    }
  }

  useEffect(() => {
    getList()
  }, [id])

  return {
    list,
  }
}

this is the test file listreports.spec.tsx:

import { render, screen } from '@testing-library/react'
import { renderHook } from '@testing-library/react-hooks'
import { rest } from 'msw'
import { setupServer } from 'msw/node'
import '@testing-library/jest-dom/extend-expect'
import useReportDownload from './useReportDownload'
import ReportDownload from '.'

const data = [
  {
    id: '1',
    name: 'Test',
    url: 'https://test.com',
    actions: [
      {
        buttonType: 'icon',
        event: 'download',
        icon: 'download',
        label: 'Download',
      },
    ],
  },
  {
    id: '2',
    name: 'Test2',
    url: 'https://test2.com',
    actions: [
      {
        buttonType: 'icon',
        event: 'download',
        icon: 'download',
        label: 'Download',
      },
    ],
  },
]

const server = setupServer(
  rest.get('campaigns/1/proof-execution', async (req, res, ctx) =>
    res(ctx.json(data))
  )
)

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

describe('useReportDownload', () => {
  it('should return the expected result', () => {
    const { result } = renderHook(() => useReportDownload())
    expect(result.current.list).toEqual([])
    expect(result.current.handleAction).toBeInstanceOf(Function)
    expect(result.current.handlePage).toBeInstanceOf(Function)
    expect(result.current.handleSelectedReports).toBeInstanceOf(Function)
    expect(result.current.handleSelectAllReports).toBeInstanceOf(Function)
    expect(result.current.selectedReports).toEqual([])
  })
  it('should return the expected result', async () => {
    render(<ReportDownload />)
    const text = await screen.findByText('Test')
    // eslint-disable-next-line no-console
    console.log(text)
  })
})

this is the listreports.tsx component that uses the above hook :

import React from 'react'
import { Box } from '@mui/material'
import useReportDownload from './useReportDownload'
import NoResults from '~/components/NoResults'
import { ReactComponent as NoResultsImage } from '~/images/noResults.svg'
import TableList from '~/TableList'
import { tableColumns } from '~/constants'
import * as Styled from '~/styles'
import { cosmosService } from '~/services/cosmos'
import { i18n } from '~/i18n'

interface Props {
  isHeaderBarAvailable?: boolean;
  headComponent?: React.ReactNode;
}

const ReportDownload = ({
  isHeaderBarAvailable = true,
  headComponent,
}: Props) => {
  const {
    list,
    handleAction,
    handlePage,
    handleSelectedReports,
    handleSelectAllReports,
    selectedReports,
  } = useReportDownload()

  const listContainer = () => (
    <>
      {list.length === 0 ? (
        <NoResults
          title={i18n.t('noResults.title')}
          description={i18n.t('noResults.description')}
          image={<NoResultsImage />}
        />
      ) : (
        <TableList
          enableCheckBox
          enableBulkSelect
          loading={false}
          columns={tableColumns}
          page={1}
          perPage={1}
          totalNumRows={list.length}
          enablePagination={false}
          rows={list}
          sortBy="id"
          orderBy="desc"
          selectedOptions={selectedReports}
          onCheckBoxChange={handleSelectedReports}
          onCheckBoxChangeAll={handleSelectAllReports}
          onPageChange={handlePage}
          onNumRowsChange={handlePage}
          onOrderChange={handlePage}
          onAction={handleAction}
        />
      )}
    </>
  )

  const fileComponent = () => (
    <Styled.Grid>
      <Styled.SelectedItemsBox>
        {i18n.t('reports.details.selectedItems')}
        <b>{selectedReports?.length}</b>
      </Styled.SelectedItemsBox>
      <Styled.Button
        onClick={() => cosmosService.downloadMedias(list, selectedReports)}
      >
        {i18n.t('reports.details.exportButton')}
      </Styled.Button>
    </Styled.Grid>
  )

  return (
    <Box>
      {headComponent}
      {isHeaderBarAvailable && <Box height="10%" />}
      {selectedReports?.length > 0 && fileComponent()}
      <Box height="100%">{listContainer()}</Box>
    </Box>
  )
}

export default ReportDownload

the problem is the mock data is not working, I want to test that when fetching data the list should have the data, but I have this error

✕ should return the expected result (1037 ms)

  ● useReportDownload › should return the expected result

    Unable to find an element with the text: Test. 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
          class="MuiBox-root css-0"
        >
          <div
            class="MuiBox-root css-1w5i5lh"
          />
          <div
            class="MuiBox-root css-10klw3m"
          >
            <div
              class="MuiBox-root css-32vdxk"
            >
              <div
                class="MuiBox-root css-24os1g"
              >
                <svg>
                  noResults.svg
                </svg>
              </div>
              <div
                class="MuiBox-root css-xi606m"
              >
                <p
                  class="MuiTypography-root MuiTypography-body1 css-eflgtu-MuiTypography-root"
                >
                  No Results
                </p>
                <p
                  class="MuiTypography-root MuiTypography-body1 css-66p3eu-MuiTypography-root"
                >
                  Your search has not returned any results
                </p>
              </div>
            </div>
          </div>
        </div>
      </div>
    </body>

      61 |   it('should return the expected result', async () => {
      62 |     render(<ReportDownload />)
    > 63 |     const text = await screen.findByText('Test')
         |                               ^
      64 |     // eslint-disable-next-line no-console
      65 |     console.log(text)
      66 |   })

      at waitForWrapper (node_modules/@testing-library/dom/dist/wait-for.js:173:27)
      at findByText (node_modules/@testing-library/dom/dist/query-helpers.js:101:33)
      at Object.<anonymous> (src/components/ReportDownload/UseReportDownload.spec.tsx:63:31)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 passed, 2 total
Snapshots:   0 total
Time:        3.977 s, estimated 4 s

so what is wrong?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source