为什么在单独的' it '块测试中查询失败



我有一个React SignUp组件。我正在使用Jest作为运行器和测试库来编写测试。

注册组件代码(使用materialize进行样式化)是:

import React, { useState } from "react";
import Card from "@material-ui/core/Card";
import CardActions from "@material-ui/core/CardActions";
import CardContent from "@material-ui/core/CardContent";
import Button from "@material-ui/core/Button";
import TextField from "@material-ui/core/TextField";
import Typography from "@material-ui/core/Typography";
import Icon from "@material-ui/core/Icon";
import { makeStyles } from "@material-ui/core/styles";
import { create } from "./api-user.js";
import Dialog from "@material-ui/core/Dialog";
import DialogActions from "@material-ui/core/DialogActions";
import DialogContent from "@material-ui/core/DialogContent";
import DialogContentText from "@material-ui/core/DialogContentText";
import DialogTitle from "@material-ui/core/DialogTitle";
import { Link } from "react-router-dom";
const useStyles = makeStyles((theme) => ({
card: {
maxWidth: 600,
margin: "auto",
textAlign: "center",
marginTop: theme.spacing(5),
paddingBottom: theme.spacing(2),
},
error: {
verticalAlign: "middle",
},
title: {
marginTop: theme.spacing(2),
color: theme.palette.openTitle,
},
textField: {
marginLeft: theme.spacing(1),
marginRight: theme.spacing(1),
width: 300,
},
submit: {
margin: "auto",
marginBottom: theme.spacing(2),
},
}));
export default function Signup() {
const classes = useStyles();
const [values, setValues] = useState({
name: "",
password: "",
email: "",
open: false,
error: "",
});
const handleChange = (name) => (event) => {
setValues({ ...values, [name]: event.target.value });
};
const clickSubmit = () => {
const user = {
name: values.name || undefined,
email: values.email || undefined,
password: values.password || undefined,
};
create(user).then((data) => {
if (data.error) {
setValues({ ...values, error: data.error });
} else {
setValues({ ...values, error: "", open: true });
}
});
};
return (
<div>
<Card className={classes.card}>
<CardContent>
<Typography variant="h6" className={classes.title}>
Sign Up
</Typography>
<TextField
role="name"
id="name"
label="Name"
className={classes.textField}
value={values.name}
onChange={handleChange("name")}
margin="normal"
/>
<br />
<TextField
role="email"
id="email"
type="email"
label="Email"
className={classes.textField}
value={values.email}
onChange={handleChange("email")}
margin="normal"
/>
<br />
<TextField
role="password"
id="password"
type="password"
label="Password"
className={classes.textField}
value={values.password}
onChange={handleChange("password")}
margin="normal"
/>
<br />{" "}
{values.error && (
<Typography component="p" color="error">
<Icon color="error" className={classes.error}>
error
</Icon>
{values.error}
</Typography>
)}
</CardContent>
<CardActions>
<Button
color="primary"
variant="contained"
onClick={clickSubmit}
className={classes.submit}
>
Submit
</Button>
</CardActions>
</Card>
<Dialog open={values.open} disableBackdropClick={true}>
<DialogTitle>New Account</DialogTitle>
<DialogContent>
<DialogContentText>
New account successfully created.
</DialogContentText>
</DialogContent>
<DialogActions>
<Link to="/signin">
<Button color="primary" autoFocus="autoFocus" variant="contained">
Sign In
</Button>
</Link>
</DialogActions>
</Dialog>
</div>
);
}

我试图呈现组件,然后验证表单有Name,EmailPassword输入。测试文件如下所示:

import React from "react";
import { screen, render, cleanup, fireEvent } from "@testing-library/react";
import SignUp from "./Signup";
describe("App component", () => {
beforeAll(() => {
render(<SignUp />);
});
it("should have the input field for name", () => {
const nameInput = screen.getByLabelText("Name");
expect(nameInput).toBeInTheDocument();
});
it("should have the input field for email", () => {
const emailInput = screen.getByLabelText("Email");
expect(emailInput).toBeInTheDocument();
});
it("should have the input field for password", () => {
const passwordInput = screen.getByLabelText("Password");
expect(passwordInput).toBeInTheDocument();
});
afterAll(cleanup);
});

问题:无论我测试输入的顺序如何,第一个case/test总是通过。.getByLabelText查询能够找到第一个it块的组件,但在接下来的2块中失败。

为上面的文件运行测试的消息是:

