Repository navigation
Conversation
🦋 Changeset detectedLatest commit: fe57cf9 The changes in this PR will be included in the next version bump. This PR includes changesets to release 9 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
…book/react-native/test Adds Testing Library-style queries, userEvent and waitFor for React Native elements, instrumented so their calls show in the Interactions panel. With ondeviceInteractions enabled, play functions get canvas and userEvent in their context, like on the web. Also keeps the Interactions panel's log when the story that's already shown is selected again.
…tions # Conflicts: # examples/expo-example/.rnstorybook/storybook.requires.ts
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds an experimental on-device Interactions panel, built into
@storybook/react-nativelike the backgrounds panel, and web-stylecanvasanduserEventfor play functions. Everything is behind a newfeatures.ondeviceInteractionsflag; with the flag off, behavior is unchanged.Play functions are written the same way as on Storybook web:
and the panel lists each call, as on the web:
userEventneeds React Native's Canary release channel, where elements supportEventTarget: React Native routes a dispatchedchangeorclickto the component's ordinaryonChangeText,onValueChangeandonPressprops. The queries work on current stable versions.@storybook/react-native/testThe React Native counterpart of
storybook/test(src/test). It exportswithin,userEventandwaitFor, instrumented like their web versions, and re-exportsexpect,fn,spyOnand the mocking utilities fromstorybook/test.ByRole,ByText,ByLabelText,ByPlaceholderText,ByDisplayValue,ByAltTextandByTestId, each withgetBy/getAllBy/queryBy/queryAllBy/findBy/findAllBy. Matchers are strings, regexes or functions, withexactandnormalizer; errors use Testing Library's wording. Roles come fromrole/accessibilityRole(mapped to ARIA names, e.g.header→heading), with implicit roles forTextInput,SwitchandImage; the accessible name comes fromaria-label/accessibilityLabel,aria-labelledby/accessibilityLabelledBy, then the text inside.click(presses the nearest pressable, so clicking a button's text works, and toggles switches),dblClick,type(appends one character at a time, withdelay),clear,keyboardandsetup(). Special keys,hover,tabandselectOptionsaren't supported.Uses React Native internals: element props (
accessibilityRole,placeholder,value, …) aren't exposed by the element API, sogetPropsreads them from the fiber (__internalInstanceHandle.stateNode.canonical.currentProps, the path React Native's privategetCurrentPropsuses). It's the only place that does, and it throws a clear error if the path changes.What the flag turns on
src/interactions): lists the instrumented calls with their status and errors, shows PASS/FAIL/RUNS, and has a Rerun button that emitsFORCE_REMOUNT. It records from when it registers, so the log is complete even if the panel opens after the play function ran.canvas,userEventandcanvasElement: amountannotation waits for the story wrapperViewto attach, sets it ascanvasElement, and adds instrumentedcanvasanduserEventto the context.mount()resolves withcanvas, as on the web.reactNative.playFn.StoryRender.remount()waits for a running play function and then falls back towindow.location.reload(), which never resolves on React Native.ReactNativePreview.onForceRemountcancels the run, waits for itsSTORY_RENDER_PHASE_CHANGEDtoaborted/errored/finished, then callsremount(). If several remounts arrive in quick succession, only the last one runs. The story wrapper's key includes a mount counter, so a remount renders the story fresh.async: true, the instrumenter gets theplayingphase change after the play function has started and drops its first calls.instanceof HTMLElementargument as a DOM element, readinglocalName,classListandinnerText. React Native definesHTMLElementas its own element class, souserEvent.click(element)orexpect(element)threw. The flag adds those three getters to the element prototype (localNameis thetagName), so elements show as<RN:TextInput>. The instrumenter also walks the keys of objects returned from instrumented calls; it skips DOM elements, but React Native elements look like plain objects and walking their fiber overflowed the stack, so ourinstrument()calls return elements as they are.Both instrumenter workarounds would be better fixed in Storybook core.
Example and docs
examples/expo-exampleenables the flag and addsPlayFunctionExample, which usescanvasqueries,stepandexpect(the example is on React Native 0.86, withoutuserEvent).docs/intro/configuration/interactions.md, and the flag added to the feature flag tables.Testing
src/test/helpers.test.ts: each query type, matcher options, error messages,findBywaiting, anduserEventtyping (controlled and uncontrolled),keyboard,clear, clicking through to the pressable, switches, and the error when elements can't dispatch events.src/interactions/interactions.test.ts: play functions getcanvasElement,canvasanduserEvent; Rerun during a running play function reruns it without callingwindow.location.reload(fails without the override); the panel keeps its log when the shown story is selected again; call formatting.pnpm test,pnpm lint,pnpm format:checkandpnpm check:typespass.canvasanduserEvent. The panel shows the calls above, the invalid-email story passes, and a missing element fails withUnable to find an element with the text: "Submit".PlayFunctionExample/Assertionspasses with itscanvasqueries listed, Rerun works, and selecting the shown story again over the WebSocket channel keeps the log.