GithubHelp home page GithubHelp logo

gatsby-plugin-testing's Introduction

Gatsby Unit Testing Plugin

This plugin allows unit testing of Gatsby components that depend on GraphQL queries.

The problem

Gatsby components that use data from GraphQL (which is most of them) cannot easily be unit tested. The Gatsby documentation suggests breaking components into two parts: a pure component without any queries and a surrounding component that only handles the query. Only the pure component can be tested.

This is not only awkward for your component code but it also makes it impossible to unit test that your components are receiving the GraphQL data they expect or that the GraphQL query is of the correct format.

The solution

Gatsby Unit Testing Plugin stores your query data when you build your project. It will then be available to components on later test runs.

Because data is stored when you run gatsby build or gatsby develop, these are the steps to start testing:

  1. Set up Jest
  2. Add the gatsby-plugin-testing to your project
  3. Run gatsby build or gatsby develop
  4. Run your tests

If you modify the queries of your components, you must rerun gatsby build since your tests will otherwise use query results that reflect the previous queries.

The following section describes the setup steps in detail. You can also have them all performed automatically by running a recipe using the following command and following the prompts:

gatsby recipes https://gist.githubusercontent.com/ehrencrona/1a2d715e39eab707be6915d3b78eec2b/raw/8abb9c3ff9caa6d605b2d163b4d9a8559601eef8/testing.mdx

Set up Jest

If you have not yet set up tests in your project, configure Jest as described in the Gatsby unit testing documentation.

Add the gatsby-plugin-testing to your project

To start unit testing, install the plugin using yarn add --dev gatsby-plugin-testing or npm install --only=dev gatsby-plugin-testing

Add the plugin to your gatsby-config.js:

module.exports = {
  ...
  plugins: [
    ...
    "gatsby-plugin-testing"
  ]
}

Then create a file called __mocks__/gatsby.js in your project containing a single line:

export * from "gatsby-plugin-testing/__mocks__/gatsby"

Run gatsby build

Now run gatsby build or gatsby develop in your project. You should see

[gatsby-plugin-testing] stored static queries

somewhere in the build output. If you don't, check that you have completed all previous steps.

When running gatsby develop, you will see this output repeated every time your queries change.

The queries will be stored in a file .testing-static-queries.json. This file does not need to be checked in so you can add it to your .gitignore.

Run your tests

Unit testing components with static queries should now "just work".

You can also run your tests in watch mode. If you change a query, your tests will re-run automatically with the most recent data.

Watch mode requires leaving gatsby develop running. In other words, first start gatsby develop, then open a new terminal window and launch your tests there in watch mode.

Static queries

No code modifications should be necessary to test components with static queries. Let's look at the Image component from the Gatsby starter project:

() => {
  const data = useStaticQuery(graphql`
    query {
      placeholderImage: file(relativePath: { eq: "gatsby-astronaut.png" }) {
        childImageSharp {
          fluid(maxWidth: 300) {
            ...GatsbyImageSharpFluid
          }
        }
      }
    }
  `)

  return <Img fluid={data.placeholderImage.childImageSharp.fluid} />
}

The following test will unit test this component for you

import React from "react"
import renderer from "react-test-renderer"
import Image from "../image"

describe("Image", () => {
  it("renders correctly", () => {
    const tree = renderer
      .create(<Image />)
      .toJSON()

      expect(tree).toMatchSnapshot()
  })
})

The same goes for static queries using the StaticQuery component.

Page queries

Testing a page query with variables involves only one additional step; you must specify which specific page you're testing.

Consider the following page rendering markdown:

export const query = graphql`
  query Markdown($id: String) {
    markdownRemark(id: { eq: $id }) {
      id
      frontmatter {
        title
      }
    }
  }
`

const MarkdownPage = ({data}) => {
  return (
    <Layout>
      <h1>{data.markdownRemark.frontmatter.title}</h1>
    </Layout>
  )
}