FAIL  client/user/SignUp.test.js
App component
✓ should have the input field for name (13 ms)
✕ should have the input field for email (3 ms)
✕ should have the input field for password (1 ms)
● App component › should have the input field for email
TestingLibraryElementError: Unable to find a label with the text of: Email
Ignored nodes: comments, script, style
<body />
12 |   });
13 |   it("should have the input field for email", () => {
> 14 |     const emailInput = screen.getByLabelText("Email");
|                               ^
15 |     expect(emailInput).toBeInTheDocument();
16 |   });
17 |   it("should have the input field for password", () => {
at Object.getElementError (node_modules/@testing-library/dom/dist/config.js:40:19)
at getAllByLabelText (node_modules/@testing-library/dom/dist/queries/label-text.js:116:38)
at node_modules/@testing-library/dom/dist/query-helpers.js:62:17
at node_modules/@testing-library/dom/dist/query-helpers.js:111:19
at Object.getByLabelText (client/user/SignUp.test.js:14:31)
● App component › should have the input field for password

和当我切换顺序为:

it("should have the input field for email", () => {
const emailInput = screen.getByLabelText("Email");
expect(emailInput).toBeInTheDocument();
});
it("should have the input field for name", () => {
const nameInput = screen.getByLabelText("Name");
expect(nameInput).toBeInTheDocument();
});
it("should have the input field for password", () => {
const passwordInput = screen.getByLabelText("Password");
expect(passwordInput).toBeInTheDocument();
});

消息变为:

FAIL  client/user/SignUp.test.js
App component
✓ should have the input field for email (19 ms)
✕ should have the input field for name (8 ms)
✕ should have the input field for password (6 ms)
● App component › should have the input field for name
TestingLibraryElementError: Unable to find a label with the text of: Name
Ignored nodes: comments, script, style
<body />
13 |   });
14 |   it("should have the input field for name", () => {
> 15 |     const nameInput = screen.getByLabelText("Name");
|                              ^
16 |     expect(nameInput).toBeInTheDocument();
17 |   });
18 |   it("should have the input field for password", () => {
at Object.getElementError (node_modules/@testing-library/dom/dist/config.js:40:19)
at getAllByLabelText (node_modules/@testing-library/dom/dist/queries/label-text.js:116:38)
at node_modules/@testing-library/dom/dist/query-helpers.js:62:17
at node_modules/@testing-library/dom/dist/query-helpers.js:111:19
at Object.getByLabelText (client/user/SignUp.test.js:15:30)
● App component › should have the input field for password
TestingLibraryElementError: Unable to find a label with the text of: Password
Ignored nodes: comments, script, style
<body />
17 |   });
18 |   it("should have the input field for password", () => {
> 19 |     const passwordInput = screen.getByLabelText("Password");
|                                  ^
20 |     expect(passwordInput).toBeInTheDocument();
21 |   });
22 |   afterAll(cleanup);
at Object.getElementError (node_modules/@testing-library/dom/dist/config.js:40:19)
at getAllByLabelText (node_modules/@testing-library/dom/dist/queries/label-text.js:116:38)
at node_modules/@testing-library/dom/dist/query-helpers.js:62:17
at node_modules/@testing-library/dom/dist/query-helpers.js:111:19
at Object.getByLabelText (client/user/SignUp.test.js:19:34) 

正如你现在看到的,email的查询与其他2个(nameemail)相比有效

更有趣的是,当我在单个it块内使用所有3个查询时,所有测试都通过了:

it("should have the input field for name", () => {
const nameInput = screen.getByLabelText("Name");
expect(nameInput).toBeInTheDocument();
const emailInput = screen.getByLabelText("Email");
expect(emailInput).toBeInTheDocument();
const passwordInput = screen.getByLabelText("Password");
expect(passwordInput).toBeInTheDocument();
}); 

,它验证所有3个查询,你可以测试(SodeSandBox: https://codesandbox.io/s/react-testing-library-material-ui-select-forked-5rixw3?file=/src/App.test.js:254-891)它通过改变查询的参数,它会失败,如果你改变它像const emailInput = screen.getByLabelText("Email-failing");

有人能告诉我,为什么测试库工作在同一块,而不是在单独的块?我如何测试三个输入?我也尝试过不同的查询方法,例如.getByRole的角色属性,它以相同的方式表现,即在单个块和第二和第三块/测试失败。

在所有测试之前呈现组件。您应该在每个测试中呈现组件。不要在beforeAll块中使用render,在每个"it"块中使用它。

import React from "react";
import { screen, render, cleanup, fireEvent } from "@testing- 
library/react";
import SignUp from "./Signup";
describe("App component", () => {
it("should have the input field for name", () => {
render(<SignUp />);
const nameInput = screen.getByLabelText("Name");
expect(nameInput).toBeInTheDocument();
});
it("should have the input field for email", () => {
render(<SignUp />);
const emailInput = screen.getByLabelText("Email");
expect(emailInput).toBeInTheDocument();
});
it("should have the input field for password", () => {
render(<SignUp />);
const passwordInput = screen.getByLabelText("Password");
expect(passwordInput).toBeInTheDocument();
});
afterAll(cleanup);
});

最新更新