< Previous: Using Jest to Test Our React Components | Next: Time for Ajax: Using Jest with Asynchronous Tests > |
Now, if you cast your mind back to much earlier in this book you might remember this: "REMINDER OF IMPORTANT WARNING: Code much later in this book relies on you passing a string parameter to selectMode()
rather than using the data-mode
attribute approach." Well, you've finally reached the point where your choice matters.
If you remember, we looked at two ways of writing the selectMode()
method: passing a string parameter or using a data-mode
attribute. Both approaches have their uses in normal coding, but when it comes to testing there's a catch: Jest doesn't support the dataset
property, which means when it simulates a click on a button the selectMode()
method will fail if it tries to read the data-mode
attribute.
Fortunately you heeded my warning and used the approach that passes a string parameter, right? Right. That means we can write our third test really easily: we just find all the buttons in the document, read the button at index 1, simulate a click on it, then make sure the Detail component's mode
state is set to 'forks'.
Add this test beneath the existing two:
__tests__/Detail-test.js
it('shows forks when the button is tapped', () => {
const rendered = TestUtils.renderIntoDocument(
<Detail params={{repo: ''}} />
);
const btns = TestUtils.scryRenderedDOMComponentsWithTag(rendered, 'button');
const forksButton = btns[1];
TestUtils.Simulate.click(forksButton);
expect(rendered.state.mode).toEqual('forks');
});
There are three things there that might be interesting. First, we need to use index 1 for the "forks" button because JavaScript arrays count from 0. In our detail component, button 0 is "Commits", button 1 is "Forks" and button 2 is "Pulls".
Second, the TestUtils.Simulate.click()
method is new, and I hope it's pretty self-explanatory: it simulates a click on something in our document, in this case a button.
Third, this code is a bit fragile and thus not really suitable for use in production. The reason for this is the way the button is accessed: we assume the forks button is at index 1, but if a designer comes along and moves it then the test will break even though the button is there and still functioning.
The way to fix this is to give each button a unique ref
property, which is React's way of identifying things that have been rendered. Please amend the end of the render()
method in Detail.js to this:
src/pages/Detail.js
return (<div>
<p>You are here:
<IndexLink to="/" activeClassName="active">Home</IndexLink>
> {this.props.params.repo}</p>
<button onClick={this.selectMode.bind(this, 'commits')} ref="commits">
Show Commits
</button>
<button onClick={this.selectMode.bind(this, 'forks')} ref="forks">
Show Forks
</button>
<button onClick={this.selectMode.bind(this, 'pulls')} ref="pulls">
Show Pulls
</button>
{content}
</div>);
Now that each button has a unique ref
property we can find it directly, without even having to call scryRenderedDOMComponentsWithTag()
. Update the third test to this:
__tests__/Detail-test.js
it('shows forks when the button is tapped', () => {
const rendered = TestUtils.renderIntoDocument(
<Detail params={{repo: ''}} />
);
const forksButton = rendered.refs.forks;
TestUtils.Simulate.click(forksButton);
expect(rendered.state.mode).toEqual('forks');
});
As you can see, we can just dip right into the refs
property to find forks
, and that new test will work regardless of where the button gets moved to in the future.
Buy the book for $10
Get the complete, unabridged Hacking with React e-book and take your learning to the next level - includes a 45-day no questions asked money back guarantee!
If this was helpful, please take a moment to tell others about Hacking with React by tweeting about it!
< Previous: Using Jest to Test Our React Components | Next: Time for Ajax: Using Jest with Asynchronous Tests > |
Copyright ©2016 Paul Hudson. Follow me: @twostraws.