reactjs - TextInput onChangeText 设置 useState 值在 React Native Testing with Enzyme 中不起作用
问题描述
如果 TextInput 等于“”,我想测试用户不应该导航到任何其他屏幕。
我试图让控制台日志更正确地理解,但现在的问题是,在input.simulate("changeText", "any@email.com");
正确发生之后,控制台日志说来自测试的传入值是“any@email.com”,但是在setValue(text);
发生之后,console.log 说 useState 值是“ ”。
为什么状态没有改变?我需要用 更新包装器.update()
吗?
这是我的 React Native 代码:
import React, { useState } from "react";
import { View, Button, TextInput } from "react-native";
export const LoginContainer = (props) => {
const [value, setValue] = useState("");
const handleClick = () => {
if (value !== "") {
props.navigation.navigate("any other screen");
}
}
return (
<View>
<TextInput
test-id="login-input"
onChangeText={(text) => {
console.log("INPUT_TEXT:", text);
setValue(text);
console.log("STATE_TEXT:", value);
}}
value={value}
/>
<Button test-id="login-button" onPress={() => handleClick()} />
</View>
);
}
控制台日志:
console.log
INPUT_TEXT: any@email.com
at onChangeText (....)
console.log
STATE_TEXT:
at onChangeText (....)
expect(jest.fn()).toHaveBeenCalledTimes(expected)
Expected number of calls: 1
Received number of calls: 0
测试代码:
import "react-native";
import React from "react";
import { shallow } from 'enzyme';
import { LoginContainer } from "...";
import { findByTestAttr } from '...';
const navigation = {
navigate: jest.fn()
}
describe('correct login action', () => {
const wrapper = shallow(<LoginContainer navigation={navigation} />);
let input = findByTestAttr(wrapper, "login-input");
let button = findByTestAttr(wrapper, "login-button");
test('should not navigate to login mail screen if email adress is not entered', () => {
input.simulate("changeText", "any@email.com");
button.simulate("press");
expect(navigation.navigate).toHaveBeenCalledTimes(1);
//input.simulate("changeText", "");
//button.simulate("press");
//expect(navigation.navigate).toHaveBeenCalledTimes(0);
});
});
解决方案
你好 setValue 是一个异步函数所以它不会立即更新状态,你可以看到下一个值直到下一次渲染
添加一个console.log,如下所示
import React, { useState } from "react";
import { View, Button, TextInput } from "react-native";
export const LoginContainer = (props) => {
const [value, setValue] = useState("");
const handleClick = () => {
if (value !== "") {
props.navigation.navigate("any other screen");
}
}
// try to add console.log here and you will see the new value after click
console.log("STATE_TEXT:", value);
return (
<View>
<TextInput
test-id="login-input"
onChangeText={(text) => {
console.log("INPUT_TEXT:", text);
setValue(text);
}}
// if you want the setValue to be executed immediately you can call it inside promise like below, however the value will still the same even after re-rendering
//onChangeText={(text) => {
//console.log("INPUT_TEXT:", text);
//Promise.resolve().then(() => {
//setValue(text);
//console.log("STATE_TEXT after calling it inside promise:", value);
//});
//console.log("STATE_TEXT:", value);
//});
value={value}
/>
<Button test-id="login-button" onPress={() => handleClick()} />
</View>
);
}
默认情况下,反应在反应事件处理程序结束时重新渲染组件。有关如何反应更新状态的更多信息,请在此处查看此博客
推荐阅读
- android - Android:使用已安装的文件管理器之一打开目录路径
- cpu - 更小的晶体管意味着信誉的运气?
- python - 使用多个 if-else 子句对 pandas 数据帧进行矢量化以拆分域
- unity3d - unity webgl 构建缓冲视频
- php - .htaccess mod_rewrite 规则以匹配干净的 URL 以及其他自定义参数
- angular - Angular 7 升级:RxJs switchMap 和 ObservableInput 的返回类型
- android - 如何在删除之前从应用程序内部文件夹中复制文件?
- ssis - SSIS 从 csv 平面文件源中删除左零
- django - Django 设置:没有这样的表 auth_user
- reactjs - 两页相互重叠