Storybook is one of the best tools for building client components. It allows us to create UI in isolation, document it, and even cover it with automated tests.
I explained why automated tests are worth pursuing in Why You MUST Have Automated Tests. In this post, we'll go deeper into how to write them efficiently with Storybook.
We have a form with an email, password fields, and a submit button. The user enters their credentials, submits the form, and sees the confirmation message. Here is what the form looks like:
And this is the HTML structure of the form:
<form>
<label for="email">Email</label> <input id="email" type="email" name="email" />
<label for="password">Password</label> <input id="password" type="password" name="password" />
<button type="submit">Submit</button>
</form>
Here are the steps we need to take to write a test for this story:
userEvent.click(selector)
).There are four elements to interact with. Here is how we can do it:
input
tag, which translates to role=textbox
in Testing Library. They also have a <label>
which we will use to narrow the element selection.button
element, that translates to role=button
in Testing Library. The text on the button is Submit
we will also use it to narrow down the selection.With all that said, we get the code like this:
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
// Click and type in the email field
await userEvent.click(canvas.getByRole("textbox", { name: "Email" }));
await userEvent.type(canvas.getByRole("textbox", { name: "Email" }), "example@gmail.com");
// Click and type in the password field
await userEvent.click(canvas.getByRole("textbox", { name: "Password" }));
await userEvent.type(canvas.getByRole("textbox", { name: "Password" }), "secret-password");
// Submit the form
await userEvent.click(canvas.getByRole("button", { name: "Submit" }));
// Assert that the confirmation message is displayed
expect(canvas.getByText("Form submitted successfully")).toBeInTheDocument();
};
It does the job, but writing it is a lot of work. What if there are more steps to take? What if the form is more complex?
What if all of this was done for you? Presenting: Storybook Test Codegen Addon!
With this addon, simply turn on the recording and interact with your stories. The addon will generate a test code for you!
Whenever you interact with the story in recording mode, the addon determines the type of interaction and target element.
Only interactions that can be re-created using Testing Library are recorded, such as click, double click, type, and keydown (for enter and shift keys). The other interactions are ignored.
As for the target element, the algorithm prioritizes aria-role, label, placeholder, text, title, and test-id and falls back to CSS selectors if none of the above can be used. (once again, according to Testing Library's guiding principles)
While the idea of the library is that it should be enough to copy the code as is, you may still want to make some changes, such as adding assertions and reformatting the code.
If you want to assert that the element is displayed, click on it during the recording.
Then, when the test is generated, you can change the code from await userEvent.click(...)
to await expect(...).toBeInTheDocument()
as long as the test still works as expected, and this click wasn't a required interaction. Add expect
before or after the click
if the interaction was needed.
Writing tests is crucial for stable software. But it takes time. To keep up with the pace of development, we need to automate this process as much as possible. That is where Storybook Test Codegen comes in handy. Give it a try, and let me know what you think!