Git Product home page Git Product logo

storybook-chrome-screenshot's Introduction

Storybook Chrome Screenshot Addon

DEMO

npm CircleCI David

A Storybook Addon, Save the screenshot image of your stories ๐Ÿ“ท via Puppeteer.

storybook-chrome-screenshot takes a screenshot and saves it.
It is primarily responsible for image generation necessary for Visual Testing such as reg-viz.

Table of Contents

Features

  • ๐Ÿ“ท Take screenshots of each stories. via Puppeteer.
  • ๐Ÿš€ Provide flexible screenshot shooting options.
  • ๐ŸŽ‰ Supports the following framework / View framework.

How it works

storybook-chrome-screenshot executes Storybook in a child process and accesses the launched page using Puppeteer. It is a very simple mechanism.
For that reason, you can easily shoot screenshots by simply creating a story that works with the browser.

Getting Started

It is very easy to introduce storybook-chrome-screenshot in your project.

Installation

First install storybook-chrome-screenshot.

$ npm install --save-dev storybook-chrome-screenshot

Note: Please do not use globally but let it operate locally.

Register Addon

Next, register Addon.

.storybook/addons.js

// Other addons...
import 'storybook-chrome-screenshot/register';

Register initialization process

Add initScreenshot decorator. It has to be before the first withScreenshot decorator. Addon uses it to catch the finish of the components' rendering.

Example: .storybook/config.js

import { addDecorator } from '@storybook/react';
import { initScreenshot } from 'storybook-chrome-screenshot';

addDecorator(initScreenshot());

Setup your stories

Create a story with withScreenshot.

React

import React from 'react';
import { storiesOf } from '@storybook/react';
import { withScreenshot } from 'storybook-chrome-screenshot';
import Button from './Button';

storiesOf('Button', module).add('with text', withScreenshot()(() => <Button>Text</Button>));

Angular

This function works well even if you use Angular:

import { storiesOf } from '@storybook/angular';
import { withScreenshot } from 'storybook-chrome-screenshot';
import { MyButtonComponent } from '../src/app/my-button/my-button.component';

storiesOf('Button', module).add(
  'with custom label',
  withScreenshot()(() => ({
    component: MyButtonComponent,
    props: {
      text: 'Text'
    }
  }))
);

Vue.js

Of course, Vue.js works the same way:

import { storiesOf } from '@storybook/vue';
import { withScreenshot } from 'storybook-chrome-screenshot';
import MyButton from './Button.vue';

storiesOf('MyButton', module)
  .add(
    'pre-registered component',
    withScreenshot()(() => ({
      template: '<my-button :rounded="true">A Button with rounded edges</my-button>'
    }))
  )
  .add(
    'template + component',
    withScreenshot()(() => ({
      components: { MyButton },
      template: '<my-button>Button rendered in a template</my-button>'
    }))
  )
  .add(
    'render + component',
    withScreenshot()(() => ({
      render: (h) => h(MyButton, { props: { color: 'pink' } }, ['renders component: MyButton'])
    }))
  );

Run storybook-chrome-screenshot Command

Open package.json and add a screenshot script for run storybook-chrome-screenshot command.

{
  "scripts": {
    "screenshot": "storybook-chrome-screenshot -p 9001 -c .storybook"
  }
}

Note: Parameters such as ports and configuration files should match the parameters of the Storybook you are currently using.

After that, just run the npm run screenshot command, shotting a component wrapped with withScreenshot and save the images.

$ npm run screenshot

Support for addDecorator

Or by using addDecorator(), it is possible to shotting all the decorated stories.

import { storiesOf } from '@storybook/react';
import { withScreenshot } from 'storybook-chrome-screenshot';

storiesOf('Button', module)
  .addDecorator(
    withScreenshot({
      /* ...options */
    })
  )
  .add('with primary', () => <Button primary>Primary Button</Button>)
  .add('with secondary', () => <Button secondary>Secondary Button</Button>);

API

initScreenshot()

This decorator has to be added to every story. Addon uses it to understand when story's rendering is finished.

Important!. initScreenshot has to be added before the first withScreenshot.

Example: .storybook/config.js

import { addDecorator } from '@storybook/react';
import { initScreenshot } from 'storybook-chrome-screenshot';

addDecorator(initScreenshot());

withScreenshot(options = {})

Notify Puppeteer of the story wrapped in this function and let it recognize it as the target of the screenshot.

The following objects of options can be specified.

{
  namespace: 'global',    // namespace for your screenshots. It is using in the filenames, e.g.  Button-with-primary_global.png
  delay: 0,               // Delay milliseconds when shooting screenshots
  waitFor: '',            // User defined trigger function name to shoot screenshots. See "Full control the screenshot timing" section below.
  viewport: {             // Browser's viewport when shooting screenshots. (See: https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagesetviewportviewport)
    width: 1024,
    height: 768,
    deviceScaleFactor: 1,
    isMobile: false,
    hasTouch: false,
    isLandscape: false,
  },
  filePattern: '{kind}-{story}-{knobs}_{ns}-{vp}' // file pattern, combined from kind, story name, used knobs, namespace and viewport
}

Also, By passing the array to viewport, you can easily shoot multiple Viewports.

