Search code examples
react-nativereact-testing-library

Testing onLayout in React Native


I am trying to test a component that uses the onLayout event using @testing-library/react-native, with the component using a setState function through the components props but the function is never called:

expect(jest.fn()).toHaveBeenCalledWith(...expected)

Expected: 100

Number of calls: 0

How can I make this work? What is wrong?

Component:

type Props = {
  children: React.ReactNode
  setHeaderHeight: React.Dispatch<React.SetStateAction<number>>
}

const HeaderSetHeightWrapper = ({ children, setHeaderHeight }: Props) => {
  return (
    <Wrapper
      onLayout={({
        nativeEvent: {
          layout: { height }
        }
      }) => {
        setHeaderHeight(Math.floor(height))
      }}
      testID="header-h"
    >
      {children}
    </Wrapper>
  )
}

const Wrapper = styled.View`
  position: absolute;
  left: 0;
  top: 0;
`

Test:

it('should set the header height on layout', async () => {
  const mockHeight = 100

  const setHeaderHeight = jest.fn()

  const { getByTestId } = render(
    <HeaderSetHeightWrapper setHeaderHeight={setHeaderHeight}>
      <View style={{ width: 100, height: mockHeight }} />
    </HeaderSetHeightWrapper>
  )

  const wrapper = getByTestId('header-h')

  fireEvent(wrapper, new NativeTestEvent('onLayout', { nativeEvent: { layout: { height: mockHeight } } }))

  await wait(() => expect(setHeaderHeight).toHaveBeenCalledWith(mockHeight))
})

Solution

  • @testing-library/react-native has a fireEvent.layout trigger now, at least as of v5.0.3:

    import { render, act, fireEvent } from '@testing-library/react-native';
    
    test(() => {
      const { getByTestId } = render(<MyComponent />);
      const view = getByTestId('my-view');
      act(() => {
        fireEvent.layout(view, {
          nativeEvent: {
            layout: {
              width: 300,
              // etc
            },
          },
        });
      });
    });
    

    This should trigger the onLayout event handler.