To write a unit test for it, import getPageQueryData from gatsby-plugin-testing and pass it to the component as query data.

It takes a single parameter, which is the path of the page you're testing. Assuming you have a my-first-page.md file that is displayed by the above page on the URL /my-first-page, the following code will render it:

import { getPageQueryData } from "gatsby-plugin-testing"

describe("MarkdownPage", () => {
  it("renders", async () => {
    const tree = renderer
      .create(<MarkdownPage data={await getPageQueryData("my-first-page")} />)
      .toJSON()

    expect(tree).toMatchSnapshot()
  })
})

Note that getPageQueryData is an async function so you must call await.

Snapshots

For some components it may be a problem that the Graph QL data is "live". If you're testing a page displaying the latest blog post, the test will fail every time you publish a new post.

To "freeze" the Graph QL data of your test, you can snapshot it. If you wrap a test with withQuerySnapshot, it will snapshot the Graph QL data when you first run the test. On subsequent runs, the test will use the snapshotted data instead of the query results in Gatsby.

  import { withQuerySnapshot } from "gatsby-plugin-testing"

  it('renders', withQuerySnapshot(() => {
      ...
      expect(component).toMatchSnapshot()
    })
  )

This concept is similar to snapshots in Jest, except that the data serves as input to your code rather than being its output.

Beyond freezing data to make tests more stable, it also enables them to run without a gatsby build, which can be useful in a CI environment.

Snapshots are stored together with Jest snapshots in files called __snapshots__/<your test name>.gql.json.

To update the snapshots to the current data you have three options:

  • delete the snapshots manually and run the tests
  • set the environment variable UPDATE_GQL to true and run the tests. On Linux and Macs you'd run UPDATE_GQL=true jest (replace "jest" by whatever command you use to run your tests, e.g. yarn test).
  • run tests in watch mode and press "g". This will update all GraphQL snapshots.

For snapshots to work you need to configure the following in your Jest configuration. It can be found either in a file called jest.config.js in your project root or under the key jest in your package.json

  watchPathIgnorePatterns: ["\\.gql\\.json$"],
  watchPlugins: ["gatsby-plugin-testing/jest-plugin"],

The first line makes Jest watchers not trigger when snapshots are updated. The second line adds the "g" option to Jest when you run in watch mode.

Contact

Problems? Suggestions? Feel free to open a Github issue or contact me at [email protected]

gatsby-plugin-testing's People

Contributors

ehrencrona avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

gatsby-plugin-testing's Issues

Plugin doesn't work with Gatsby ^2.24.33

Hello! Thank you for this plugin, it helped me a lot!
I've started to use it a few months ago and yesterday I needed to update the project and... It crashed...
I searched for the reason and found that in the new versions of Gatsby, the StaticQueries directory has changed. So I tried to fix it and I've founded a solution that works for the old versions and the new ones. Would be great to have your opinion about this and, if you allow me, I would like to merge my PR (after code review).

Sorry if I wrote a wrong sentence, I'm still learning English. I'm from Brazil. ;)

Thanks in advance.

Problem after updating Gatsby

Hey thanks for the great plugin, it really saves us a lot of time configuring testing.
After updating Gatsby to latest version, when I start dev server and compilation finishes, gatsby-plugin-testing indefinitely shows a spinner as if it is doing something, although development bundle has finished being created.

success write out requires - 0.001s
success Re-building development bundle - 2.169s
⠄ [gatsby-plugin-testing] stored static queries

"Cannot set property 'isWithSnapshot' of undefined"

Getting TypeError: Cannot set property 'isWithSnapshot' of undefined when running a test like

describe('BGImageContainer', () => {
  it(
    'matches snapshot',
    withQuerySnapshot(() => {
      const tree = create(<BgImageContainer />);
      expect(tree).toMatchSnapshot();
    }),
  );
});

Gatsby v3.6.2
gatsby-plugin-testing v0.3.4

How can I call graphql directly from a test

I want to write a test that checks frontmatter data in all my pages.

The best I think of now is loop through pages by page name and get the page data for each one like your getPageQueryData function does.

But since the graphql data is populated somewhere can I just grab it directly?

getPageQueryData does not find page

I'm getting an error whenever I request for a specific URL in my tests:

The page path "languages" page query data was requested for is unknown. Known paths: dev-404-page, index, languages, sq

As you can see, "languages" is listed in the known paths. This is my simple test:

describe("Language page", () => {
  it("renders correctly", async () => {
    const tree = renderer
      .create(<LanguagePage data={await getPageQueryData("languages")} />)
      .toJSON()
    expect(tree).toMatchSnapshot()
  })
})

Unable to get static query data on Windows

I have set up testing for a project, and I work on it both on Linux and Windows,
all the tests that have static-query pass without problem on Linux,
however on Windows static queries are not loaded and it throws.

● Index › renders with fixtures

    While getting static query data: Did not find component C:\Users\xx\xx\project\src\components\Sections\Index\IELTS\Courses.tsx, only: 
	C:/Users/xx/xx/project/src/components/Sections/Index/IELTS/Courses.tsx
    C:/Users/xx/xx/project/src/components/Sections/Index/Speaking/Courses.tsx

 Do you need to re-run gatsby build?
          at getQueryHashForComponentPath (C:\Users\xx\xx\project\node_modules\gatsby-plugin-testing\src\static-query.js:75:11)

I have run gatsby build, the page queries have no problem, the same test runs flawlessly on Linux.

It seems like it finds the component, but there's a problem with handling of slashes/backslashes.

setup issues on Jest 28

Plugin is installed, Jasmine2 is installed, and I've added this to jest.config.js:
testRunner: "jest-jasmine2"

But when I run gatsby develop, it gives this:
If you need withQuerySnapshots, Jasmine needs to be the current test runner.
Install it using e.g. "npm i jest-jasmine2", then add "testRunner": "jest-jasmine2" to your Jest configuration.
Your Jest configuration is typically in jest.config.js in the root of your project.
Read more at https://jestjs.io/docs/configuration#testrunner-string

I am using Jest 28. I saw this comment on SO which suggest a compatibility issue?

versions of things:

"dependencies": {
    "@contentful/rich-text-plain-text-renderer": "^15.12.1",
    "@gatsby-cloud-pkg/gatsby-plugin-preview": "^1.0.13",
    "@mdx-js/mdx": "^1.6.22",
    "@mdx-js/react": "^1.6.22",
    "gatsby": "^4.15.0",
    "gatsby-plugin-advanced-sitemap": "^2.1.0",
    "gatsby-plugin-image": "^2.15.0",
    "gatsby-plugin-manifest": "^4.15.0",
    "gatsby-plugin-mdx": "^3.15.0",
    "gatsby-plugin-react-helmet": "^5.15.0",
    "gatsby-plugin-robots-txt": "^1.7.1",
    "gatsby-plugin-s3": "^0.3.8",
    "gatsby-plugin-sharp": "^4.15.0",
    "gatsby-plugin-testing": "^0.3.5",
    "gatsby-source-contentful": "^7.13.1",
    "gatsby-source-filesystem": "^4.15.0",
    "gatsby-transformer-sharp": "^4.15.0",
    "jest-jasmine2": "^28.1.1",
    "react": "^17.0.1",
    "react-dom": "^17.0.1",
    "react-helmet": "^6.1.0"
  },
  "devDependencies": {
    "@types/jest": "^28.1.2",
    "@types/node": "^17.0.35",
    "@types/react": "^17.0.45",
    "@types/react-dom": "^17.0.17",
    "@types/react-test-renderer": "^17.0.2",
    "identity-obj-proxy": "^3.0.0",
    "react-test-renderer": "^17.0.2",
    "ts-jest": "^28.0.5",
    "typescript": "^4.6.4"
  }

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.