Blitz is pivoting to framework agnostic toolkit. Click to learn more.
🚀Announcing Flightcontrol - Easily Deploy Blitz.js and Next.js to AWS 🚀
Back to Documentation Menu

Testing

Topics

Jump to a Topic

The blitz dependency also automatically installs and configures jest, @testing-library/react, @testing-library/react-hooks, and @testing-library/jest-dom for you.

Jest

Jest is a delightful testing framework that's simple to use. To run tests in your app, you will run jest or jest --watch from the terminal.

To make a new test, make a file named something.test.ts (or .js, .tsx, etc). Here's an example:

import something from "./somewhere"

it("does something", () => {
  const result = something()
  expect(result).toBe(true)
})

For more details on using Jest, read the Jest documentation

Jest Config

Blitz provides a Jest preset that configures lots of complex things for you, including TypeScript support.

If you need to customize the jest config, you can do so in jest.config.js.

// jest.config.js
module.exports = {
  preset: "blitz",
}

Client vs Server Environments

The following test files will run in the Jest server environment:

  • *.test.* files inside an api, queries, or mutations folder
  • *.server.test.* files

All other files will run in the Jest client environment (with jsdom).

@testing-library

@testing-library is a family of packages that help you test UI components in a user-centric way. It's a better alternative to Enzyme, if you've used that in the past.

The following packages are installed for you. Refer to their documentation as needed.

Testing Utilities

Blitz provides some basic testing utilities in the generated test/utils.tsx file. These are intended for use with Jest and React Testing Library to allow advanced configuration for your testing environment. Customizing this file can be useful for testing things like global providers as well as certain parts of your app which Blitz handles internally such as routing and data querying.

BlitzProvider

This component works as the global provider for data queries and mutations in your tests. Internally, it wraps the QueryClient component from react-query and adds some additional configuration options.

BlitzProvider accepts the following props:

  • client - The global query client used by React Query. By default the queryClient exported from blitz is used unless you override it.

  • contextSharing - Controls whether or not the provider context can be shared across multiple applications. This can be useful when working in certain environments such as micro-frontends. Defaults to false.

  • dehydratedState - The server state passed along to the application containing the results of server-side queries. Useful for testing queries that need to be prerendered in markup and hydrated on the client.

End-to-end testing with Cypress

Cypress is a front-end testing framework that enables testing options for both unit tests and integration tests.

If you plan to integrate it into your Blitz application, you can look at our example with a Cypress setup. It includes a simple factory pattern, a command for creating and logging in a user, and a few example tests.

Isolated mutation/query testing

If you want to test your mutations/queries in an isolated manner, you will need to mock the ctx object:

// test/createMockContext.ts
import {
  Ctx,
  getSession,
  MiddlewareRequest as Req,
  MiddlewareResponse as Res,
} from "blitz"
import httpMocks from "node-mocks-http"
import { User } from "db"

// This import is crucial, as it modifies global state by calling sessionMiddleware
// Most importantly, this sets the isAuthorized method in global.sessionConfig
import "../blitz.config"
import { getPublicSessionData } from "../app/auth/utils/getPublicSessionData"

interface CreateMockContextOptions {
  user?: User
  reqOptions?: httpMocks.RequestOptions
  resOptions?: httpMocks.ResponseOptions
}

// Based on https://github.com/blitz-js/blitz/issues/2654#issuecomment-904426530
// Creates a mock context for use in tests and scripts. Attempts to make it the
// "real deal" by calling the same initialization logic that creates actual
// session contexts.
export default async function createMockContext<C extends Ctx>({
  user,
  reqOptions,
  resOptions,
}: CreateMockContextOptions = {}) {
  const mocks = httpMocks.createMocks<any, any>(reqOptions, resOptions)
  const mockReq: Req = mocks.req
  const mockRes: Res<C> = mocks.res

  // Ensures the response has the blitzCtx object which is required for
  // authorization checks
  await getSession(mockReq, mockRes)

  // Simulate login by saving public session data
  if (user) {
    // Need to use Object.assign instead of spread operator,
    // because $publicData is readonly (only has a getter)
    // make sure to add **your** session's public data
    Object.assign(mockRes.blitzCtx.session.$publicData, {
      id: user.id,
      role: user.role,
    })
  }

  return { req: mockReq, res: mockRes, ctx: mockRes.blitzCtx }
}

Later in your tests you can use it like this:

import db from "db"
import getUsers from "./getUsers"
import createMockContext from "../../../test/createMockContext"

beforeEach(async () => {
  await db.$reset()
})

describe("getUsers query", () => {
  it("rejects access for regular users", async () => {
    const user = await db.user.create({
      data: {
        email: "user@example.com",
        role: "USER",
      },
    })
    const { ctx } = await createMockContext({ user })

    await expect(async () => {
      await getUsers({}, ctx)
    }).rejects.toThrow("You are not authorized to access this")
  })
})

Idea for improving this page? Edit it on GitHub.