Coder Social home page Coder Social logo

macku / jest-puppe-shots Goto Github PK

View Code? Open in Web Editor NEW
85.0 4.0 3.0 209 KB

A Jest plugin for creating screenshots of React components with a little help of Puppeteer

License: MIT License

JavaScript 97.39% HTML 2.61%
jest screenshot snapshot testing unittest react enzyme javascript js visual-regression

jest-puppe-shots's Introduction

jest-puppe-shots

NPM version node Build Status dependencies Status devDependencies Status peerDependencies Status

A Jest plugin for creating screenshots of React components with a little help of Puppeteer

How it works?

A jest-puppe-shots is a Jest plugin that can help you create Visual Regression tests for your React components. If you ever used Enzyme or Snapshots you will love the jest-puppe-shots.

The Snapshot testing approach is really awesome but it has one downside: it cannot be used to make visual regression tests of your components. Thanks to the Puppeteer API it's now possible to use Chromium browser in Jest and create real screenshots of your components!

Installation

You can install the plugin using NPM:

npm install jest-puppe-shots --save-dev

or by Yarn:

yarn add jest-puppe-shots --dev

Additional dependencies

You will have to install jest and react-dom if you don't have them yet:

npm install jest react-dom

Async/Await

The jest-puppe-shots API is written on top of the Puppeteer which means the currently supported version of Node is 7.6+. You will also have to setup your Babel configuration to use the Async/Await from ES7.

Here you can find the tutorial how to setup your Babel settings to use it.

Jest Configuration

Before starting using the jest-puppe-shots you will need to change your Jest configuration file.

Open the jest.config.json file in your project and add additional entry:

{
  "preset": "jest-puppe-shots-preset"
}

If you are are using the jest.config.js file, then instead adjust your configuration like this:

module.exports = {
  // You config goes here

  preset: 'jest-puppe-shots-preset'
}

Taking Screenshots

After setting up the configuration you can start writing your first integration test that will take screenshots. The jest-puppe-shots it utilizing a couple of concepts and tools under the hood:

  • It's using Puppeteer to start Chromium browser in the headless mode
  • It takes a Screenshot of the component and stores it as a Snapshot inside your repository under the __image_snapshots__ directory. If you are not familiar with the Jest Snapshots testing take a look at Jest documentation page.
  • Uses the .toMatchImageSnapshot() matcher to compare the base screenshot with the current version token during the test execution.

Writing First Integration Test

Take a look at the example test code:

const { openNewPage } = require('jest-puppe-shots'); // 1. Require the jest-puppe-shots module into your test
import { openNewPage } from 'jest-puppe-shots'; // or use the ES module import if you like

import MyComponent from './MyComponent'; // 2. Import your React component

let page;
beforeEach(async () => {
  page = await openNewPage(); // 3. Open new page for taking screenshots
});

test('should render <Foo> component', async () => {
  const component = await page.mount( // 4. Mount your component
    <MyComponent className="my-component">
      <strong>Hello World!</strong>
    </MyComponent>
  );

  const screenshot = await page.takeScreenshot(component); // 5. Take a screenshot of your component

  expect(screenshot).toMatchImageSnapshot(); // 6. Assert image snapshots and you're done!
});

Running this code for the first time by Jest, will produce a Base Screenshot and store it inside the repository at your-test-location/__image_snapshots__ directory.

To update the Base Screenshot run Jest with --updateSnapshot or -u parameter.

Mounting additional CSS

If your components are based on additional CSS code from your code base like ex. reset.css you might like to mount the static content on the page:

import path from 'path';
import { openNewPage } from 'jest-puppe-shots';

let page;
beforeEach(async () => {
  page = await openNewPage();
  await page.mountCssContext(path.resolve('../path/to/my-assets-dir', [
    'css/reset.css',
    'css/custom-styles.css'
  ]))
});

Mounting the CSS directory might also help you with loading static content files like images or font.

Loading external CSS and JS files

You can also load and put an external CSS and JS files on your page:

import { openNewPage } from 'jest-puppe-shots';

let page;
beforeEach(async () => {
  page = await openNewPage();
  await page.loadExternalCss(
    'https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.0/normalize.min.css',
    'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css'
  );

  await page.loadExternalJs(
    'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js'
  );
});

Both loadExternalCss and loadExternalJs function can accept multiple arguments so you can pass as URLs as you want.

