This episode covers Gatsby testing and quality assurance: unit testing with Jest and React Testing Library, integration testing for pages, accessibility testing and SEO audits, and static analysis with ESLint.

A large site can only last if it's backed by automated testing. Gatsby gives you freedom to choose your testing tooling, and the most common pattern is Jest for unit testing plus React Testing Library for rendering and interacting with components.
Episode 16 covers unit testing with Jest and React Testing Library, integration testing for Gatsby pages, accessibility testing and SEO audits, and static analysis with ESLint.
Gatsby provides gatsby-plugin-jest so Jest immediately understands Gatsby's Babel transforms and aliases. Once installed, additional configuration can live in jest.config.js.
npm install --save-dev jest @testing-library/react @testing-library/jest-dom gatsby-plugin-jestThe gatsby-plugin-jest plugin injects the transforms Gatsby needs into Jest, including support for the gatsby module inside the components being tested.
Unit tests verify a component's behavior in isolation. Here's an example button component that displays a click count:
import { useState } from "react"
const Counter = () => {
const [count, setCount] = useState(0)
return (
<button onClick={() => setCount(count + 1)}>
Klik: {count}
</button>
)
}
export default CounterThen write the test in a counter.test.js file:
import { render, screen, fireEvent } from "@testing-library/react"
import Counter from "./counter"
test("counter bertambah saat tombol diklik", () => {
render(<Counter />)
const button = screen.getByRole("button", { name: /klik/i })
fireEvent.click(button)
expect(screen.getByText(/klik: 1/i)).toBeInTheDocument()
})screen.getByRole and screen.getByText are the recommended ways to select elements in React Testing Library because they encourage testing behavior rather than implementation.
Gatsby pages often use useStaticQuery and Link. When testing a page, those modules need to be mocked so the test doesn't require a full build. Create a __mocks__/gatsby.js file at the project root:
const React = require("react")
exports.useStaticQuery = () => ({
site: {
siteMetadata: { title: "Test Site" },
},
})
exports.Link = ({ to, children }) =>
React.createElement("a", { href: to }, children)With the mock above, pages using useStaticQuery and Link can render directly inside Jest without running GraphQL.
Integration tests render an entire page with all of its components, then check the content that appears:
import { render, screen } from "@testing-library/react"
import IndexPage from "../pages/index"
test("halaman index menampilkan judul", () => {
render(<IndexPage />)
expect(screen.getByRole("heading", { level: 1 })).toBeInTheDocument()
})The difference between unit tests and integration tests is scope: unit tests focus on one component, integration tests ensure many components work together as a single page.
Automated accessibility testing catches issues like contrast, wrong aria attributes, or elements without labels. jest-axe runs axe-core rules on top of the rendered output:
npm install --save-dev jest-axeInside a test, run the accessibility rules against the rendered output:
import { render } from "@testing-library/react"
import { axe, toHaveNoViolations } from "jest-axe"
import HomePage from "../pages/home"
expect.extend(toHaveNoViolations)
test("halaman home tidak memiliki pelanggaran aksesibilitas", async () => {
const { container } = render(<HomePage />)
expect(await axe(container)).toHaveNoViolations()
})expect(...).toHaveNoViolations() fails automatically if any accessibility rule violation is found on the rendered page.
Lighthouse remains the final audit outside unit tests: run it against a production build and check the SEO, best practices, and accessibility categories. This audit catches things unit tests can't detect, like a missing meta description or an undefined viewport.
Gatsby bundles ESLint with rules from eslint-config-react-app. To add custom rules, add an ESLint config file or adjust package.json. The gatsby develop command also shows lint warnings right in the terminal.
Combine ESLint with scripts in package.json so any change that breaks the rules fails the pipeline immediately:
{
"scripts": {
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
"test": "jest"
}
}npm run lint and npm test can be called in CI before the build. Running both regularly keeps quality in check without relying on manual review alone.
Key takeaways:
gatsby-plugin-jest integrates Jest with Gatsby's tooling.gatsby module enables page tests without a build.jest-axe automatically detects accessibility violations.In the next episode, episode 17, we'll discuss progressive web app — making a Gatsby site installable and offline-first via a service worker, web app manifest, and caching strategies.