因此,我正在从基于类的组件转移到功能组件,但是在使用 jest/enzyme 为显式使用钩子的功能组件内部的方法编写测试时卡住了。这是我的代码的精简版。
function validateEmail(email: string): boolean {
return email.includes('@');
}
const Login: React.FC<IProps> = (props) => {
const [isLoginDisabled, setIsLoginDisabled] = React.useState<boolean>(true);
const [email, setEmail] = React.useState<string>('');
const [password, setPassword] = React.useState<string>('');
React.useLayoutEffect(() => {
validateForm();
}, [email, password]);
const validateForm = () => {
setIsLoginDisabled(password.length < 8 || !validateEmail(email));
};
const handleEmailChange = (evt: React.FormEvent<HTMLFormElement>) => {
const emailValue = (evt.target as HTMLInputElement).value.trim();
setEmail(emailValue);
};
const handlePasswordChange = (evt: React.FormEvent<HTMLFormElement>) => {
const passwordValue = (evt.target as HTMLInputElement).value.trim();
setPassword(passwordValue);
};
const handleSubmit = () => {
setIsLoginDisabled(true);
// ajax().then(() => { setIsLoginDisabled(false); });
};
const renderSigninForm = () => (
<>
<form>
<Email
isValid={validateEmail(email)}
onBlur={handleEmailChange}
/>
<Password
onChange={handlePasswordChange}
/>
<Button onClick={handleSubmit} disabled={isLoginDisabled}>Login</Button>
</form>
</>
);
return (
<>
{renderSigninForm()}
</>);
};
export default Login;
我知道我可以通过导出来为 validateEmail
编写测试。但是如何测试 validateForm
或 handleSubmit
方法。如果它是基于类的组件,我可以只是浅化组件并从实例中使用它
const wrapper = shallow(<Login />);
wrapper.instance().validateForm()
但这不适用于功能组件,因为无法以这种方式访问内部方法。有什么方法可以访问这些方法,或者在测试时功能组件是否应该被视为黑盒?
原文由 acesmndr 发布,翻译遵循 CC BY-SA 4.0 许可协议
在我看来,你不应该担心单独测试 FC 内部的方法,而是测试它的副作用。例如:
由于您可能使用的是异步的 useEffect,因此您可能希望将您的期望包装在 setTimeout 中:
您可能想要做的另一件事是提取与与表单介绍纯函数交互无关的任何逻辑。例如:而不是:
您可以重构:
Helpers.js
登录组件.jsx
这样你可以单独测试
isPasswordValid
和isEmailValid
,然后在测试Login
组件时,你可以 模拟你的 imports 。然后剩下的唯一要测试你的Login
组件的事情就是点击时,导入的方法被调用,然后是基于这些响应的行为,例如:这种方法的主要优点是
Login
组件应该只处理 更新表单 而不是其他任何东西。这可以非常直接地进行测试。任何其他逻辑 都应单独处理( 关注点分离)。