graphile-test 0.1.1 → 2.0.1
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/LICENSE +1 -1
- package/README.md +66 -39
- package/clean.d.ts +9 -0
- package/clean.js +67 -0
- package/esm/clean.js +57 -0
- package/esm/graphile-test.js +172 -0
- package/esm/index.js +2 -0
- package/graphile-test.d.ts +12 -0
- package/graphile-test.js +179 -0
- package/index.d.ts +2 -0
- package/index.js +18 -0
- package/package.json +30 -58
- package/main/clean.js +0 -104
- package/main/env.js +0 -28
- package/main/gql.js +0 -15
- package/main/graphql.js +0 -346
- package/main/index.js +0 -53
- package/module/clean.js +0 -46
- package/module/env.js +0 -19
- package/module/gql.js +0 -2
- package/module/graphql.js +0 -152
- package/module/index.js +0 -4
package/module/clean.js
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
// Thanks Graphile again!
|
|
2
|
-
// https://github.com/graphile/starter/blob/ce3c683ee19d4c92444431324b76941347fd85db/%40app/db/__tests__/helpers.ts#L46-L76
|
|
3
|
-
const uuidRegexp = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
4
|
-
|
|
5
|
-
const idReplacement = v => !v ? v : '[ID]';
|
|
6
|
-
|
|
7
|
-
export const pruneDates = row => mapValues(row, (v, k) => {
|
|
8
|
-
if (!v) {
|
|
9
|
-
return v;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
if (v instanceof Date) {
|
|
13
|
-
return '[DATE]';
|
|
14
|
-
} else if (typeof v === 'string' && k.match(/(_at|At)$/) && v.match(/^20[0-9]{2}-[0-9]{2}-[0-9]{2}/)) {
|
|
15
|
-
return '[DATE]';
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
return v;
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
const mapValues = (objs, fn) => Object.entries(objs).reduce((a, [key, value]) => {
|
|
22
|
-
a[key] = fn(value, key);
|
|
23
|
-
return a;
|
|
24
|
-
}, {});
|
|
25
|
-
|
|
26
|
-
export const pruneIds = row => mapValues(row, (v, k) => (k === 'id' || k.endsWith('_id')) && (typeof v === 'string' || typeof v === 'number') ? idReplacement(v) : v);
|
|
27
|
-
export const pruneIdArrays = row => mapValues(row, (v, k) => k.endsWith('_ids') && Array.isArray(v) ? `[UUIDs-${v.length}]` : v);
|
|
28
|
-
export const pruneUUIDs = row => mapValues(row, (v, k) => {
|
|
29
|
-
if (typeof v !== 'string') {
|
|
30
|
-
return v;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const val = v;
|
|
34
|
-
return ['uuid', 'queue_name'].includes(k) && v.match(uuidRegexp) ? '[UUID]' : k === 'gravatar' && val.match(/^[0-9a-f]{32}$/i) ? '[gUUID]' : v;
|
|
35
|
-
});
|
|
36
|
-
export const pruneHashes = row => mapValues(row, (v, k) => k.endsWith('_hash') && typeof v === 'string' && v[0] === '$' ? '[hash]' : v);
|
|
37
|
-
export const prune = obj => pruneHashes(pruneUUIDs(pruneIds(pruneIdArrays(pruneDates(obj)))));
|
|
38
|
-
export const snapshot = obj => {
|
|
39
|
-
if (Array.isArray(obj)) {
|
|
40
|
-
return obj.map(snapshot);
|
|
41
|
-
} else if (obj && typeof obj === 'object') {
|
|
42
|
-
return mapValues(prune(obj), snapshot);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return obj;
|
|
46
|
-
};
|
package/module/env.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { cleanEnv, str, port } from 'envalid';
|
|
2
|
-
export const env = cleanEnv(process.env, {
|
|
3
|
-
PGUSER: str({
|
|
4
|
-
default: 'postgres'
|
|
5
|
-
}),
|
|
6
|
-
PGHOST: str({
|
|
7
|
-
default: 'localhost'
|
|
8
|
-
}),
|
|
9
|
-
PGPASSWORD: str({
|
|
10
|
-
default: 'password'
|
|
11
|
-
}),
|
|
12
|
-
PGPORT: port({
|
|
13
|
-
default: 5432
|
|
14
|
-
}),
|
|
15
|
-
PGDATABASE: str(),
|
|
16
|
-
SCHEMA: str()
|
|
17
|
-
}, {
|
|
18
|
-
dotEnvPath: null
|
|
19
|
-
});
|
package/module/gql.js
DELETED
package/module/graphql.js
DELETED
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
|
|
2
|
-
|
|
3
|
-
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
|
|
4
|
-
|
|
5
|
-
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
|
|
6
|
-
|
|
7
|
-
import pg from 'pg';
|
|
8
|
-
import { createPostGraphileSchema, withPostGraphileContext } from 'postgraphile';
|
|
9
|
-
import { graphql } from 'graphql';
|
|
10
|
-
import MockReq from 'mock-req';
|
|
11
|
-
import { print } from 'graphql/language/printer';
|
|
12
|
-
export const GraphQLTest = (options, connectionString) => {
|
|
13
|
-
pg.defaults.poolSize = 1; // This is the role that your normal PostGraphile connection string would use,
|
|
14
|
-
// e.g. `postgres://POSTGRAPHILE_AUTHENTICATOR_ROLE:password@host/db`
|
|
15
|
-
|
|
16
|
-
const POSTGRAPHILE_AUTHENTICATOR_ROLE = 'authenticated'; // Contains the PostGraphile schema and rootPgPool
|
|
17
|
-
|
|
18
|
-
let ctx;
|
|
19
|
-
|
|
20
|
-
const setup = async () => {
|
|
21
|
-
const rootPgPool = new pg.Pool({
|
|
22
|
-
connectionString
|
|
23
|
-
});
|
|
24
|
-
const schema = await createPostGraphileSchema(rootPgPool, options.schema, options); // Store the context
|
|
25
|
-
|
|
26
|
-
ctx = {
|
|
27
|
-
rootPgPool,
|
|
28
|
-
options,
|
|
29
|
-
schema
|
|
30
|
-
};
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
const teardown = async () => {
|
|
34
|
-
try {
|
|
35
|
-
if (!ctx) {
|
|
36
|
-
return null;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const {
|
|
40
|
-
rootPgPool
|
|
41
|
-
} = ctx;
|
|
42
|
-
ctx = null;
|
|
43
|
-
await rootPgPool.end();
|
|
44
|
-
return null;
|
|
45
|
-
} catch (e) {
|
|
46
|
-
console.error(e); // eslint-disable-line
|
|
47
|
-
|
|
48
|
-
return null;
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
const graphQL = async function graphQL() {
|
|
53
|
-
// Any additional items to set on `req` (e.g. `{user: {id: 17}}`)
|
|
54
|
-
let reqOptions = {}; // Place test assertions in this function
|
|
55
|
-
|
|
56
|
-
let checker = () => {};
|
|
57
|
-
|
|
58
|
-
if (arguments.length === 1) {
|
|
59
|
-
checker = arguments[0];
|
|
60
|
-
} else if (arguments.length == 2) {
|
|
61
|
-
reqOptions = arguments[0];
|
|
62
|
-
checker = arguments[1];
|
|
63
|
-
} else {
|
|
64
|
-
throw new Error('no args supplied to graphQL');
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const {
|
|
68
|
-
schema,
|
|
69
|
-
rootPgPool,
|
|
70
|
-
options
|
|
71
|
-
} = ctx;
|
|
72
|
-
const req = new MockReq(_objectSpread({
|
|
73
|
-
url: options.graphqlRoute || '/graphql',
|
|
74
|
-
method: 'POST',
|
|
75
|
-
headers: {
|
|
76
|
-
Accept: 'application/json',
|
|
77
|
-
'Content-Type': 'application/json'
|
|
78
|
-
}
|
|
79
|
-
}, reqOptions));
|
|
80
|
-
const {
|
|
81
|
-
pgSettings: pgSettingsGenerator
|
|
82
|
-
} = options;
|
|
83
|
-
const pgSettings = typeof pgSettingsGenerator === 'function' ? await pgSettingsGenerator(req) : pgSettingsGenerator;
|
|
84
|
-
await withPostGraphileContext(_objectSpread(_objectSpread({}, options), {}, {
|
|
85
|
-
pgPool: rootPgPool,
|
|
86
|
-
pgSettings
|
|
87
|
-
}), async context => {
|
|
88
|
-
/* BEGIN: pgClient REPLACEMENT */
|
|
89
|
-
// We're not going to use the `pgClient` that came with
|
|
90
|
-
// `withPostGraphileContext` because we want to ROLLBACK at the end. So
|
|
91
|
-
// we need to replace it, and re-implement the settings logic. Sorry.
|
|
92
|
-
const replacementPgClient = await rootPgPool.connect();
|
|
93
|
-
await replacementPgClient.query('begin');
|
|
94
|
-
await replacementPgClient.query("select set_config('role', $1, true)", [POSTGRAPHILE_AUTHENTICATOR_ROLE]);
|
|
95
|
-
const localSettings = new Map(); // Set the custom provided settings before jwt claims and role are set
|
|
96
|
-
// this prevents an accidentional overwriting
|
|
97
|
-
|
|
98
|
-
if (typeof pgSettings === 'object') {
|
|
99
|
-
for (const key of Object.keys(pgSettings)) {
|
|
100
|
-
localSettings.set(key, String(pgSettings[key]));
|
|
101
|
-
}
|
|
102
|
-
} // If there is at least one local setting.
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if (localSettings.size !== 0) {
|
|
106
|
-
// Actually create our query.
|
|
107
|
-
const values = [];
|
|
108
|
-
const sqlQuery = `select ${Array.from(localSettings).map(([key, value]) => {
|
|
109
|
-
values.push(key);
|
|
110
|
-
values.push(value);
|
|
111
|
-
return `set_config($${values.length - 1}, $${values.length}, true)`;
|
|
112
|
-
}).join(', ')}`; // Execute the query.
|
|
113
|
-
|
|
114
|
-
await replacementPgClient.query(sqlQuery, values);
|
|
115
|
-
}
|
|
116
|
-
/* END: pgClient REPLACEMENT */
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
let checkResult;
|
|
120
|
-
|
|
121
|
-
try {
|
|
122
|
-
// This runs our GraphQL query, passing the replacement client
|
|
123
|
-
const query = async (q, variables) => {
|
|
124
|
-
if (typeof q !== 'string') q = print(q);
|
|
125
|
-
return await graphql(schema, q, null, _objectSpread(_objectSpread({}, context), {}, {
|
|
126
|
-
pgClient: replacementPgClient
|
|
127
|
-
}), variables);
|
|
128
|
-
}; // This is were we call the `checker` so you can do your assertions.
|
|
129
|
-
// Also note that we pass the `replacementPgClient` so that you can
|
|
130
|
-
// query the data in the database from within the transaction before it
|
|
131
|
-
// gets rolled back.
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
checkResult = await checker(query, replacementPgClient);
|
|
135
|
-
} finally {
|
|
136
|
-
// Rollback the transaction so no changes are written to the DB - this
|
|
137
|
-
// makes our tests fairly deterministic.
|
|
138
|
-
await replacementPgClient.query('rollback');
|
|
139
|
-
replacementPgClient.release();
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
return checkResult;
|
|
143
|
-
});
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
return {
|
|
147
|
-
setup,
|
|
148
|
-
teardown,
|
|
149
|
-
graphQL,
|
|
150
|
-
withContext: cb => cb(ctx)
|
|
151
|
-
};
|
|
152
|
-
};
|
package/module/index.js
DELETED