Как протестировать компоненты react-jsonschema-form с помощью @testing-library/user-event

#reactjs #unit-testing #react-testing-library #react-jsonschema-forms #user-event

#reactjs #модульное тестирование #react-testing-library #react-jsonschema-forms #пользователь-событие

Вопрос:

Я не могу написать даже самые простые тесты для формы react jsonschema. Поскольку изменения входных элементов, похоже, не отражаются в dom.

Учитывая минимальную форму, подобную этой:

 const schema = {
  title: "Todo", type: "object",
  properties: {
    title: { type: "string", title: "Title", default: "A new task" }
  }
};

const formData = { title: "First task aaa" };

export class MyForm extends React.Component {
  render() { return <Form schema={schema} formData={formData} />; }
}
 

минимальный тест будет выглядеть так

 test("changes input", async () => {
  render(<MyForm />);
  const input = screen.getByRole("textbox");
  expect(input.value).toBe("First task aaa");
  await userEvent.type(input, "567890", { delay: 10 });
  expect(input.value).toBe("567890");
});
 

(Полный пример приведен в Codesandbox.)

После ввода в поле формы текст First task aaa должен быть заменен на 567890 . К сожалению, это не так. input.value сохраняет значение First task aaa .

Я использовал много вариантов запуска событий и ожидания результатов, но всегда значение входного элемента остается неизменным.

Чего мне не хватает для тестирования <MyForm /> компонента? Мне кажется довольно стандартным.

Ответ №1:

Я также могу воспроизвести вашу проблему, и похоже, что react-jsonschema-form плохо работает с fireEvent or userEvent .

Однако, используя функцию моделирования react-doms, это работает:

 import React from "react";
import { Simulate } from 'react-dom/test-utils'
import { render } from "@testing-library/react";
import { MyForm } from "./form.js";

// Tests in codesandbox fail in Safari - use Firefox or Chrome
// click on the "Tests" tab in the upper right.

test("changes input", async () => {
  const { getByLabelText } = render(<MyForm />);
  const input = getByLabelText("Title");
  expect(input.value).toBe("First task aaa");

  Simulate.change(input, { target: { value: '567890' }})

  expect(input.value).toBe("567890");
});
 

Ответ №2:

С точки зрения того, что вы используете fluent-ui библиотеку форм для своего пользовательского интерфейса, и это свяжет входное значение с вашим formData.title полем. Это может прервать userEvent.type действие. Чтобы просто протестировать userEvent.type функциональность, вы можете создать свой компонент формы с чистым элементом ввода и привязать значение по умолчанию к defaultValue элемента ввода.

Например:

 export class MyForm extends React.Component {
  render() {
    return <input type="text" defaultValue="First task aaa" />;
  }
}
 

В случае, если вы увидите ошибку ниже в своем тестовом выводе:

 expect(element).toHaveValue(567890)

    Expected the element to have value:
      567890
    Received:
      First task aaa567890

      13 |   expect(input).toHaveValue("First task aaa");
      14 |   userEvent.type(input, '567890');
    > 15 |   expect(input).toHaveValue('567890');
         |                 ^
      16 | });

 

Как вы можете видеть, userEvent.type к текущему значению будет добавлен дополнительный ввод. Итак, вы можете просто использовать Simulate.change функциональность или использовать userEvent.clear функцию перед своей userEvent.type строкой, как показано ниже.

 test("changes input", async () => {
  render(<MyForm />);
  const input = screen.getByRole("textbox");

  expect(input).toHaveValue("First task aaa");
  userEvent.clear(input);
  userEvent.type(input, "567890");
  expect(input).toHaveValue("567890");
});
 

Этот ответ может быть полезен для вашего вопроса.
Приветствия!