Why useEffect is not being triggered in react-testing-library?

Viewed 905

My Component:

const Component = ({product, show = false}: Props) => {
  const hook = useHook();
  const rendered = useRef(false);
  const [displayStyle, setDisplayStyle] = useState('none');
  const [showBar, setShowBar] = useState(show);
  const isInHook = () => hook.contains(product);

  useEffect(() => {
    if (!rendered.current) return;

    if (isInHook()) {
      setShowBar(false);
      setTimeout(() => {
        setDisplayStyle('none');
      }, 100);
    }
  }, [isInHook()]);     // Triggered when product is added to hook

  useEffect(() => {
    if (isInHook()) return;

    if (show) {
      setShowBar(true);
      setDisplayStyle('flex');
    } else if (!show && rendered.current) {
      setShowBar(false);
      setTimeout(() => {
        setDisplayStyle('none');
      }, 100);
    }

    if (!rendered.current) rendered.current = true;
  }, [show]);     // Triggered on show param change

  return (
        <StyledComponent show={showBar} displayStyle={displayStyle}>
          <Button
            title="Add product"
            onClick={() => {
              hook.add(product);
            }}
          >
            Add product
          </Button>
        </StyledComponent>
  );
};

export default Component;

Here we have isInHook that returns true/false for contains(product) and useEffect listening to it. It works perfectly and when product is added to hook, it triggers useEffect setting display of StyledComponent to none.

Problem comes when I tried testing it for disappearance using RTL:

const hook = [];

jest.mock('../hooks/use-hook', () => {
  return jest.fn(() => ({
    contains: (product) => hook.includes(product.slug),
    add: (product) => hook.push(product.slug),
  }));
});

it('is hidden once added to hook', async () => {
    let show = !hook.includes(data.original.slug);

    render(
      <Component
        show={show}
        product={product}
      />,
    );

    const barEl = screen.getByRole('button').closest('div');
    const addToHookBtn = screen.getByRole('button');
    expect(barEl).toBeInTheDocument();
    fireEvent.click(addToHookBtn);
    expect(hook.includes(product.slug)).toBeTruthy();
    await waitFor(() => {
      expect(barEl).toHaveStyle(`display: none`);
    });
});

When you click on the button, it adds product to array inside the hook and after that bar with the button disappears.

Here I mocked hook using jest, and expect(hook.includes(product.slug)).toBeTruthy() passes as true, which means that fireEvent.click(addToHookBtn) works properly. However, useEffect that supposed to get triggered on isInHook() not getting triggered. I also tried specifying show as false right before fireEvent, but I still can't get barEl display to be none. Why useEffect is not getting triggered on test even though expect(hook.includes(product.slug)).toBeTruthy() is passing?

0 Answers
Related