как проверить реагировать на выбор с помощью библиотеки реагирования на тестирование - PullRequest
0 голосов
/ 08 апреля 2019

App.js

import React, { Component } from "react";
import Select from "react-select";

const SELECT_OPTIONS = ["FOO", "BAR"].map(e => {
  return { value: e, label: e };
});

class App extends Component {
  state = {
    selected: SELECT_OPTIONS[0].value
  };

  handleSelectChange = e => {
    this.setState({ selected: e.value });
  };

  render() {
    const { selected } = this.state;
    const value = { value: selected, label: selected };
    return (
      <div className="App">
        <div data-testid="select">
          <Select
            multi={false}
            value={value}
            options={SELECT_OPTIONS}
            onChange={this.handleSelectChange}
          />
        </div>
        <p data-testid="select-output">{selected}</p>
      </div>
    );
  }
}

export default App;

App.test.js

import React from "react";
import {
  render,
  fireEvent,
  cleanup,
  waitForElement,
  getByText
} from "react-testing-library";
import App from "./App";

afterEach(cleanup);

const setup = () => {
  const utils = render(<App />);
  const selectOutput = utils.getByTestId("select-output");
  const selectInput = document.getElementById("react-select-2-input");
  return { selectOutput, selectInput };
};

test("it can change selected item", async () => {
  const { selectOutput, selectInput } = setup();
  getByText(selectOutput, "FOO");
  fireEvent.change(selectInput, { target: { value: "BAR" } });
  await waitForElement(() => getByText(selectOutput, "BAR"));
});

Этот минимальный пример работает, как и ожидалось, в браузере, но тест не пройден. Я думаю, что обработчик onChange в не вызывается. Как я могу вызвать обратный вызов onChange в тесте? Каков предпочтительный способ найти элемент для fireEvent? Спасибо

Ответы [ 2 ]

2 голосов
/ 08 апреля 2019

Это самый задаваемый вопрос о RTL: D

Лучшая стратегия состоит в том, чтобы использовать jest.mock (или эквивалент в вашей среде тестирования), чтобы смоделировать выборку и визуализировать выборку HTML вместо этого.

Для получения дополнительной информации о том, почему это лучший подход, я написал кое-что, что относится и к этому случаю. ОП спросил о выборе в Material-UI, но идея та же.

Оригинальный вопрос и мой ответ:

Потому что вы не можете контролировать этот интерфейс. Это определено в стороннем модуле.

Итак, у вас есть два варианта:

Вы можете выяснить, какой HTML создает библиотека материалов, а затем использовать container.querySelector, чтобы найти его элементы и взаимодействовать с ним. Это займет некоторое время, но это должно быть возможно. После того, как вы сделали все это, вы должны надеяться, что при каждом новом выпуске они не слишком изменяют структуру DOM, или вам, возможно, придется обновить все ваши тесты.

Другой вариант - полагать, что Material-UI собирается создать работающий компонент, который могут использовать ваши пользователи. Основываясь на этом доверии, вы можете просто заменить этот компонент в своих тестах на более простой.

Да, первый вариант проверяет то, что видит пользователь, но второй вариант легче поддерживать.

По моему опыту, второй вариант хорош, но, конечно, ваш вариант использования может отличаться, и вам, возможно, придется протестировать фактический компонент.

Это пример того, как вы могли бы посмеяться над выбором:

jest.mock("react-select", () => ({ options, value, onChange }) => {
  function handleChange(event) {
    const option = options.find(
      option => option.value === event.currentTarget.value
    );
    onChange(option);
  }
  return (
    <select data-testid="select" value={value} onChange={handleChange}>
      {options.map(({ label, value }) => (
        <option key={value} value={value}>
          {label}
        </option>
      ))}
    </select>
  );
});

Вы можете прочитать больше здесь .

0 голосов
/ 17 мая 2019

В моем проекте я использую реагирующую библиотеку и jest-dom.Я столкнулся с той же проблемой - после некоторого исследования я нашел решение, основанное на потоке: https://github.com/airbnb/enzyme/issues/400

Обратите внимание, что функция верхнего уровня для рендеринга должна быть асинхронной, а также отдельные шаги.

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

Также внутри getSelectItem должен быть асинхронный обратный вызов.

const DOWN_ARROW = { keyCode: 40 };

it('renders and values can be filled then submitted', async () => {
  const {
    asFragment,
    getByLabelText,
    getByText,
  } = render(<MyComponent />);

  ( ... )

  // the function
  const getSelectItem = (getByLabelText, getByText) => async (selectLabel, itemText) => {
    fireEvent.keyDown(getByLabelText(selectLabel), DOWN_ARROW);
    await waitForElement(() => getByText(itemText));
    fireEvent.click(getByText(itemText));
  }

  // usage
  const selectItem = getSelectItem(getByLabelText, getByText);

  await selectItem('Label', 'Option');

  ( ... )

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...