it-source

React 컴포넌트에서 프로펠러 업데이트를 테스트하는 방법

criticalcode 2023. 4. 1. 09:33
반응형

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.'

테스트하려는 것은 속성 업데이트일 뿐 다른 속성을 가진 요소의 새 인스턴스를 만드는 것은 아닙니다.이 숙박업소를 갱신할 수 있는 더 좋은 방법이 있을까요?

AirBnB의 효소 라이브러리는 질문에 대한 우아한 해결책을 제공합니다.

얕은 래퍼 또는 jsdom 래퍼에서 호출할 수 있는 setProps 메서드를 제공합니다.

    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);
    });

동일한 컨테이너 노드에서 다른 소품으로 요소를 다시 렌더링하는 경우 다시 마운트되는 대신 업데이트됩니다.React.render를 참조하십시오.

당신의 경우,ReactDOM.render대신 직접TestUtils.renderIntoDocument후자는 호출될 때마다 새로운 컨테이너 노드를 생성하고, 따라서 새로운 컴포넌트도 만듭니다.

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);
});

주의: 이것이 실제로 소품을 바꾸지는 않습니다.

하지만 제게는 제 논리를 시험해보고 싶었어요componentWillReceiveProps그래서 전화드렸습니다.myComponent.componentWillReceiveProps(/*new props*/)직접적으로.

소품이 바뀌었을 때 리액트가 메서드를 호출하는지, 소품이 바뀌었을 때 리액트가 소품을 세팅하는지 테스트할 필요가 없었다.그냥 소품이 전달된 것과 다르면 애니메이션이 트리거된다.

또, 테스트·라이브러리의 회답은 이쪽에서 찾을 수 없었습니다만, 이 호에는 다음과 같은 예가 기재되어 있습니다.

const {container} = render(<Foo bar={true} />)

// update the props, re-render to the same container
render(<Foo bar={false} />, {container})

또는, 현재는 테스트 라이브러리에서도 같은 것을 실현하는 방법을 제공하고 있습니다.

이것은 오래된 질문입니다만, 다른 사람이 우연히 발견했을 경우에 대비해, 다음의 설정이 도움이 되었습니다.

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가 일반적인 컴포넌트 업데이트를 실행합니다.

다음은 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;

비동기 콜백을 사용한 react-dom 렌더를 사용한 테스트:

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();
    });
});

효소를 사용하여 구성요소를 마운트하고 여기에 소품을 추가할 수 있습니다.

import React form 'react';
import component;
import {configure, mount} form 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import {expect} from 'chai';

configure({adapter: new Adapter()});

describe('Testing component', () => {
  let wrapper;
  beforeEach(() => {
    component = mount(<MyComponent value={false} />);
  });
  it('should update the state of the component when the value prop is changed', function(){

    expect(component.props().children.props.value).toBe(false);
});

둘다요.TestUtils.renderIntoDocument그리고.ReactDOM.render에서 반환된 값을 사용합니다.ReactDOM.render. React 문서에 따르면:

ReactDOM.render()는 현재 루트 ReactComponent 인스턴스에 대한 참조를 반환합니다.그러나 이 반환값을 사용하는 것은 레거시이므로 향후 React 버전에서 구성 요소를 비동기식으로 렌더링할 수 있으므로 사용하지 않는 것이 좋습니다.루트 React Component 인스턴스에 대한 참조가 필요한 경우 권장되는 솔루션은 콜백 참조를 루트 요소에 연결하는 것입니다.

이 조언을 받아들여 다음과 같이 하면 어떨까요?

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);
});

방법(with)ReactDOM.render(<MyComponent ref=...는 HOC

언급URL : https://stackoverflow.com/questions/30614454/how-to-test-a-prop-update-on-react-component

반응형