如何在单元测试中更改 TextInput 的选择并触发其 onSelectionChange 事件?

问题描述 投票:0回答:1

我有一个带有我正在测试的 TextInput 的 React Native 组件。该组件的部分行为依赖于通过 onSelectionChange 处理当前选择位置 - 也就是说,当我们键入时,文本光标在文本字段中的位置很重要。

该组件看起来基本上是这样的:

type Selection = { start: number, end?: number };

const Component = () => {
  const [value, setValue] = useState("");
  const [selection, setSelection] = useState<Selection>({ start: 0, end: 0 });

  // do some things with value and selection, e.g.:
  useEffect(() => {
    console.debug(value.slice(selection.start, selection.end));
  }, [value, selection.start, selection.end]);

  return (
    <TextInput
      testID="input"
      value={text}
      onChangeText={setMessageText}
      selection={selection}
      onSelectionChange={setSelection}
    />
  );
}

在我们对该组件的单元测试中,我可以很好地更改该值来测试与该值关联的行为(通过 React Native 测试库的 fireEvent.changeText):

const input = screen.getByTestId("input");
fireEvent.changeText(input, "some text");

但是,更改文本不会移动文本光标,因此

selection
始终保持为
{ start: 0 }
。为了正确测试该组件的行为,我需要能够将选择设置为其他位置。这意味着我需要我的代码在
setSelection({ start: 3, end: 3 })
更改后以某种方式调用
value
等。

如何在单元测试中触发 onSelectionChange 事件?

我认为这个问题本质上是两件事之一:

  • 如何触发选择更改事件,使其从
    onSelectionChange
    出现?
  • 或者,如何访问绑定到 TextInput 的
    onSelectionChange
    属性的函数以便直接调用它?

我是否应该为

<TextInput />
设置一个玩笑模拟,并在文本更改时自动更新选择?

react-native textselection selectionchanged react-native-textinput react-native-testing-library
1个回答
0
投票

我发现我实际上可以通过对象的 props 直接访问 onSelectionChange 绑定:

const input = screen.getByTestId("input");
const onSelectionChange = input.props["onSelectionChange"];

这意味着我可以构建选择更改事件并在测试期间调用它们:

import { act, fireEvent, render, screen } from "@testing-library/react-native";

let onSelectionChange: (event: NativeSyntheticEvent<TextInputSelectionChangeEventData>) => void;

/** This creates a mocked Text Input Selection event that just contains a selection. */
function makeSelectionEvent(selection: { start: number, end: number }) {
  const event: NativeSyntheticEvent<TextInputSelectionChangeEventData> = {
    nativeEvent: {
      selection,
    } as any,
  } as any;
  return event;
}

beforeEach(() => {
  render(<Component />);

  const input = screen.getByTestId("input");
  onSelectionChange = input.props["onSelectionChange"];
});

test(`change the value and selection`, () => {
  const input = screen.getByTestId("input");

  fireEvent.changeText(input, "text");
  act(() => {
    onSelectionChange(makeSelectionEvent({ start: 4, end: 4 });
  });

  // Our component will now have both its value and selection updated.
  expect(...)
});
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.