reactjs - 使用 Mount 时 Enzyme 返回的节点多于现有节点
问题描述
组件.tsx
import React, { ChangeEvent, FormEvent, useEffect, useState } from "react";
import { Form, FormControl, FormGroup, FormLabel } from "react-bootstrap";
import Button from "react-bootstrap/Button";
import Card from "react-bootstrap/Card";
import { useHistory } from "react-router-dom";
import { StorageKeys } from "../ProtectedRoute";
import "./styles.scss";
const Login = () => {
const history = useHistory();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const handleSetEmail = (event: ChangeEvent<HTMLInputElement>) =>
setEmail(event.target.value);
const handleSetPassword = (event: ChangeEvent<HTMLInputElement>) =>
setPassword(event.target.value);
const handleSubmit = (event: FormEvent<HTMLElement>) => {
event.preventDefault();
console.log("email::", email);
console.log("password::", password);
localStorage.setItem(StorageKeys.TOKEN, "TODO: Auth");
history.push("/");
};
useEffect(() => {
localStorage.removeItem(StorageKeys.TOKEN);
}, []);
return (
<div id="login">
<Card id="loginCard">
<Card.Header>Login</Card.Header>
<Card.Body>
<Form onSubmit={handleSubmit}>
<FormGroup>
<FormLabel>Email address</FormLabel>
<FormControl type="email" id="email" placeholder="Enter email"
value={email} onChange={handleSetEmail}
required={true} />
</FormGroup>
<FormGroup>
<FormLabel>Password</FormLabel>
<FormControl type="password" id="password" placeholder="Password"
value={password} onChange={handleSetPassword}
required={true} />
</FormGroup>
<div className={"button-container"}>
<Button id="submit" variant="primary" type="submit">
Submit
</Button>
</div>
</Form>
</Card.Body>
</Card>
</div>
);
};
export default Login;
这在shallow
用于渲染组件时有效:
登录.test.tsx
import { mount, shallow } from "enzyme";
import React from "react";
import Login from "./index";
describe("Login Component", () => {
test("can properly submit form", () => {
jest.spyOn(window.localStorage.__proto__, "removeItem");
const wrapper = shallow(<Login />);
// This works just find, finds only the one #email input.
const emailInput = wrapper.find("#email");
emailInput.simulate("change", { target: { value: testLoginData.email } });
});
});
使用时mount
会引发错误:
Error: Method “simulate” is meant to be run on 1 node. 2 found instead
import { mount, shallow } from "enzyme";
import React from "react";
import Login from "./index";
describe("Login Component", () => {
test("can properly submit form", () => {
jest.spyOn(window.localStorage.__proto__, "removeItem");
const wrapper = mount(<Login />);
const emailInput = wrapper.find("#email");
// This will now complain about there being too many nodes.
emailInput.simulate("change", { target: { value: testLoginData.email } });
});
});
是什么赋予了?我需要使用 mount 来进行我正在进行的测试,为什么肯定只有一个元素时会找到多个元素。
我可以使用以下方法修补它,但我不应该……对吗?!
emailInput.at(0).simulate("change", { target: { value: testLoginData.email } });
解决方案
所以这是因为你<FormControl
是第一个id
并且<input
是第二个(反之亦然)。
有很多方法:
.at(0)
会起作用,但是这样你永远不会知道你是否(因为代码中的错误)渲染了多个元素。如果条件渲染{someFlag && <....
中假定互斥的条件不是,则可能会发生这种情况。所以真的,这是一个糟糕的方式。- 模拟
FormControl
为最终元素 - 所以<input
将不再返回.find()
(老实说从未使用过,只是假设它会工作 - 但仍然看起来很混乱,并且每个测试文件都需要额外的样板代码,所以不是非常少数的方法):
jest.mock('../FormControl.jsx', () => null);
- 用于
hostNodes()
仅过滤本机元素(如<span>
要返回):
const emailInput = wrapper.find("#email").hostNodes();
我投票支持第 3 个选项,因为它对于捕获代码逻辑的错误是最可靠且仍然安全的。
推荐阅读
- java - 如何限制 SQL 中的 CLOB 列?
- android - gradle 同步错误“原因:无效类型代码:2D”
- c# - 变量不能是非输入类型 - GraphQL .Net 约定
- c# - 在 GET HttpWebRequest 中传递授权令牌
- python - 如何将行子集传递给自定义函数并返回列表?
- ios - 如何使用 ARKit 计算点 2 到点 3 和点 3 到 4 的距离等等?
- typescript - 在 Typescript 中,为什么 JSX.IntrinsicElements 不像文档描述的那样工作?
- java - 如何在android中检查txt文件中的一行是否以“h”开头?
- android - 如何在多个活动上实现 admob 横幅
- c# - 使用 AForge 裁剪时特定计算机上的奇怪行为