Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save phabreeze/1b294f33a72bbd1c19116f7e07406286 to your computer and use it in GitHub Desktop.

Select an option

Save phabreeze/1b294f33a72bbd1c19116f7e07406286 to your computer and use it in GitHub Desktop.

Revisions

  1. @dferber90 dferber90 revised this gist Sep 30, 2018. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion visual-regression-testing.md
    Original file line number Diff line number Diff line change
    @@ -10,7 +10,7 @@ This gist walks you through a `create-react-app` application as an example of ho

    I will write a more detailed article soon. This gist is for the curious.

    *You can also check out [this repo](https://gist.github.com/dferber90/6fe76cde582b8746191478fac34c8b7d) which is what you'll end up with in case you get confused along the way.*
    *You can also check out [this repo](https://github.com/dferber90/visual-regression-testing-create-react-app-example) which is what you'll end up with in case you get confused along the way.*

    ## ToC

  2. @dferber90 dferber90 revised this gist Sep 24, 2018. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions visual-regression-testing.md
    Original file line number Diff line number Diff line change
    @@ -10,6 +10,8 @@ This gist walks you through a `create-react-app` application as an example of ho

    I will write a more detailed article soon. This gist is for the curious.

    *You can also check out [this repo](https://gist.github.com/dferber90/6fe76cde582b8746191478fac34c8b7d) which is what you'll end up with in case you get confused along the way.*

    ## ToC

    - [Visual Regression Testing with Jest](#visual-regression-testing-with-jest)
  3. @dferber90 dferber90 revised this gist Sep 24, 2018. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion visual-regression-testing.md
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,6 @@
    # Visual Regression Testing with Jest

    <img src="https://i.imgur.com/GqGN2gY.jpg" />
    <img src="https://i.imgur.com/7Te0cDC.png" />

    This is a walkthrough of how to set up Visual Regression Testing with Jest for an application created with [`create-react-app`](https://github.com/facebook/create-react-app).

  4. @dferber90 dferber90 renamed this gist Sep 24, 2018. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  5. @dferber90 dferber90 revised this gist Sep 24, 2018. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion log.md
    Original file line number Diff line number Diff line change
    @@ -61,7 +61,7 @@ yarn add jest-image-snapshot jsdom-screenshot jest-transform-file jest-transform

    Edit `package.json` to add the Visual Regression Testing libraries to Jest.

    ```json
    ```js
    // package.json
    "jest": {
    // ... more stuff ...
  6. @dferber90 dferber90 created this gist Sep 24, 2018.
    226 changes: 226 additions & 0 deletions log.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,226 @@
    # Visual Regression Testing with Jest

    <img src="https://i.imgur.com/GqGN2gY.jpg" />

    This is a walkthrough of how to set up Visual Regression Testing with Jest for an application created with [`create-react-app`](https://github.com/facebook/create-react-app).

    The following walkthrough uses React as an example, but the approach should work for any modern frontend library! I assume it can be used with _Angular_, _Vue_, _Cycle.js_ and more.

    This gist walks you through a `create-react-app` application as an example of how to set up Visual Regression Testing in Jest using libraries I wrote recently which enable this: [`jsdom-screenshot`](https://github.com/dferber90/jsdom-screenshot), [`jest-transform-css`](https://github.com/dferber90/jest-transform-css) and [`jest-transform-file`](https://github.com/dferber90/jest-transform-file).

    I will write a more detailed article soon. This gist is for the curious.

    ## ToC

    - [Visual Regression Testing with Jest](#visual-regression-testing-with-jest)
    - [Set up `create-react-app`](#set-up-create-react-app)
    - [Set up Visual Regression Testing libraries](#set-up-visual-regression-testing-libraries)
    - [Add `react-testing-library`](#add-react-testing-library)
    - [More features](#more-features)
    - [Interacting with components before taking the screenshot](#interacting-with-components-before-taking-the-screenshot)
    - [PostCSS, CSS Modules, Styled Components, ..](#postcss-css-modules-styled-components-)
    - [Request Interception](#request-interception)
    - [Static File Serving](#static-file-serving)
    - [Debugging](#debugging)
    - [Summary](#summary)
    - [Disclaimer](#Disclaimer)

    ## Set up `create-react-app`

    Create a new create-react-app project called "vrt-cra" (short for visual-regression-testing-create-react-app), or with whatever name you prefer.

    ```
    npx create-react-app vrt-cra
    ```

    Open project

    ```
    cd vrt-cra
    ```

    Eject project, as we need a more sophisticated setup.

    You will be asked whether you really want to eject, confirm it by typing <kbd>y</kbd> and pressing <kbd>Enter</kbd>.

    ```
    yarn eject
    ```

    > You can start the application to see what it looks like by running `yarn start`.
    > You can also run the tests once to ensure they work properly with `yarn test App.test.js`. You have to quit them with `q` after they ran as they start in _watch_ mode automatically.
    ## Set up Visual Regression Testing libraries

    Now we need to add some libraries to enable Visual Regression Testing: [`jsdom-screenshot`](https://github.com/dferber90/jsdom-screenshot), [`jest-transform-css`](https://github.com/dferber90/jest-transform-css) and [`jest-transform-file`](https://github.com/dferber90/jest-transform-file):

    ```
    yarn add jest-image-snapshot jsdom-screenshot jest-transform-file jest-transform-css
    ```

    Edit `package.json` to add the Visual Regression Testing libraries to Jest.

    ```json
    // package.json
    "jest": {
    // ... more stuff ...

    // add this entry
    "setupTestFrameworkScriptFile": "./src/setupTests.js",

    // this entry already exists, change it from "node" to "jsdom"
    "testEnvironment": "jsdom",

    // this entry already exists, change it
    "transform": {
    "^.+\\.(js|jsx|mjs)$": "<rootDir>/node_modules/babel-jest",
    "^.+\\.css$": "jest-transform-css",
    "^.+\\.svg$": "jest-transform-file",
    "^(?!.*\\.(js|jsx|mjs|css|json|svg)$)": "<rootDir>/config/jest/fileTransform.js"
    },

    // ... more stuff ...
    }
    ```

    _Notice that we added "svg" to the list of files not handled by `fileTransform.js` in the last line, as we're now transforming SVGs through `jest-transform-file` instead._

    Extend the `expect` with the `toMatchImageSnapshot` function so that we can compare images.

    ```js
    // src/setupTests.js
    import { toMatchImageSnapshot } from "jest-image-snapshot";
    expect.extend({ toMatchImageSnapshot });
    ```

    Adapt the `App.test.js` test.

    ```js
    // src/App.test.js
    import React from "react";
    import ReactDOM from "react-dom";
    import { generateImage } from "jsdom-screenshot";
    import App from "./App";

    it("has no visual regressions", async () => {
    // render App into jsdom
    const div = document.createElement("div");
    document.body.appendChild(div);
    ReactDOM.render(<App />, div);

    // prevent spinner from rotating to ensure consistent screenshots
    document
    .getElementsByClassName("App-logo")[0]
    .setAttribute("style", "animation: none");

    // Take screenshot with generateImage()
    const screenshot = await generateImage();
    // and compare it to the previous sceenshot with toMatchImageSnapshot()
    expect(screenshot).toMatchImageSnapshot();

    // clean up for next test
    ReactDOM.unmountComponentAtNode(div);
    document.body.removeChild(div);
    });
    ```

    🎉 This is already the end of the setup for basic Visual Regression Testing!

    We can now rerun the tests with `yarn test App.test.js`.

    _Notice that you must restart your tests completely (exit the "watch" mode) as we changed the configuration quite a bit._

    You will see a screenshot was saved to `src/__image_snapshots__`. The next time you run your tests, another screenshot will get taken and compared with the one already existing there. If they match, your tests succeed as there were no visual regressions. When they differ, an image showing the differences will be created and your tests will fail. In case the changes were on purpose, the saved image can be updated by pressing <kbd>u</kbd> in the tests, as may already know from Jest's snapshotting feature (not to confuse with screenshots).

    This is great as it gives you confidence that your layout did not change. You don't need to make any tests for classnames anymore, just take a screenshot instead.

    Make some changes to `App.js` and see how it affects the tests.

    _A sidenote on performance: Taking a screenshot (the `generateImage` function) takes one or two seconds, depeding on your system and the size of the sreenshot. So use the feature wisely._

    ## Add `react-testing-library`

    The setup is quite cumbersome for each test as we're manually mounting the `div`, rendering the application and cleaning up. We can let [`react-testing-library`](https://github.com/kentcdodds/react-testing-library) handle that. If you're not using React, you can use [`dom-testing-library`](https://github.com/kentcdodds/dom-testing-library) instead.

    Add `react-testing-library` and `jest-dom`.

    ```
    yarn add react-testing-library jest-dom
    ```

    Enable `jest-dom` helpers and clean up `react-testing-library` automatically.

    ```js
    // src/setupTests.js

    // add some helpful assertions
    import "jest-dom/extend-expect";

    // clean up after each test
    import "react-testing-library/cleanup-after-each";

    // This was here before as we added it earlier. We still need it.
    import { toMatchImageSnapshot } from "jest-image-snapshot";

    expect.extend({ toMatchImageSnapshot });
    ```

    And now, we can clean up our test in `App.test.js`:

    ```js
    // src/App.test.js
    import React from "react";
    import { generateImage } from "jsdom-screenshot";
    import { render } from "react-testing-library";
    import App from "./App";

    it("has no visual regressions", async () => {
    // render App into jsdom
    render(<App />);

    // prevent spinner from rotating to ensure consistent screenshots
    document
    .getElementsByClassName("App-logo")[0]
    .setAttribute("style", "animation: none");

    // Take screenshot with generateImage()
    const screenshot = await generateImage();
    // and compare it to the previous sceenshot with toMatchImageSnapshot()
    expect(screenshot).toMatchImageSnapshot();
    });
    ```

    ## More features

    #### Interacting with components before taking the screenshot

    It is possible to interact with any component before taking the screenshot. The screenshot will contain whatever the jsdom used in tests contains at that moment. See [`react-testing-library`](https://github.com/kentcdodds/react-testing-library) for more information about that.

    #### PostCSS, CSS Modules, Styled Components, ..

    This example showed how to use [`jest-transform-css`](https://github.com/dferber90/jest-transform-css) with global CSS. The library can also handle [CSS modules](https://github.com/css-modules/css-modules) and [Styled Components](https://www.styled-components.com/). See [`jest-transform-css`](https://github.com/dferber90/jest-transform-css) for setup instructions.

    #### Request interception

    In case your components make requests when mounted, you can use Request Interception to respond to requests from the tests. See [`jsdom-screenshot`](https://github.com/dferber90/jsdom-screenshot) for more information.

    #### Static File Serving

    A tiny webserver gets started by passing `generateImage({ serve: ['public'] })` which can serve local assets for the screenshots. See [`jsdom-screenshot`](https://github.com/dferber90/jsdom-screenshot) for more information.

    #### Debugging

    It is possible to print the markup that the screenshot gets taken of by passing `generateImage({ debug: true })`. See [`jsdom-screenshot`](https://github.com/dferber90/jsdom-screenshot) for more information.

    ## Summary

    This setup has shown how to do Visual Regression Testing in Jest by the example of a `create-react-app` application. We were able to load the component's styles and the SVG file (or any other images). The walkthrough hinted at how we can use

    A more advanced setup can be found at [visual-regression-testing-example](https://github.com/dferber90/visual-regression-testing-example).

    ## Disclaimer

    This setup is highly experimental. I tried it with a few different configurations and it worked fine so far, but I'm sure there is more that needs to be fixed. Handle it with care, it is early stage!

    > Feel free to ask any questions on Twitter: [@dferber90](https://twitter.com/dferber90/)!