我有一个带有我正在测试的 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
出现?onSelectionChange
属性的函数以便直接调用它?我是否应该为
<TextInput />
设置一个玩笑模拟,并在文本更改时自动更新选择?
我发现我实际上可以通过对象的 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(...)
});