hakima maarouf
hakima maarouf

Reputation: 2310

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 ?

Upvotes: 0

Views: 4815

Answers (1)

Som Shekhar Mukherjee
Som Shekhar Mukherjee

Reputation: 8188

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.

Upvotes: 2

Related Questions