[英]TextInput onChangeText set useState value is not working in React Native Testing with Enzyme
如果 TextInput 等於“”,我想測試用戶不應該導航到任何其他屏幕。
我試圖讓控制台日志更正確地理解,但現在的問題是,在input.simulate("changeText", "any@email.com");
之后發生正確,控制台日志顯示來自測試的傳入值是“any@email.com”但在setValue(text);
發生console.log 說useState 值是“”。
為什么 state 沒有變化? 我需要用.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 是一個異步的 function 所以它不會立即更新 state,你可以看到下一個值直到下一次渲染
添加一個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>
);
}
默認情況下,反應在反應事件處理程序結束時重新渲染組件。 有關如何反應更新 state 的更多信息,請在此處查看此博客
我用這里的解決方案解決了這個問題。
test('should not navigate to login mail screen if email adress is not entered', () => {
const wrapper = shallow(<LoginContainer navigation={navigation} />);
input = findByTestAttr(wrapper, "login-input");
input.simulate("changeText", "any@email.com");
wrapper.update(); // update after changing the state
// After performing update, should find button element
button = findByTestAttr(wrapper, "login-button");
button.simulate("press");
expect(navigation.navigate).toHaveBeenCalledTimes(1);
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.