在 React Native 中测试 onLayout

Testing onLayout in React Native

我正在尝试使用 @testing-library/react-native 测试使用 onLayout 事件的组件,该组件通过组件道具使用 setState 函数,但从未调用该函数:

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

Expected: 100

Number of calls: 0

我怎样才能完成这项工作?怎么了?

组件:

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;
`

测试:

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))
})
wrapper.find('Wrapper').simulate('layout')

@testing-library/react-native 现在有一个 fireEvent.layout 触发器,至少从 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
        },
      },
    });
  });
});

这应该会触发 onLayout 事件处理程序。

以后有需要的可以用fireEvent(element, eventName, data),它的文档是here,它的类型是:

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

因此,要触发 onLayout,请使用 layout 事件名称:

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