Roadmap

  • Transform the *.less and *.sass files into CSS code when importing component modules by Jest
  • Better support for the Enzyme like API. You should be able to use ex. get, or find functions after mounting component
  • Making screenshots of component parts by ex. selecting DOM nodes
  • More built-in renderers and support for custom renderers (pass a function)
  • Debugging: allow to start test without the headless mode and see what browser is doing

FAQ

What version of Jest do I need to use?

You will have to install Jest 22+. The main reason of that is version 22 introduced the globalSetup and globalTeardown options APIs.

What Node version is supported?

Since both Puppeteer and jest-puppe-shots are heavily depending on the async/await API you will have to use Node 7.6+ that enabled the support for it.

I don't want to run Puppeteer each time I'm running my tests. It takes ages to start Jest and it's getting slow!

No problem! You don't need to launch Puppeteer for you regular Unit Tests. You will just have to adjust your environment a little bit. Take a look at the example:

  1. Edit your package.json file and provide additional entries for running screenshot tests:

Before

{
  "scripts": {
    "test": "jest",
    "test:watch": "jest --watch"
  }
}

After

{
  "scripts": {
    "test": "jest",
    "test:watch": "jest --watch",
    "test:screenshots": "cross-env TAKE_SCREENSHOTS=true jest",
    "test:watch:screenshots": "cross-env TAKE_SCREENSHOTS=true jest --watch"
  }
}

We are using the cross-env package in order to set environment variables for all the operating systems.

  1. Rename your jest.config.json to jest.config.js and adjust the source code to use jest-puppe-shots preset only when we need it.

Before

{
  "preset": "jest-puppe-shots-preset"
}

After

let config = {
  /* Your Jest config goes here */
};

if (process.env.TAKE_SCREENSHOTS) {
  config.preset = 'jest-puppe-shots-preset';
}

module.exports = config;
  1. Right now you can run unit tests as usual by npm run test and you can launch integration tests by running npm run test:screenshots

I'm using styled-components to provide my CSS code. Is it supported?

That's fine. Good news for you is that jest-puppe-shots is supporting styled-components. All you need to do is to inform runner that you would like to use a custom renderer.

Edit your Jest config file jest.config.json and add new globals entry to the configuration:

{
  "globals": {
    "__JEST_PUPPE_SHOTS_RENDERER__": "STYLED_COMPONENTS"
  }
}

Currently, there are two supported renderers:

  • REACT_SERVER (default) - It's using the react-dom/server package to render component as string
  • STYLED_COMPONENTS - It's using the ServerStyleSheet from styled-components to intercept the produced CSS styles and inject them on the page

jest-puppe-shots's People

Contributors

apieceofbart avatar dustincomp avatar macku avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

jest-puppe-shots's Issues

Allow setupTests config

Hi,

I try to use it with create-react-app, however it doesn't allow altering jest preset without ejecting.

Is it possible to setup jest-puppe-shots in setupJest.js file?

Problem with testing components when component size has been changed

Hello
We have a problem with testing react components, when its size has been changed, in such case jest-image-snapshots throws error "toMatchImageSnapshot(): Received image size must match baseline snapshot size in order to make comparison."
In general that's not a problem when creating screenshot of whole page, but jest-puppe-shots makes screenshot of small part of it and it can differ in size in such case as adding new line to component.
I thought about always creating big screenshot (something like 1000x1000px) but comparision of such big screenshots takes too long.
I tried to come up with another solution, unfortunately I couldn't find any, so I could use any help with this issue. :)

Tests throws error when rendered output has new lines

Hello
There is a problem when rendered output has new lines. Most of the time that's not a problem, but svg elements can have new lines in path elements.
In my case that was:

<svg>
<path d={`M150 0 
L75 200 
L225 200 Z`} />
</svg>

The problem is in this fragment (lib/renderer/common.js , line 1):

const wrapReactHtmlOutput = html => `document.body.innerHTML = '${html.replace("'", "\\'")}'`;

all you have to do is to change it so it uses template literals:

const wrapReactHtmlOutput = html => `document.body.innerHTML = \`${html.replace("'", "\\'")}\``;

also now I'm not sure if this replace is even needed, as variable html isn't surrounded by it anymore.

Mounting Additional CSS Example has error

This example is not a valid use of path.resolve() and following this format will throw an error.

 await page.mountCssContext(path.resolve('../path/to/my-assets-dir', [
    'css/reset.css',
    'css/custom-styles.css'
  ]))

I've tried altering it to this, but

 await page.mountCssContext(path.resolve('build'), [
    'style.css'
  ])

But I am consistently getting the error Error: loading style from build/style.css. Can you provide an updated additional css example that is working correctly?

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.