{
  viewport: [
    // Mobile
    {
      width: 300,
      height: 420,
      isMobile: true,
      hasTouch: true,
    },
    // Tablet
    {
      width: 768,
      height: 800,
      isMobile: true,
      hasTouch: true,
    },
    // Desktop
    {
      width: 1024,
      height: 768,
    },
  ],
}

setScreenshotOptions(options = {})

Sets the default value of the option used with withScreenshot().
It is useful for changing Viewport of all stories.

Example: .storybook/config.js

import { setScreenshotOptions } from 'storybook-chrome-screenshot';

setScreenshotOptions({
  viewport: {
    width: 768,
    height: 400,
    deviceScaleFactor: 2
  }
});

getScreenshotOptions()

Get the current option used with withScreenshot().

import { getScreenshotOptions } from 'storybook-chrome-screenshot';

console.log(getScreenshotOptions());
// => Current screenshot options...

Command Line Options

$ $(npm bin)/storybook-chrome-screenshot --help

  Usage: storybook-chrome-screenshot [options]


  Options:

    -V, --version                    output the version number
    -p, --port [number]              Storybook server port. (default: 9001)
    -h, --host [string]              Storybook server host. (default: localhost)
    -s, --static-dir <dir-names>     Directory where to load static files from.
    -c, --config-dir [dir-name]      Directory where to load Storybook configurations from. (default: .storybook)
    -o, --output-dir [dir-name]      Directory where screenshot images are saved. (default: __screenshots__)
    --parallel [number]              Number of Page Instances of Puppeteer to be activated when shooting screenshots. (default: 4)
    --filter-kind [regexp]           Filter of kind with RegExp. (example: "Button$")
    --filter-story [regexp]          Filter of story with RegExp. (example: "^with\s.+$")
    --inject-files <file-names>      Path to the JavaScript file to be injected into frame. (default: )
    --browser-timeout [number]       Timeout milliseconds when Puppeteer opens Storybook. (default: 30000)
    --puppeteer-launch-config [json] JSON string of launch config for Puppeteer. (default: {"args":["--no-sandbox","--disable-setuid-sandbox", "--disable-dev-shm-usage"]})
    --silent                         Suppress standard output.
    --debug                          Enable debug mode.
    -h, --help                       output usage information

Tips

Disable component animation

When shooting screenshots, you may want to disable component animation. In this case it is easiest to inject Script using the --inject-files option.

You can create ./disable-animation.js and disable CSS Animation with the next snippet.

(() => {
  const $iframe = document.getElementById('storybook-preview-iframe');
  const $doc = $iframe.contentDocument;
  const $style = $doc.createElement('style');

  $style.innerHTML = `* {
    transition: none !important;
    animation: none !important;
  }`;

  $doc.body.appendChild($style);
})();

Pass the created file to the --inject-files option.

$ $(npm bin)/storybook-chrome-screenshot --inject-files ./disable-animation.js [...more options]

Full control the screenshot timing

Sometimes you may want to full-manage the timing of performing screenshot. Use the waitFor option if you think so. This string parameter should points a global function to return Promise.

For example, the following setting makes the screenshot function wait for firing of fontLoading:

<!-- ./storybook/preview-head.html -->
<link rel="preload" href="/some-heavy-asset.woff" as="font" onload="this.setAttribute('loaded', 'loaded')">
<script>
function fontLoading() {
  const loaded = () => !!document.querySelector('link[rel="preload"][loaded="loaded"]');
  if (loaded()) return Promise.resolve();
  return new Promise((resolve, reject) => {
    const id = setInterval(() => {
      if (!loaded()) return;
      clearInterval(id);
      resolve();
    }, 50);
  });
}
</script>
import { setScreenshotOptions } from 'storybook-chrome-screenshot';

setScreenshotOptions({
  waitFor: 'fontLoading',
});

Examples

TODO

The following tasks remain. Contributes are welcome ๐Ÿ˜ƒ

  • Global Options.
  • Shooting at an arbitrary timing. (No plan for support)
  • Support for Angular.
  • Support for Vue.js.
  • More unit testing.

Contribute

  1. Fork it!
  2. Create your feature branch: git checkout -b my-new-feature
  3. Commit your changes: git commit -am 'Add some feature'
  4. Push to the branch: git push origin my-new-feature
  5. Submit a pull request ๐Ÿ’ช

Bugs, feature requests and comments are more than welcome in the issues.

Development

We will develop using the following npm scripts.

npm run test

We will run Lint, unit test, E2E test in order.
Each test can also be executed individually with the following command.

# Run TSLint
$ npm run test:lint

# Run unit test using Jest
$ npm run test:unit

# Run E2E test
$ npm run test:e2e

# Run unit tests in watch mode
$ npm run test:watch

npm run build

Compile the source code written in TypeScript.

License

MIT ยฉ tsuyoshiwada

storybook-chrome-screenshot's People

Contributors

wadackel avatar quramy avatar alexeybondarenko avatar renovate-bot avatar thekashey avatar jtbandes avatar marcobiedermann avatar meghna avatar avaly avatar kogai avatar wreulicke avatar

Watchers

James Cloos avatar theMaimu avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.