graphile-test 2.1.5 โ†’ 2.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -16,70 +16,98 @@
16
16
  </a>
17
17
  </p>
18
18
 
19
- ## Install
19
+ `graphile-test` builds on top of [`pgsql-test`](https://github.com/launchql/launchql/tree/main/packages/pgsql-test) to provide robust GraphQL testing utilities for PostGraphile-based projects.
20
20
 
21
- ```sh
22
- npm install graphile-test
23
- ```
21
+ It provides a seamless setup for isolated, seeded, role-aware Postgres databases and injects GraphQL helpers for snapshot testing, role context, and mutation/query assertions.
22
+
23
+ ## ๐Ÿš€ Features
24
24
 
25
- ## How to Use
25
+ * ๐Ÿ” **Per-test rollback** via savepoints for isolation
26
+ * ๐Ÿ” **RLS-aware context injection** (`setContext`)
27
+ * ๐Ÿงช **GraphQL integration testing** with `query()` and snapshot support
28
+ * ๐Ÿ“ฆ **Seed support** for `.sql`, JSON, CSV, LaunchQL, or Sqitch
29
+ * ๐Ÿ“Š **Introspection query snapshotting**
30
+ * ๐Ÿ”ง **Raw SQL fallback** via `pg.client.query`
26
31
 
27
- ### 1. Create Required Postgres Role
32
+ ## ๐Ÿ“ฆ Install
28
33
 
29
- ```sql
30
- CREATE ROLE authenticated;
34
+ ```bash
35
+ npm install graphile-test
31
36
  ```
32
37
 
33
- ### 2. Write a Test
38
+ ## โœจ Quick Start
34
39
 
35
40
  ```ts
36
- import { GraphQLTest, snapshot } from 'graphile-test';
37
- import { MyGraphQLQuery } from '../src/queries';
38
-
39
- const dbname = 'graphile_test_db';
40
- const schemas = ['app_public'];
41
+ import { getConnections, seed } from 'graphile-test';
41
42
 
42
- const { setup, teardown, graphQL } = GraphQLTest({
43
- dbname,
44
- schemas,
45
- authRole: 'postgres',
46
- });
43
+ let db, query, teardown;
47
44
 
48
45
  beforeAll(async () => {
49
- await setup();
50
- });
51
- afterAll(async () => {
52
- await teardown();
46
+ ({ db, query, teardown } = await getConnections({
47
+ schemas: ['app_public'],
48
+ authRole: 'authenticated'
49
+ }, [
50
+ seed.sqlfile(['../sql/test.sql', '../sql/grants.sql'])
51
+ ]));
53
52
  });
54
53
 
55
- it('query', async () => {
56
- await graphQL(async query => {
57
- const data = await query(MyGraphQLQuery);
58
- expect(snapshot(data)).toMatchSnapshot();
59
- });
54
+ beforeEach(() => db.beforeEach());
55
+ afterEach(() => db.afterEach());
56
+ afterAll(() => teardown());
57
+
58
+ it('runs a GraphQL mutation', async () => {
59
+ const res = await query(`mutation { ... }`);
60
+ expect(res.errors).toBeUndefined();
60
61
  });
61
62
  ```
62
63
 
63
- ## Testing Setup
64
+ ## ๐Ÿ“˜ API
64
65
 
65
- Before running tests, prepare your database:
66
+ ### `getConnections(options, seeders)`
66
67
 
67
- ```sh
68
- createdb graphile_test_db
69
- psql -f sql/test.sql graphile_test_db
70
- ```
68
+ Returns an object with:
69
+
70
+ * `query` โ€“ A GraphQL executor function: `query(gqlDoc, variables?)`
71
+ * `db`, `pg` โ€“ `PgTestClient` instances
72
+ * `teardown()` โ€“ Clean up temp DBs
73
+
74
+ ### `PgTestClient`
71
75
 
72
- ## Environment Variables
76
+ Supports:
73
77
 
74
- You can override the default Postgres connection settings by setting the following environment variables:
78
+ * `query`, `any`, `one`, etc. (via `pg-promise`-like helpers)
79
+ * `beforeEach()` / `afterEach()` โ€“ for savepoint transaction handling
80
+ * `setContext({...})` โ€“ sets Postgres config (e.g., `role`, `myapp.user_id`)
75
81
 
76
- ```sh
77
- export PGUSER=your_pg_user
78
- export PGHOST=your_pg_host
79
- export PGPORT=your_pg_port
82
+ **See full `PgTestClient` API docs**: [pgsql-test โ†’ PgTestClient API Overview](https://www.npmjs.com/package/pgsql-test#pgtestclient-api-overview)
83
+
84
+ ## ๐Ÿงช Example Tests
85
+
86
+ ### GraphQL mutation + snapshot
87
+
88
+ ```ts
89
+ const res = await query(MY_MUTATION, { input: { ... } });
90
+ expect(snapshot(res)).toMatchSnapshot();
80
91
  ```
81
92
 
82
- Once set, these will be automatically picked up by `graphile-test` when establishing connections.
93
+ ### RLS testing with role switch
94
+
95
+ ```ts
96
+ db.setContext({ role: 'anonymous' });
97
+ const res = await query(MY_PROTECTED_QUERY);
98
+ expect(res.errors[0].message).toMatch(/permission denied/);
99
+ ```
100
+
101
+ ## ๐Ÿงฑ Under the Hood
102
+
103
+ `graphile-test` wraps and extends `pgsql-test` with GraphQL helpers like `query()` and introspection snapshot tools. You can drop into raw SQL testing anytime via `pg.client.query()` (superuser) or `db.client.query()` (RLS user).
104
+
105
+ ## โœ… Best Practices
106
+
107
+ * Use `db.setContext({ role, user_id })` to simulate authentication.
108
+ * Always wrap tests with `beforeEach` / `afterEach`.
109
+ * Use `snapshot()` to track GraphQL result changes.
110
+ * Use `useRoot: true` to test schema visibility without RLS.
83
111
 
84
112
  ## Related LaunchQL Tooling
85
113
 
package/connect.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ import type { GetConnectionOpts } from 'pgsql-test';
2
+ import type { PgTestClient } from 'pgsql-test/test-client';
3
+ import type { SeedAdapter } from 'pgsql-test/seed/types';
4
+ import type { DocumentNode, ExecutionResult } from 'graphql';
5
+ export type GraphQLQueryFn<T = ExecutionResult> = (query: string | DocumentNode, variables?: Record<string, any>, commit?: boolean, reqOptions?: Record<string, any>) => Promise<T>;
6
+ export interface GetConnectionsInput {
7
+ useRoot?: boolean;
8
+ schemas: string[];
9
+ authRole?: string;
10
+ }
11
+ /**
12
+ * Combines PostgreSQL test setup with GraphQL test context
13
+ */
14
+ export declare const getConnections: (input: GetConnectionsInput & GetConnectionOpts, seedAdapters?: SeedAdapter[]) => Promise<{
15
+ pg: PgTestClient;
16
+ db: PgTestClient;
17
+ teardown: () => Promise<void>;
18
+ query: GraphQLQueryFn;
19
+ }>;
package/connect.js ADDED
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getConnections = void 0;
4
+ const pgsql_test_1 = require("pgsql-test");
5
+ const graphile_test_1 = require("./graphile-test");
6
+ /**
7
+ * Combines PostgreSQL test setup with GraphQL test context
8
+ */
9
+ const getConnections = async (input, seedAdapters) => {
10
+ const conn = await (0, pgsql_test_1.getConnections)(input, seedAdapters);
11
+ const { pg, db, teardown: dbTeardown } = conn;
12
+ const gqlContext = (0, graphile_test_1.GraphQLTest)(input, conn);
13
+ await gqlContext.setup();
14
+ const teardown = async () => {
15
+ await gqlContext.teardown();
16
+ await dbTeardown();
17
+ };
18
+ const query = (query, variables, commit, reqOptions) => gqlContext.query({ query, variables, commit, reqOptions });
19
+ return {
20
+ pg,
21
+ db,
22
+ teardown,
23
+ query
24
+ };
25
+ };
26
+ exports.getConnections = getConnections;
package/context.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ import { ExecutionResult, DocumentNode } from 'graphql';
2
+ import { PostGraphileOptions } from 'postgraphile';
3
+ import type { Client, Pool } from 'pg';
4
+ import { GetConnectionOpts, GetConnectionResult } from 'pgsql-test';
5
+ import { GetConnectionsInput } from './connect';
6
+ export declare const runGraphQLInContext: <T = ExecutionResult<{
7
+ [key: string]: any;
8
+ }, {
9
+ [key: string]: any;
10
+ }>>({ input, conn, pgPool, schema, options, authRole, query, variables, reqOptions }: {
11
+ input: GetConnectionsInput & GetConnectionOpts;
12
+ conn: GetConnectionResult;
13
+ pgPool: Pool;
14
+ schema: any;
15
+ options: PostGraphileOptions;
16
+ authRole: string;
17
+ query: string | DocumentNode;
18
+ variables?: Record<string, any>;
19
+ reqOptions?: Record<string, any>;
20
+ }) => Promise<T>;
21
+ export declare function setContextOnClient(pgClient: Client, pgSettings: Record<string, string>, role: string): Promise<void>;
package/context.js ADDED
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.runGraphQLInContext = void 0;
7
+ exports.setContextOnClient = setContextOnClient;
8
+ const graphql_1 = require("graphql");
9
+ const postgraphile_1 = require("postgraphile");
10
+ // @ts-ignore
11
+ const mock_req_1 = __importDefault(require("mock-req"));
12
+ const runGraphQLInContext = async ({ input, conn, pgPool, schema, options, authRole, query, variables, reqOptions = {} }) => {
13
+ if (!conn.pg.client) {
14
+ throw new Error('pgClient is required and must be provided externally.');
15
+ }
16
+ const req = new mock_req_1.default({
17
+ url: options.graphqlRoute || '/graphql',
18
+ method: 'POST',
19
+ headers: {
20
+ Accept: 'application/json',
21
+ 'Content-Type': 'application/json'
22
+ },
23
+ ...reqOptions
24
+ });
25
+ const pgSettingsGenerator = options.pgSettings;
26
+ // @ts-ignore
27
+ const pgSettings = typeof pgSettingsGenerator === 'function'
28
+ ? await pgSettingsGenerator(req)
29
+ : pgSettingsGenerator || {};
30
+ // @ts-ignore
31
+ return await (0, postgraphile_1.withPostGraphileContext)({ ...options, pgPool, pgSettings }, async (context) => {
32
+ const pgConn = input.useRoot ? conn.pg : conn.db;
33
+ const pgClient = pgConn.client;
34
+ // IS THIS BAD TO HAVE ROLE HERE
35
+ await setContextOnClient(pgClient, pgSettings, authRole);
36
+ await pgConn.ctxQuery();
37
+ const printed = typeof query === 'string' ? query : (0, graphql_1.print)(query);
38
+ const result = await (0, graphql_1.graphql)({
39
+ schema,
40
+ source: printed,
41
+ contextValue: { ...context, pgClient },
42
+ variableValues: variables ?? null
43
+ });
44
+ return result;
45
+ });
46
+ };
47
+ exports.runGraphQLInContext = runGraphQLInContext;
48
+ // IS THIS BAD TO HAVE ROLE HERE
49
+ async function setContextOnClient(pgClient, pgSettings, role) {
50
+ await pgClient.query(`select set_config('role', $1, true)`, [role]);
51
+ for (const [key, value] of Object.entries(pgSettings)) {
52
+ await pgClient.query(`select set_config($1, $2, true)`, [key, String(value)]);
53
+ }
54
+ }
package/esm/connect.js ADDED
@@ -0,0 +1,22 @@
1
+ import { getConnections as getPgConnections } from 'pgsql-test';
2
+ import { GraphQLTest } from './graphile-test';
3
+ /**
4
+ * Combines PostgreSQL test setup with GraphQL test context
5
+ */
6
+ export const getConnections = async (input, seedAdapters) => {
7
+ const conn = await getPgConnections(input, seedAdapters);
8
+ const { pg, db, teardown: dbTeardown } = conn;
9
+ const gqlContext = GraphQLTest(input, conn);
10
+ await gqlContext.setup();
11
+ const teardown = async () => {
12
+ await gqlContext.teardown();
13
+ await dbTeardown();
14
+ };
15
+ const query = (query, variables, commit, reqOptions) => gqlContext.query({ query, variables, commit, reqOptions });
16
+ return {
17
+ pg,
18
+ db,
19
+ teardown,
20
+ query
21
+ };
22
+ };
package/esm/context.js ADDED
@@ -0,0 +1,46 @@
1
+ import { graphql, print } from 'graphql';
2
+ import { withPostGraphileContext } from 'postgraphile';
3
+ // @ts-ignore
4
+ import MockReq from 'mock-req';
5
+ export const runGraphQLInContext = async ({ input, conn, pgPool, schema, options, authRole, query, variables, reqOptions = {} }) => {
6
+ if (!conn.pg.client) {
7
+ throw new Error('pgClient is required and must be provided externally.');
8
+ }
9
+ const req = new MockReq({
10
+ url: options.graphqlRoute || '/graphql',
11
+ method: 'POST',
12
+ headers: {
13
+ Accept: 'application/json',
14
+ 'Content-Type': 'application/json'
15
+ },
16
+ ...reqOptions
17
+ });
18
+ const pgSettingsGenerator = options.pgSettings;
19
+ // @ts-ignore
20
+ const pgSettings = typeof pgSettingsGenerator === 'function'
21
+ ? await pgSettingsGenerator(req)
22
+ : pgSettingsGenerator || {};
23
+ // @ts-ignore
24
+ return await withPostGraphileContext({ ...options, pgPool, pgSettings }, async (context) => {
25
+ const pgConn = input.useRoot ? conn.pg : conn.db;
26
+ const pgClient = pgConn.client;
27
+ // IS THIS BAD TO HAVE ROLE HERE
28
+ await setContextOnClient(pgClient, pgSettings, authRole);
29
+ await pgConn.ctxQuery();
30
+ const printed = typeof query === 'string' ? query : print(query);
31
+ const result = await graphql({
32
+ schema,
33
+ source: printed,
34
+ contextValue: { ...context, pgClient },
35
+ variableValues: variables ?? null
36
+ });
37
+ return result;
38
+ });
39
+ };
40
+ // IS THIS BAD TO HAVE ROLE HERE
41
+ export async function setContextOnClient(pgClient, pgSettings, role) {
42
+ await pgClient.query(`select set_config('role', $1, true)`, [role]);
43
+ for (const [key, value] of Object.entries(pgSettings)) {
44
+ await pgClient.query(`select set_config($1, $2, true)`, [key, String(value)]);
45
+ }
46
+ }
@@ -1,173 +1,30 @@
1
- import { getGraphileSettings } from '@launchql/graphile-settings';
2
- import pg from 'pg';
3
- import { createPostGraphileSchema, withPostGraphileContext } from 'postgraphile';
4
- import { graphql } from 'graphql';
5
- // @ts-ignore
6
- import MockReq from 'mock-req';
7
- import { print } from 'graphql/language/printer';
8
- import { getEnvOptions } from '@launchql/types';
9
- const opt = getEnvOptions();
10
- export const GraphQLTest = ({ dbname, schemas, authRole = 'authenticated' }) => {
11
- const getDbString = (db) => `postgres://${opt.pg.user}:${opt.pg.password}@${opt.pg.host}:${opt.pg.port}/${db}`;
12
- const options = {
13
- ...getGraphileSettings({
14
- graphile: {
15
- schema: schemas
16
- }
17
- }),
18
- graphqlRoute: '/graphql',
19
- graphiqlRoute: '/graphiql'
20
- };
21
- pg.defaults.poolSize = 1;
22
- const POSTGRAPHILE_AUTHENTICATOR_ROLE = authRole;
23
- let ctx = null;
1
+ import { runGraphQLInContext } from './context';
2
+ import { createPostGraphileSchema } from 'postgraphile';
3
+ import { getGraphileSettings } from 'graphile-settings';
4
+ export const GraphQLTest = (input, conn) => {
5
+ const { schemas, authRole } = input;
6
+ let schema;
7
+ let options;
8
+ const pgPool = conn.manager.getPool(conn.pg.config);
24
9
  const setup = async () => {
25
- const rootPgPool = new pg.Pool({
26
- connectionString: getDbString(dbname)
27
- });
28
- const schema = await createPostGraphileSchema(rootPgPool, schemas, options);
29
- ctx = { rootPgPool, options, schema };
30
- };
31
- const teardown = async () => {
32
- try {
33
- if (!ctx)
34
- return;
35
- const { rootPgPool } = ctx;
36
- ctx = null;
37
- await rootPgPool.end();
38
- }
39
- catch (e) {
40
- console.error(e);
41
- }
10
+ options = getGraphileSettings({ graphile: { schema: schemas } });
11
+ schema = await createPostGraphileSchema(pgPool, schemas, options);
42
12
  };
43
- const graphQL = async (...args) => {
44
- if (!ctx)
45
- throw new Error('Context is not initialized. Did you run setup()?');
46
- let reqOptions = {};
47
- let checker;
48
- if (args.length === 1) {
49
- checker = args[0];
50
- }
51
- else if (args.length === 2) {
52
- reqOptions = args[0];
53
- checker = args[1];
54
- }
55
- else {
56
- throw new Error('Invalid arguments supplied to graphQL');
57
- }
58
- const { schema, rootPgPool, options } = ctx;
59
- const req = new MockReq({
60
- url: options.graphqlRoute || '/graphql',
61
- method: 'POST',
62
- headers: {
63
- Accept: 'application/json',
64
- 'Content-Type': 'application/json'
65
- },
66
- ...reqOptions
67
- });
68
- const pgSettingsGenerator = options.pgSettings;
69
- // @ts-ignore
70
- const pgSettings = typeof pgSettingsGenerator === 'function' ? await pgSettingsGenerator(req) : pgSettingsGenerator || {};
71
- return await withPostGraphileContext({ ...options, pgPool: rootPgPool, pgSettings }, async (context) => {
72
- const replacementPgClient = await rootPgPool.connect();
73
- await replacementPgClient.query('begin');
74
- await replacementPgClient.query("select set_config('role', $1, true)", [POSTGRAPHILE_AUTHENTICATOR_ROLE]);
75
- for (const [key, value] of Object.entries(pgSettings)) {
76
- await replacementPgClient.query("select set_config($1, $2, true)", [key, String(value)]);
77
- }
78
- try {
79
- const query = async (q, variables) => {
80
- if (typeof q !== 'string')
81
- q = print(q);
82
- return await graphql(schema, q, null, { ...context, pgClient: replacementPgClient }, variables);
83
- };
84
- return await checker(query, replacementPgClient);
85
- }
86
- finally {
87
- await replacementPgClient.query('rollback');
88
- replacementPgClient.release();
89
- }
13
+ const teardown = async () => { };
14
+ const query = async (opts) => {
15
+ return await runGraphQLInContext({
16
+ input,
17
+ schema,
18
+ options,
19
+ authRole,
20
+ pgPool,
21
+ conn,
22
+ ...opts
90
23
  });
91
24
  };
92
- async function graphQLQuery(...args) {
93
- if (!ctx)
94
- throw new Error('Context is not initialized. Did you run setup()?');
95
- let reqOptions = {};
96
- let Query;
97
- let vars;
98
- let commit = false;
99
- if (args.length === 1) {
100
- Query = args[0];
101
- }
102
- else if (args.length === 2) {
103
- if (typeof args[1] === 'boolean') {
104
- Query = args[0];
105
- commit = args[1];
106
- }
107
- else {
108
- Query = args[0];
109
- vars = args[1];
110
- }
111
- }
112
- else if (args.length === 3) {
113
- if (typeof args[2] === 'boolean') {
114
- Query = args[0];
115
- vars = args[1];
116
- commit = args[2];
117
- }
118
- else {
119
- reqOptions = args[0];
120
- Query = args[1];
121
- vars = args[2];
122
- }
123
- }
124
- else if (args.length === 4) {
125
- reqOptions = args[0];
126
- Query = args[1];
127
- vars = args[2];
128
- commit = args[3];
129
- }
130
- else {
131
- throw new Error('Invalid arguments supplied to graphQLQuery');
132
- }
133
- const { schema, rootPgPool, options } = ctx;
134
- const req = new MockReq({
135
- url: options.graphqlRoute || '/graphql',
136
- method: 'POST',
137
- headers: {
138
- Accept: 'application/json',
139
- 'Content-Type': 'application/json'
140
- },
141
- ...reqOptions
142
- });
143
- const pgSettingsGenerator = options.pgSettings;
144
- // @ts-ignore
145
- const pgSettings = typeof pgSettingsGenerator === 'function' ? await pgSettingsGenerator(req) : pgSettingsGenerator || {};
146
- return await withPostGraphileContext({ ...options, pgPool: rootPgPool, pgSettings }, async (context) => {
147
- const replacementPgClient = await rootPgPool.connect();
148
- await replacementPgClient.query('begin');
149
- await replacementPgClient.query("select set_config('role', $1, true)", [POSTGRAPHILE_AUTHENTICATOR_ROLE]);
150
- for (const [key, value] of Object.entries(pgSettings)) {
151
- await replacementPgClient.query("select set_config($1, $2, true)", [key, String(value)]);
152
- }
153
- try {
154
- if (typeof Query !== 'string')
155
- Query = print(Query);
156
- return await graphql(schema, Query, null, { ...context, pgClient: replacementPgClient }, vars);
157
- }
158
- finally {
159
- await replacementPgClient.query(commit ? 'commit' : 'rollback');
160
- replacementPgClient.release();
161
- }
162
- });
163
- }
164
- ;
165
25
  return {
166
26
  setup,
167
27
  teardown,
168
- graphQL,
169
- graphQLQuery,
170
- // @ts-ignore
171
- withContext: (cb) => cb(ctx)
28
+ query
172
29
  };
173
30
  };
package/esm/index.js CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from './clean';
2
2
  export * from './graphile-test';
3
+ export { seed } from 'pgsql-test';
package/esm/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -1,20 +1,4 @@
1
- import { DocumentNode } from 'graphql';
2
- export interface GraphQLTestOptions {
3
- dbname: string;
4
- schemas: string[];
5
- authRole?: string;
6
- }
7
- export declare const GraphQLTest: ({ dbname, schemas, authRole }: GraphQLTestOptions) => {
8
- setup: () => Promise<void>;
9
- teardown: () => Promise<void>;
10
- graphQL: (...args: any[]) => Promise<any>;
11
- graphQLQuery: {
12
- (Query: string | DocumentNode): Promise<any>;
13
- (Query: string | DocumentNode, commit: boolean): Promise<any>;
14
- (Query: string | DocumentNode, vars: Record<string, any>): Promise<any>;
15
- (Query: string | DocumentNode, vars: Record<string, any>, commit: boolean): Promise<any>;
16
- (reqOptions: Record<string, any>, Query: string | DocumentNode, vars: Record<string, any>): Promise<any>;
17
- (reqOptions: Record<string, any>, Query: string | DocumentNode, vars: Record<string, any>, commit: boolean): Promise<any>;
18
- };
19
- withContext: <T>(cb: (ctx: typeof ctx) => T) => T;
20
- };
1
+ import type { GraphQLTestContext } from './types';
2
+ import { GetConnectionsInput } from './connect';
3
+ import { GetConnectionOpts, GetConnectionResult } from 'pgsql-test';
4
+ export declare const GraphQLTest: (input: GetConnectionsInput & GetConnectionOpts, conn: GetConnectionResult) => GraphQLTestContext;
package/graphile-test.js CHANGED
@@ -1,180 +1,34 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.GraphQLTest = void 0;
7
- const graphile_settings_1 = require("@launchql/graphile-settings");
8
- const pg_1 = __importDefault(require("pg"));
4
+ const context_1 = require("./context");
9
5
  const postgraphile_1 = require("postgraphile");
10
- const graphql_1 = require("graphql");
11
- // @ts-ignore
12
- const mock_req_1 = __importDefault(require("mock-req"));
13
- const printer_1 = require("graphql/language/printer");
14
- const types_1 = require("@launchql/types");
15
- const opt = (0, types_1.getEnvOptions)();
16
- const GraphQLTest = ({ dbname, schemas, authRole = 'authenticated' }) => {
17
- const getDbString = (db) => `postgres://${opt.pg.user}:${opt.pg.password}@${opt.pg.host}:${opt.pg.port}/${db}`;
18
- const options = {
19
- ...(0, graphile_settings_1.getGraphileSettings)({
20
- graphile: {
21
- schema: schemas
22
- }
23
- }),
24
- graphqlRoute: '/graphql',
25
- graphiqlRoute: '/graphiql'
26
- };
27
- pg_1.default.defaults.poolSize = 1;
28
- const POSTGRAPHILE_AUTHENTICATOR_ROLE = authRole;
29
- let ctx = null;
6
+ const graphile_settings_1 = require("graphile-settings");
7
+ const GraphQLTest = (input, conn) => {
8
+ const { schemas, authRole } = input;
9
+ let schema;
10
+ let options;
11
+ const pgPool = conn.manager.getPool(conn.pg.config);
30
12
  const setup = async () => {
31
- const rootPgPool = new pg_1.default.Pool({
32
- connectionString: getDbString(dbname)
33
- });
34
- const schema = await (0, postgraphile_1.createPostGraphileSchema)(rootPgPool, schemas, options);
35
- ctx = { rootPgPool, options, schema };
36
- };
37
- const teardown = async () => {
38
- try {
39
- if (!ctx)
40
- return;
41
- const { rootPgPool } = ctx;
42
- ctx = null;
43
- await rootPgPool.end();
44
- }
45
- catch (e) {
46
- console.error(e);
47
- }
13
+ options = (0, graphile_settings_1.getGraphileSettings)({ graphile: { schema: schemas } });
14
+ schema = await (0, postgraphile_1.createPostGraphileSchema)(pgPool, schemas, options);
48
15
  };
49
- const graphQL = async (...args) => {
50
- if (!ctx)
51
- throw new Error('Context is not initialized. Did you run setup()?');
52
- let reqOptions = {};
53
- let checker;
54
- if (args.length === 1) {
55
- checker = args[0];
56
- }
57
- else if (args.length === 2) {
58
- reqOptions = args[0];
59
- checker = args[1];
60
- }
61
- else {
62
- throw new Error('Invalid arguments supplied to graphQL');
63
- }
64
- const { schema, rootPgPool, options } = ctx;
65
- const req = new mock_req_1.default({
66
- url: options.graphqlRoute || '/graphql',
67
- method: 'POST',
68
- headers: {
69
- Accept: 'application/json',
70
- 'Content-Type': 'application/json'
71
- },
72
- ...reqOptions
73
- });
74
- const pgSettingsGenerator = options.pgSettings;
75
- // @ts-ignore
76
- const pgSettings = typeof pgSettingsGenerator === 'function' ? await pgSettingsGenerator(req) : pgSettingsGenerator || {};
77
- return await (0, postgraphile_1.withPostGraphileContext)({ ...options, pgPool: rootPgPool, pgSettings }, async (context) => {
78
- const replacementPgClient = await rootPgPool.connect();
79
- await replacementPgClient.query('begin');
80
- await replacementPgClient.query("select set_config('role', $1, true)", [POSTGRAPHILE_AUTHENTICATOR_ROLE]);
81
- for (const [key, value] of Object.entries(pgSettings)) {
82
- await replacementPgClient.query("select set_config($1, $2, true)", [key, String(value)]);
83
- }
84
- try {
85
- const query = async (q, variables) => {
86
- if (typeof q !== 'string')
87
- q = (0, printer_1.print)(q);
88
- return await (0, graphql_1.graphql)(schema, q, null, { ...context, pgClient: replacementPgClient }, variables);
89
- };
90
- return await checker(query, replacementPgClient);
91
- }
92
- finally {
93
- await replacementPgClient.query('rollback');
94
- replacementPgClient.release();
95
- }
16
+ const teardown = async () => { };
17
+ const query = async (opts) => {
18
+ return await (0, context_1.runGraphQLInContext)({
19
+ input,
20
+ schema,
21
+ options,
22
+ authRole,
23
+ pgPool,
24
+ conn,
25
+ ...opts
96
26
  });
97
27
  };
98
- async function graphQLQuery(...args) {
99
- if (!ctx)
100
- throw new Error('Context is not initialized. Did you run setup()?');
101
- let reqOptions = {};
102
- let Query;
103
- let vars;
104
- let commit = false;
105
- if (args.length === 1) {
106
- Query = args[0];
107
- }
108
- else if (args.length === 2) {
109
- if (typeof args[1] === 'boolean') {
110
- Query = args[0];
111
- commit = args[1];
112
- }
113
- else {
114
- Query = args[0];
115
- vars = args[1];
116
- }
117
- }
118
- else if (args.length === 3) {
119
- if (typeof args[2] === 'boolean') {
120
- Query = args[0];
121
- vars = args[1];
122
- commit = args[2];
123
- }
124
- else {
125
- reqOptions = args[0];
126
- Query = args[1];
127
- vars = args[2];
128
- }
129
- }
130
- else if (args.length === 4) {
131
- reqOptions = args[0];
132
- Query = args[1];
133
- vars = args[2];
134
- commit = args[3];
135
- }
136
- else {
137
- throw new Error('Invalid arguments supplied to graphQLQuery');
138
- }
139
- const { schema, rootPgPool, options } = ctx;
140
- const req = new mock_req_1.default({
141
- url: options.graphqlRoute || '/graphql',
142
- method: 'POST',
143
- headers: {
144
- Accept: 'application/json',
145
- 'Content-Type': 'application/json'
146
- },
147
- ...reqOptions
148
- });
149
- const pgSettingsGenerator = options.pgSettings;
150
- // @ts-ignore
151
- const pgSettings = typeof pgSettingsGenerator === 'function' ? await pgSettingsGenerator(req) : pgSettingsGenerator || {};
152
- return await (0, postgraphile_1.withPostGraphileContext)({ ...options, pgPool: rootPgPool, pgSettings }, async (context) => {
153
- const replacementPgClient = await rootPgPool.connect();
154
- await replacementPgClient.query('begin');
155
- await replacementPgClient.query("select set_config('role', $1, true)", [POSTGRAPHILE_AUTHENTICATOR_ROLE]);
156
- for (const [key, value] of Object.entries(pgSettings)) {
157
- await replacementPgClient.query("select set_config($1, $2, true)", [key, String(value)]);
158
- }
159
- try {
160
- if (typeof Query !== 'string')
161
- Query = (0, printer_1.print)(Query);
162
- return await (0, graphql_1.graphql)(schema, Query, null, { ...context, pgClient: replacementPgClient }, vars);
163
- }
164
- finally {
165
- await replacementPgClient.query(commit ? 'commit' : 'rollback');
166
- replacementPgClient.release();
167
- }
168
- });
169
- }
170
- ;
171
28
  return {
172
29
  setup,
173
30
  teardown,
174
- graphQL,
175
- graphQLQuery,
176
- // @ts-ignore
177
- withContext: (cb) => cb(ctx)
31
+ query
178
32
  };
179
33
  };
180
34
  exports.GraphQLTest = GraphQLTest;
package/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from './clean';
2
2
  export * from './graphile-test';
3
+ export { seed } from 'pgsql-test';
package/index.js CHANGED
@@ -14,5 +14,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.seed = void 0;
17
18
  __exportStar(require("./clean"), exports);
18
19
  __exportStar(require("./graphile-test"), exports);
20
+ var pgsql_test_1 = require("pgsql-test");
21
+ Object.defineProperty(exports, "seed", { enumerable: true, get: function () { return pgsql_test_1.seed; } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "graphile-test",
3
- "version": "2.1.5",
3
+ "version": "2.1.7",
4
4
  "author": "Dan Lynch <pyramation@gmail.com>",
5
5
  "description": "PostGraphile Testing",
6
6
  "main": "index.js",
@@ -34,12 +34,12 @@
34
34
  "graphql-tag": "2.12.6"
35
35
  },
36
36
  "dependencies": {
37
- "@launchql/graphile-settings": "^2.1.5",
38
37
  "@launchql/types": "^2.1.5",
38
+ "graphile-settings": "^2.1.7",
39
39
  "graphql": "^15.5.2",
40
40
  "mock-req": "^0.2.0",
41
41
  "pg": "^8.16.0",
42
42
  "postgraphile": "^4.14.1"
43
43
  },
44
- "gitHead": "4f0b0637695c6f54c5de85d31776961057c51a08"
44
+ "gitHead": "8a638ef47a175c964a63431017d83587e62efbb8"
45
45
  }
package/types.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ import { DocumentNode, ExecutionResult } from 'graphql';
2
+ export interface GraphQLQueryOptions {
3
+ query: string | DocumentNode;
4
+ variables?: Record<string, any>;
5
+ commit?: boolean;
6
+ reqOptions?: Record<string, any>;
7
+ }
8
+ export interface GraphQLTestContext {
9
+ setup: () => Promise<void>;
10
+ teardown: () => Promise<void>;
11
+ query: <T = ExecutionResult>(opts: GraphQLQueryOptions) => Promise<T>;
12
+ }
package/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });