Skip to content

Commit 15b7cc5

Browse files
author
settings-as-code-release
committed
test(sections): fragment fake dispatches GraphQL ops through the mock handlers
tryGraphql routes by operation name onto the e2e mock's GraphQL handlers, records a mutation in the fake's write log, and folds handler errors to the client's ApiError statuses, so a section that reads GraphQL while planning can run the unit proofs over the fake. Written on feat/snapshot-core-sections and carried here so every branch stacked on this one shares it.
1 parent 34481f2 commit 15b7cc5

1 file changed

Lines changed: 35 additions & 7 deletions

File tree

‎test/sections/fragment-fake.ts‎

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,23 @@
22
* A stateful GithubClient derived from the e2e mock's handlers: requests route through the
33
* pipeline's endpoint matching onto the same handlers over a seeded MockState, so a unit proof
44
* runs against the mock's own transformers, not a second hand-written inverse. Two views: one
5-
* section's fragment (a request outside it is refused), or the whole merged registry.
5+
* section's fragment (a request outside it is refused), or the whole merged registry. GraphQL
6+
* dispatches by operation name onto the mock's GraphQL handlers the same way.
67
*/
78

89
import type { ApiError, GithubClient } from "../../src/github/api.js";
910
import type { SectionKey } from "../../src/schema.js";
1011
import type { SectionMeta } from "../../src/sections/contract/module.js";
11-
import { matchEndpoint } from "../e2e/mock/dispatch.js";
12-
import { HANDLERS } from "../e2e/mock/handlers.js";
12+
import { allGraphqlOps } from "../../src/sections/registry.js";
13+
import { graphqlOpForBody, matchEndpoint } from "../e2e/mock/dispatch.js";
14+
import { GRAPHQL_HANDLERS, HANDLERS } from "../e2e/mock/handlers.js";
1315
import { buildStateForSlug, type LiveState, type MockState } from "../e2e/mock/state.js";
14-
import type { Handler } from "../e2e/mock/support.js";
16+
import type { Handler, Json } from "../e2e/mock/support.js";
1517
import { REPO } from "./section-run.js";
1618

1719
export interface FragmentFake extends GithubClient {
1820
readonly state: MockState;
19-
/** Every non-GET request that reached a handler, as "METHOD /path". */
21+
/** Every write that reached a handler: "METHOD /path", or "GRAPHQL <opName>" for a mutation. */
2022
readonly writes: string[];
2123
}
2224

@@ -85,8 +87,34 @@ function handlerFake(
8587
}
8688
return { data: response.body };
8789
},
88-
async tryGraphql() {
89-
throw new Error(`${only ?? "the registry fake"} issues no GraphQL`);
90+
async tryGraphql(op, variables) {
91+
const dispatched = graphqlOpForBody({ operationName: op.name }, allGraphqlOps());
92+
const handler = dispatched === null ? undefined : GRAPHQL_HANDLERS[dispatched.key];
93+
if (
94+
dispatched === null ||
95+
(only !== null && dispatched.op.section !== only) ||
96+
handler === undefined
97+
) {
98+
return { error: { status: 404, message: `unexpected GRAPHQL ${op.name}`, body: "" } };
99+
}
100+
if (op.kind === "write") {
101+
writes.push(`GRAPHQL ${op.name}`);
102+
}
103+
const result = handler({ state, op: dispatched.op, variables: variables as Json });
104+
if (result.errors !== undefined) {
105+
// The client's status fold (apiErrorFromGraphqlErrors): FORBIDDEN 403, NOT_FOUND 404, else 422.
106+
const types = result.errors.map((entry) => entry.type);
107+
const status = types.includes("FORBIDDEN") ? 403 : types.includes("NOT_FOUND") ? 404 : 422;
108+
return {
109+
error: {
110+
status,
111+
message: result.errors.map((entry) => entry.message).join("; "),
112+
body: JSON.stringify(result.errors),
113+
graphqlTypes: [...types].sort(),
114+
},
115+
};
116+
}
117+
return { data: result.data };
90118
},
91119
};
92120
}

0 commit comments

Comments
 (0)