1

I have a component which I am trying to test -

export const Block = ({ title }) => {
      const [isSmall, setIsSmall] = useState(false);
      

      reutrn (

            <BlockContainer
                  onBlockContainerResize={(width: number) => (width < 180 ? setIsSmall(true) : setIsSmall(false))}
            >
                  <div className={isSmall ? 'title--small' : 'title'} data-testid={isSmall ? 'isSmall' : ''}>
                        {title}
                  </div>
                  <div className={isSmall ? 'desc--small' : 'desc'}>
                        {desc}
                  </div>
            </BlockContainer>
      )
}

I added a data-testid as I want to avoid testing classNames as this goes against react-testing-library principles. I just want to make sure that if the container is below 180px, then isSmall is set to true.

For my test I am using a div as the container rather than the parent component BlockContainer -

test('should set isSmall to true if container width is below 180px', () => {
  render(
      <div style={{ width: '170px' }}>
        <Block
          title="test title"
          desc="test description"
        />
      </div>
  );

  expect(within(screen.getByTestId('isSmall')).queryByText('test title')).toBeInTheDocument();
});

However when trying this, isSmall is not being set to true and so the datatest-id is not being set. I am confused as to why this is happening?

Here is the BlockContainer implementation -

export const BlockContainer: FunctionComponent<BlockContainerProps> = ({
  children,
  onBlockContainerResize,
}) => {
  const blockRef = useRef<HTMLDivElement>(null);

  useResizeObserver(blockRef, (entry) => onBlockContainerResize?.(entry.contentRect.width));

  return (
    <div
      ref={blockRef}
    >
      {children}
    </div>
  );
};
1

1 Answer 1

1

When testing with React Testing Library, it is important to know what other components do. For example, you are initializing the isSmall state to false, and only setting it to true on the callback of onBlockContainerResize, but you are not making any action to make this happen. You need to trigger that callback to make the change.

Said that, in RTL the main objective is to test what the final user sees and mock what the final user does. That means that to trigger that callback, you would need to mimic the user behaviour (for instance, resizing the container). So we need to know how does de user do that (inside the BlockContainer component), and then trigger that with a fireEvent from RTL, after rendering the component and before asserting it.

Furthermore, I wouldn't put a data-testid property in a div and render it depending on the state. That couples your test to the implementation of the component. I would take that div, and check its size, which is what the final user would do, as a user does not know about internal states.

Hope these tips help. If not, we will need an example of the implementation of BlockContainer to see how this event can be triggered.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for your comments. I have added the BlockContainer implementation above!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.