Skip to content

Commit 03263b7

Browse files
committed
Fix server tests for V5
1 parent 001e008 commit 03263b7

File tree

2 files changed

+98
-94
lines changed

2 files changed

+98
-94
lines changed

@app/server/__tests__/helpers.ts

Lines changed: 94 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
1-
import { Request, Response } from "express";
2-
import { ExecutionResult, graphql, GraphQLSchema } from "graphql";
3-
import { Pool, PoolClient } from "pg";
1+
import { makeWithPgClientViaPgClientAlreadyInTransaction } from "@dataplan/pg/adaptors/pg";
2+
import { execute,hookArgs } from "grafast";
43
import {
5-
createPostGraphileSchema,
6-
PostGraphileOptions,
7-
withPostGraphileContext,
8-
} from "postgraphile";
4+
ExecutionArgs,
5+
ExecutionResult,
6+
GraphQLSchema,
7+
parse,
8+
validate,
9+
} from "graphql";
10+
import { Pool, PoolClient } from "pg";
11+
import { postgraphile,PostGraphileInstance } from "postgraphile";
912

1013
import {
1114
createSession,
1215
createUsers,
1316
poolFromUrl,
1417
} from "../../__tests__/helpers";
15-
import { getPostGraphileOptions } from "../src/graphile.config";
18+
import { getPreset } from "../src/graphile.config";
1619

1720
export * from "../../__tests__/helpers";
1821

@@ -96,7 +99,7 @@ export function sanitize(json: any): any {
9699
// Contains the PostGraphile schema and rootPgPool
97100
interface ICtx {
98101
rootPgPool: Pool;
99-
options: PostGraphileOptions<Request, Response>;
102+
pgl: PostGraphileInstance;
100103
schema: GraphQLSchema;
101104
}
102105
let ctx: ICtx | null = null;
@@ -106,17 +109,14 @@ export const setup = async () => {
106109
connectionString: process.env.TEST_DATABASE_URL,
107110
});
108111

109-
const options = getPostGraphileOptions({ rootPgPool });
110-
const schema = await createPostGraphileSchema(
111-
rootPgPool,
112-
"app_public",
113-
options
114-
);
112+
const preset = getPreset({ rootPgPool, authPgPool: rootPgPool });
113+
const pgl = postgraphile(preset);
114+
const schema = await pgl.getSchema();
115115

