Подтвердить что ты не робот

Как проверить обновление prop на компоненте React

Каков правильный способ модульного тестирования обновления поддержки компонента React.

Вот моя тестовая арматура:

describe('updating the value', function(){
        var component;
        beforeEach(function(){
            component = TestUtils.renderIntoDocument(<MyComponent value={true} />);
        });

        it('should update the state of the component when the value prop is changed', function(){
            // Act
            component.props.value = false;
            component.forceUpdate();
            // Assert
            expect(component.state.value).toBe(false);
        });
});

Это работает отлично, и тест проходит, однако это отображает ответное предупреждающее сообщение

'Warning: Dont set .props.value of the React component <exports />. Instead specify the correct value when initially creating the element or use React.cloneElement to make a new element with updated props.'

Все, что я хочу проверить, - это обновление свойства, а не создание нового экземпляра элемента с другим свойством. Есть ли лучший способ сделать это обновление свойств?

4b9b3361

Ответ 1

Если вы повторно визуализируете элемент с разными реквизитами в одном контейнере node, он будет обновлен вместо повторной установки. См. React.render.

В вашем случае вы должны использовать ReactDOM.render непосредственно вместо TestUtils.renderIntoDocument. Позднее создает новый контейнер node каждый раз, когда он вызывается, и, следовательно, новый компонент тоже.

var node, component;
beforeEach(function(){
    node = document.createElement('div');
    component = ReactDOM.render(<MyComponent value={true} />, node);
});

it('should update the state of the component when the value prop is changed', function(){
    // `component` will be updated instead of remounted
    ReactDOM.render(<MyComponent value={false} />, node);
    // Assert that `component` has updated its state in response to a prop change
    expect(component.state.value).toBe(false);
});

Ответ 2

AirBnB Enzyme библиотека предоставляет и элегантное решение этого вопроса.

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

    it("Component should call componentWillReceiveProps on update", () => {
        const spy = sinon.spy(Component.prototype, "componentWillReceiveProps");
        const wrapper = shallow(<Component {...props} />);

        expect(spy.calledOnce).to.equal(false);
        wrapper.setProps({ prop: 2 });
        expect(spy.calledOnce).to.equal(true);
    });

Ответ 3

Предостережение: на самом деле это не повлияет на реквизиты.

Но для меня все, что я хотел, это проверить мою логику в componentWillReceiveProps. Поэтому я вызываю myComponent.componentWillReceiveProps(/*new props*/) напрямую.

Мне не нужно было/не хотеть тестировать, что React вызывает этот метод при изменении реквизита или что React устанавливает реквизит при изменении реквизита, только если какая-то анимация срабатывает, если реквизит отличается от того, что было передано.

Ответ 4

Это старый вопрос, но в случае, если кто-то еще наткнулся на это, следующая настройка работала для меня красиво:

it('updates component on property update', () => {
    let TestParent = React.createClass({
        getInitialState() {
            return {value: true};
        },
        render() {
            return <MyComponent value={this.state.value}/>;
        }
    });
    component = TestUtils.renderIntoDocument(<TestParent/>);
    component.setState({value: false});
    // Verification code follows
});

Это заставляет React запускать обычное обновление компонента.

Ответ 5

Оба TestUtils.renderIntoDocument и ReactDOM.render используют возвращаемое значение из ReactDOM.render. Согласно React docs:

ReactDOM.render() теперь возвращает ссылку на экземпляр root ReactComponent. Однако использование этого возвращаемого значения является устаревшим и его следует избегать, поскольку будущие версии React могут в некоторых случаях подвергать компоненты асинхронно. Если вам нужна ссылка на экземпляр root ReactComponent, предпочтительным решением является присоединение обратного вызова ref к корневому элементу

Что, если мы возьмем этот совет и сделаем что-то вроде этого:

let component, node;

const renderComponent = (props = {}) => {
  ReactDOM.render(<MyComponent ref={r => component = r} {...props} />, node);
}

beforeEach(function(){
    node = document.createElement('div');
    renderComponent({value: true}, node); 
});

it('should update the state of the component when the value prop is changed', function(){
    // `component` will be updated instead of remounted
    renderComponent({value: false}, node); 
    // Assert that `component` has updated its state in response to a prop change
    expect(component.state.value).toBe(false);
});

Ответ 6

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

Установка jsdom, если не проверка в браузере:

var jsdom = require('jsdom').jsdom;
var document = jsdom('<!doctype html><html><body><div id="test-div"></div></body></html>');
global.document = document;
global.window = doc.defaultView;

Тестирование с использованием рендеринга реагирования с асинхронным обратным вызовом:

var node, component;
beforeEach(function(done){
    node = document.getElementById('test-div')
    ReactDOM.render(<MyComponent value={true} />, node, function() {
        component = this;
        done();
    });
});

it('should update the state of the component when the value prop is changed', function(done){
    // `component` will be updated instead of remounted
    ReactDOM.render(<MyComponent value={false} />, node, function() {
        component = this;
        // Assert that `component` has updated its state in response to a prop change
        expect(component.state.value).toBe(false);
        done();
    });
});