4

I am trying to do some unit testing by using findRenderedComponentWithType and findRenderedComponentWithType to find components. However, I am having a bit of trouble.

I have a shallow rendered component <Layout /> and within it, I want to find <UserMenu />.

var Layout = React.createClass({
    render: function(){
        console.log(this.props);
        return (
            <div id="data-trader">
                <header className="header">
                    <UserMenu user={this.props.user} />
                </header>
                <SideMenu user={this.props.user}/>
            </div>
        );
    }
});

module.exports = Layout;

Within my test file, I tried this:

describe('Layout', function() {
    beforeEach(function(){
        fakeDOM = TestUtils.createRenderer();
        it('should exist as a component', function(done) {
            expect(<Layout/>).to.exist;
            done();
        });
        fakeDOM.render(<Layout />);
        renderedFakeDOMOutput = fakeDOM.getRenderOutput();
    });
    it('should have login button when props.user is undefined', function(done) {
        renderedFakeDOMOutput.props.user = undefined;
        let UserMenuComponent = TestUtils.scryRenderedComponentsWithType(renderedFakeDOMOutput, UserMenu);
        done();
    });
});

However, scryRenderedComponentsWithType and findRenderedComponentWithType cannot find anything of the components with the type UserMenu.

I also tried to create another file where it exports the UserMenu component but I get the same output or 0 found (Array length 0) or error when no components are found (Error: Did not find exactly one match for componentType:function UserMenu()).

Liondancer
  • 15,721
  • 51
  • 149
  • 255

1 Answers1

1

I know it's not a direct solution to the question you're asking, but when I tried shallow rendering, I struggled with it just as you are. React's own docs describe this feature as an early release with "some limitations".

Shallow testing currently has some limitations, namely not supporting refs. We're releasing this feature early and would appreciate the React community's feedback on how it should evolve.

I got tired of banging my head against the wall and went with a more straight-forward solution that I found elsewhere.

http://substantial.com/blog/2014/11/11/test-driven-react-how-to-manually-mock-components/

In case that link ever goes bad: Basically, it says to use Rewire to swap out your sub-components with something you create inline in your test. Here is exactly what I do:

rewire-module.js (copied from the blog post)

module.exports = function rewireModule(rewiredModule, varValues) {
    var rewiredReverts = [];

    beforeEach(function () {
        var key, value, revert;
        for (key in varValues) {
            if (varValues.hasOwnProperty(key)) {
                value = varValues[key];
                revert = rewiredModule.__set__(key, value);
                rewiredReverts.push(revert);
            }
        }
    });

    afterEach(function () {
        rewiredReverts.forEach(function (revert) {
            revert();
        });
    });

    return rewiredModule;
};

MyList.jsx (snippet)

<div>
    { items.map(item => <MyListItem key={item.id} item={item}/>) }
</div>

MyList-test.jsx (snippet)

let rewireModule = require('../utils/rewire-module');
let rewire = require('rewire');
let MyList = rewire('./MyList.jsx');

rewireModule(MyList, {
    MyListItem: React.createClass({
        propTypes: {
            item: React.PropTypes.object.isRequired
        },
        render: function () {
            return <div className="MyListItem"/>;
        }
    })
});

it('should render data', function () {
    // init
    MyStore.onLoadCompleted([
        {id: 1, name: 'Test 1'},
        {id: 2, name: 'Test 2'}
    ]);

    let listComponent = TestUtils.renderIntoDocument(<MyList/>);
    let listItems = TestUtils.scryRenderedDOMComponentsWithClass(listComponent, 'MyListItem');
    expect(listItems.length).to.equal(2);

    // cleanup
    React.unmountComponentAtNode(listComponent.getDOMNode());
});

As you may have figured, I basically use "className" as my element identifiers to find them later.

Sometimes if I want to search for specific sub-components with specific data, I'll build something unique into the className.

rewireModule(MyList, {
    MyListItem: React.createClass({
        propTypes: {
            item: React.PropTypes.object.isRequired
        },
        render: function () {
            return <div className={'MyListItem_' + item.id}/>;
        }
    })
});

it('should render data', function () {
    // init
    MyStore.onLoadCompleted([
        {id: 1, name: 'Test 1'},
        {id: 2, name: 'Test 2'}
    ]);

    let listComponent = TestUtils.renderIntoDocument(<MyList/>);
    TestUtils.findRenderedDOMComponentWithClass(listComponent, 'MyListItem_1');
    TestUtils.findRenderedDOMComponentWithClass(listComponent, 'MyListItem_2');

    // cleanup
    React.unmountComponentAtNode(listComponent.getDOMNode());
});
Jeff Fairley
  • 8,071
  • 7
  • 46
  • 55