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>
);
};
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.