最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How can I trigger a state change in a unit test with React DOM? - Stack Overflow

programmeradmin7浏览0评论

I'm using the React Test Utilities to unit test some of my code. I call renderIntoDocument to render a custom ponent and then use findDOMNode to test out what got rendered. The trouble I'm running into is that I'm not sure how to update the state and effectively trigger a re-render within the context of a unit test.

Here's some sample code -- pay attention to the code ment:

import React from 'react';
import ReactDOM from 'react-dom';
import TestUtils from 'react-dom/test-utils';
import MyCustomComponent from '../../app/ponents/MyCustomComponent';

describe('My Test Suite', () => {
    let ponent, node;
    test('verify state change', () => {
        const items = [{'value': '1'}];
        ponent = TestUtils.renderIntoDocument(
            <MyCustomComponent items={items} />
        );
        node = ReactDOM.findDOMNode(ponent);
        expect(node.querySelector('input[type=text]').value).toEqual('1');
        ponent.state.items = [{'value': '2'}];
        // do something here to trigger a re-render?
        expect(node.querySelector('input[type=text]').value).toEqual('2');
    });
});

Unfortunately it seems simply changing the state variable doesn't do anything. And I can't call ponentponentWillReceiveProps() because that doesn't seem to be defined.

Please note that I do want the same ponent to call its render function rather than replacing it with, effectively, a brand new ponent. The reason is because I found a bug where the ponent was rendering things based on this.props instead of this.state, and I want a test to show that it's always using data from the state and not from the initial values.

I'm using the React Test Utilities to unit test some of my code. I call renderIntoDocument to render a custom ponent and then use findDOMNode to test out what got rendered. The trouble I'm running into is that I'm not sure how to update the state and effectively trigger a re-render within the context of a unit test.

Here's some sample code -- pay attention to the code ment:

import React from 'react';
import ReactDOM from 'react-dom';
import TestUtils from 'react-dom/test-utils';
import MyCustomComponent from '../../app/ponents/MyCustomComponent';

describe('My Test Suite', () => {
    let ponent, node;
    test('verify state change', () => {
        const items = [{'value': '1'}];
        ponent = TestUtils.renderIntoDocument(
            <MyCustomComponent items={items} />
        );
        node = ReactDOM.findDOMNode(ponent);
        expect(node.querySelector('input[type=text]').value).toEqual('1');
        ponent.state.items = [{'value': '2'}];
        // do something here to trigger a re-render?
        expect(node.querySelector('input[type=text]').value).toEqual('2');
    });
});

Unfortunately it seems simply changing the state variable doesn't do anything. And I can't call ponent.ponentWillReceiveProps() because that doesn't seem to be defined.

Please note that I do want the same ponent to call its render function rather than replacing it with, effectively, a brand new ponent. The reason is because I found a bug where the ponent was rendering things based on this.props instead of this.state, and I want a test to show that it's always using data from the state and not from the initial values.

Share Improve this question asked Dec 29, 2017 at 20:23 soapergemsoapergem 10k20 gold badges109 silver badges166 bronze badges 4
  • have you already tried ReactDOM.render(<MyComponent />, node); to force rendering the ponent? – Marouen Mhiri Commented Dec 29, 2017 at 20:27
  • @MarouenMhiri wouldn't that just effectively create a new instance of the ponent? (Rather than re-rendering the existing instance?) – soapergem Commented Dec 29, 2017 at 20:27
  • This will update the ponent instead of remounting it! I think this is what you searching for. – Marouen Mhiri Commented Dec 29, 2017 at 20:29
  • The RenderIntoDocument does generate a new instance when called,, but ReactDom.render does update the ponent if it's exists – Marouen Mhiri Commented Dec 29, 2017 at 20:30
Add a ment  | 

1 Answer 1

Reset to default 7

Enzyme from AirBnb has some great utilities for this. You'll need to install the dependencies but it's simple enough to get it configured. Then, you can simply call Enzyme's setState method on your ponent instance. An important note – your "ponent instance" in this case is a shallow rendered ponent. Your code would look something like this:

import React from 'react';
import MyCustomComponent from '../../app/ponents/MyCustomComponent';
import { shallow, configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

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

describe('My Test Suite', () => {

    test('verify state change', () => {
        const items = [{'value': '1'}];
        const wrapper = shallow(<MyCustomComponent items={items} />);

        // find your shallow rendered ponent and check its value
        expect(wrapper.find('input[type="text"]').value).toEqual('1');

        // set the state of the ponent
        wrapper.setState({ items: [{'value': '2'}] });

        // state should be updated, make sure its value was properly set
        expect(wrapper.find('input[type="text"]').value).toEqual('2');
    });
});

All of this assumes that you are using state in your ponent properly. In your case, items appears to be passed in as a prop. If you are setting state by just copying props, you may want to rethink your strategy. In any case, this approach should be identical to how state updates in React work – you're operating on the same ponent instance without unmounting and remounting the ponent. Hope this helps.

发布评论

评论列表(0)

  1. 暂无评论