-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add tests for the UrlInputButton component. #3550
Add tests for the UrlInputButton component. #3550
Conversation
Codecov Report
@@ Coverage Diff @@
## master #3550 +/- ##
==========================================
+ Coverage 34.9% 35.76% +0.86%
==========================================
Files 263 267 +4
Lines 6727 6744 +17
Branches 1227 1221 -6
==========================================
+ Hits 2348 2412 +64
+ Misses 3694 3657 -37
+ Partials 685 675 -10
Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hideokamoto, thanks for starting this PR. Your tests look very good and work perfectly fine. I left a few comments where we can code something differently. Let me know what do you think about those suggestions.
I also think that descriptions put on it
blocks could be further improved.
*/ | ||
import { shallow, mount } from 'enzyme'; | ||
|
||
/** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same section is already defined above and it doesn't contain any import statements. Let's remove this obsolete comment.
blocks/url-input/test/button.js
Outdated
describe( 'UrlInputButton', () => { | ||
it( 'should has valid class in wrapper tag', () => { | ||
const wrapper = shallow( <UrlInputButton /> ); | ||
expect( wrapper.hasClass( 'blocks-url-input__button' ) ).toBeTruthy(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When validating boolean values toBe( true )
seems to be a better choice, which performs the comparison using ===
. See this thread on StackOverflow where it is greatly explained.
blocks/url-input/test/button.js
Outdated
const wrapper = shallow( <UrlInputButton onChange={ onChangeMock } /> ); | ||
wrapper.setState( { expanded: true } ); | ||
wrapper.find( { value: '' } ).simulate( 'change' ); | ||
expect( onChangeMock.mock.calls.length ).toBe( 1 ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Jest also offers toHaveBeenCalledTimes which in my opinion reads better:
expect( onChangeMock ).toHaveBeenCalledTimes( 1 );
blocks/url-input/test/button.js
Outdated
it( 'should call onChange function at once if value changes at once', () => { | ||
const onChangeMock = jest.fn(); | ||
const wrapper = shallow( <UrlInputButton onChange={ onChangeMock } /> ); | ||
wrapper.setState( { expanded: true } ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was wondering why this code updates the state of the component externally instead of using the same event as in the previous test. Can you explain?
To make it easier to read we can wrap this method in a function like this:
const startEditing = ( wrapper ) => wrapper.find( 'IconButton.components-toolbar__control' ).simulate( 'click' );
and then use it as follows:
startEditing( wrapper );
blocks/url-input/test/button.js
Outdated
const onChangeMock = jest.fn(); | ||
const wrapper = shallow( <UrlInputButton onChange={ onChangeMock } /> ); | ||
wrapper.setState( { expanded: true } ); | ||
wrapper.find( { value: '' } ).simulate( 'change' ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another option is to look for UrlInput
instead of an element with an empty value:
wrapper.find( 'UrlInput' ).simulate( 'change' );
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks !
But I've try this code, our test doesn't work well..
FAIL blocks/url-input/test/button.js
● UrlInputButton › should call onChange function at once if value changes at once
Method “simulate” is only meant to be run on a single node. 0 found instead.
at ShallowWrapper.single (node_modules/enzyme/build/ShallowWrapper.js:1614:17)
at ShallowWrapper.simulate (node_modules/enzyme/build/ShallowWrapper.js:925:21)
at Object.<anonymous> (blocks/url-input/test/button.js:40:28)
at process._tickCallback (node.js:438:9)
And I've try this code to debug the test.
const onChangeMock = jest.fn();
const wrapper = shallow( <UrlInputButton onChange={ onChangeMock } /> );
expect(wrapper.debug()).toBe('')
I think UrlInput
tag is converted as '_class'.
<div className=\"blocks-url-input__button\">
<IconButton icon=\"admin-links\" label=\"Edit Link\" onClick={[Function]} className=\"components-toolbar__control\" />
<form className=\"blocks-format-toolbar__link-modal\" onSubmit={[Function]}>
<IconButton className=\"blocks-url-input__back\" icon=\"arrow-left-alt\" label=\"Close\" onClick={[Function]} />
<_class value=\"\" onChange={[Function]} />
<IconButton icon=\"editor-break\" label=\"Submit\" type=\"submit\" />
</form>
</div>
So I'll try to use data-
attributes to getUrlInput
component.
reference: https://blog.kentcdodds.com/making-your-ui-tests-resilient-to-change-d37a6ee37269
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<_class value=\"\" onChange={[Function]} />
- Yes, somehow it doesn't have display name set. We can use data-test for the time being. I will look into it later.
Thanks for reviewing my code :) |
@hideokamoto thanks for addressing my comments, much appreciated. I will polish test descriptions and merge. |
It should be good to go 🚢 |
@@ -59,7 +59,7 @@ class UrlInputButton extends Component { | |||
label={ __( 'Close' ) } | |||
onClick={ this.toggle } | |||
/> | |||
<UrlInput value={ url || '' } onChange={ onChange } /> | |||
<UrlInput value={ url || '' } onChange={ onChange } data-test="UrlInput" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't be affecting the output of the original component just to satisfy needs of unit testing. We could have achieved the same with wrapper.find( UrlInput )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, agreed. It was a really bad idea which would only work if we would be able to provide Babel plugin which removes those data-test
attributes ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #7981
Description
Related to progress on the issue -> Unit Testing Components #641
Added some unit test scripts for UrlInputButton component.
How Has This Been Tested?
Run unit test command.
Checklist: