[RFC] Explicit Actions Args Mocking #23649
Replies: 3 comments 11 replies
-
I have been working on implementing this in this PR: #23888 It basically re-exports an instrumented version of Using However, I'm not entirely sure about using Pros of using
|
Beta Was this translation helpful? Give feedback.
-
I have another TypeScript issue with automocked args, and I wonder if this proposal might also help to solve it as well. Currently, TypeScript does not realize that such automocked args like |
Beta Was this translation helpful? Give feedback.
-
Hey everyone! Just wanted to let you all know that this RFC was accepted, implemented and released in the prerelease of Storybook 7.6.0. You can read the blog post here: https://storybook.js.org/blog/storybook-test/ |
Beta Was this translation helpful? Give feedback.
-
Status: accepted; championed by @kasperpeulen
🖼️ Overview
Outcome
We want a CSF story to render the same no matter if
argTypes
inference (which requires docgen provided byaddon-docs
) is available or not. Ideally,argTypes
, even when explicitly specified, shouldn’t influence story rendering at all.Purpose
📚 Context
When creating a new storybook with
storybook init
the followingactions
parameter is automatically set:This code will mark any argType as an
action
when it matches this regex.Those story
argTypes
can be specified manually, but more often are inferred by analysing the source code in node, using libraries such asreact-docgen-typescript
.When
argTypes
are considered actions by this regex,@storybook/addon-actions
will “enhance” the user provided args so that anaction
function is provided for all the component props that start withonX
(onClick, onKeyDown etc.)This feature can be quite useful, the action function will automatically log those user events to the action panel:
Next to that, we enhance those actions args to be jest spies with
@storybook/addon-interactions
so that you can assert on events in the play function:The rendering problem
This feature is quite magical and implicit. Usually argTypes are not explicitly written down but inferred using docgen. If docgen is not enabled, it won’t work. For example, when you import a CSF file directly in a unit test with portable stories (using the
composeStories
function of the renderer).Next to that,
argTypes
inference is one of our biggest performance bottleneck, as it often based ontypescript
which can be slow, and much slower than just building the stories itself.We would like to get to a world where users can disable docgen in storybook and can even use CSF files outside of the storybook environment. There are two important scenario’s where this is not the case at the moment.
Required action args
If a story requires an action prop (e.g.
onLoad
) to render, it will break when inferred argTypes are not available.The play function
The play function is called during rendering the story, and might use action args:
Testing integrations might want to build storybook to test if the play function assertions are correct. If those integrations can build storybook without docgen enabled, this will boost the performance of the feedback such an integration can give. However, this play function will now fail when docgen is disabled.
The TypeScript problem
Because of this magical regex based action arg enhancing, we need to somehow tell TypeScript that all action args are optional (as they will get a default value). But the argTypes inference works using a regex
"^on[A-Z].*"
that can be overridden by users, and it is not possible to make TS mark action args as optional based on this user provided regex.At this moment, we mark any void function as optional. As event handlers are usual void functions, and if they are not, we won’t be able to mock them correctly anyway (as they require a return value). However, it still can be that a user writes an action arg like
handleSubmit
that is a void function, and will be marked as optional by TS, even though this action might not match the user provided regex.This gives us the the following problems:
args
types incorrectly make() => void
properties optional #23068💡 Proposed Solution
Explicit action args when needed for rendering
The user should explicitly provide required action args and action args used in the play function using a new package called
@storybook/test
:Those explicit action args will be assigned a mock function that is compatible with both
jest
andvitest
. This package should replace@storybook/jest
and as start could be the same except for this renaming:The jest export only contained the stuff from
jest-mock
anyway, and ideally we should replace it with thevitest
implementation, asvitest
is ESM based and can be treeshaken. Also renaming the package from jest → test makes sure that people understand that the play function doesn’t actually requires ajest
test runner in anyway. And that play function can be called invitest
tests as well.In the future we want to use this package to contain more test specific functionalities, such as utilities to mock dates, timers, strings etc. Possibly even mocking modules?
Attach action logger to implementation when addon-actions is installed
The idea is that
mock.fn
is just a very generic mock function, and can be used in a test environment as well. But if used in storybook, and when theaddon-actions
is installed, it should trigger a channel event that logs to the action panel. We can use an arg enhancer for that:Deprecate implicit action args used during rendering
In a new minor release for Storybook 7, we will show a runtime deprecation warning whenever an action arg is being called when rendering the story, whenever the
action
arg is not explicitly provided , but implicitly byargTypes
orargTypesRegex
.We include playing the
play
function as part of rendering the story in this definition. So when actions are being invoked by the play function, or when actions are being asserted, it will also show a runtime warning.In Storybook 8, we will upgrade this warning to an actual error.
When such an “implicit” action (using
argTypesRegex
) is being called after rendering, it won’t throw an error. In this way the action panel should keep working as it is today.Remove the TS magic
When an action arg is required, we currently do some TS magic to turn this action arg optional instead:
However, with this proposal, we actually want to trigger people writing their required action args out, so that the story doesn’t break when
argTypes
inference is not available.As this is a breaking change, we will delay this change to 8.0.
Remove argTypesRegex from sb init template
At this moment, we automatically set the argTypesRegex in
.storybook/main.ts
We do think that this regex can be useful when you automatically want to log a zillion possible event handlers. Think about a fat UI component, such as found in MUI:
However, we don’t want to set this by default anymore, and make it an opt-in when users think it is useful in their specific scenario.
Risks
Unresolved questions
Alternatives considered / Abandoned Ideas
argTypes
🚀 Rollout Plan
How do we plan to release these deliverables to customers? Should we opt for incremental release? Should the feature be hidden behind a feature flag? How are we planning to monitor and alert on any issues related to this project?
In a 7.x release
@storybook/test
package for explicit action argsargTypesRegex
from sb initIn the 8.0 release
Beta Was this translation helpful? Give feedback.
All reactions