@elench/testkit 0.1.66 → 0.1.68
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 +37 -62
- package/lib/app/doctor.mjs +139 -0
- package/lib/app/typecheck.mjs +203 -0
- package/lib/cli/commands/doctor.mjs +39 -0
- package/lib/cli/commands/typecheck.mjs +28 -0
- package/lib/cli/entrypoint.mjs +2 -0
- package/lib/config/index.mjs +11 -0
- package/lib/config/runtime.mjs +11 -1
- package/lib/config/runtime.test.mjs +26 -0
- package/lib/coverage/index.test.mjs +4 -2
- package/lib/discovery/file-metadata.mjs +122 -0
- package/lib/discovery/file-metadata.test.mjs +51 -0
- package/lib/discovery/index.mjs +10 -2
- package/lib/discovery/index.test.mjs +19 -19
- package/lib/runner/planning.mjs +10 -3
- package/lib/runner/planning.test.mjs +26 -0
- package/lib/runner/template-steps.mjs +7 -0
- package/lib/setup/index.d.ts +96 -20
- package/lib/setup/index.mjs +194 -50
- package/lib/setup/index.test.mjs +220 -62
- package/lib/setup/next-runtime-tsconfig.mjs +43 -0
- package/lib/setup/next-runtime-tsconfig.test.mjs +57 -0
- package/lib/shared/build-config.mjs +208 -0
- package/lib/shared/build-config.test.mjs +150 -0
- package/node_modules/@elench/next-analysis/package.json +1 -1
- package/node_modules/@elench/testkit-bridge/package.json +2 -2
- package/node_modules/@elench/testkit-protocol/package.json +1 -1
- package/node_modules/@elench/ts-analysis/package.json +1 -1
- package/package.json +5 -5
package/lib/setup/index.mjs
CHANGED
|
@@ -18,11 +18,11 @@ export function defineHttpProfile(profile) {
|
|
|
18
18
|
return profile || {};
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
export function
|
|
22
|
-
return
|
|
21
|
+
export function defineTestkitFile(metadata) {
|
|
22
|
+
return metadata || {};
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
export function
|
|
25
|
+
export function postgresDatabase(options = {}) {
|
|
26
26
|
return {
|
|
27
27
|
provider: "local",
|
|
28
28
|
...options,
|
|
@@ -76,7 +76,7 @@ export function verifyModule(specifier, options = {}) {
|
|
|
76
76
|
return moduleStep(specifier, options);
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
function buildDatabaseTemplateConfig(options = {}) {
|
|
80
80
|
const migrate = normalizeTemplateStepList(options.migrate);
|
|
81
81
|
const seed = normalizeTemplateStepList(options.seed);
|
|
82
82
|
const verify = normalizeTemplateStepList(options.verify);
|
|
@@ -90,6 +90,52 @@ export function seededDatabaseTemplate(options = {}) {
|
|
|
90
90
|
};
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
export function templateDatabase(options = {}) {
|
|
94
|
+
const {
|
|
95
|
+
inputs,
|
|
96
|
+
schema,
|
|
97
|
+
migrate,
|
|
98
|
+
seed,
|
|
99
|
+
verify,
|
|
100
|
+
...databaseOptions
|
|
101
|
+
} = options;
|
|
102
|
+
return postgresDatabase({
|
|
103
|
+
...databaseOptions,
|
|
104
|
+
template: buildDatabaseTemplateConfig(options.template || { inputs, schema, migrate, seed, verify }),
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function postgresFixture(options = {}) {
|
|
109
|
+
const { discovery, envFiles, ...databaseOptions } = options;
|
|
110
|
+
return {
|
|
111
|
+
discovery: discovery || {
|
|
112
|
+
roots: [".testkit-fixture"],
|
|
113
|
+
},
|
|
114
|
+
envFiles,
|
|
115
|
+
local: false,
|
|
116
|
+
database: postgresDatabase(databaseOptions),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function databaseServiceEnv(prefix, serviceName) {
|
|
121
|
+
const normalizedPrefix = String(prefix || "").trim().replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
122
|
+
if (!normalizedPrefix) {
|
|
123
|
+
throw new Error("databaseServiceEnv prefix must be a non-empty string");
|
|
124
|
+
}
|
|
125
|
+
if (!serviceName || !String(serviceName).trim()) {
|
|
126
|
+
throw new Error("databaseServiceEnv serviceName must be a non-empty string");
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
[`${normalizedPrefix}_DATABASE_HOST`]: `{dbHost:${serviceName}}`,
|
|
131
|
+
[`${normalizedPrefix}_DATABASE_PORT`]: `{dbPort:${serviceName}}`,
|
|
132
|
+
[`${normalizedPrefix}_DATABASE_NAME`]: `{dbName:${serviceName}}`,
|
|
133
|
+
[`${normalizedPrefix}_DATABASE_USER`]: `{dbUser:${serviceName}}`,
|
|
134
|
+
[`${normalizedPrefix}_DATABASE_PASSWORD`]: `{dbPassword:${serviceName}}`,
|
|
135
|
+
[`${normalizedPrefix}_DATABASE_SSL`]: "0",
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
93
139
|
export function nodeToolchain(options = {}) {
|
|
94
140
|
return {
|
|
95
141
|
kind: "node",
|
|
@@ -97,61 +143,154 @@ export function nodeToolchain(options = {}) {
|
|
|
97
143
|
};
|
|
98
144
|
}
|
|
99
145
|
|
|
100
|
-
export function
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
146
|
+
export function tscBuild(options = {}) {
|
|
147
|
+
return {
|
|
148
|
+
kind: "tsc",
|
|
149
|
+
cwd: options.cwd,
|
|
150
|
+
entry: options.entry || "src/index.ts",
|
|
151
|
+
tsconfig: options.tsconfig || "tsconfig.json",
|
|
152
|
+
outDir: options.outDir || "dist",
|
|
153
|
+
inputs: Array.isArray(options.inputs) ? [...options.inputs] : undefined,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
105
156
|
|
|
157
|
+
export function scriptBuild(script, options = {}) {
|
|
106
158
|
return {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
port,
|
|
112
|
-
baseUrl,
|
|
113
|
-
readyUrl: options.readyUrl || `${baseUrl}${readyPath}`,
|
|
114
|
-
readyTimeoutMs: options.readyTimeoutMs,
|
|
115
|
-
env: options.env || {},
|
|
116
|
-
},
|
|
159
|
+
kind: "script",
|
|
160
|
+
script,
|
|
161
|
+
cwd: options.cwd,
|
|
162
|
+
inputs: Array.isArray(options.inputs) ? [...options.inputs] : undefined,
|
|
117
163
|
};
|
|
118
164
|
}
|
|
119
165
|
|
|
120
|
-
export function
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
166
|
+
export function stepsBuild(options = {}) {
|
|
167
|
+
return {
|
|
168
|
+
kind: "steps",
|
|
169
|
+
inputs: Array.isArray(options.inputs) ? [...options.inputs] : undefined,
|
|
170
|
+
steps: Array.isArray(options.steps) ? [...options.steps] : [],
|
|
171
|
+
};
|
|
172
|
+
}
|
|
124
173
|
|
|
174
|
+
export function nextBuild(options = {}) {
|
|
125
175
|
return {
|
|
126
|
-
|
|
176
|
+
kind: "next",
|
|
177
|
+
cwd: options.cwd,
|
|
178
|
+
distDir: options.distDir || "dist",
|
|
179
|
+
tsconfig: options.tsconfig || "tsconfig.json",
|
|
180
|
+
inputs: Array.isArray(options.inputs) ? [...options.inputs] : undefined,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export function nodeApp(options = {}) {
|
|
185
|
+
const {
|
|
186
|
+
baseUrl: explicitBaseUrl,
|
|
187
|
+
build: explicitBuild,
|
|
188
|
+
buildInputs,
|
|
189
|
+
cwd = ".",
|
|
190
|
+
entry = "src/index.ts",
|
|
191
|
+
env = {},
|
|
192
|
+
envFiles,
|
|
193
|
+
outDir = "dist",
|
|
194
|
+
port,
|
|
195
|
+
readyPath = "/health",
|
|
196
|
+
readyTimeoutMs,
|
|
197
|
+
readyUrl: explicitReadyUrl,
|
|
198
|
+
runtime,
|
|
199
|
+
start: explicitStart,
|
|
200
|
+
toolchain,
|
|
201
|
+
tsconfig = "tsconfig.json",
|
|
202
|
+
...serviceConfig
|
|
203
|
+
} = options;
|
|
204
|
+
|
|
205
|
+
const normalizedPort = requiredNumber(port, "nodeApp port");
|
|
206
|
+
const baseUrl = explicitBaseUrl || "http://127.0.0.1:{port}";
|
|
207
|
+
const build = explicitBuild === undefined ? tscBuild({
|
|
208
|
+
cwd,
|
|
209
|
+
entry,
|
|
210
|
+
tsconfig,
|
|
211
|
+
outDir,
|
|
212
|
+
inputs: buildInputs,
|
|
213
|
+
}) : explicitBuild;
|
|
214
|
+
const start = explicitStart || resolveNodeAppStart(build, entry);
|
|
215
|
+
|
|
216
|
+
return {
|
|
217
|
+
...serviceConfig,
|
|
218
|
+
envFiles,
|
|
219
|
+
runtime: {
|
|
220
|
+
...(runtime || {}),
|
|
221
|
+
build,
|
|
222
|
+
toolchain: toolchain ?? runtime?.toolchain,
|
|
223
|
+
},
|
|
127
224
|
local: {
|
|
128
225
|
cwd,
|
|
129
|
-
start
|
|
130
|
-
port,
|
|
226
|
+
start,
|
|
227
|
+
port: normalizedPort,
|
|
131
228
|
baseUrl,
|
|
132
|
-
readyUrl:
|
|
133
|
-
readyTimeoutMs
|
|
134
|
-
env
|
|
229
|
+
readyUrl: explicitReadyUrl || `${baseUrl}${readyPath}`,
|
|
230
|
+
readyTimeoutMs,
|
|
231
|
+
env,
|
|
135
232
|
},
|
|
136
233
|
};
|
|
137
234
|
}
|
|
138
235
|
|
|
139
|
-
export function
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
236
|
+
export function nextApp(options = {}) {
|
|
237
|
+
const {
|
|
238
|
+
baseUrl: explicitBaseUrl,
|
|
239
|
+
browser,
|
|
240
|
+
build: explicitBuild,
|
|
241
|
+
buildInputs,
|
|
242
|
+
cwd = ".",
|
|
243
|
+
dependsOn,
|
|
244
|
+
env = {},
|
|
245
|
+
envFiles,
|
|
246
|
+
mode = "dev",
|
|
247
|
+
port,
|
|
248
|
+
readyTimeoutMs,
|
|
249
|
+
readyUrl: explicitReadyUrl,
|
|
250
|
+
runtime,
|
|
251
|
+
start: explicitStart,
|
|
252
|
+
toolchain,
|
|
253
|
+
...serviceConfig
|
|
254
|
+
} = options;
|
|
255
|
+
|
|
256
|
+
const normalizedPort = requiredNumber(port, "nextApp port");
|
|
257
|
+
const baseUrl = explicitBaseUrl || "http://127.0.0.1:{port}";
|
|
258
|
+
const build =
|
|
259
|
+
explicitBuild === undefined
|
|
260
|
+
? mode === "start"
|
|
261
|
+
? nextBuild({ cwd, inputs: buildInputs })
|
|
262
|
+
: null
|
|
263
|
+
: explicitBuild;
|
|
264
|
+
const start =
|
|
265
|
+
explicitStart ||
|
|
266
|
+
(mode === "start"
|
|
267
|
+
? "./node_modules/.bin/next start --port {port}"
|
|
268
|
+
: "./node_modules/.bin/next dev -p {port}");
|
|
144
269
|
|
|
145
270
|
return {
|
|
146
|
-
...
|
|
271
|
+
...serviceConfig,
|
|
272
|
+
envFiles,
|
|
273
|
+
dependsOn: Array.isArray(dependsOn) ? [...dependsOn] : dependsOn,
|
|
274
|
+
browser,
|
|
275
|
+
runtime: {
|
|
276
|
+
...(runtime || {}),
|
|
277
|
+
build,
|
|
278
|
+
toolchain: toolchain ?? runtime?.toolchain,
|
|
279
|
+
},
|
|
147
280
|
local: {
|
|
148
281
|
cwd,
|
|
149
|
-
start
|
|
150
|
-
port,
|
|
282
|
+
start,
|
|
283
|
+
port: normalizedPort,
|
|
151
284
|
baseUrl,
|
|
152
|
-
readyUrl:
|
|
153
|
-
readyTimeoutMs
|
|
154
|
-
env:
|
|
285
|
+
readyUrl: explicitReadyUrl || baseUrl,
|
|
286
|
+
readyTimeoutMs,
|
|
287
|
+
env: mode === "start"
|
|
288
|
+
? {
|
|
289
|
+
NEXT_DIST_DIR: env.NEXT_DIST_DIR || "{prepareDir}/dist",
|
|
290
|
+
NEXT_TSCONFIG_PATH: env.NEXT_TSCONFIG_PATH || "{prepareDir}/tsconfig.json",
|
|
291
|
+
...env,
|
|
292
|
+
}
|
|
293
|
+
: env,
|
|
155
294
|
},
|
|
156
295
|
};
|
|
157
296
|
}
|
|
@@ -235,16 +374,6 @@ export {
|
|
|
235
374
|
runtimeJson,
|
|
236
375
|
};
|
|
237
376
|
|
|
238
|
-
function defaultGoStartCommand(options) {
|
|
239
|
-
if (options.command) {
|
|
240
|
-
return `go run ${options.command}`;
|
|
241
|
-
}
|
|
242
|
-
if (options.entrypoint) {
|
|
243
|
-
return `go run ${options.entrypoint}`;
|
|
244
|
-
}
|
|
245
|
-
return "go run ./cmd/server";
|
|
246
|
-
}
|
|
247
|
-
|
|
248
377
|
function requiredNumber(value, label) {
|
|
249
378
|
if (!Number.isInteger(value) || value <= 0) {
|
|
250
379
|
throw new Error(`${label} must be a positive integer`);
|
|
@@ -252,6 +381,14 @@ function requiredNumber(value, label) {
|
|
|
252
381
|
return value;
|
|
253
382
|
}
|
|
254
383
|
|
|
384
|
+
function resolveNodeAppStart(build, entry) {
|
|
385
|
+
if (build?.kind === "tsc") {
|
|
386
|
+
const compiled = compiledEntryFromSource(entry || build.entry || "src/index.ts", build.outDir || "dist");
|
|
387
|
+
return `node {prepareDir}/${compiled}`;
|
|
388
|
+
}
|
|
389
|
+
return `./node_modules/.bin/tsx ${entry || "src/index.ts"}`;
|
|
390
|
+
}
|
|
391
|
+
|
|
255
392
|
function normalizeTemplateStepList(value) {
|
|
256
393
|
if (value == null) return [];
|
|
257
394
|
return Array.isArray(value) ? [...value] : [value];
|
|
@@ -265,6 +402,13 @@ function normalizeSchemaStep(value) {
|
|
|
265
402
|
return value;
|
|
266
403
|
}
|
|
267
404
|
|
|
405
|
+
function compiledEntryFromSource(entry, outDir) {
|
|
406
|
+
const normalized = String(entry || "src/index.ts").replaceAll("\\", "/");
|
|
407
|
+
const compiled = normalized.replace(/\.[cm]?[jt]sx?$/i, ".js");
|
|
408
|
+
const relative = compiled.startsWith("src/") ? compiled.slice(4) : compiled;
|
|
409
|
+
return `${outDir}/${relative}`.replace(/\/+/g, "/");
|
|
410
|
+
}
|
|
411
|
+
|
|
268
412
|
function envValue(name) {
|
|
269
413
|
const env = getRuntimeEnv();
|
|
270
414
|
const value = env?.rawEnv?.[name] || env?.[name];
|
package/lib/setup/index.test.mjs
CHANGED
|
@@ -1,38 +1,76 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
databaseServiceEnv,
|
|
4
|
+
defineTestkitFile,
|
|
5
|
+
nextApp,
|
|
6
|
+
nextBuild,
|
|
5
7
|
nodeToolchain,
|
|
8
|
+
nodeApp,
|
|
9
|
+
postgresDatabase,
|
|
10
|
+
postgresFixture,
|
|
6
11
|
schemaSql,
|
|
7
12
|
seedCommand,
|
|
8
13
|
seedModule,
|
|
9
|
-
|
|
10
|
-
|
|
14
|
+
stepsBuild,
|
|
15
|
+
templateDatabase,
|
|
16
|
+
tscBuild,
|
|
11
17
|
verifyCommand,
|
|
12
18
|
verifyModule,
|
|
13
19
|
} from "./index.mjs";
|
|
14
20
|
|
|
15
21
|
describe("setup helpers", () => {
|
|
16
|
-
it("
|
|
17
|
-
|
|
22
|
+
it("defines file-local metadata plainly", () => {
|
|
23
|
+
expect(defineTestkitFile({ skip: "Auth is stubbed", locks: ["background-workers"] })).toEqual({
|
|
24
|
+
skip: "Auth is stubbed",
|
|
25
|
+
locks: ["background-workers"],
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("builds a Next app preset for dev mode", () => {
|
|
30
|
+
const config = nextApp({ port: 3000 });
|
|
18
31
|
|
|
19
32
|
expect(config.local.start).toBe("./node_modules/.bin/next dev -p {port}");
|
|
20
33
|
});
|
|
21
34
|
|
|
22
|
-
it("
|
|
23
|
-
const config =
|
|
35
|
+
it("builds a Next app preset for start mode with managed runtime env defaults", () => {
|
|
36
|
+
const config = nextApp({ cwd: "frontend", port: 3000, mode: "start" });
|
|
37
|
+
|
|
38
|
+
expect(config.local.start).toBe("./node_modules/.bin/next start --port {port}");
|
|
39
|
+
expect(config.local.env).toMatchObject({
|
|
40
|
+
NEXT_DIST_DIR: "{prepareDir}/dist",
|
|
41
|
+
NEXT_TSCONFIG_PATH: "{prepareDir}/tsconfig.json",
|
|
42
|
+
});
|
|
43
|
+
expect(config.runtime.build).toEqual({
|
|
44
|
+
kind: "next",
|
|
45
|
+
cwd: "frontend",
|
|
46
|
+
distDir: "dist",
|
|
47
|
+
tsconfig: "tsconfig.json",
|
|
48
|
+
inputs: undefined,
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("allows Next start apps to disable managed builds explicitly", () => {
|
|
53
|
+
const config = nextApp({ cwd: "frontend", port: 3000, mode: "start", build: null });
|
|
24
54
|
|
|
25
|
-
expect(config.
|
|
55
|
+
expect(config.runtime.build).toBeNull();
|
|
56
|
+
expect(config.local.env).toMatchObject({
|
|
57
|
+
NEXT_DIST_DIR: "{prepareDir}/dist",
|
|
58
|
+
NEXT_TSCONFIG_PATH: "{prepareDir}/tsconfig.json",
|
|
59
|
+
});
|
|
26
60
|
});
|
|
27
61
|
|
|
28
|
-
it("
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
62
|
+
it("builds a Node app preset with tsc build defaults", () => {
|
|
63
|
+
const config = nodeApp({ port: 3000, entry: "src/server.ts" });
|
|
64
|
+
|
|
65
|
+
expect(config.local.start).toBe("node {prepareDir}/dist/server.js");
|
|
66
|
+
expect(config.runtime.build).toEqual({
|
|
67
|
+
kind: "tsc",
|
|
68
|
+
cwd: ".",
|
|
69
|
+
entry: "src/server.ts",
|
|
70
|
+
tsconfig: "tsconfig.json",
|
|
71
|
+
outDir: "dist",
|
|
72
|
+
inputs: undefined,
|
|
73
|
+
});
|
|
36
74
|
});
|
|
37
75
|
|
|
38
76
|
it("builds node toolchain profiles with a node kind", () => {
|
|
@@ -43,6 +81,41 @@ describe("setup helpers", () => {
|
|
|
43
81
|
});
|
|
44
82
|
});
|
|
45
83
|
|
|
84
|
+
it("builds explicit build presets", () => {
|
|
85
|
+
expect(tscBuild({ entry: "src/server.ts", outDir: "build" })).toEqual({
|
|
86
|
+
kind: "tsc",
|
|
87
|
+
cwd: undefined,
|
|
88
|
+
entry: "src/server.ts",
|
|
89
|
+
tsconfig: "tsconfig.json",
|
|
90
|
+
outDir: "build",
|
|
91
|
+
inputs: undefined,
|
|
92
|
+
});
|
|
93
|
+
expect(nextBuild({ cwd: "frontend" })).toEqual({
|
|
94
|
+
kind: "next",
|
|
95
|
+
cwd: "frontend",
|
|
96
|
+
distDir: "dist",
|
|
97
|
+
tsconfig: "tsconfig.json",
|
|
98
|
+
inputs: undefined,
|
|
99
|
+
});
|
|
100
|
+
expect(
|
|
101
|
+
stepsBuild({
|
|
102
|
+
inputs: ["scripts/prepare.mjs"],
|
|
103
|
+
steps: [seedCommand("node scripts/prepare.mjs")],
|
|
104
|
+
})
|
|
105
|
+
).toEqual({
|
|
106
|
+
kind: "steps",
|
|
107
|
+
inputs: ["scripts/prepare.mjs"],
|
|
108
|
+
steps: [
|
|
109
|
+
{
|
|
110
|
+
kind: "command",
|
|
111
|
+
cmd: "node scripts/prepare.mjs",
|
|
112
|
+
cwd: undefined,
|
|
113
|
+
inputs: undefined,
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
46
119
|
it("emits semantic database template steps using the underlying step shapes", () => {
|
|
47
120
|
expect(schemaSql("db/schema.sql")).toEqual({
|
|
48
121
|
kind: "sql-file",
|
|
@@ -76,67 +149,152 @@ describe("setup helpers", () => {
|
|
|
76
149
|
});
|
|
77
150
|
});
|
|
78
151
|
|
|
79
|
-
it("builds
|
|
152
|
+
it("builds declarative template databases from schema, seed, and verify intents", () => {
|
|
80
153
|
expect(
|
|
81
|
-
|
|
154
|
+
templateDatabase({
|
|
82
155
|
inputs: ["db/schema.sql", "scripts/seed.ts"],
|
|
83
156
|
schema: "db/schema.sql",
|
|
84
157
|
seed: seedCommand("npm run db:seed"),
|
|
85
158
|
verify: verifyModule("scripts/verify.ts#verifySeed"),
|
|
86
159
|
})
|
|
87
160
|
).toEqual({
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
161
|
+
provider: "local",
|
|
162
|
+
template: {
|
|
163
|
+
inputs: ["db/schema.sql", "scripts/seed.ts"],
|
|
164
|
+
migrate: [
|
|
165
|
+
{
|
|
166
|
+
kind: "sql-file",
|
|
167
|
+
path: "db/schema.sql",
|
|
168
|
+
cwd: undefined,
|
|
169
|
+
inputs: undefined,
|
|
170
|
+
},
|
|
171
|
+
],
|
|
172
|
+
seed: [
|
|
173
|
+
{
|
|
174
|
+
kind: "command",
|
|
175
|
+
cmd: "npm run db:seed",
|
|
176
|
+
cwd: undefined,
|
|
177
|
+
inputs: undefined,
|
|
178
|
+
},
|
|
179
|
+
],
|
|
180
|
+
verify: [
|
|
181
|
+
{
|
|
182
|
+
kind: "module",
|
|
183
|
+
specifier: "scripts/verify.ts#verifySeed",
|
|
184
|
+
cwd: undefined,
|
|
185
|
+
inputs: undefined,
|
|
186
|
+
},
|
|
187
|
+
],
|
|
188
|
+
},
|
|
113
189
|
});
|
|
114
190
|
});
|
|
115
191
|
|
|
116
192
|
it("prepends schema before explicit migrate steps and normalizes singletons to arrays", () => {
|
|
117
193
|
expect(
|
|
118
|
-
|
|
194
|
+
templateDatabase({
|
|
119
195
|
schema: schemaSql("db/schema.sql", { cwd: "db" }),
|
|
120
196
|
migrate: seedCommand("echo migrate"),
|
|
121
197
|
})
|
|
122
198
|
).toEqual({
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
199
|
+
provider: "local",
|
|
200
|
+
template: {
|
|
201
|
+
inputs: undefined,
|
|
202
|
+
migrate: [
|
|
203
|
+
{
|
|
204
|
+
kind: "sql-file",
|
|
205
|
+
path: "db/schema.sql",
|
|
206
|
+
cwd: "db",
|
|
207
|
+
inputs: undefined,
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
kind: "command",
|
|
211
|
+
cmd: "echo migrate",
|
|
212
|
+
cwd: undefined,
|
|
213
|
+
inputs: undefined,
|
|
214
|
+
},
|
|
215
|
+
],
|
|
216
|
+
seed: [],
|
|
217
|
+
verify: [],
|
|
218
|
+
},
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it("builds declarative postgres database helpers", () => {
|
|
223
|
+
expect(postgresDatabase({ reset: false })).toEqual({
|
|
224
|
+
provider: "local",
|
|
225
|
+
reset: false,
|
|
226
|
+
});
|
|
227
|
+
expect(
|
|
228
|
+
templateDatabase({
|
|
229
|
+
reset: true,
|
|
230
|
+
schema: "db/schema.sql",
|
|
231
|
+
seed: seedCommand("npm run db:seed"),
|
|
232
|
+
})
|
|
233
|
+
).toEqual({
|
|
234
|
+
provider: "local",
|
|
235
|
+
reset: true,
|
|
236
|
+
template: {
|
|
237
|
+
inputs: undefined,
|
|
238
|
+
migrate: [
|
|
239
|
+
{
|
|
240
|
+
kind: "sql-file",
|
|
241
|
+
path: "db/schema.sql",
|
|
242
|
+
cwd: undefined,
|
|
243
|
+
inputs: undefined,
|
|
244
|
+
},
|
|
245
|
+
],
|
|
246
|
+
seed: [
|
|
247
|
+
{
|
|
248
|
+
kind: "command",
|
|
249
|
+
cmd: "npm run db:seed",
|
|
250
|
+
cwd: undefined,
|
|
251
|
+
inputs: undefined,
|
|
252
|
+
},
|
|
253
|
+
],
|
|
254
|
+
verify: [],
|
|
255
|
+
},
|
|
140
256
|
});
|
|
141
257
|
});
|
|
258
|
+
|
|
259
|
+
it("builds support database presets and env bindings", () => {
|
|
260
|
+
expect(
|
|
261
|
+
postgresFixture({
|
|
262
|
+
reset: true,
|
|
263
|
+
})
|
|
264
|
+
).toEqual({
|
|
265
|
+
discovery: {
|
|
266
|
+
roots: [".testkit-fixture"],
|
|
267
|
+
},
|
|
268
|
+
envFiles: undefined,
|
|
269
|
+
local: false,
|
|
270
|
+
database: {
|
|
271
|
+
provider: "local",
|
|
272
|
+
reset: true,
|
|
273
|
+
},
|
|
274
|
+
});
|
|
275
|
+
expect(databaseServiceEnv("ONIX", "catalog")).toEqual({
|
|
276
|
+
ONIX_DATABASE_HOST: "{dbHost:catalog}",
|
|
277
|
+
ONIX_DATABASE_PORT: "{dbPort:catalog}",
|
|
278
|
+
ONIX_DATABASE_NAME: "{dbName:catalog}",
|
|
279
|
+
ONIX_DATABASE_USER: "{dbUser:catalog}",
|
|
280
|
+
ONIX_DATABASE_PASSWORD: "{dbPassword:catalog}",
|
|
281
|
+
ONIX_DATABASE_SSL: "0",
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
it("does not leak preset-only helper fields into node app configs", () => {
|
|
286
|
+
const config = nodeApp({
|
|
287
|
+
port: 3000,
|
|
288
|
+
entry: "src/server.ts",
|
|
289
|
+
buildInputs: ["src", "package.json"],
|
|
290
|
+
env: { API_KEY: "test" },
|
|
291
|
+
readyPath: "/live",
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
expect(config).not.toHaveProperty("entry");
|
|
295
|
+
expect(config).not.toHaveProperty("buildInputs");
|
|
296
|
+
expect(config).not.toHaveProperty("readyPath");
|
|
297
|
+
expect(config.local.env).toEqual({ API_KEY: "test" });
|
|
298
|
+
expect(config.local.readyUrl).toBe("http://127.0.0.1:{port}/live");
|
|
299
|
+
});
|
|
142
300
|
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
|
|
4
|
+
export async function writeNextRuntimeTsconfig(context = {}) {
|
|
5
|
+
const serviceDir = context.cwd || context.productDir;
|
|
6
|
+
const prepareDir = context.prepareDir;
|
|
7
|
+
if (!serviceDir || !prepareDir) {
|
|
8
|
+
throw new Error("writeNextRuntimeTsconfig requires cwd and prepareDir");
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const outputPath = path.join(prepareDir, "tsconfig.json");
|
|
12
|
+
const outputDir = path.dirname(outputPath);
|
|
13
|
+
const relative = (target) => path.relative(outputDir, target).replaceAll(path.sep, "/");
|
|
14
|
+
const srcDir = path.join(serviceDir, "src");
|
|
15
|
+
const testsDir = path.join(serviceDir, "tests");
|
|
16
|
+
|
|
17
|
+
const config = {
|
|
18
|
+
extends: relative(path.join(serviceDir, "tsconfig.json")),
|
|
19
|
+
compilerOptions: {
|
|
20
|
+
paths: {
|
|
21
|
+
"@/*": [relative(path.join(srcDir, "*"))],
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
include: [
|
|
25
|
+
relative(path.join(serviceDir, "next-env.d.ts")),
|
|
26
|
+
`${relative(srcDir)}/**/*.ts`,
|
|
27
|
+
`${relative(srcDir)}/**/*.tsx`,
|
|
28
|
+
`${relative(srcDir)}/**/*.mts`,
|
|
29
|
+
`${relative(path.join(prepareDir, "dist", "types"))}/**/*.ts`,
|
|
30
|
+
`${relative(path.join(prepareDir, "dist", "dev", "types"))}/**/*.ts`,
|
|
31
|
+
],
|
|
32
|
+
exclude: [
|
|
33
|
+
"node_modules",
|
|
34
|
+
`${relative(srcDir)}/**/__testkit__/**`,
|
|
35
|
+
`${relative(testsDir)}/**`,
|
|
36
|
+
".next/cache",
|
|
37
|
+
".next/dev",
|
|
38
|
+
],
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
42
|
+
fs.writeFileSync(outputPath, `${JSON.stringify(config, null, 2)}\n`);
|
|
43
|
+
}
|