How to Setup Visual Testing With Storybook, Jest and Puppeteer
I don’t need to tell you that Storybook is a powerful tool for visualizing components; But it therefore also sounds like the perfect environment to do Visual Testing. A form of testing where a current snapshot is compared with one from the past.
Let’s set up Visual Testing using Jest; As a well-established framework, it combines unit testing in extend to visual testing. In short: Run the Jest tests, it checks whether any visual change occurred by comparing the current state of a component with a previous snapshot.
To achieve this we will need a little more than Jest only, some other tools are needed: we will make snapshots using puppeteer (a package that allows you to spin up a browser and take screenshots), which will lay the foundation for comparing snapshots. The comparison is done with jest-screenshot: A package that generates a difference between 2 snapshots; then it checks whether a test will fail or not, as icing on the cake it is also capable of generating an html-based report that interactively shows where the differences occurred.
Step 1 — Prerequisites
You probably already have a project with Storybook and some components.
npx create-react-app a-react-visual-testing --template typescript
npx sb init
I made some basic components: A Text (with some variants) and a Button.
Step 2 — Setup Testing
As already mentioned, we need a few things: Jest sounds pretty obvious; Puppeteer allows us to spin up a browser and take screenshots of our components; Jest-screenshot is a package that can compare snapshots with each other.
npm i -D jest puppeteer jest-puppeteer jest-screenshot
First we need to configure Jest-screenshot to work with Jest:
At this point we can write our first test. But it was this moment when I realized that I really don’t like writing tests at all.
But since we don’t provide any special logic for each component, let me write a joint function that can provide every single component with Visual Testing using a minimal setup:
Let’s walk ahead for a moment; take this story for our Text component:
You see where this is going? Storybook generates its urls for it’s stories like this: ${component} — ${variant}
eg. http://localhost:6006/?path=/story/text--title
also the fullscreen version, which is the most interesting when taking sceenshots:
eg. http://localhost:6006/iframe.html?id=text--title
In this example, the component is called “Text” and the variant is the name of the story, namely “Title”. This is easy to put into a config to base our Visual Testing on:
This is our minimal test for the “Text” component. You see a setup-config with a single key “text”. “text” is the name of the component in Storybook. This key has an array. These array are the variants, all the different stories that are available for our Text.
If we go with this config to our screenshotTest function, we get the following test:
So what happens: Jest will spot the “Text.test.js”. Will then trigger the function above to set up a test-suit using the keys in the config. In each test-suit, tests will be set up for the number of variants (the strings in the array of the config). Each test consists of spinning a puppeteer instance; navigate it to the fullscreen view in Storybook for this component and this variant; take a screenshot; and finally pass or fail the test by comparing it with an existing screenshot; when the test is completed, the instance will close to save resources.
For now we need to serve Storybook before we can run our tests:
npx start-storybook -p 9090
When it is ready in the browser, we can run our tests in a second terminal:
npx jest
When the tests are complete you should see something like this in the console:
This first time, all tests will pass; Snapshots have been generated in the “.snapshots” folder. These will be the baseline for our future tests so it might not be a bad idea to validate the snapshots.
Step 3 — Snapshots
Hard working on my News website I find out that I prefer to change the body color default to green; just because I love my shrek-friends:
So I have this new style for my text variants; Unfortunately as awkward as it might be, I accidentally also changed the “textTransform” of the title to lowercases while I was changing my color.
Unsuspectingly, I want to do a deploy a few days later and I run my tests: Woah, much has failed?!
When I check the automatically generated report at
“jest-screenshot-report/index.html”. I see that regressions have indeed surfaced.
First I see that my Title has changed: Good job Jest!! Let me quickly fix that one, because that was indeed not the intention.
Now, the following error: I did indeed change my body text color to green. I am not going to change that back? This means that with the current config my tests will always fail from now on. To avoid this we can pass a flag to our jest command:
You can run Jest with a flag that will tell it to re-generate snapshots:
— updateSnapshot
You may also use the equivalent single-character: -u
For simplicity, I adjust my npm-scripts:
Now that is fixed, I run my tests again and check if there are any regressions left. If not, I commit my new changes along with my new snapshots.
Step 4 — Automation
I would like to automate my tests some more: run a command; get some coffee and check the results when I get back.
To make this automation possible, we are going to make a Storybook build. This can then be served using an http-server. Then we can run our tests on this server.
To spin up this environment, we use the “http-server”-package, which spins (as the name suggests) a small web-server from where static files can be served.
To detect if our server is running and ready to run our tests, we use a package called “start-server-and-test”, this one runs a command; wait; and runs another command when a response comes from a specific address.
npm i -D start-server-and-test http-server
Then we further extend our npm-scripts:
First we built our Storybook; Then we start an http-server that serves this freshly build Storybook; and wait to get a response on port 9090. When we got response, we can safely run our visualization tests.
With this I am satisfied and I can build my News website with confidence that my components will continue to look the way they should, done with regressions.
Thank you for reading my first article; Hope it was able to get you going to do some visual testing of your components.
Anyway; Always welcome to shoot some suggestions, feedback, ..