@snowtop/ent 0.2.9 → 0.2.11
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/action/index.d.ts +7 -4
- package/action/index.js +1 -0
- package/auth/index.d.ts +2 -1
- package/core/base.d.ts +1 -1
- package/core/config.d.ts +4 -0
- package/core/config.js +5 -1
- package/core/convert.d.ts +4 -0
- package/core/convert.js +70 -2
- package/core/date.js +5 -2
- package/core/db.d.ts +45 -3
- package/core/db.js +260 -24
- package/core/ent.js +9 -5
- package/core/extensions.d.ts +8 -3
- package/core/extensions.js +10 -1
- package/core/global_schema.js +1 -1
- package/core/loaders/loader.d.ts +4 -4
- package/core/logger.js +4 -2
- package/core/privacy.d.ts +2 -6
- package/core/privacy.js +8 -2
- package/core/query/index.d.ts +4 -2
- package/graphql/graphql.d.ts +2 -0
- package/graphql/graphql.js +91 -22
- package/graphql/index.d.ts +6 -3
- package/index.d.ts +10 -5
- package/package.json +15 -15
- package/schema/base_schema.d.ts +1 -1
- package/schema/index.d.ts +5 -4
- package/schema/schema.d.ts +3 -1
- package/scripts/custom_graphql.js +71 -53
- package/scripts/read_schema.js +6 -11
- package/scripts/stdout.d.ts +1 -0
- package/scripts/stdout.js +18 -0
- package/testutils/ent-graphql-tests/index.d.ts +6 -0
- package/testutils/ent-graphql-tests/index.js +142 -54
|
@@ -41,17 +41,22 @@ const glob = __importStar(require("glob"));
|
|
|
41
41
|
const path = __importStar(require("path"));
|
|
42
42
|
const fs = __importStar(require("fs"));
|
|
43
43
|
const typescript_1 = __importDefault(require("typescript"));
|
|
44
|
+
const url_1 = require("url");
|
|
44
45
|
const graphql_1 = require("../graphql/graphql");
|
|
45
46
|
const readline = __importStar(require("readline"));
|
|
46
47
|
const imports_1 = require("../imports");
|
|
47
48
|
const process_1 = require("process");
|
|
48
49
|
const child_process_1 = require("child_process");
|
|
49
50
|
const const_1 = require("../core/const");
|
|
51
|
+
const stdout_1 = require("./stdout");
|
|
50
52
|
const { parseArgs } = require("./parse_args");
|
|
51
53
|
// need to use the GQLCapture from the package so that when we call GQLCapture.enable()
|
|
52
54
|
// we're affecting the local paths as opposed to a different instance
|
|
53
55
|
// life is hard
|
|
54
56
|
const MODULE_PATH = const_1.GRAPHQL_PATH;
|
|
57
|
+
function isBunRuntime() {
|
|
58
|
+
return process.env.ENT_RUNTIME === "bun" || process.versions.bun;
|
|
59
|
+
}
|
|
55
60
|
function parseJSONC(fileName, text) {
|
|
56
61
|
const { config, error } = typescript_1.default.parseConfigFileTextToJson(fileName, text);
|
|
57
62
|
if (error) {
|
|
@@ -171,22 +176,28 @@ async function captureDynamic(filePath, gqlCapture) {
|
|
|
171
176
|
return;
|
|
172
177
|
}
|
|
173
178
|
return new Promise((resolve, reject) => {
|
|
174
|
-
let cmd = "";
|
|
175
|
-
const args = [];
|
|
176
179
|
const env = {
|
|
177
180
|
...process.env,
|
|
178
181
|
};
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
182
|
+
let cmd = "ts-node";
|
|
183
|
+
const args = [];
|
|
184
|
+
const runtime = isBunRuntime() ? "bun" : "node";
|
|
185
|
+
if (runtime === "bun") {
|
|
186
|
+
cmd = "bun";
|
|
187
|
+
args.push(filePath);
|
|
184
188
|
}
|
|
185
189
|
else {
|
|
186
|
-
|
|
187
|
-
|
|
190
|
+
if (process.env.ENABLE_SWC) {
|
|
191
|
+
cmd = "node";
|
|
192
|
+
// we seem to get tsconfig-paths by default because child process but not 100% sure...
|
|
193
|
+
args.push("-r", "@swc-node/register");
|
|
194
|
+
env.SWCRC = "true";
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
args.push("--transpileOnly");
|
|
198
|
+
}
|
|
199
|
+
args.push(filePath);
|
|
188
200
|
}
|
|
189
|
-
args.push(filePath);
|
|
190
201
|
const r = (0, child_process_1.spawn)(cmd, args, {
|
|
191
202
|
env,
|
|
192
203
|
});
|
|
@@ -233,33 +244,10 @@ async function processJSON(gqlCapture, json) {
|
|
|
233
244
|
processCustomTypes(json.customTypes, gqlCapture);
|
|
234
245
|
}
|
|
235
246
|
}
|
|
236
|
-
async function
|
|
237
|
-
if (jsonPath !== undefined) {
|
|
238
|
-
const json = parseJSONC(jsonPath, fs.readFileSync(jsonPath, {
|
|
239
|
-
encoding: "utf8",
|
|
240
|
-
}));
|
|
241
|
-
processJSON(gqlCapture, json);
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
if (filesCsv !== undefined) {
|
|
245
|
-
let files = filesCsv.split(",");
|
|
246
|
-
for (let i = 0; i < files.length; i++) {
|
|
247
|
-
// TODO fix. we have "src" in the path we get here
|
|
248
|
-
files[i] = path.join(filePath, "..", files[i]);
|
|
249
|
-
}
|
|
250
|
-
await requireFiles(files);
|
|
251
|
-
return;
|
|
252
|
-
}
|
|
247
|
+
async function loadGraphQLDecoratorFiles(filePath) {
|
|
253
248
|
// TODO delete all of this eventually
|
|
254
249
|
// TODO configurable paths eventually
|
|
255
250
|
// for now only files that are in the include path of the roots are allowed
|
|
256
|
-
const rootFiles = [
|
|
257
|
-
// right now, currently expecting all custom ent stuff to be in the ent object
|
|
258
|
-
// eventually, create a path we check e.g. ent/custom_gql/ ent/graphql?
|
|
259
|
-
// for now can just go in graphql/resolvers/ (not generated)
|
|
260
|
-
path.join(filePath, "ent/index.ts"),
|
|
261
|
-
path.join(filePath, "/graphql/resolvers/index.ts"),
|
|
262
|
-
];
|
|
263
251
|
const ignore = [
|
|
264
252
|
"**/generated/**",
|
|
265
253
|
"**/tests/**",
|
|
@@ -268,35 +256,64 @@ async function captureCustom(filePath, filesCsv, jsonPath, gqlCapture) {
|
|
|
268
256
|
// ignore test files.
|
|
269
257
|
"**/*.test.ts",
|
|
270
258
|
];
|
|
259
|
+
const customGraphQLEntFiles = glob.sync(path.join(filePath, "/ent/**/*.ts"), {
|
|
260
|
+
// not in action files since we can't customize payloads (yet?)
|
|
261
|
+
ignore: [...ignore, "**/actions/**"],
|
|
262
|
+
});
|
|
271
263
|
const customGQLResolvers = glob.sync(path.join(filePath, "/graphql/resolvers/**/*.ts"), {
|
|
272
|
-
// no actions for now to speed things up
|
|
273
|
-
// no index.ts or internal file.
|
|
274
264
|
ignore: ignore,
|
|
275
265
|
});
|
|
276
266
|
const customGQLMutations = glob.sync(path.join(filePath, "/graphql/mutations/**/*.ts"), {
|
|
277
|
-
// no actions for now to speed things up
|
|
278
|
-
// no index.ts or internal file.
|
|
279
267
|
ignore: ignore,
|
|
280
268
|
});
|
|
281
|
-
const files =
|
|
269
|
+
const files = customGraphQLEntFiles
|
|
270
|
+
.concat(customGQLResolvers, customGQLMutations)
|
|
271
|
+
.filter(fileImportsGraphQLDecorators);
|
|
282
272
|
await requireFiles(files);
|
|
283
273
|
}
|
|
274
|
+
async function captureCustom(filePath, filesCsv, jsonPath, gqlCapture) {
|
|
275
|
+
if (jsonPath !== undefined) {
|
|
276
|
+
const json = parseJSONC(jsonPath, fs.readFileSync(jsonPath, {
|
|
277
|
+
encoding: "utf8",
|
|
278
|
+
}));
|
|
279
|
+
await processJSON(gqlCapture, json);
|
|
280
|
+
await loadGraphQLDecoratorFiles(filePath);
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
if (filesCsv !== undefined) {
|
|
284
|
+
let files = filesCsv.split(",");
|
|
285
|
+
for (let i = 0; i < files.length; i++) {
|
|
286
|
+
// TODO fix. we have "src" in the path we get here
|
|
287
|
+
files[i] = path.join(filePath, "..", files[i]);
|
|
288
|
+
}
|
|
289
|
+
await requireFiles(files);
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
await loadGraphQLDecoratorFiles(filePath);
|
|
293
|
+
}
|
|
294
|
+
function fileImportsGraphQLDecorators(file) {
|
|
295
|
+
const contents = fs.readFileSync(file, {
|
|
296
|
+
encoding: "utf8",
|
|
297
|
+
});
|
|
298
|
+
return /@snowtop\/ent\/graphql(?:\/graphql)?/.test(contents);
|
|
299
|
+
}
|
|
284
300
|
async function requireFiles(files) {
|
|
285
|
-
|
|
286
|
-
if (fs.existsSync(file)) {
|
|
287
|
-
|
|
288
|
-
|
|
301
|
+
for (const file of files) {
|
|
302
|
+
if (!fs.existsSync(file)) {
|
|
303
|
+
throw new Error(`file ${file} doesn't exist`);
|
|
304
|
+
}
|
|
305
|
+
try {
|
|
306
|
+
if (isBunRuntime()) {
|
|
307
|
+
await Promise.resolve(`${(0, url_1.pathToFileURL)(file).href}`).then(s => __importStar(require(s)));
|
|
289
308
|
}
|
|
290
|
-
|
|
291
|
-
|
|
309
|
+
else {
|
|
310
|
+
await require(file);
|
|
292
311
|
}
|
|
293
312
|
}
|
|
294
|
-
|
|
295
|
-
throw new Error(
|
|
313
|
+
catch (e) {
|
|
314
|
+
throw new Error(`${e.message} loading ${file}`);
|
|
296
315
|
}
|
|
297
|
-
}
|
|
298
|
-
throw new Error(err);
|
|
299
|
-
});
|
|
316
|
+
}
|
|
300
317
|
}
|
|
301
318
|
// filePath is path-to-src
|
|
302
319
|
async function parseImports(filePath) {
|
|
@@ -350,9 +367,10 @@ async function main() {
|
|
|
350
367
|
// for local dev, get the one from the file system. otherwise, get the one
|
|
351
368
|
// from node_modules
|
|
352
369
|
let gqlCapture;
|
|
353
|
-
if (process.env.LOCAL_SCRIPT_PATH) {
|
|
370
|
+
if (process.env.LOCAL_SCRIPT_PATH || isBunRuntime()) {
|
|
354
371
|
const r = require("../graphql/graphql");
|
|
355
372
|
gqlCapture = r.GQLCapture;
|
|
373
|
+
gqlCapture.enable(true);
|
|
356
374
|
}
|
|
357
375
|
else {
|
|
358
376
|
const r = require(gqlPath);
|
|
@@ -466,7 +484,7 @@ async function main() {
|
|
|
466
484
|
for (const k in fields) {
|
|
467
485
|
buildClasses(fields[k]);
|
|
468
486
|
}
|
|
469
|
-
|
|
487
|
+
await (0, stdout_1.writeJSONToStdout)({
|
|
470
488
|
args,
|
|
471
489
|
inputs,
|
|
472
490
|
fields,
|
|
@@ -478,7 +496,7 @@ async function main() {
|
|
|
478
496
|
unions,
|
|
479
497
|
files: allFiles,
|
|
480
498
|
customTypes,
|
|
481
|
-
})
|
|
499
|
+
});
|
|
482
500
|
}
|
|
483
501
|
main()
|
|
484
502
|
.then()
|
package/scripts/read_schema.js
CHANGED
|
@@ -39,7 +39,8 @@ const { parseArgs } = require("./parse_args");
|
|
|
39
39
|
const parse_1 = require("../parse_schema/parse");
|
|
40
40
|
const ast_1 = require("../tsc/ast");
|
|
41
41
|
const names_1 = require("../names/names");
|
|
42
|
-
|
|
42
|
+
const stdout_1 = require("./stdout");
|
|
43
|
+
async function main() {
|
|
43
44
|
const options = parseArgs(process.argv.slice(2));
|
|
44
45
|
if (!options.path) {
|
|
45
46
|
throw new Error("path required");
|
|
@@ -80,16 +81,10 @@ function main() {
|
|
|
80
81
|
potentialSchemas[(0, names_1.toClassName)(schema)] = s;
|
|
81
82
|
}
|
|
82
83
|
// console.log(potentialSchemas);
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
(0, parse_1.parseSchema)(potentialSchemas, globalSchema).then((result) => {
|
|
86
|
-
console.log(JSON.stringify(result));
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
try {
|
|
90
|
-
main();
|
|
84
|
+
const result = await (0, parse_1.parseSchema)(potentialSchemas, globalSchema);
|
|
85
|
+
await (0, stdout_1.writeJSONToStdout)(result);
|
|
91
86
|
}
|
|
92
|
-
catch
|
|
87
|
+
main().catch((err) => {
|
|
93
88
|
console.error(err);
|
|
94
89
|
process.exit(1);
|
|
95
|
-
}
|
|
90
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function writeJSONToStdout(value: unknown): Promise<void>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.writeJSONToStdout = writeJSONToStdout;
|
|
4
|
+
async function writeJSONToStdout(value) {
|
|
5
|
+
await writeToStdout(JSON.stringify(value));
|
|
6
|
+
}
|
|
7
|
+
async function writeToStdout(payload) {
|
|
8
|
+
// Bun can exit before a large piped stdout write is fully consumed.
|
|
9
|
+
await new Promise((resolve, reject) => {
|
|
10
|
+
process.stdout.write(payload, (err) => {
|
|
11
|
+
if (err) {
|
|
12
|
+
reject(err);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
resolve();
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
}
|
|
@@ -2,11 +2,17 @@ import { Express, RequestHandler } from "express";
|
|
|
2
2
|
import { GraphQLSchema } from "graphql";
|
|
3
3
|
import supertest from "supertest";
|
|
4
4
|
import { Viewer } from "../../core/base";
|
|
5
|
+
export declare function cleanupBunGraphQLTestAgent(agent: any): Promise<void>;
|
|
6
|
+
type BunTestTarget = {
|
|
7
|
+
app: Express;
|
|
8
|
+
url: string;
|
|
9
|
+
};
|
|
5
10
|
export type Option = [string, any] | [string, any, string];
|
|
6
11
|
interface queryConfig {
|
|
7
12
|
viewer?: Viewer;
|
|
8
13
|
init?: (app: Express) => void;
|
|
9
14
|
test?: supertest.Agent | ((express: Express) => supertest.Agent);
|
|
15
|
+
bunTest?: (target: BunTestTarget) => supertest.Agent;
|
|
10
16
|
schema: GraphQLSchema;
|
|
11
17
|
headers?: object;
|
|
12
18
|
debugMode?: boolean;
|
|
@@ -1,52 +1,46 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
4
|
};
|
|
38
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.cleanupBunGraphQLTestAgent = cleanupBunGraphQLTestAgent;
|
|
39
7
|
exports.expectQueryFromRoot = expectQueryFromRoot;
|
|
40
8
|
exports.expectMutation = expectMutation;
|
|
41
9
|
// NB: this is copied from ent-graphql-tests package until I have time to figure out how to share code here effectively
|
|
42
10
|
// the circular dependencies btw this package and ent-graphql-tests seems to imply something needs to change
|
|
43
11
|
const express_1 = __importDefault(require("express"));
|
|
44
|
-
const fs = __importStar(require("fs"));
|
|
45
|
-
const graphql_1 = require("graphql");
|
|
46
12
|
const graphql_helix_1 = require("graphql-helix");
|
|
47
13
|
const supertest_1 = __importDefault(require("supertest"));
|
|
48
14
|
const util_1 = require("util");
|
|
49
15
|
const auth_1 = require("../../auth");
|
|
16
|
+
const bunAgentServerClose = Symbol("bunAgentServerClose");
|
|
17
|
+
const bunAgentServerCleanups = new Set();
|
|
18
|
+
let bunAgentServerCleanupRegistered = false;
|
|
19
|
+
function registerBunAgentServerCleanup(cleanup) {
|
|
20
|
+
let cleanupPromise;
|
|
21
|
+
const cleanupOnce = () => {
|
|
22
|
+
cleanupPromise = cleanupPromise || cleanup();
|
|
23
|
+
return cleanupPromise;
|
|
24
|
+
};
|
|
25
|
+
bunAgentServerCleanups.add(cleanupOnce);
|
|
26
|
+
const afterAllFn = globalThis
|
|
27
|
+
.afterAll;
|
|
28
|
+
if (!bunAgentServerCleanupRegistered && typeof afterAllFn === "function") {
|
|
29
|
+
bunAgentServerCleanupRegistered = true;
|
|
30
|
+
afterAllFn(async () => {
|
|
31
|
+
const cleanups = [...bunAgentServerCleanups];
|
|
32
|
+
bunAgentServerCleanups.clear();
|
|
33
|
+
await Promise.all(cleanups.map((cleanup) => cleanup()));
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return cleanupOnce;
|
|
37
|
+
}
|
|
38
|
+
async function cleanupBunGraphQLTestAgent(agent) {
|
|
39
|
+
const cleanup = agent?.[bunAgentServerClose];
|
|
40
|
+
if (cleanup) {
|
|
41
|
+
await cleanup();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
50
44
|
function server(config) {
|
|
51
45
|
const viewer = config.viewer;
|
|
52
46
|
if (viewer) {
|
|
@@ -83,25 +77,113 @@ function server(config) {
|
|
|
83
77
|
app.use(config.graphQLPath || "/graphql", ...handlers);
|
|
84
78
|
return app;
|
|
85
79
|
}
|
|
80
|
+
// Bun can load GraphQL types from a different module realm than the schema under test,
|
|
81
|
+
// so constructor identity checks are not reliable here.
|
|
82
|
+
function isWrappingTypeLike(typ) {
|
|
83
|
+
return !!typ && typeof typ === "object" && "ofType" in typ;
|
|
84
|
+
}
|
|
85
|
+
function isListTypeLike(typ) {
|
|
86
|
+
return (isWrappingTypeLike(typ) &&
|
|
87
|
+
(typ.constructor?.name === "GraphQLList" || /^\[.*\]$/.test(String(typ))));
|
|
88
|
+
}
|
|
89
|
+
function isObjectTypeLike(typ) {
|
|
90
|
+
return (!!typ && typeof typ === "object" && typeof typ.getFields === "function");
|
|
91
|
+
}
|
|
92
|
+
function isScalarTypeLike(typ) {
|
|
93
|
+
return (!!typ &&
|
|
94
|
+
typeof typ === "object" &&
|
|
95
|
+
typeof typ.serialize === "function" &&
|
|
96
|
+
typeof typ.parseValue === "function" &&
|
|
97
|
+
typeof typ.parseLiteral === "function");
|
|
98
|
+
}
|
|
99
|
+
function isEnumTypeLike(typ) {
|
|
100
|
+
return (!!typ &&
|
|
101
|
+
typeof typ === "object" &&
|
|
102
|
+
typeof typ.getValues === "function" &&
|
|
103
|
+
typeof typ.toConfig === "function");
|
|
104
|
+
}
|
|
86
105
|
function getInnerType(typ, list) {
|
|
87
|
-
if ((
|
|
88
|
-
if (typ
|
|
106
|
+
if (isWrappingTypeLike(typ)) {
|
|
107
|
+
if (isListTypeLike(typ)) {
|
|
89
108
|
return getInnerType(typ.ofType, true);
|
|
90
109
|
}
|
|
91
110
|
return getInnerType(typ.ofType, list);
|
|
92
111
|
}
|
|
93
112
|
return [typ, list];
|
|
94
113
|
}
|
|
95
|
-
function
|
|
114
|
+
async function createBunTestHarness(config, persistentAgent, testFactory) {
|
|
115
|
+
const app = config.server ? config.server : server(config);
|
|
116
|
+
const httpServer = await new Promise((resolve) => {
|
|
117
|
+
const srv = app.listen(0, () => resolve(srv));
|
|
118
|
+
});
|
|
119
|
+
const address = httpServer.address();
|
|
120
|
+
if (!address || typeof address === "string") {
|
|
121
|
+
throw new Error("could not determine test server address");
|
|
122
|
+
}
|
|
123
|
+
const url = `http://127.0.0.1:${address.port}`;
|
|
124
|
+
let closePromise;
|
|
125
|
+
const close = () => {
|
|
126
|
+
closePromise =
|
|
127
|
+
closePromise ||
|
|
128
|
+
new Promise((resolve, reject) => {
|
|
129
|
+
httpServer.close((err) => (err ? reject(err) : resolve()));
|
|
130
|
+
});
|
|
131
|
+
return closePromise;
|
|
132
|
+
};
|
|
133
|
+
if (persistentAgent) {
|
|
134
|
+
try {
|
|
135
|
+
let agent;
|
|
136
|
+
// Keep the existing Express app factory contract. If bunTest is present,
|
|
137
|
+
// it owns the URL-backed agent and testFactory still runs against the app.
|
|
138
|
+
const factoryAgent = testFactory?.(app);
|
|
139
|
+
if (config.bunTest) {
|
|
140
|
+
agent = config.bunTest({ app, url });
|
|
141
|
+
}
|
|
142
|
+
else if (factoryAgent) {
|
|
143
|
+
agent = factoryAgent;
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
agent = supertest_1.default.agent(url);
|
|
147
|
+
}
|
|
148
|
+
agent[bunAgentServerClose] = registerBunAgentServerCleanup(close);
|
|
149
|
+
return { agent };
|
|
150
|
+
}
|
|
151
|
+
catch (err) {
|
|
152
|
+
await close();
|
|
153
|
+
throw err;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
agent: (0, supertest_1.default)(url),
|
|
158
|
+
cleanup: close,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
async function makeGraphQLRequest(config, query, fieldArgs) {
|
|
96
162
|
let agent;
|
|
163
|
+
let cleanup;
|
|
97
164
|
if (config.test) {
|
|
98
165
|
if (typeof config.test === "function") {
|
|
99
|
-
|
|
166
|
+
if (process.versions.bun) {
|
|
167
|
+
({ agent } = await createBunTestHarness(config, true, config.test));
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
const factoryAgent = config.test(config.server ? config.server : server(config));
|
|
171
|
+
if (!factoryAgent) {
|
|
172
|
+
throw new Error("config.test must return a supertest agent");
|
|
173
|
+
}
|
|
174
|
+
agent = factoryAgent;
|
|
175
|
+
}
|
|
100
176
|
}
|
|
101
177
|
else {
|
|
102
178
|
agent = config.test;
|
|
103
179
|
}
|
|
104
180
|
}
|
|
181
|
+
else if (process.versions.bun && config.bunTest) {
|
|
182
|
+
({ agent } = await createBunTestHarness(config, true));
|
|
183
|
+
}
|
|
184
|
+
else if (process.versions.bun) {
|
|
185
|
+
({ agent, cleanup } = await createBunTestHarness(config, false));
|
|
186
|
+
}
|
|
105
187
|
else {
|
|
106
188
|
agent = (0, supertest_1.default)(config.server ? config.server : server(config));
|
|
107
189
|
}
|
|
@@ -109,7 +191,7 @@ function makeGraphQLRequest(config, query, fieldArgs) {
|
|
|
109
191
|
// handle files
|
|
110
192
|
fieldArgs.forEach((fieldArg) => {
|
|
111
193
|
let [typ, list] = getInnerType(fieldArg.type, false);
|
|
112
|
-
if (typ
|
|
194
|
+
if (isScalarTypeLike(typ) && typ.name == "Upload") {
|
|
113
195
|
let value = config.args[fieldArg.name];
|
|
114
196
|
if (list) {
|
|
115
197
|
expect(Array.isArray(value)).toBe(true);
|
|
@@ -150,31 +232,29 @@ function makeGraphQLRequest(config, query, fieldArgs) {
|
|
|
150
232
|
ret.field("map", JSON.stringify(m));
|
|
151
233
|
idx = 0;
|
|
152
234
|
for (let [key, val] of files) {
|
|
153
|
-
if (typeof val === "string") {
|
|
154
|
-
val = fs.createReadStream(val);
|
|
155
|
-
}
|
|
156
235
|
ret.attach(`${idx}`, val, key);
|
|
157
236
|
idx++;
|
|
158
237
|
}
|
|
159
|
-
return
|
|
238
|
+
return { agent, request: ret, cleanup };
|
|
160
239
|
}
|
|
161
240
|
else {
|
|
162
|
-
return
|
|
241
|
+
return {
|
|
163
242
|
agent,
|
|
164
|
-
agent
|
|
243
|
+
request: agent
|
|
165
244
|
.post(config.graphQLPath || "/graphql")
|
|
166
245
|
.set((config.headers || {}))
|
|
167
246
|
.send({
|
|
168
247
|
query: query,
|
|
169
|
-
variables
|
|
248
|
+
variables,
|
|
170
249
|
}),
|
|
171
|
-
|
|
250
|
+
cleanup,
|
|
251
|
+
};
|
|
172
252
|
}
|
|
173
253
|
}
|
|
174
254
|
function buildTreeFromQueryPaths(schema, fieldType, ...options) {
|
|
175
255
|
let fields;
|
|
176
256
|
const [typ] = getInnerType(fieldType, false);
|
|
177
|
-
if (typ
|
|
257
|
+
if (isObjectTypeLike(typ)) {
|
|
178
258
|
fields = typ.getFields();
|
|
179
259
|
}
|
|
180
260
|
let topLevelTree = {};
|
|
@@ -189,7 +269,7 @@ function buildTreeFromQueryPaths(schema, fieldType, ...options) {
|
|
|
189
269
|
if (!typ) {
|
|
190
270
|
throw new Error(`can't find type for ${match[1]} in schema`);
|
|
191
271
|
}
|
|
192
|
-
if (typ
|
|
272
|
+
if (isObjectTypeLike(typ)) {
|
|
193
273
|
fields = typ.getFields();
|
|
194
274
|
}
|
|
195
275
|
}
|
|
@@ -243,7 +323,7 @@ function buildTreeFromQueryPaths(schema, fieldType, ...options) {
|
|
|
243
323
|
subField = root?.[p];
|
|
244
324
|
if (subField) {
|
|
245
325
|
[subField] = getInnerType(subField.type, false);
|
|
246
|
-
if (subField
|
|
326
|
+
if (isObjectTypeLike(subField)) {
|
|
247
327
|
root = subField.getFields();
|
|
248
328
|
}
|
|
249
329
|
}
|
|
@@ -251,7 +331,7 @@ function buildTreeFromQueryPaths(schema, fieldType, ...options) {
|
|
|
251
331
|
if (!subField) {
|
|
252
332
|
return false;
|
|
253
333
|
}
|
|
254
|
-
return (
|
|
334
|
+
return isScalarTypeLike(subField) || isEnumTypeLike(subField);
|
|
255
335
|
}
|
|
256
336
|
if (i === parts.length - 1 && typeof option[1] === "object") {
|
|
257
337
|
if (!scalarFieldAtLeaf(parts)) {
|
|
@@ -382,8 +462,16 @@ async function expectFromRoot(config, ...options) {
|
|
|
382
462
|
if (config.debugMode) {
|
|
383
463
|
console.log(q);
|
|
384
464
|
}
|
|
385
|
-
|
|
386
|
-
|
|
465
|
+
const { agent: st, request, cleanup, } = await makeGraphQLRequest(config, q, fieldArgs);
|
|
466
|
+
let res;
|
|
467
|
+
try {
|
|
468
|
+
res = await request.expect("Content-Type", /json/);
|
|
469
|
+
}
|
|
470
|
+
finally {
|
|
471
|
+
if (cleanup) {
|
|
472
|
+
await cleanup();
|
|
473
|
+
}
|
|
474
|
+
}
|
|
387
475
|
if (config.debugMode) {
|
|
388
476
|
console.log((0, util_1.inspect)(res.body, false, 3));
|
|
389
477
|
}
|