ejanson
ejanson

Reputation: 499

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

Upvotes: 12

Views: 5733

Answers (3)

Rafael Tavares
Rafael Tavares

Reputation: 6471

You can use fireEvent(element, eventName, data), its documentation is here, and its type is:

type FireEventFunction = (
  element: ReactTestInstance,
  eventName: string,
  ...data: Array<any>
) => void;

So, to fire onLayout, use the layout event name:

// You can use any getBy* or another selector that returns a ReactTestInstance
fireEvent(getByText('Some label'), 'layout', {
  nativeEvent: { layout: { height: 100 } },  // The event data you need
});

Upvotes: 14

Fela Maslen
Fela Maslen

Reputation: 2162

@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.

Upvotes: 10

Adam Katz
Adam Katz

Reputation: 6962

wrapper.find('Wrapper').simulate('layout')

Upvotes: -3

Related Questions