0

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 ?

hakima maarouf
  • 1,010
  • 1
  • 9
  • 26
  • Have you tried checking if data is in the component using console logs? – Konrad May 08 '22 at 21:31
  • I put a console.log in useEffect and yes it returns the data I received from the real api but the mocked data I don't know how can I see if it's empty or not – hakima maarouf May 08 '22 at 22:30

1 Answers1

2

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.

SSM
  • 2,855
  • 1
  • 3
  • 10
  • Thank you for the answer.. but I got this error I don't know why ```Error: Cross origin http://localhost forbidden``` I tried this solution https://github.com/axios/axios/issues/1754#issuecomment-486924528 but it not working – hakima maarouf May 13 '22 at 15:04
  • I added it in handlers.js but unfortunately I keep getting the same error – hakima maarouf May 13 '22 at 17:52
  • Can you add your code for `getClientInfo`, that will add more clarity to why you're getting this error. – SSM May 13 '22 at 18:01
  • Also, probably the order matters, try putting `ctx.set` before `ctx.json`. I've updated my code as well. – SSM May 13 '22 at 18:09
  • The same error console.error ```Error: Cross origin http://localhost forbidden at dispatchError``` .. I updated my question by adding getClientInfo method – hakima maarouf May 13 '22 at 19:09
  • For a similar question there is this solution https://stackoverflow.com/a/67118857/14994239 but I don't understand how to set ```testURL``` the solution talking about.. and thank you so much for your help I appreciate it – hakima maarouf May 13 '22 at 19:14
  • 1
    I just tested you don't need to configure CORS with MSW, so you can remove that headers part. And I don't know why it doesn't, I see that you importing `mswServer` in your test, that's unnecessary, remove that, you've already started the server in `setupTests`. Other thing that you can do is remove the second test and see if the first one works. – SSM May 14 '22 at 05:17
  • If you are still facing issues, share a codesandbox link, so that I can run the code myself and find out the issue. – SSM May 14 '22 at 05:19
  • Were you able to solve the problem? If this answer was helpful consider accepting it. – SSM May 15 '22 at 10:53
  • I changed ```getByLabelText``` to```findByLabelText``` and I got ```expect(received).toHaveValue() received value must be an HTMLElement or an SVGElement. Received has type: object Received has value: {}``` – hakima maarouf May 29 '22 at 11:11
  • 1
    @hakimamaarouf Yeah those were typos, I've updated my answer. But you don't need `findBy`, `getBy` should be fine because the input element is there initially. Do one thing add a `console.log` inside `rest.get` and see if this prints. And even better would be if you share your code in repl.it and so that I can debug directly. – SSM May 29 '22 at 12:32
  • @hakimamaarouf Also try the `findByDisplayValue` approach that I've added in my answer. – SSM May 29 '22 at 12:37
  • ```findByDisplayValue``` i got ``Unable to find an element with the display value: 100.`` I'm going to share my project code maybe I'm missing something. For the console log I don't know where should I see its result since im using cmd windows to run the tests – hakima maarouf May 29 '22 at 12:50
  • 1
    Yeah share your code, don't put the exact code just put the piece that is required for the test. Like replace the `TextField` component with the native `input` element. – SSM May 29 '22 at 12:54
  • here is the link of my project I made it simple with just one component Client in src/components/Client the tests are in src/unit-tests https://github.com/hamaarouf/msw-react-app.git thank you in advance for your time and help! – hakima maarouf May 29 '22 at 14:55
  • 1
    You have other API calls in your Client component as well, which are *not* mocked. Those need to be mocked as well – SSM May 29 '22 at 15:29
  • I did mock them but I got the same error also I tried to remove them, I just kept the one of informationsClient but I still got an empty recieved value – hakima maarouf May 29 '22 at 17:07
  • Remove all the unnecessary stuff from the github link, keep only one single API, then I might be able to debug, currently there's too much stuff. – SSM May 29 '22 at 17:40
  • done https://github.com/hamaarouf/msw-react-app – hakima maarouf May 29 '22 at 17:50
  • Finally! I've updated my answer to point out the changes that are required. I've also tested it on my end and it works fine, so just make those two changes and you would be good to go. – SSM May 29 '22 at 19:40