React + Jest - тестирование асинхронных компонентов и ожидание монтирования - PullRequest
0 голосов
/ 03 июня 2018

Я пытаюсь протестировать компонент React, который имеет асинхронную componentDidMount.

Само обещание не нужно подвергать насмешке, оно не обязательно для доступа к внешнему контенту, в основном это просто оболочка дляреквизит.

Однако, чтобы проверить это, мне нужно использовать wrapper.update() 4 раза , что мне кажется действительно странным.

Решения в:

у меня все не сработало.

Вот как выглядит мой тест (который сейчас работает, но это решение совсем не элегантно и не слишком масштабируемо):

import * as React from 'react'
import { shallow, mount } from 'enzyme'
import LargeSelector from './LargeSelector'

describe('<LargeSelector />', async () => {
    const componentDidMountSpy = jest.spyOn(LargeSelector.prototype, 'componentDidMount')

    describe('search', async () => {
        it('should save initial response in cache', async () => {
            const wrapper = await shallow(<LargeSelector query={async (search) => ['search:' + search]} />)

            // WHY DO I NEED 4 UPDATES???
            await wrapper.update()
            await wrapper.update()
            await wrapper.update()
            await wrapper.update()

            expect(LargeSelector.prototype.componentDidMount).toHaveBeenCalledTimes(1) // works fine
            // these 2 only pass the expectation if I call wrapper.update() no less than 4 times    
            expect(wrapper.state()).toHaveProperty('options', ['search:'])
            expect(wrapper.state()).toHaveProperty('initialOptions', ['search:'])
        })
    })
})

Вот реализации componentDidMount и filterResults (вызов в первом):

public async componentDidMount() {
    if (this.props.searchOnInit) {
        const results = await this.filterResults('', [])
        if (this.props.cacheInitialResponse) {
            this.setState({ initialOptions: results })
        }
    }
}

private async filterResults(search: string, filters: IFilter[]) {
    const results = await this.props.query(search, filters)
    this.setState({ options: results })
    return results
}

Ответы [ 3 ]

0 голосов
/ 11 сентября 2018

Я столкнулся с точно такой же проблемой.Проблема в том, что тест не будет ждать выполнения обещаний.Мое решение состояло в том, чтобы использовать обратный вызов done, предоставленный Jest, в качестве сигнала завершения теста.

Примерно так:

it('wait async code before assert something', (doneCallback) => {
    const wrapper = shallow(<Component />);

    setImediate(() => {
        expect(wrapper.find('.async').length).toBe(1);
        doneCallback();
    });
});
0 голосов
/ 31 января 2019

энзим-асинхронные-помощники мне очень помогли с такой проблемой.
Вы можете легко заставить ее работать, добавив loading состояние и затем сделав что-то вроде:

import * as React from 'react';
import { shallow, mount } from 'enzyme';
import LargeSelector from './LargeSelector';
import { waitForState } from 'enzyme-async-helpers';

describe('<LargeSelector />', async () => {

  describe('search', async () => {
    it('should save initial response in cache', async () => {
      const wrapper = await shallow(<LargeSelector query={async (search) => ['search:' + search]} />);

      await waitForState(wrapper, state => state.loading === false);

      expect(LargeSelector.prototype.componentDidMount).toHaveBeenCalledTimes(1); 
      expect(wrapper.state()).toHaveProperty('options', ['search:']);
      expect(wrapper.state()).toHaveProperty('initialOptions', ['search:']);
    });
  });
});

И:
this.setState({ initialOptions: results })
Необходимо обновить до:
this.setState({ initialOptions: results, loading: false })

0 голосов
/ 06 июня 2018

Странное поведение, вероятно, из-за того, что вы использовали async для реализации componentDidMount.

В настоящее время весь процесс рендеринга React является синхронным, поэтому все, что связано с его потоком рендеринга, должно рассматриваться как синхронное.И случается, что в настоящее время команда React также разрабатывает функцию критических изменений, чтобы разрешить асинхронный рендеринг .

Но!Даже после того, как эта функция станет доступной, имейте в виду, что componentDidMount ловушка жизненного цикла будет по-прежнему синхронной, а также все остальные ловушки, поэтому важно знать, что React не будет ждать, пока какое-либо обещание будет разрешено.внутри крючки.

Вы можете запустить Обещание внутри componentDidMount, если оно соответствует вашему варианту использования, и позволить разрешенному результату изменить состояние.Но перехват жизненного цикла завершится до того, как он разрешится, это повлияет на ваш тестовый пример, поскольку тесту нужно будет дождаться обработки этого результата разрешенного Обещания, прежде чем его утверждать, вы можете использовать jest.runAllTicks () чтобы гарантировать такое поведение.

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