Test your Storybook

gaetanrdn

Gaëtan Redin

Posted on February 13, 2022

Test your Storybook

Storybook for Angular

Context

Nx 13 — Angular 13 — Storybook 6.5.0-alpha.36

Why?

More your application grows more you risk to introduce bugs. In a recent project, we have to kind of tests: Unit tests (so many) and some integration tests. We work incrementally and add features during sprints and rework older ones with more functional rules. Even if we test all devs with unit test, there is a moment that you realize you couldn’t test everything with unit testing.

We have develop a Storybook which contains all our components / directives. Sometimes, we check some of it during a development and Ho surprise, it’s broken :-(. Yet All our unit tests are okay…

How?

I was looking for a solution to introduce easily some functional tests without testing the interactions with the backend. Our goal was only to test functionally our HMI.

I already heard talking about Cypress and after doing some research I found a perfect solution for us. Nx offer the possibility to include an e2e application with Cypress configuration for testing our Storybook (Miracle).

I install all the requirements and start to write some functional tests. What a surprise, some tests failed whereas all our unit tests and integration tests works… As a lead dev, it was first a deception, because it means I didn’t guarantee the quality of our application. But, on second thought, what a joy to see I can still learn and discover new things! I’m sure many of us have already be in this situation. So let’s quit chatting, this is how to do it.

Installation

I suppose you already have a Nx — Angular project with Storybook. Here we just talk about Cypress installation for Storybook.

nx generate [@nrwl/storybook](http://twitter.com/nrwl/storybook):cypress-project --name={your_app_name} --linter=eslint --no-interactive
Enter fullscreen mode Exit fullscreen mode

My app is called “storybook” and that’s the result of the command:

nx generate [@nrwl/storybook](http://twitter.com/nrwl/storybook):cypress-project --name=storybook --linter=eslint --no-interactive
UPDATE package.json
CREATE apps/storybook-e2e/cypress.json             
CREATE apps/storybook-e2e/src/fixtures/example.json
CREATE apps/storybook-e2e/src/support/commands.ts  
CREATE apps/storybook-e2e/src/support/index.ts     
CREATE apps/storybook-e2e/tsconfig.json            
CREATE apps/storybook-e2e/project.json             
UPDATE workspace.json                              
CREATE apps/storybook-e2e/.eslintrc.json           
UPDATE nx.json
Enter fullscreen mode Exit fullscreen mode

In the package.json , we can see two more dev dependencies: @nrwl/cypress and cypress , logic.

In the storybook-e2e/tsconfig.json , we have this:

{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "sourceMap": _false_,
    "outDir": "../../dist/out-tsc",
    "allowJs": _true_,
    "types": ["cypress", "node"]
  },
  "include": ["src/ **/*.ts", "src/** /*.js"]
}
Enter fullscreen mode Exit fullscreen mode

Nothing special, except the type “cypress”.

Now let’s have a look into the storybook-e2e/project.json file:

{
  "root": "apps/storybook-e2e",
  "sourceRoot": "apps/storybook-e2e/src",
  "projectType": "application",
  "targets": {
    "e2e": {
      "executor": "@nrwl/cypress:cypress",
      "options": {
        "cypressConfig": "apps/storybook-e2e/cypress.json",
        "devServerTarget": "storybook:storybook"
      },
      "configurations": {
        "ci": {
          "devServerTarget": "storybook:storybook:ci"
        }
      }
    },
    "lint": {
      "executor": "@nrwl/linter:eslint",
      "outputs": ["{options.outputFile}"],
      "options": {
        "lintFilePatterns": ["apps/storybook-e2e/**/*.{js,ts}"]
      }
    }
  },
  "tags": [],
  "implicitDependencies": ["storybook"]
}
Enter fullscreen mode Exit fullscreen mode

As we can see, the target server is defined with our storybook app "devServerTarget":"storybook:storybook:ci" which is launch in ci mode. So there is an implicit dependency with our Storybook app "implicitDependencies": ["storybook"] .

You already can to try it:

nx e2e {your_app_name}-e2e
Enter fullscreen mode Exit fullscreen mode

It will failed with something like:

Can't run because no spec files were found.

We searched for any files inside of this folder:

...\apps\storybook-e2e\src\integration
Enter fullscreen mode Exit fullscreen mode

Yes, we don’t have write tests yet. If you don’t know how to write cypress tests, you can read the documentation here which is perfect.

This commands is perfect for the testing in terminal. But some of us prefer to see it in a real window. To open cypress and execute the tests on demand, I suggest you to create another cypress.json like this:

// cypress.local.json
{
  "fileServerFolder": ".",
  "fixturesFolder": "apps/storybook-e2e/src/fixtures",
  "integrationFolder": "apps/storybook-e2e/src/integration",
  "modifyObstructiveCode": _false_,
  "supportFile": "apps/storybook-e2e/src/support/index.ts",
  "pluginsFile": _false_,
  "video": _true_,
  "videosFolder": "../../dist/cypress/apps/storybook-e2e/videos",
  "screenshotsFolder": "../../dist/cypress/apps/storybook-e2e/screenshots",
  "chromeWebSecurity": _false_,
  "baseUrl": "http://localhost:4400" // set the url of your local Storybook
}
Enter fullscreen mode Exit fullscreen mode

Add this command into your package.json :

"test:storybook:local": "cypress open --browser ~\\chrome-win\\chrome.exe -C apps/storybook-e2e/cypress.local.json"
Enter fullscreen mode Exit fullscreen mode

Here I use chromium as browser and I specify my local cypress config.

Now you can launch your local storybook and your local cypress:

nx run storybook:storybook
npm run test:storybook:local
Enter fullscreen mode Exit fullscreen mode

It will fail until you will have write some tests.

To help writing test for Storybook, I suggest you to install the following library:

npm i -D cypress-storybook
Enter fullscreen mode Exit fullscreen mode

Then import the helper commands into the support index file:

// apps/storybook-e2e/src/support/index.ts
import 'cypress-storybook/cypress'
Enter fullscreen mode Exit fullscreen mode

Then import that in the storybook preview file, it help storybook to understand the cypress commands:

// apps/storybook/.storybook/preview.js
import 'cypress-storybook/angular'
Enter fullscreen mode Exit fullscreen mode

At last, in your test file what you have to do:

describe('MyComponent', () => {
    beforeEach(() => {
      cy.visitStorybook();
      cy.loadStory('title-of-my-story', 'MyStoryName');
    });

    it('my test', () => {
    ...
    });
});
Enter fullscreen mode Exit fullscreen mode

In the documentation, it’s recommended to wrap the cy.visitStorybook(); in a before and not a beforeEach but when I tried, it does not reset the Story in form cases between each test.

Conclusion

Now you will be more armed to defeat bugs! No excuse, particularly if you use Nx which helps a lot for the configuration. I suggest you to write some commands to simplify writing tests like a fillForm command which get a fixture and a form tag for example. It will make your test more readable.

Thanks for reading.

Learn more

💖 💪 🙅 🚩
gaetanrdn
Gaëtan Redin

Posted on February 13, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Test your Storybook
storybook Test your Storybook

February 13, 2022