4

我正在尝试通过使用findRenderedComponentWithTypefindRenderedComponentWithType查找组件来进行一些单元测试。但是,我遇到了一些麻烦。

我有一个浅渲染组件<Layout />,我想在其中找到<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;

在我的测试文件中,我尝试了这个:

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

但是,scryRenderedComponentsWithType找不到findRenderedComponentWithType任何类型为 的组件UserMenu

我还尝试在组件所在exports的位置创建另一个文件,UserMenu但我得到相同的输出或找到 0(数组长度 0)或在未找到组件时出错(Error: Did not find exactly one match for componentType:function UserMenu())。

4

1 回答 1

1

我知道这不是您所问问题的直接解决方案,但是当我尝试浅渲染时,我和您一样挣扎。React 自己的文档将此功能描述为具有“一些限制”的早期版本。

浅层测试目前有一些限制,即不支持 refs。我们将提前发布此功能,并感谢 React 社区对它应该如何发展的反馈。

我厌倦了用头撞墙,并采用了我在其他地方找到的更直接的解决方案。

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

万一该链接变坏了:基本上,它说使用Rewire将您的子组件替换为您在测试中创建的内联内容。这正是我所做的:

rewire-module.js(从博客文章中复制)

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(片段)

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

MyList-test.jsx(片段)

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

正如您可能已经想到的,我基本上使用“className”作为我的元素标识符,以便以后找到它们。

有时,如果我想搜索具有特定数据的特定子组件,我会在 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());
});
于 2015-08-17T20:05:44.853 回答