[SOLVED] react testing library ternary operator, finding right component

Issue

This Content is from Stack Overflow. Question asked by walee

I’m beginner with React testing, learning by coding, here i have a component ‘cam.tsx’
i want to test it, when i want to test Add function it goes straight like this, but when i want to test Update function it still shows Add function in my test, how to test both of them ?

describe("Testing component ", () => {
 
  
  const Camera = (): RenderResult =>
    render(
      <Provider store={store}>
        <Cam
          }}
        />{" "}
      </Provider>
    );

 

  test("Cam", () => {
    Camera();
    const name = screen.queryByTestId(/^AddName/i);
  
  });
});

cam.tsx:

 const option = state.mode;

  return (
    <React.Fragment>
      <div data-testid="header">
        {option == ADD ? Add() : <></>}
        {option == UPDATE ? Update() : <></>}
      </div>
    </React.Fragment>

English is not my mother language, so could be mistakes



Solution

Here is how to test a component that conditionally renders components from state and can be updated via props.

import {render, screen} from '@testing-library/react';
import {Cam} from './Cam';

test('renders add by default', () => {
    render(<Cam/>);

    expect(screen.getByTestId('addForm'))
        .toBeInTheDocument();
    expect(screen.queryByTestId('updateForm'))
        .not.toBeInTheDocument();
});

test('renders edit by passing props', () => {
    const {rerender} = render(<Cam mode={undefined}/>);

    rerender(<Cam mode={'UPDATE'} />)

    expect(screen.getByTestId('updateForm'))
        .toBeInTheDocument();
    expect(screen.queryByTestId('addForm'))
        .not.toBeInTheDocument();
});

However, it is known in the React community that updating state via props is usually an anti-pattern. This is because you now have two sources of truth for state and can be easy to have these two states conflicting. You should instead just use props to manage rendering.

If state comes from a parent component, use props.

export function Cam(props) {
    const option = props.mode;

    return (
        <div data-testid="header">
            {option === ADD ? Add() : <></>}
            {option === UPDATE ? Update() : <></>}
        </div>
    );
}

If you really want to keep state in the child component even if props are passed in, you should update props in an useEffect hook. Additionally, you should use the setState function rather than setting state manually state.mode = props.mode

Use the useEffect hook to update state via props.

...
    const [state, setState] = useState({mode: ADD});

    useEffect(() => {
        if (props.mode) {
            setState({mode: props.mode});
        }
    }, [props.mode]) <-- checks this value to prevent infinite loop.

    const option = state.mode;

    return (
...


This Question was asked in StackOverflow by walee and Answered by g0rb It is licensed under the terms of CC BY-SA 2.5. - CC BY-SA 3.0. - CC BY-SA 4.0.

people found this article helpful. What about you?