#reactjs #material-ui #formik #react-testing-library
#reactjs #материал-пользовательский интерфейс #formik #react-testing-library
Вопрос:
Мне сложно работать с библиотекой тестирования react и понимать запросы, которые мне нужно использовать, чтобы выбрать компоненты, которые мне нужно протестировать. Запросы становятся слишком упрощенными, когда DOM становится все более подробным с такими фреймворками, как material ui и formik.
Я создал изолированную среду для кода, чтобы проиллюстрировать проблему. Там вы можете проверить неудачный тест.
https://codesandbox.io/embed/px277lj1x
Проблема, которую я получаю, заключается в том, что запрос getLabelTextBy() не возвращает компонент. Похоже, что метка aria by или атрибут for не отображаются в пользовательском интерфейсе material. Не уверен, как исправить эту ошибку.
Код также приведен ниже для справки
//Subject under test
import React from "react";
import { Button } from "@material-ui/core";
import { TextField } from "formik-material-ui";
import { Field, Form, Formik } from "formik";
import * as yup from "yup";
const validationSchema = yup.object().shape({
name: yup.string().required("Office name is required"),
address: yup.string().required("Address is required")
});
export default () => (
<Formik
initialValues={{
name: "",
address: ""
}}
validationSchema={validationSchema}
onSubmit={(values, { setSubmitting }) => {
setSubmitting(false);
console.log("form is submitted with", values);
}}
render={({ submitForm, isSubmitting, isValid }) => (
<Form>
<Field
label="Office Name"
name="name"
required
type="text"
component={TextField}
/>
<Field
label="Address Line 1"
name="addressLine1"
type="text"
component={TextField}
/>
<Button
variant="contained"
color="primary"
fullWidth={false}
size="medium"
disabled={isSubmitting || !isValid}
onClick={submitForm}
data-testid="submitButton"
>
Submit
</Button>
</Form>
)}
/>
);
// Test
import React from "react";
import { render, fireEvent } from "react-testing-library";
import App from "./App";
describe("Create Office Form tests", () => {
it("button should not be disabled when all required fields are filled up", () => {
const { getByLabelText, getByTestId, debug } = render(<App />);
const values = {
"office name": "office",
address: "address 1"
};
for (const key in values) {
const input = getByLabelText(key, { exact: false, selector: "input" });
fireEvent.change(input, { target: { value: values[key] } });
}
const button = getByTestId("submitButton");
expect(button.disabled).not.toBeDefined();
});
});
Ответ №1:
Вы должны добавить id
в свой Field
, потому что for
атрибут label ожидает идентификатор элемента ввода, на который он ссылается:
<Field
id="myName"
label="Office Name"
name="name"
required
type="text"
component={TextField}
/>
Рабочий пример:
Комментарии:
1. Пример не работает, кнопка отключена после заполнения формы. Просто попытался запустить тесты в codesandbox, и они завершились неудачей.
Ответ №2:
Несколько вещей. Создатель библиотеки не рекомендует использовать {getByLabelText, getByTestId, debug}. Вам следует использовать screen.getByLabelText()
.
Если есть изменение, возможно, оно не ожидает нового рендеринга, поэтому было бы лучше дождаться его или обернуть ожидание в метод waitFor.
Кроме того, expect(button.disabled).not.toBeDefined()
не должно быть правильным. Я думаю, вы просто проверяете, отключена кнопка или нет, верно? Таким образом, вы можете использовать expect(button).toBeDisabled()
или not.toBeDisabled()
По крайней мере, чтобы протестировать это, я думаю, вам следует отключить цикл for и проверить его в обычном режиме. Вы можете использовать screen.debug (компонент), чтобы отобразить HTML-код после некоторого действия.