ProvenPin Install

GraphQL schema mocking with @graphql-tools/schema and @graphql-tools/mock: working versions (tested 2026-10-15)

Build an executable schema with makeExecutableSchema and layer deterministic mocks, a MockStore, MockList and partial real resolvers on top with addMocksToSchema, including mutations that write to the store.

passed5 passed · 0 failed2026-10-15 20:08 UTC
Status
passed
Last passed
2026-10-15 20:08 UTC
Tests
5 / 5
Language
TypeScript
Runtime
node v22.23.3
pinned versions5
@graphql-tools/schema@10.1.5@graphql-tools/mock@9.1.18graphql@17.0.2@types/node@26.6.5tsx@4.23.15
run it
npm install --no-audit --no-fund --ignore-scripts=false
npm test
test environment
node v22.23.3
linux 6.17.0-1022-azure
x64
runner: github-actions 38799498972

The code

Exactly the files that passed. Your agent can pull them with get_recipe("graphql-tools-schema-mock") (install), or see them on GitHub.

package.json
{
  "name": "graphql-tools-schema-mock",
  "private": true,
  "type": "module",
  "scripts": {
    "test": "node --import tsx --test test/*.test.ts"
  },
  "dependencies": {
    "@graphql-tools/schema": "10.1.5",
    "@graphql-tools/mock": "9.1.18",
    "graphql": "17.0.2"
  },
  "devDependencies": {
    "@types/node": "26.6.5",
    "tsx": "4.23.15"
  }
}
src/schema.ts
import { makeExecutableSchema } from "@graphql-tools/schema";
import { addMocksToSchema, createMockStore, MockList } from "@graphql-tools/mock";
import { graphql, type GraphQLSchema } from "graphql";

export const typeDefs = /* GraphQL */ `
  type Course { id: ID!, title: String!, hours: Int!, instructor: Instructor!, tags: [String!]! }
  type Instructor { id: ID!, name: String!, courses: [Course!]! }
  type Query { courses(limit: Int): [Course!]!, course(id: ID!): Course, me: Instructor! }
  type Mutation { renameCourse(id: ID!, title: String!): Course! }
`;

/** Real resolvers for the parts that exist; mocks fill in the rest (handy for frontend work before the API is done). */
export function buildSchema(seed = 1) {
  const base = makeExecutableSchema({ typeDefs });
  let n = seed;
  const nextInt = () => (n = (n * 48271) % 2147483647); // deterministic PRNG instead of Math.random
  const mocks = {
    ID: () => `id-${nextInt() % 1000}`,
    Int: () => (nextInt() % 100) + 1,
    String: () => `str-${nextInt() % 1000}`,
    Course: () => ({ tags: () => new MockList(2) }),
    Instructor: () => ({ name: "Phil Morin" }),
  };
  const store = createMockStore({ schema: base, mocks });
  const schema = addMocksToSchema({
    schema: base,
    store,
    preserveResolvers: true,
    resolvers: (s) => ({
      Query: {
        courses: (_: unknown, { limit }: { limit?: number }) => Array.from({ length: limit ?? 3 }, (_, i) => s.get("Course", `c${i + 1}`)),
        course: (_: unknown, { id }: { id: string }) => (id.startsWith("c") ? s.get("Course", id) : null),
      },
      Mutation: {
        renameCourse: (_: unknown, { id, title }: { id: string; title: string }) => {
          s.set("Course", id, "title", title);
          return s.get("Course", id);
        },
      },
    }),
  });
  return { schema, store };
}

export const run = (schema: GraphQLSchema, source: string, variableValues?: Record<string, unknown>) =>
  graphql({ schema, source, variableValues }) as Promise<{ data?: any; errors?: readonly { message: string }[] }>;
test/schema.test.ts
import { test } from "node:test";
import assert from "node:assert/strict";
import { buildSchema, run } from "../src/schema.ts";

test("mocked query returns shape-correct data", async () => {
  const { schema } = buildSchema();
  const r = await run(schema, "{ courses(limit: 2) { id title hours tags instructor { name } } }");
  assert.equal(r.errors, undefined);
  assert.equal(r.data.courses.length, 2);
  for (const c of r.data.courses) {
    assert.equal(typeof c.title, "string");
    assert.ok(Number.isInteger(c.hours) && c.hours >= 1 && c.hours <= 100);
    assert.equal(c.tags.length, 2);
    assert.equal(c.instructor.name, "Phil Morin");
  }
  assert.deepEqual(r.data.courses.map((c: { id: string }) => c.id), ["c1", "c2"]);
});

test("mocks are deterministic for a seed", async () => {
  const q = "{ course(id: \"c1\") { title hours } }";
  const a = await run(buildSchema(7).schema, q);
  const b = await run(buildSchema(7).schema, q);
  assert.deepEqual(a.data, b.data);
});

test("store keeps entities consistent across queries", async () => {
  const { schema } = buildSchema();
  const first = await run(schema, '{ course(id: "c1") { title instructor { id } } }');
  const again = await run(schema, '{ courses(limit: 1) { title instructor { id } } }');
  assert.deepEqual(again.data.courses[0], first.data.course);
});

test("mutation writes to the mock store", async () => {
  const { schema, store } = buildSchema();
  const m = await run(schema, 'mutation($t: String!) { renameCourse(id: "c2", title: $t) { id title } }', { t: "CITS Orientation" });
  // graphql 17 returns null-prototype result objects, so spread before deepEqual
  assert.deepEqual({ ...m.data.renameCourse }, { id: "c2", title: "CITS Orientation" });
  assert.equal(store.get("Course", "c2", "title"), "CITS Orientation");
  const q = await run(schema, '{ course(id: "c2") { title } }');
  assert.equal(q.data.course.title, "CITS Orientation");
});

test("custom resolver can return null and validation errors still apply", async () => {
  const { schema } = buildSchema();
  assert.equal((await run(schema, '{ course(id: "x9") { id } }')).data.course, null);
  const bad = await run(schema, "{ courses { nope } }");
  assert.match(bad.errors![0].message, /Cannot query field "nope"/);
});

Connect to ProvenPin

Add the free MCP server so your agent can pull this recipe and others like it. Same setup as the docs.

terminal
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp

Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.