116116
// Store the context
117117
ctx = {
118118
rootPgPool,
119-
options,
119+
pgl,
120120
schema,
121121
};
122122
};
@@ -146,9 +146,10 @@ export const runGraphQLQuery = async function runGraphQLQuery(
146146
) => void | ExecutionResult | Promise<void | ExecutionResult> = () => {} // Place test assertions in this function
147147
) {
148148
if (!ctx) throw new Error("No ctx!");
149-
const { schema, rootPgPool, options } = ctx;
149+
const { schema, rootPgPool, pgl } = ctx;
150+
const resolvedPreset = pgl.getResolvedPreset();
150151
const req = new MockReq({
151-
url: options.graphqlRoute || "/graphql",
152+
url: resolvedPreset.grafserv?.graphqlPath || "/graphql",
152153
method: "POST",
153154
headers: {
154155
Accept: "application/json",
@@ -159,92 +160,91 @@ export const runGraphQLQuery = async function runGraphQLQuery(
159160
const res: any = { req };
160161
req.res = res;
161162

162-
const {
163-
pgSettings: pgSettingsGenerator,
164-
additionalGraphQLContextFromRequest,
165-
} = options;
166-
const pgSettings =
167-
(typeof pgSettingsGenerator === "function"
168-
? await pgSettingsGenerator(req)
169-
: pgSettingsGenerator) || {};
163+
let checkResult: ExecutionResult | void;
164+
const document = parse(query);
165+
const errors = validate(schema, document);
166+
if (errors.length > 0) {
167+
throw errors[0];
168+
}
169+
const args: ExecutionArgs = {
170+
schema,
171+
document,
172+
contextValue: {
173+
__TESTING: true,
174+
},
175+
variableValues: variables,
176+
};
177+
await hookArgs(
178+
args,
179+
{ node: { req, res }, expressv4: { req, res } },
180+
resolvedPreset
181+
);
170182

171183
// Because we're connected as the database owner, we should manually switch to
172184
// the authenticator role
173-
if (!pgSettings.role) {
174-
pgSettings.role = process.env.DATABASE_AUTHENTICATOR;
185+
const context = args.contextValue as Grafast.Context;
186+
if (!context.pgSettings?.role) {
187+
context.pgSettings = context.pgSettings ?? {};
188+
context.pgSettings.role = process.env.DATABASE_AUTHENTICATOR as string;
175189
}
176190

177-
await withPostGraphileContext(
178-
{
179-
...options,
180-
pgPool: rootPgPool,
181-
pgSettings,
182-
pgForceTransaction: true,
183-
},
184-
async (context) => {
185-
let checkResult;
186-
const { pgClient } = context;
187-
try {
188-
// This runs our GraphQL query, passing the replacement client
189-
const additionalContext = additionalGraphQLContextFromRequest
190-
? await additionalGraphQLContextFromRequest(req, res)
191-
: null;
192-
const result = await graphql(
193-
schema,
194-
query,
195-
null,
196-
{
197-
...context,
198-
...additionalContext,
199-
__TESTING: true,
200-
},
201-
variables
202-
);
203-
// Expand errors
204-
if (result.errors) {
205-
if (options.handleErrors) {
206-
result.errors = options.handleErrors(result.errors);
207-
} else {
208-
// This does a similar transform that PostGraphile does to errors.
209-
// It's not the same. Sorry.
210-
result.errors = result.errors.map((rawErr) => {
211-
const e = Object.create(rawErr);
212-
Object.defineProperty(e, "originalError", {
213-
value: rawErr.originalError,
214-
enumerable: false,
215-
});
216-
217-
if (e.originalError) {
218-
Object.keys(e.originalError).forEach((k) => {
219-
try {
220-
e[k] = e.originalError[k];
221-
} catch (err) {
222-
// Meh.
223-
}
224-
});
191+
const pgClient = await rootPgPool.connect();
192+
try {
193+
await pgClient.query("begin");
194+
195+
// Override withPgClient with a transactional version for the tests
196+
const withPgClient = makeWithPgClientViaPgClientAlreadyInTransaction(
197+
pgClient,
198+
true
199+
);
200+
context.withPgClient = withPgClient;
201+
202+
const result = (await execute(args, resolvedPreset)) as ExecutionResult;
203+
// Expand errors
204+
if (result.errors) {
205+
if (resolvedPreset.grafserv?.maskError) {
206+
result.errors = result.errors.map(resolvedPreset.grafserv.maskError);
207+
} else {
208+
// This does a similar transform that PostGraphile does to errors.
209+
// It's not the same. Sorry.
210+
result.errors = result.errors.map((rawErr) => {
211+
const e = Object.create(rawErr);
212+
Object.defineProperty(e, "originalError", {
213+
value: rawErr.originalError,
214+
enumerable: false,
215+
});
216+
217+
if (e.originalError) {
218+
Object.keys(e.originalError).forEach((k) => {
219+
try {
220+
e[k] = e.originalError[k];
221+
} catch (err) {
222+
// Meh.
225223
}
226-
return e;
227224
});
228225
}
229-
}
230-
231-
// This is were we call the `checker` so you can do your assertions.
232-
// Also note that we pass the `replacementPgClient` so that you can
233-
// query the data in the database from within the transaction before it
234-
// gets rolled back.
235-
checkResult = await checker(result, {
236-
pgClient,
226+
return e;
237227
});
228+
}
229+
}
238230

239-
// You don't have to keep this, I just like knowing when things change!
240-
expect(sanitize(result)).toMatchSnapshot();
231+
// This is were we call the `checker` so you can do your assertions.
232+
// Also note that we pass the `replacementPgClient` so that you can
233+
// query the data in the database from within the transaction before it
234+
// gets rolled back.
235+
checkResult = await checker(result, {
236+
pgClient,
237+
});
241238

242-
return checkResult == null ? result : checkResult;
243-
} finally {
244-
// Rollback the transaction so no changes are written to the DB - this
245-
// makes our tests fairly deterministic.
246-
await pgClient.query("rollback");
247-
}
239+
// You don't have to keep this, I just like knowing when things change!
240+
expect(sanitize(result)).toMatchSnapshot();
241+
242+
return checkResult == null ? result : checkResult;
243+
} finally {
244+
try {
245+
await pgClient.query("rollback");
246+
} finally {
247+
pgClient.release();
248248
}
249-
);
249+
}
250250
};

@app/server/__tests__/tsconfig.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"extends": "../tsconfig.json",
3+
"include": ["."]
4+
}

0 commit comments

Comments
 (0)