2016-12-22 15 views
4

В моих тестах я хотел бы заблокировать основной поток до тех пор, пока один из моих компонентов не завершит свои методы жизненного цикла через componentDidUpdate() после того, как я инициирую событие, которое заставляет его добавлять дочерние компоненты к себе. Как я могу это сделать?Подождите, пока компонент React не завершит обновление

Что-то вроде этого:

describe('my <Component />',() => { 
    it('should do what I want when its button is clicked twice',() => { 
    const wrapper = mount(<Component />); 
    const button = wrapper.find('button'); 

    // This next line has some side effects that cause <Component /> to add 
    // some children components to itself... 
    button.simulate('click', mockEvent); 

    // ... so I want to wait for those children to completely go through 
    // their lifecycle methods ... 
    wrapper.instance().askReactToBlockUntilTheComponentIsFinishedUpdating(); 

    // ... so that I can be sure React is in the state I want it to be in 
    // when I further manipulate the <Component /> 
    button.simulate('click', mockEvent); 

    expect(whatIWant()).to.be.true; 
    }); 
}); 

(я хочу сделать это, потому что, прямо сейчас, я получаю это предупреждение:

Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. 

Я считаю, я получаю это, потому что мои тесты вызывают мое компонент, чтобы изменить его внутреннее состояние быстрее, чем внутренняя многопоточная магия React, которая может идти в ногу с этим, поэтому к моменту, когда я запускаю button.simulate('click') во второй раз, React создал экземпляры новых дочерних компонентов, но еще не закончил их установку. для Реагировать на завершение обновления ING моего компонента и его детей это лучший способ решить эту проблему)

+1

Что делает обработчик щелчка делать? Все изменения состояния должны быть синхронными, если только у вас нет определенного таймера/асинхронного содержимого. – Jacob

+1

Обновления DOM также синхронны, если вы не делаете что-то странное или не используете экзотический аромат React. Я не удивлюсь, если ваше предупреждение «setState» из-за того, что ваш компонент сам делает «setState» перед монтированием. – Jacob

+1

@Jacob Я использую стороннюю библиотеку, [React Widgets] (https://jquense.github.io/react-widgets/docs/). Мой '' имеет React Widgets 'DateTimePicker' как один из его дочерних элементов, и предупреждение, похоже, испускается из' DateTimePicker'. Так что, к сожалению, я точно знаю, что меняет мое событие, и я легко не могу попытаться заглянуть в компонент, чтобы убедиться, что это не плохое поведение. – Kevin

ответ

1

Попробуйте оборачивать ваши expect() блок в setImmediate() блоке:.

describe('my <Component />',() => { 
    it('should do what I want when its button is clicked twice', (done) => { 
    const wrapper = mount(<Component />); 
    const button = wrapper.find('button'); 

    button.simulate('click', mockEvent); 
    button.simulate('click', mockEvent); 

    setImmediate(() => { 
     expect(whatIWant()).to.be.true; 
     done(); 
    }); 
    }); 
}); 

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

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

Вот большой вопрос, с дополнительной информацией о setImmediate(): setImmediate vs. nextTick

Вот документация setImmediate() в узле: https://nodejs.org/api/timers.html#timers_setimmediate_callback_args

+0

Я пробовал этот 'setImmediate()' трюк в некоторых моих тестах, но не в конкретной ситуации, описанной в моем вопросе. Так что есть драконы, и это решение может не сработать. – Kevin

+0

Если в 'setImmediate()' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ' Любая работа вокруг? – vleong

+0

@VLeong Вы пишете свои тесты как асинхронные тесты, используя функцию 'done' в своих' it' -блоках? См. Https://mochajs.org/#asynchronous-code – Kevin

 Смежные вопросы

  • Нет связанных вопросов^_^