Jest - Как проверить правильность вывода методов реагирования? - PullRequest
0 голосов
/ 19 ноября 2018

У меня возникают проблемы при попытке понять, как я могу использовать Jest для проверки вывода метода в файле реакции. Я совершенно новичок в этом стиле веб-разработки, поэтому любая помощь приветствуется.

У меня есть файл js, подобный этому:

import * as React from 'react';
import 'es6-promise';
import 'isomorphic-fetch';

export default class FetchData extends React.Component {
    constructor() {
        super();
        this.state = { documents: [], loading: true };
        fetch('api/SampleData/GetDocuments')
            .then(response => response.json())
            .then(data => {
                this.setState({ documents: data, loading: false });
            });
    }

    render() {
        let contents = this.state.loading ? <p><em>Loading...</em></p>
            : FetchData.renderdocumentsTable(this.state.documents);

        return <div>
            <button onClick={() => { this.refreshData() }}>Refresh</button>
            <p>This component demonstrates bad document data from the server.</p>
            {contents}
        </div>;
    }

    refreshData() {
        fetch('api/SampleData/GetDocuments')
            .then(response => response.json())
            .then(data => {
                this.setState({ documents: data, loading: false });
            });
    }

    static renderdocumentsTable(documents) {
        return <table className='table'>
            <thead>
                <tr>
                    <th>Filename</th>
                    <th>CurrentSite</th>
                    <th>CorrectSite</th>
                </tr>
            </thead>
            <tbody>
                {documents.map(document =>
                    <tr className="document-row" key={document.documentId}>
                        <td>{document.filename}</td>
                        <td>{document.currentSite}</td>
                        <td>{document.correctSite}</td>
                    </tr>
                )}
            </tbody>
        </table>;
    }
}

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

Спасибо, Alex

1 Ответ

0 голосов
/ 19 ноября 2018

Я придерживаюсь следующего подхода:

  1. Звуковые зависимости , вызываемые явно тестируемым компонентом.
  2. Инициализирующий компонент с shallow()
  3. пробует разные модификации
  4. Проверка компонента с помощью .toMatchSnapshot()

Под "пробовать разные модификации" я имею в виду либо создание компонента с разными начальными props, либо взаимодействие с внутренними элементами компонента 'props.

test('closes list on button clicked', () => {
    let wrapper = shallow(<MyComponent prop1={'a'} prop2={'b'} />);
    wrapper.find('button').at(0).simulate('click');
    expect(wrapper).toMatchSnapshot();
});

Таким образом, вам никогда не нужно тестировать методы отдельно. Почему я считаю, что это имеет смысл?

Несмотря на то, что все тесты для каждого метода пройдены успешно, мы все еще не можем сказать, работает ли он в целом (ложноположительная реакция). Также, если мы сделаем какой-либо рефакторинг, такой как метод переименования, наши тесты на метод не пройдут. В то же время компонент все еще может работать отлично, и мы тратим больше времени на исправление тестов, просто чтобы они прошли (ложноотрицательная реакция).

С другой стороны, фокусируясь на результатах render() (это то, что адаптер Enzyme делает под капотом .toMatchSnapshot() matcher), мы проверяем, что делает наш элемент в рамках проекта React.

[UPD] Пример на основе вашего кода:

describe("<FetchData />", () => {
  let wrapper;
  global.fetch = jest.fn();

  beforeEach(() => {
    fetch.mockClear();
  });

  function makeFetchReturning(documents) {
    fetch.mockImplementation(() => Promise.resolve({ json: () => documents }));
  }

  function initComponent() {
    // if we run this in beforeEach we would not able to mock different return value for fetch() mock
    wrapper = shallow(<FetchData />); 
  }

  test("calls appropriate API endpoint", () => {
    makeFetchReturning([]);
    initComponent();
    expect(fetch).toHaveBeenCalledWith("api/SampleData/GetDocuments");
  });

  test("displays loading placeholder until data is fetched", () => {
    // promise that is never resolved
    fetch.mockImplementation(() => new Promise(() => {})); 
    initComponent();
    expect(wrapper).toMatchSnapshot();
  });

  test("looks well when empty data returned", () => {
    makeFetchReturning([]);
    initComponent();
    expect(wrapper).toMatchSnapshot();
  });

  test("reloads documents and displays them", () => {
    makeFetchReturning([]);
    initComponent();
    // no matter what values we include in mock but it should be something non-empty
    makeFetchReturning([{fileName: '_', currentSite: '1', correctSite: '2'}]);
    wrapper.find('button').at(0).simulate('click');
    expect(fetch).toHaveBeenCalledTimes(2);
    expect(wrapper).toMatchSnapshot();
  })

});
...