使用酶的.instance()
访问组件方法的方法
当然,有几个先决条件。
- 您必须首先使用酶渲染组件一次shallow http://airbnb.io/enzyme/docs/api/shallow.html or mount http://airbnb.io/enzyme/docs/api/mount.html功能取决于您是否需要[和/或您喜欢的方式] simulate http://airbnb.io/enzyme/docs/api/ReactWrapper/simulate.html嵌套子级上的事件。这还为您提供了一个酶包装器,您可以从中访问组件实例及其方法。
- 你需要包裹诗农测试间谍 http://sinonjs.org/docs/#spies围绕这些实例方法并使用重新渲染.update http://airbnb.io/enzyme/docs/api/ReactWrapper/update.html获取带有间谍的包装器版本,您可以对其进行断言。
Example:
// Import requisite modules
import React from 'react';
import sinon from 'sinon';
import { mount } from 'enzyme';
import { expect } from 'chai';
import PlayerList from './PlayerList';
// Describe what you'll be testing
describe('PlayerList component', () => {
// Mock player list
const playerList = [
{
id : 1,
imgUrl: 'http://placehold.it/100?text=P1',
name : 'Player One'
}
];
// Nested describe just for our instance methods
describe('Instance methods', () => {
// Stub the selectPlayer method.
const selectPlayer = sinon.stub();
// Full DOM render including nested Player component
const wrapper = mount(
<PlayerList playerList={ playerList } selectPlayer={ selectPlayer } />
);
// Get the component instance
const instance = wrapper.instance();
// Wrap the instance methods with spies
instance.createListItems = sinon.spy(instance.createListItems);
instance.onSelect = sinon.spy(instance.onSelect);
// Re-render component. Now with spies!
wrapper.update();
it('should call createListItems on render', () => {
expect(instance.createListItems).to.have.been.calledOnce;
});
it('should call onSelect on child link click', () => {
expect(instance.onSelect).to.not.have.been.called;
wrapper.find('li > a').at(0).simulate('click');
expect(instance.onSelect).to.have.been.calledOnce;
expect(instance.onSelect).to.have.been.calledWith(playerList[0].id);
});
});
});
Notes:
- 当使用上面的代码时
PlayerList
and Player
,我发现你没有分配一个名为player
to Player
;相反,你正在分配item={ item }
。为了使其在本地工作,我将其更改为<Player player={ item } … />
.
- In
onSelect
you are checking whether the received i
argument is falsey and then calling selectPlayer(1)
. I didn't include a test case for this in the above example because the logic concerns me for a couple of reasons:
- 我怀疑是否
i
可能永远是0
?如果是这样,它将始终评估为 false 并传递到该块中。
- Because
Player
calls onSelect(this.props.player.id)
, 我怀疑是否this.props.player.id
永远会是undefined
?如果是这样,我想知道为什么你会有一个项目props.playerList
没有id
财产。
但如果你想测试现在的逻辑,它会看起来像这样......
测试逻辑示例onSelect
:
describe('PlayerList component', () => {
…
// Mock player list should contain an item with `id: 0`
// …and another item with no `id` property.
const playerList = [
…, // index 0 (Player 1)
{ // index 1
id : 0,
imgUrl: 'http://placehold.it/100?text=P0',
name : 'Player Zero'
},
{ // index 2
imgUrl: 'http://placehold.it/100?text=P',
name : 'Player ?'
}
];
describe('Instance methods', { … });
describe('selectPlayer', () => {
const selectPlayer = sinon.stub();
const wrapper = mount(
<PlayerList playerList={ playerList } selectPlayer={ selectPlayer } />
);
const instance = wrapper.instance();
// There is no need to simulate clicks or wrap spies on instance methods
// …to test the call to selectPlayer. Just call the method directly.
it('should call props.selectPlayer with `id` if `id` is truthy', () => {
instance.onSelect(playerList[0].id); // id: 1
expect(selectPlayer).to.have.been.calledOnce;
expect(selectPlayer).to.have.been.calledWith(playerList[0].id);
});
it('should call props.selectPlayer(1) if `id` is 0', () => {
instance.onSelect(playerList[1].id); // id: 0
expect(selectPlayer).to.have.been.calledTwice;
expect(selectPlayer).to.have.been.calledWith(1);
});
it('should call props.selectPlayer(1) if `id` is undefined', () => {
instance.onSelect(playerList[2].id); // undefined
expect(selectPlayer).to.have.been.calledThrice;
expect(selectPlayer).to.have.been.calledWith(1);
});
});
});