'Mock Service Worker returns empty

I'm new to react testing library. I am trying to test a simple component that call some apis and then it fills inputs with the data of these apis. But when I run npm test it keeps showing me this : the recieved value is empty

Expected the element to have value: 100 Received:

   7 |     it('displays returned client info on successful fetch', async () => {
   8 |       render(<Client />);
>  9 |       expect(await screen.findByLabelText('IFU')).toHaveValue('100');
     |                                                   ^
  10 |     });
  11 |
  12 |     it('displays error message when fetching tasks raises error', async () => {

  at Object.<anonymous> (src/unit-tests/Client.test.js:9:51)

here is my test

import { render, screen } from '@testing-library/react';
import Client from './../components/Client';
import { mswServer } from './api-mocks/msw-server';
import { clientHandlerException } from './api-mocks/handlers';

describe('Component: Client', () => {
    it('displays returned client info on successful fetch', async () => {
      render(<Client />);
      expect(await screen.findByLabelText('IFU')).toHaveValue('100');
    });

    it('displays error message when fetching tasks raises error', async () => {
        mswServer.use(clientHandlerException);
        render(<Client />);
      });
}); 

handlers.js

import { rest } from 'msw';

const importateur = {numeroRc: "1000", description: "desc one", ifu: "100",  ice: "789", company: "mycom", city: "paris"}

     export const clientHandler = rest.get("http://localhost:8080/api/informationsClient", async (req, res, ctx) => {
      // res(ctx.json(mockClientInfo))
      return res(
        ctx.status(200),
        ctx.json(importateur)
      )
    });
    
    export const clientHandlerException = rest.get("http://localhost:8080/api/informationsClient", async (req, res, ctx) =>
        res(ctx.status(500), ctx.json({ message: 'Deliberately broken request' }))
    );
    
    export const handlers = [clientHandler];

msw-server.js

import { setupServer } from 'msw/node';
import { handlers } from './handlers';

export const mswServer = setupServer(...handlers);

setupTests.js

import '@testing-library/jest-dom';
import { mswServer } from './msw-server';

beforeAll(() => mswServer.listen());
afterEach(() => mswServer.resetHandlers());
afterAll(() => mswServer.close());

My component

export interface IClient {
    numeroRc: string,
    description: string,
    ifu: string,
    ice: string
  }
  
const Client = (props: ClientProps) => {

const [clientData, setClientData] = React.useState<IClient>(
      {numeroRc: "",
      description: "",
      ifu: "",
      ice: ""}
    );
 //other useEffect s that call other apis  

 React.useEffect(() => {
        (async () => {      
          const response = await getClientInfo();
          setClientData(response as IClient);   
        })();  
  
    }, [])

    return(
        <Stack direction="row" spacing={3} className='client' >
            <TextField id="numro-rc" label="Numero RC" variant="outlined" value={clientData.numeroRc}/>
            <TextField id="client" label="Client" variant="outlined" value={clientData.description}/>
            <TextField id="ifu" label="IFU" variant="outlined" value={clientData.ifu} />
            <TextField title='ice' id="ice" label="ICE" variant="outlined" value={clientData.ice} />
        </Stack>
    );
}

UPDATE

getClientInfo is a method that call my api using axios ( I put all my apis calls inside a file api.tsx)

axios.defaults.baseURL = 'http://localhost:8080/api'
...

    export const getClientInfo = async () => {
        try {
            const response =  await axios.get(`/informationsClient`);
            return response.data;  
        } catch(e) {
            console.log(e);
            return 0;
        }
    }

please what it could be the issue ?



Solution 1:[1]

The problem is that you're not awaiting for the value but the element, and the element is there when the component is mounted with a value of "", hence your assertion fails.

So, you need to await for the value, you can use waitFor for the same.

import { render, screen, waitFor } from "@testing-library/react";

describe("Component: Client", () => {
  it("displays returned client info on successful fetch", async () => {
    render(<Client />);
    const element = screen.getByLabelText("IFU");
    await waitFor(() => {
      expect(element).toHaveValue("100");
    });
  });
});

You can also do it using findByDisplayValue:

import { render, screen, waitFor } from "@testing-library/react";

describe("Component: Client", () => {
  it("displays returned client info on successful fetch", async () => {
    render(<Client />);
    const element = await screen.findByDisplayValue("100");
    expect(element).toBeInTheDocument();
  });
});

UPDATE:

Once you've made the following two changes, both the above methods of testing would work fine.

  • You've created a setupTests.ts file inside api-mocks which has no effect because CRA doesn't consider any setupTest.ts file but only the one that is there inside src. You would notice there's already a setupTest.ts file inside src, just move all your setup code into this file.

  • The mock server returns an array but your clientData state expects an object, so do either of the following:

    • Update the mock server to return an object instead of an array (in handlers.js) js const client = { numeroRc: "1000", description: "desc one", ifu: "100", ice: "789", company: "mycom", city: "paris" };

    • Or extract the object from the array before setting the state (in Client.tsx).

      const response = await getClientInfo();
      setClientData(response[0]);
      

You also need to give an onChange handler to all your inputs to get rid of the warnings.

Sources

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

Source: Stack Overflow

Solution Source
Solution 1