Skip to content

Storybook: Add StoryShots integration to generate unit tests - #18031

Merged
gziolo merged 6 commits into
masterfrom
add/storybook-storyshots
Nov 26, 2019
Merged

Storybook: Add StoryShots integration to generate unit tests#18031
gziolo merged 6 commits into
masterfrom
add/storybook-storyshots

Conversation

@gziolo

@gziolo gziolo commented Oct 18, 2019

Copy link
Copy Markdown
Member

Description

Part of #17973.
Depends on #18030.

StoryShots adds automatic Jest Snapshot Testing for Storybook.

I followed the docs at this page:
https://github.com/storybookjs/storybook/tree/master/addons/storyshots/storyshots-core

Testing

Run npm run test-unit packages/components/storybook/

Known issue

There is a known issue with using React hooks with components in stories:
storybookjs/storybook#8177

I'm seeing the following:

  ● @wordpress/components › Checkbox Control › Default

    Invariant Violation: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
    1. You might have mismatching versions of React and the renderer (such as React DOM)
    2. You might be breaking the Rules of Hooks
    3. You might have more than one copy of React in the same app
    See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.

      17 | 
      18 | export const _default = () => {
    > 19 |      const [ isChecked, setChecked ] = useState( true );
         |                                        ^
      20 |      return (
      21 |              <CheckboxControl
      22 |                      label="Is author"

This issue was resolved by refactoring #18030. This PR was rebased with update/storybook-enhancements to solve it here as well.

@gziolo gziolo added [Type] Automated Testing Testing infrastructure changes impacting the execution of end-to-end (E2E) and/or unit tests. Storybook Storybook and its stories for components labels Oct 18, 2019
@gziolo
gziolo requested review from epiqueras and mkaz October 18, 2019 22:00
@gziolo gziolo self-assigned this Oct 18, 2019
Comment thread packages/components/storybook/config.js Outdated
@gziolo

gziolo commented Oct 21, 2019

Copy link
Copy Markdown
Member Author

I figured out that some tests can't work in this setup. ClipboardButton is one of them:
Screen Shot 2019-10-21 at 14 38 54

We can skip such stories using the convention. In this case, it would be DontTest keyword in the title. It shows up in the UI at the moment, but it should be easy to introduce a helper function which appends this pattern only in the test env.

@gziolo

gziolo commented Oct 21, 2019

Copy link
Copy Markdown
Member Author

cc @diegohaz and @ItsJonQ who recently spent some time on writing unit tests for UI components. I'd love to hear your feedback on the presented approach.

@gziolo gziolo added the [Type] Technical Prototype Offers a technical exploration into an idea as an example of what's possible label Oct 21, 2019
@gziolo
gziolo marked this pull request as ready for review October 21, 2019 12:45
@epiqueras

Copy link
Copy Markdown
Contributor

I figured out that some tests can't work in this setup. ClipboardButton is one of them:

What makes it break? Is there anyway we can mock it?

In this case, it would be DontTest keyword in the title.

We can also just add an explicit list of (?!) to the storyKindRegex since the list will probably be somehow limited.

@gziolo
gziolo force-pushed the update/storybook-enhancements branch 2 times, most recently from 8249379 to cceee54 Compare October 22, 2019 11:29
@gziolo

gziolo commented Oct 22, 2019

Copy link
Copy Markdown
Member Author

I figured out that some tests can't work in this setup. ClipboardButton is one of them:

What makes it break? Is there anyway we can mock it?

In this case, it would be DontTest keyword in the title.

We can also just add an explicit list of (?!) to the storyKindRegex since the list will probably be somehow limited.

I figured out that some tests can't work in this setup. ClipboardButton is one of them:

This is the full error:

  ● @wordpress/components › ClipboardButton › Default

    TypeError: Cannot read property 'firstChild' of null

      27 |      componentDidMount() {
      28 |              const { container, getText, onCopy } = this;
    > 29 |              const button = container.firstChild;
         |                                       ^
      30 | 
      31 |              this.clipboard = new Clipboard( button, {
      32 |                      text: getText,

      at ClipboardButton.firstChild [as componentDidMount] (packages/components/src/clipboard-button/index.js:29:28)
      at commitLifeCycles (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:10930:22)
      at commitLayoutEffects (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13583:7)
      at HTMLUnknownElement.callCallback (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:10487:14)
      at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:193:27)
      at HTMLUnknownElementImpl._dispatch (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:119:9)
      at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:82:17)
      at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/nodes/HTMLElement-impl.js:30:27)
      at HTMLUnknownElement.dispatchEvent (node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:157:21)
      at Object.invokeGuardedCallbackDev (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:10537:16)
      at invokeGuardedCallback (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:10590:31)
      at commitRootImpl (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13355:9)
      at unstable_runWithPriority (node_modules/scheduler/cjs/scheduler.development.js:643:12)
      at runWithPriority (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:1887:10)
      at commitRoot (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13184:3)
      at runRootCallback (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:12420:20)
      at node_modules/react-test-renderer/cjs/react-test-renderer.development.js:1935:24
      at unstable_runWithPriority (node_modules/scheduler/cjs/scheduler.development.js:643:12)
      at runWithPriority (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:1887:10)
      at flushSyncCallbackQueueImpl (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:1931:7)
      at flushSyncCallbackQueue (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:1920:3)
      at scheduleUpdateOnFiber (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:12297:9)
      at scheduleRootUpdate (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:15087:3)
      at updateContainerAtExpirationTime (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:15115:10)
      at updateContainer (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:15134:10)
      at create (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:15824:5)
      at getRenderedTree (node_modules/@storybook/addon-storyshots/dist/frameworks/react/renderTree.js:24:16)
      at node_modules/@storybook/addon-storyshots/dist/test-bodies.js:21:18
      at Object.<anonymous> (node_modules/@storybook/addon-storyshots/dist/api/snapshotsTestsTemplate.js:44:33)

What makes it break? Is there anyway we can mock it?

I guess there is something going on with how it gets mounted. I don't think it's so much important and we can skip it but feel free to investigate further.

In this case, it would be DontTest keyword in the title.

We can also just add an explicit list of (?!) to the storyKindRegex since the list will probably be somehow limited.

We can start with the blacklist at first. Good idea 👍

@gziolo
gziolo force-pushed the add/storybook-storyshots branch from 0d56672 to 3684187 Compare October 22, 2019 11:39
@epiqueras

Copy link
Copy Markdown
Contributor

Sounds good, let's do it.

@gziolo
gziolo force-pushed the update/storybook-enhancements branch from cceee54 to 34a2aa2 Compare October 24, 2019 12:06
@gziolo
gziolo force-pushed the add/storybook-storyshots branch from 3684187 to 7c6e7b3 Compare October 24, 2019 12:48
@gziolo

gziolo commented Oct 24, 2019

Copy link
Copy Markdown
Member Author

With 7c6e7b3 we have a list of skipped components in the Storyshots configuration. It should be ready to go. This branch is based on the #18030 so we can merge it there once approved.

@ItsJonQ

ItsJonQ commented Nov 12, 2019

Copy link
Copy Markdown

I'd love to hear your feedback on the presented approach.
@gziolo Hallo! Apologies for the delay!

From my experience, snapshot testing (in general) is definitely better than nothing, but I prefer having and writing unit/integration tests.

I also think writing unit tests should also be easier, which can be achieved by having testing utils (if we're staying with Enzyme) or leveraging another testing solution.

Personally, I haven't used this particular addon for Storybook.

I'm okay with keeping this in to see where it goes/how it feels :)

Maybe it can automate a portion of manually writing basic render tests, freeing up time/focus to write unit/integration tests for more complex scenarios.

@jorgefilipecosta jorgefilipecosta left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was able to run the tests with success by using "npm run test-unit storybook/test/index.js".

I'm not sure if these tests will be useful in catching regressions or not but I think the best way is to merge them and check if they helped us or they added developer overhead to update the snapshots.
We also have some interesting potential follow-ups pending like the a11y tests, so I guess we should merge this PR and see where these type of tests leaves us.

Comment thread storybook/test/index.js Outdated
Comment thread storybook/config.js Outdated
@gziolo
gziolo force-pushed the add/storybook-storyshots branch from fdaed2e to ccc705b Compare November 13, 2019 09:11
@gziolo

gziolo commented Nov 13, 2019

Copy link
Copy Markdown
Member Author

I invested more time into this issue and I managed to mock those nodes which use refs with the following commits:
1a59025
ccc705b

This means, we no longer skip any stories from snapshot testing. However, the side effect is that if there is some special use case for refs, it might require custom logic in the mocking helper. The following seem to work for now:

		createNodeMock: ( element ) => {
			if ( story.kind === 'Components|ClipboardButton' ) {
				return {
					firstChild: document.createElement( 'button' ),
				};
			}
			return element.type && document.createElement( element.type );
		},

I followed links shared by @epiqueras:

It looks like it's a general issue with snapshot testing in React apps.

@diegohaz

diegohaz commented Nov 13, 2019

Copy link
Copy Markdown
Member

One thing I noticed is that storyshot tests will still fail if a console warning is emitted. On #17875, I created a story for a deprecated thing so I could see the UI worked and the warning was shown.

image

On normal tests I can check if the warning was shown. Can I do that with Storyshots?

@gziolo
gziolo requested a review from epiqueras November 14, 2019 05:54
@gziolo

gziolo commented Nov 14, 2019

Copy link
Copy Markdown
Member Author

One thing I noticed is that storyshot tests will still fail if a console warning is emitted. On #17875, I created a story for a deprecated thing so I could see the UI worked and the warning was shown.

This raises the question of whether we should keep the legacy version of Toolbar in Storybook 🤔

I could make the point that it should be removed from there as it should be discouraged from using in new code. Having it included in the docs might create the temptation for folks to copy the example and use it in their projects when they find that it fits their needs.

I'm aware that it isn't probably the type of answers you expected but this is something we should discuss more broadly before we jump into finding a technical solution on how to mitigate it. Maybe we don't have to do it. The only downside is that this story is very useful in the process of developing the migration path for the Toolbar component.

@gziolo
gziolo force-pushed the add/storybook-storyshots branch from ccc705b to 7abdc2e Compare November 14, 2019 16:04
@gziolo gziolo mentioned this pull request Nov 15, 2019
6 tasks
@gziolo
gziolo force-pushed the add/storybook-storyshots branch 2 times, most recently from f5d6912 to 85c7ac2 Compare November 19, 2019 10:46
@gziolo
gziolo force-pushed the add/storybook-storyshots branch 2 times, most recently from 09f32e2 to 83fd01e Compare November 26, 2019 14:10
@gziolo
gziolo force-pushed the add/storybook-storyshots branch from 83fd01e to 92f46dd Compare November 26, 2019 14:20
@gziolo

gziolo commented Nov 26, 2019

Copy link
Copy Markdown
Member Author

I included documentation in 92f46dd.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Storybook Storybook and its stories for components [Type] Automated Testing Testing infrastructure changes impacting the execution of end-to-end (E2E) and/or unit tests. [Type] Technical Prototype Offers a technical exploration into an idea as an example of what's possible

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants