CtrlK
BlogDocsLog inGet started
Tessl Logo

testland/pothos-builder-tests

Wraps Pothos GraphQL schema-builder testing patterns: testing the SchemaBuilder output (lexicographicSortSchema + printSchema for snapshot tests), testing resolvers via the standard `graphql()` function from graphql-js (no server needed), integration with Apollo Server / GraphQL Yoga (Pothos emits standard graphql-js schemas), and code-first builder unit tests. Covers the SchemaBuilder API surface (queryType, mutationType, objectType, t.field, t.arg). Use when testing a Pothos-built schema before or alongside the server-runtime tests.

77

Quality

97%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

Overview
Quality
Evals
Security
Files

SKILL.md

name:
pothos-builder-tests
description:
Wraps Pothos GraphQL schema-builder testing patterns: testing the SchemaBuilder output (lexicographicSortSchema + printSchema for snapshot tests), testing resolvers via the standard `graphql()` function from graphql-js (no server needed), integration with Apollo Server / GraphQL Yoga (Pothos emits standard graphql-js schemas), and code-first builder unit tests. Covers the SchemaBuilder API surface (queryType, mutationType, objectType, t.field, t.arg). Use when testing a Pothos-built schema before or alongside the server-runtime tests.

pothos-builder-tests

Overview

Per pothos-graphql.dev, "the schema generated by Pothos is a standard graphql.js schema" - so any GraphQL test pattern works against it. The testing opportunity unique to Pothos is testing the builder output shape (which types, which fields, which deprecations) and the schema-stability over refactors.

When to use

  • Unit tests for resolvers built with Pothos.
  • Snapshot tests for the printed schema (catch unintended schema changes).
  • Combining a Pothos schema with Apollo Server / Yoga in integration tests.
  • PR review of changes to Pothos type definitions.

Authoring

Install

npm install --save-dev @pothos/core graphql

Build a test schema

Per pothos-graphql.dev/docs/guide:

import SchemaBuilder from '@pothos/core';

const builder = new SchemaBuilder({});

builder.queryType({
  fields: (t) => ({
    hello: t.string({
      args: { name: t.arg.string() },
      resolve: (_parent, { name }) => `hello, ${name || 'World'}`,
    }),
  }),
});

export const schema = builder.toSchema();

The schema is a plain graphql.GraphQLSchema instance.

Unit-test a resolver via graphql()

import { graphql } from 'graphql';
import { schema } from './schema';

test('hello resolver', async () => {
  const result = await graphql({
    schema,
    source: `{ hello(name: "alice") }`,
  });
  expect(result.errors).toBeUndefined();
  expect(result.data?.hello).toBe('hello, alice');
});

graphql() from graphql-js executes against the schema directly. No server. No HTTP. No middleware. Fast unit-test path.

Schema snapshot test

Catch any change to the public schema:

import { lexicographicSortSchema, printSchema } from 'graphql';
import { schema } from './schema';

test('schema snapshot', () => {
  // lexicographicSortSchema produces deterministic ordering
  const printed = printSchema(lexicographicSortSchema(schema));
  expect(printed).toMatchSnapshot();
});

When the schema changes, the snapshot fails and reviewers see the diff. Refactor-safe: a resolver rename that doesn't touch the schema doesn't trigger the snapshot.

Integration with Apollo Server

import { ApolloServer } from '@apollo/server';
import { schema } from './schema';

const server = new ApolloServer({ schema });
// ... use apollo-server-tests patterns from here

Integration with GraphQL Yoga

import { createYoga } from 'graphql-yoga';
import { schema } from './schema';

const yoga = createYoga({ schema });
// ... use graphql-yoga-tests patterns from here

Running

npm test
npm test -- --updateSnapshot       # accept schema changes

Testing the SchemaBuilder's plugin contract

Pothos has plugins for relay, prisma, errors, etc. Test each plugin's output:

import RelayPlugin from '@pothos/plugin-relay';

const builder = new SchemaBuilder<{ Context: AuthContext }>({
  plugins: [RelayPlugin],
  relay: { clientMutationId: 'optional' },
});

builder.queryType({ /* ... */ });
const schema = builder.toSchema();

test('relay plugin adds Node interface', () => {
  const printed = printSchema(lexicographicSortSchema(schema));
  expect(printed).toContain('interface Node');
});

Testing context-required resolvers

test('me resolver returns current user', async () => {
  const result = await graphql({
    schema,
    source: `{ me { id name } }`,
    contextValue: { user: { id: 'u1', name: 'alice' } },
  });
  expect(result.data?.me).toEqual({ id: 'u1', name: 'alice' });
});

test('me resolver errors without auth', async () => {
  const result = await graphql({
    schema,
    source: `{ me { id name } }`,
    contextValue: { user: null },
  });
  expect(result.errors?.[0].message).toMatch(/authenticate/i);
});

Parsing results

graphql() returns an ExecutionResult:

{
  data?: { ... },         // null on error if root resolver failed
  errors?: GraphQLError[],
  extensions?: { ... }
}

Snapshot tests use expect(printed).toMatchSnapshot(). The diff on failure shows exactly which types/fields changed.

CI integration

jobs:
  pothos:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: actions/setup-node@v4
        with: { node-version: '20' }
      - run: npm ci
      - run: npm test
      - name: Schema snapshot must match
        run: |
          # Fails the build if snapshot would change
          npx jest --ci tests/schema-snapshot.test.ts

The --ci flag prevents --updateSnapshot and fails on mismatch.

Anti-patterns

Anti-patternWhy it failsFix
Skipping lexicographicSortSchema for snapshotsNon-deterministic order → snapshot flakesAlways sort
Using --updateSnapshot in CIHides real schema changes--ci flag only
Testing the builder API instead of the outputPothos plugins drift; tests pass against deprecated builderTest the printed schema
Single mega-snapshot for the whole schemaOne field change → unrelated review painPer-domain snapshots (Query, Mutation, types)
No contextValue in resolver testsTests bypass auth; passes for unauthenticated pathsAlways pass test context
Server-runtime tests without Pothos-builder testsSchema regressions slip through unit testsBoth layers needed
Testing resolvers in isolation onlyMisses how plugins (relay, errors) reshape the responseBoth unit + integration
Pothos schema diverges between dev and prodDifferent plugins / configsBuild prod schema in test setup

Limitations

  • No HTTP behaviour. graphql() skips transport; for header / middleware testing use apollo-server-tests or graphql-yoga-tests.
  • Plugin combination explodes. Each Pothos plugin changes the output; test the actual combination used in prod.
  • TypeScript strict mode required. Per Pothos docs: "strict mode is essential." Tests must compile under strict.
  • Snapshot file proliferation. Multiple snapshot files for multiple build configurations can drift; manage carefully.
  • Doesn't replace contract testing. Internal schema stability isn't external compatibility - pair with graphql-schema-regression (in the qa-contract-testing plugin).

References

  • Pothos docs: pothos-graphql.dev/docs/guide.
  • graphql-js graphql() function: graphql.org/graphql-js/graphql/.
  • Sibling frameworks (where Pothos schemas plug in): apollo-server-tests, graphql-yoga-tests, mercurius-tests.
  • Companion catalogs: introspection-attack-surface-reference, persisted-query-strategy-reference.
  • Contract drift: graphql-schema-regression.

SKILL.md

tile.json