@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
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
2
|
import {
|
|
3
3
|
normalizeBrowserServiceConfig,
|
|
4
|
+
normalizeRuntimeConfig,
|
|
4
5
|
normalizeRuntimePrepareConfig,
|
|
5
6
|
normalizeTemplateLifecycleStep,
|
|
6
7
|
normalizeTemplateStepInputs,
|
|
@@ -45,6 +46,31 @@ describe("config runtime helpers", () => {
|
|
|
45
46
|
});
|
|
46
47
|
});
|
|
47
48
|
|
|
49
|
+
it("folds declarative runtime.build into runtime.prepare", () => {
|
|
50
|
+
expect(
|
|
51
|
+
normalizeRuntimeConfig(
|
|
52
|
+
{
|
|
53
|
+
build: {
|
|
54
|
+
kind: "tsc",
|
|
55
|
+
entry: "src/server.ts",
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
"api",
|
|
59
|
+
{}
|
|
60
|
+
)
|
|
61
|
+
).toMatchObject({
|
|
62
|
+
build: {
|
|
63
|
+
kind: "tsc",
|
|
64
|
+
entry: "src/server.ts",
|
|
65
|
+
tsconfig: "tsconfig.json",
|
|
66
|
+
outDir: "dist",
|
|
67
|
+
},
|
|
68
|
+
prepare: {
|
|
69
|
+
inputs: ["tsconfig.json", "package.json", "src"],
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
48
74
|
it("rejects malformed lifecycle steps and empty step inputs", () => {
|
|
49
75
|
expect(() => normalizeTemplateLifecycleStep({ kind: "module" }, "runtime.prepare.steps[0]")).toThrow(
|
|
50
76
|
/specifier must be a non-empty string/
|
|
@@ -19,13 +19,15 @@ describe("coverage graph builder", () => {
|
|
|
19
19
|
productDir,
|
|
20
20
|
"testkit.setup.ts",
|
|
21
21
|
`
|
|
22
|
-
import { defineTestkitSetup,
|
|
22
|
+
import { defineTestkitSetup, nextApp } from "@elench/testkit/setup";
|
|
23
23
|
|
|
24
24
|
export default defineTestkitSetup({
|
|
25
25
|
services: {
|
|
26
|
-
web:
|
|
26
|
+
web: nextApp({
|
|
27
27
|
cwd: ".",
|
|
28
28
|
start: "node server.js",
|
|
29
|
+
mode: "start",
|
|
30
|
+
build: null,
|
|
29
31
|
baseUrl: "http://127.0.0.1:3000",
|
|
30
32
|
readyUrl: "http://127.0.0.1:3000"
|
|
31
33
|
})
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import ts from "typescript";
|
|
4
|
+
|
|
5
|
+
export function loadTestFileMetadataMap(productDir, suitesByService = {}) {
|
|
6
|
+
const metadataByPath = new Map();
|
|
7
|
+
|
|
8
|
+
for (const suites of Object.values(suitesByService || {})) {
|
|
9
|
+
for (const suiteList of Object.values(suites || {})) {
|
|
10
|
+
for (const suite of suiteList || []) {
|
|
11
|
+
for (const filePath of suite.files || []) {
|
|
12
|
+
if (metadataByPath.has(filePath)) continue;
|
|
13
|
+
metadataByPath.set(filePath, readTestFileMetadata(productDir, filePath));
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return metadataByPath;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function readTestFileMetadata(productDir, filePath) {
|
|
23
|
+
const absolutePath = path.join(productDir, filePath);
|
|
24
|
+
if (!fs.existsSync(absolutePath)) {
|
|
25
|
+
return emptyMetadata();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const sourceText = fs.readFileSync(absolutePath, "utf8");
|
|
29
|
+
const sourceFile = ts.createSourceFile(absolutePath, sourceText, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
30
|
+
|
|
31
|
+
for (const statement of sourceFile.statements) {
|
|
32
|
+
if (!ts.isVariableStatement(statement) || !hasExportModifier(statement)) continue;
|
|
33
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
34
|
+
if (!ts.isIdentifier(declaration.name) || declaration.name.text !== "testkit") continue;
|
|
35
|
+
const config = parseMetadataInitializer(declaration.initializer);
|
|
36
|
+
if (config) return config;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return emptyMetadata();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function parseMetadataInitializer(initializer) {
|
|
44
|
+
if (!initializer) return null;
|
|
45
|
+
if (ts.isCallExpression(initializer)) {
|
|
46
|
+
const callee = getCallIdentifier(initializer.expression);
|
|
47
|
+
if (callee === "defineTestkitFile" && initializer.arguments[0] && ts.isObjectLiteralExpression(initializer.arguments[0])) {
|
|
48
|
+
return parseMetadataObject(initializer.arguments[0]);
|
|
49
|
+
}
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
if (ts.isObjectLiteralExpression(initializer)) {
|
|
53
|
+
return parseMetadataObject(initializer);
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function parseMetadataObject(node) {
|
|
59
|
+
const metadata = emptyMetadata();
|
|
60
|
+
|
|
61
|
+
for (const property of node.properties) {
|
|
62
|
+
if (!ts.isPropertyAssignment(property)) continue;
|
|
63
|
+
const key = getPropertyName(property.name);
|
|
64
|
+
if (key === "locks") {
|
|
65
|
+
metadata.locks = parseLocks(property.initializer);
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (key === "skip") {
|
|
69
|
+
metadata.skipReason = parseSkipReason(property.initializer);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return metadata;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function parseLocks(node) {
|
|
77
|
+
if (!ts.isArrayLiteralExpression(node)) return [];
|
|
78
|
+
const values = [];
|
|
79
|
+
for (const entry of node.elements) {
|
|
80
|
+
const value = readStringLiteral(entry);
|
|
81
|
+
if (value) values.push(value);
|
|
82
|
+
}
|
|
83
|
+
return [...new Set(values)].sort();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function parseSkipReason(node) {
|
|
87
|
+
const literal = readStringLiteral(node);
|
|
88
|
+
if (literal) return literal;
|
|
89
|
+
if (!ts.isObjectLiteralExpression(node)) return null;
|
|
90
|
+
for (const property of node.properties) {
|
|
91
|
+
if (!ts.isPropertyAssignment(property)) continue;
|
|
92
|
+
if (getPropertyName(property.name) !== "reason") continue;
|
|
93
|
+
return readStringLiteral(property.initializer) || null;
|
|
94
|
+
}
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function getCallIdentifier(node) {
|
|
99
|
+
if (ts.isIdentifier(node)) return node.text;
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function getPropertyName(node) {
|
|
104
|
+
if (ts.isIdentifier(node) || ts.isStringLiteral(node)) return node.text;
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function readStringLiteral(node) {
|
|
109
|
+
if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) return node.text;
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function hasExportModifier(node) {
|
|
114
|
+
return (node.modifiers || []).some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function emptyMetadata() {
|
|
118
|
+
return {
|
|
119
|
+
locks: [],
|
|
120
|
+
skipReason: null,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import os from "os";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { afterEach, describe, expect, it } from "vitest";
|
|
5
|
+
import { readTestFileMetadata } from "./file-metadata.mjs";
|
|
6
|
+
|
|
7
|
+
const tempDirs = [];
|
|
8
|
+
|
|
9
|
+
afterEach(() => {
|
|
10
|
+
for (const dir of tempDirs.splice(0)) {
|
|
11
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
describe("test file metadata", () => {
|
|
16
|
+
it("reads exported testkit metadata from object literals and helper calls", () => {
|
|
17
|
+
const productDir = fs.mkdtempSync(path.join(os.tmpdir(), "testkit-file-meta-"));
|
|
18
|
+
tempDirs.push(productDir);
|
|
19
|
+
fs.mkdirSync(path.join(productDir, "__testkit__"), { recursive: true });
|
|
20
|
+
fs.writeFileSync(
|
|
21
|
+
path.join(productDir, "__testkit__", "billing.int.testkit.ts"),
|
|
22
|
+
[
|
|
23
|
+
'import { defineTestkitFile } from "@elench/testkit/setup";',
|
|
24
|
+
'export const testkit = defineTestkitFile({',
|
|
25
|
+
' skip: "Billing is stubbed locally",',
|
|
26
|
+
' locks: ["background-workers", "background-workers"],',
|
|
27
|
+
"});",
|
|
28
|
+
].join("\n")
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
expect(readTestFileMetadata(productDir, "__testkit__/billing.int.testkit.ts")).toEqual({
|
|
32
|
+
skipReason: "Billing is stubbed locally",
|
|
33
|
+
locks: ["background-workers"],
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("returns empty metadata when no export is present", () => {
|
|
38
|
+
const productDir = fs.mkdtempSync(path.join(os.tmpdir(), "testkit-file-meta-"));
|
|
39
|
+
tempDirs.push(productDir);
|
|
40
|
+
fs.mkdirSync(path.join(productDir, "__testkit__"), { recursive: true });
|
|
41
|
+
fs.writeFileSync(
|
|
42
|
+
path.join(productDir, "__testkit__", "health.int.testkit.ts"),
|
|
43
|
+
"export default {};\n"
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
expect(readTestFileMetadata(productDir, "__testkit__/health.int.testkit.ts")).toEqual({
|
|
47
|
+
skipReason: null,
|
|
48
|
+
locks: [],
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
});
|
package/lib/discovery/index.mjs
CHANGED
|
@@ -207,8 +207,16 @@ function buildResolvedSuiteEntries(config, suite, internalType, filters) {
|
|
|
207
207
|
|
|
208
208
|
for (const filePath of suite.files || []) {
|
|
209
209
|
if (filters.fileNameSet.size > 0 && !filters.fileNameSet.has(filePath)) continue;
|
|
210
|
-
const
|
|
211
|
-
const
|
|
210
|
+
const fileMetadata = config.testkit.fileMetadataByPath?.get(filePath) || { locks: [], skipReason: null };
|
|
211
|
+
const fileLocks = [
|
|
212
|
+
...(config.testkit.requirements?.fileLocksByPath?.get(filePath) || []),
|
|
213
|
+
...(fileMetadata.locks || []),
|
|
214
|
+
];
|
|
215
|
+
const skipReason =
|
|
216
|
+
fileMetadata.skipReason ||
|
|
217
|
+
config.testkit.skip?.fileReasonByPath?.get(filePath) ||
|
|
218
|
+
suiteSkipReason ||
|
|
219
|
+
null;
|
|
212
220
|
const skipped = Boolean(skipReason);
|
|
213
221
|
if (filters.runnableOnly && skipped) continue;
|
|
214
222
|
visibleFiles.push({
|
|
@@ -30,14 +30,6 @@ describe("public discovery", () => {
|
|
|
30
30
|
start: "node server.js",
|
|
31
31
|
baseUrl: "http://127.0.0.1:3000",
|
|
32
32
|
readyUrl: "http://127.0.0.1:3000"
|
|
33
|
-
},
|
|
34
|
-
requirements: {
|
|
35
|
-
files: [
|
|
36
|
-
{
|
|
37
|
-
path: "src/api/routes/__testkit__/agent-configs-auth-gate.int.testkit.ts",
|
|
38
|
-
locks: ["route-lock"]
|
|
39
|
-
}
|
|
40
|
-
]
|
|
41
33
|
}
|
|
42
34
|
},
|
|
43
35
|
frontend: {
|
|
@@ -47,22 +39,30 @@ describe("public discovery", () => {
|
|
|
47
39
|
baseUrl: "http://127.0.0.1:3001",
|
|
48
40
|
readyUrl: "http://127.0.0.1:3001"
|
|
49
41
|
},
|
|
50
|
-
dependsOn: ["api"]
|
|
51
|
-
skip: {
|
|
52
|
-
files: [
|
|
53
|
-
{
|
|
54
|
-
path: "frontend/src/app/login/__testkit__/auth.pw.testkit.ts",
|
|
55
|
-
reason: "Auth is stubbed locally"
|
|
56
|
-
}
|
|
57
|
-
]
|
|
58
|
-
}
|
|
42
|
+
dependsOn: ["api"]
|
|
59
43
|
}
|
|
60
44
|
}
|
|
61
45
|
});
|
|
62
46
|
`
|
|
63
47
|
);
|
|
64
|
-
writeFile(
|
|
65
|
-
|
|
48
|
+
writeFile(
|
|
49
|
+
productDir,
|
|
50
|
+
"src/api/routes/__testkit__/agent-configs-auth-gate.int.testkit.ts",
|
|
51
|
+
[
|
|
52
|
+
'import { defineTestkitFile } from "@elench/testkit/setup";',
|
|
53
|
+
'export const testkit = defineTestkitFile({ locks: ["route-lock"] });',
|
|
54
|
+
"export {};",
|
|
55
|
+
].join("\n")
|
|
56
|
+
);
|
|
57
|
+
writeFile(
|
|
58
|
+
productDir,
|
|
59
|
+
"frontend/src/app/login/__testkit__/auth.pw.testkit.ts",
|
|
60
|
+
[
|
|
61
|
+
'import { defineTestkitFile } from "@elench/testkit/setup";',
|
|
62
|
+
'export const testkit = defineTestkitFile({ skip: "Auth is stubbed locally" });',
|
|
63
|
+
"export {};",
|
|
64
|
+
].join("\n")
|
|
65
|
+
);
|
|
66
66
|
|
|
67
67
|
saveHistory(productDir, {
|
|
68
68
|
version: 1,
|
package/lib/runner/planning.mjs
CHANGED
|
@@ -223,14 +223,15 @@ function applySkipRules(config, displayType, suiteName, files, opts = {}) {
|
|
|
223
223
|
};
|
|
224
224
|
}
|
|
225
225
|
const skip = config.testkit?.skip;
|
|
226
|
-
|
|
226
|
+
const metadataByPath = config.testkit?.fileMetadataByPath || null;
|
|
227
|
+
if (!skip && !metadataByPath) {
|
|
227
228
|
return {
|
|
228
229
|
files,
|
|
229
230
|
skippedFiles: [],
|
|
230
231
|
};
|
|
231
232
|
}
|
|
232
233
|
|
|
233
|
-
const matchingSuiteRules = skip
|
|
234
|
+
const matchingSuiteRules = (skip?.suites || []).filter((rule) =>
|
|
234
235
|
matchesSuiteSelectors(displayType, suiteName, [rule.selector])
|
|
235
236
|
);
|
|
236
237
|
const suiteReason = matchingSuiteRules[0]?.reason || null;
|
|
@@ -239,7 +240,9 @@ function applySkipRules(config, displayType, suiteName, files, opts = {}) {
|
|
|
239
240
|
|
|
240
241
|
for (const file of files) {
|
|
241
242
|
const normalizedFile = normalizePathSeparators(file);
|
|
242
|
-
const
|
|
243
|
+
const fileMetadata = config.testkit.fileMetadataByPath?.get(normalizedFile) || null;
|
|
244
|
+
const reason =
|
|
245
|
+
fileMetadata?.skipReason || skip?.fileReasonByPath?.get(normalizedFile) || suiteReason;
|
|
243
246
|
if (reason) {
|
|
244
247
|
skippedFiles.push({
|
|
245
248
|
path: normalizedFile,
|
|
@@ -268,9 +271,13 @@ function resolveTaskLocks(config, suite, file) {
|
|
|
268
271
|
}
|
|
269
272
|
|
|
270
273
|
const normalizedFile = normalizePathSeparators(file);
|
|
274
|
+
const fileMetadata = config.testkit.fileMetadataByPath?.get(normalizedFile) || null;
|
|
271
275
|
for (const lockName of config.testkit.requirements?.fileLocksByPath?.get(normalizedFile) || []) {
|
|
272
276
|
locks.add(lockName);
|
|
273
277
|
}
|
|
278
|
+
for (const lockName of fileMetadata?.locks || []) {
|
|
279
|
+
locks.add(lockName);
|
|
280
|
+
}
|
|
274
281
|
|
|
275
282
|
return [...locks].sort();
|
|
276
283
|
}
|
|
@@ -138,6 +138,32 @@ describe("runner-planning", () => {
|
|
|
138
138
|
]);
|
|
139
139
|
});
|
|
140
140
|
|
|
141
|
+
it("does not require repo-level skip config when file metadata is present", () => {
|
|
142
|
+
const config = makeConfig("api", {
|
|
143
|
+
suites: {
|
|
144
|
+
integration: [
|
|
145
|
+
{
|
|
146
|
+
name: "health",
|
|
147
|
+
files: ["__testkit__/health/health.int.testkit.ts"],
|
|
148
|
+
},
|
|
149
|
+
],
|
|
150
|
+
},
|
|
151
|
+
testkit: {
|
|
152
|
+
fileMetadataByPath: new Map([
|
|
153
|
+
["__testkit__/health/health.int.testkit.ts", { skipReason: null, locks: [] }],
|
|
154
|
+
]),
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
expect(collectSuites(config, ["int"], [], [])).toEqual([
|
|
159
|
+
expect.objectContaining({
|
|
160
|
+
name: "health",
|
|
161
|
+
files: ["__testkit__/health/health.int.testkit.ts"],
|
|
162
|
+
skippedFiles: [],
|
|
163
|
+
}),
|
|
164
|
+
]);
|
|
165
|
+
});
|
|
166
|
+
|
|
141
167
|
it("applies lock requirements to matching suites and files", () => {
|
|
142
168
|
const api = makeConfig("api", {
|
|
143
169
|
suites: {
|
|
@@ -21,6 +21,12 @@ import {
|
|
|
21
21
|
const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
22
22
|
const ROOT_ENTRY = path.join(PACKAGE_ROOT, "lib", "index.mjs");
|
|
23
23
|
const SETUP_ENTRY = path.join(PACKAGE_ROOT, "lib", "setup", "index.mjs");
|
|
24
|
+
const SETUP_NEXT_TSCONFIG_ENTRY = path.join(
|
|
25
|
+
PACKAGE_ROOT,
|
|
26
|
+
"lib",
|
|
27
|
+
"setup",
|
|
28
|
+
"next-runtime-tsconfig.mjs"
|
|
29
|
+
);
|
|
24
30
|
const RUNTIME_ENTRY = path.join(PACKAGE_ROOT, "lib", "runtime", "index.mjs");
|
|
25
31
|
const KNOWN_FAILURES_ENTRY = path.join(PACKAGE_ROOT, "lib", "known-failures", "index.mjs");
|
|
26
32
|
const MODULE_RUNNER_ENTRY = path.join(
|
|
@@ -225,6 +231,7 @@ function resolvePackageSubpath(specifier) {
|
|
|
225
231
|
const subpath = specifier.slice("@elench/testkit".length);
|
|
226
232
|
if (!subpath) return ROOT_ENTRY;
|
|
227
233
|
if (subpath === "/setup") return SETUP_ENTRY;
|
|
234
|
+
if (subpath === "/setup/next-runtime-tsconfig") return SETUP_NEXT_TSCONFIG_ENTRY;
|
|
228
235
|
if (subpath === "/runtime") return RUNTIME_ENTRY;
|
|
229
236
|
if (subpath === "/known-failures") return KNOWN_FAILURES_ENTRY;
|
|
230
237
|
|
package/lib/setup/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export interface DatabaseTemplateConfig {
|
|
|
7
7
|
verify?: TemplateLifecycleStepConfig[];
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
export interface
|
|
10
|
+
export interface DatabaseTemplateOptions {
|
|
11
11
|
inputs?: string[];
|
|
12
12
|
schema?: string | TemplateSqlFileStepConfig;
|
|
13
13
|
migrate?: TemplateLifecycleStepConfig | TemplateLifecycleStepConfig[];
|
|
@@ -40,6 +40,38 @@ export type TemplateLifecycleStepConfig =
|
|
|
40
40
|
| TemplateSqlFileStepConfig
|
|
41
41
|
| TemplateModuleStepConfig;
|
|
42
42
|
|
|
43
|
+
export interface TscBuildConfig {
|
|
44
|
+
kind: "tsc";
|
|
45
|
+
cwd?: string;
|
|
46
|
+
entry?: string;
|
|
47
|
+
inputs?: string[];
|
|
48
|
+
outDir?: string;
|
|
49
|
+
tsconfig?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface ScriptBuildConfig {
|
|
53
|
+
kind: "script";
|
|
54
|
+
cwd?: string;
|
|
55
|
+
inputs?: string[];
|
|
56
|
+
script: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface NextBuildConfig {
|
|
60
|
+
kind: "next";
|
|
61
|
+
cwd?: string;
|
|
62
|
+
distDir?: string;
|
|
63
|
+
inputs?: string[];
|
|
64
|
+
tsconfig?: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface StepsBuildConfig {
|
|
68
|
+
kind: "steps";
|
|
69
|
+
inputs?: string[];
|
|
70
|
+
steps?: TemplateLifecycleStepConfig[];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export type BuildConfig = TscBuildConfig | ScriptBuildConfig | NextBuildConfig | StepsBuildConfig;
|
|
74
|
+
|
|
43
75
|
export interface LocalDatabaseConfig {
|
|
44
76
|
provider: "local";
|
|
45
77
|
binding?: "shared" | "per-runtime";
|
|
@@ -66,6 +98,7 @@ export interface SkipConfig {
|
|
|
66
98
|
}
|
|
67
99
|
|
|
68
100
|
export interface RuntimeConfig {
|
|
101
|
+
build?: BuildConfig | null;
|
|
69
102
|
instances?: number;
|
|
70
103
|
maxConcurrentTasks?: number;
|
|
71
104
|
prepare?: {
|
|
@@ -144,6 +177,44 @@ export interface ServiceConfig {
|
|
|
144
177
|
skip?: SkipConfig;
|
|
145
178
|
}
|
|
146
179
|
|
|
180
|
+
export interface TestkitFileMetadata {
|
|
181
|
+
locks?: string[];
|
|
182
|
+
skip?: string | { reason: string };
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export interface NodeAppOptions extends Omit<ServiceConfig, "local" | "runtime"> {
|
|
186
|
+
baseUrl?: string;
|
|
187
|
+
build?: BuildConfig | null;
|
|
188
|
+
buildInputs?: string[];
|
|
189
|
+
cwd?: string;
|
|
190
|
+
entry?: string;
|
|
191
|
+
env?: Record<string, string>;
|
|
192
|
+
outDir?: string;
|
|
193
|
+
port: number;
|
|
194
|
+
readyPath?: string;
|
|
195
|
+
readyTimeoutMs?: number;
|
|
196
|
+
readyUrl?: string;
|
|
197
|
+
runtime?: Omit<RuntimeConfig, "build">;
|
|
198
|
+
start?: string;
|
|
199
|
+
toolchain?: string | NodeToolchainConfig;
|
|
200
|
+
tsconfig?: string;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export interface NextAppOptions extends Omit<ServiceConfig, "local" | "runtime"> {
|
|
204
|
+
baseUrl?: string;
|
|
205
|
+
build?: BuildConfig | null;
|
|
206
|
+
buildInputs?: string[];
|
|
207
|
+
cwd?: string;
|
|
208
|
+
env?: Record<string, string>;
|
|
209
|
+
mode?: "dev" | "start";
|
|
210
|
+
port: number;
|
|
211
|
+
readyTimeoutMs?: number;
|
|
212
|
+
readyUrl?: string;
|
|
213
|
+
runtime?: Omit<RuntimeConfig, "build">;
|
|
214
|
+
start?: string;
|
|
215
|
+
toolchain?: string | NodeToolchainConfig;
|
|
216
|
+
}
|
|
217
|
+
|
|
147
218
|
export interface TestkitSetup {
|
|
148
219
|
discovery?: DiscoveryConfig;
|
|
149
220
|
execution?: TestkitExecutionConfig;
|
|
@@ -166,8 +237,8 @@ export interface TestkitSetup {
|
|
|
166
237
|
|
|
167
238
|
export declare function defineTestkitSetup<T extends TestkitSetup>(setup: T): T;
|
|
168
239
|
export declare function defineHttpProfile<T extends HttpSuiteConfig>(profile: T): T;
|
|
169
|
-
export declare function
|
|
170
|
-
export declare function
|
|
240
|
+
export declare function defineTestkitFile<T extends TestkitFileMetadata>(metadata: T): T;
|
|
241
|
+
export declare function postgresDatabase(options?: Omit<LocalDatabaseConfig, "provider">): LocalDatabaseConfig;
|
|
171
242
|
export declare function commandStep(
|
|
172
243
|
cmd: string,
|
|
173
244
|
options?: Omit<TemplateCommandStepConfig, "kind" | "cmd">
|
|
@@ -200,24 +271,29 @@ export declare function verifyModule(
|
|
|
200
271
|
specifier: string,
|
|
201
272
|
options?: Omit<TemplateModuleStepConfig, "kind" | "specifier">
|
|
202
273
|
): TemplateModuleStepConfig;
|
|
203
|
-
export declare function
|
|
204
|
-
options?:
|
|
205
|
-
):
|
|
274
|
+
export declare function templateDatabase(
|
|
275
|
+
options?: DatabaseTemplateOptions & Omit<LocalDatabaseConfig, "provider" | "template">
|
|
276
|
+
): LocalDatabaseConfig;
|
|
277
|
+
export declare function postgresFixture(
|
|
278
|
+
options?: Omit<LocalDatabaseConfig, "provider"> & {
|
|
279
|
+
discovery?: DiscoveryConfig;
|
|
280
|
+
envFiles?: string[];
|
|
281
|
+
}
|
|
282
|
+
): ServiceConfig;
|
|
283
|
+
export declare function databaseServiceEnv(
|
|
284
|
+
prefix: string,
|
|
285
|
+
serviceName: string
|
|
286
|
+
): Record<string, string>;
|
|
206
287
|
export declare function nodeToolchain(options?: NodeToolchainConfig): NodeToolchainConfig;
|
|
207
|
-
export declare function
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
export declare function
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
export declare function tsxService(options: ServiceConfig["local"] & {
|
|
217
|
-
entry?: string;
|
|
218
|
-
envFiles?: string[];
|
|
219
|
-
readyPath?: string;
|
|
220
|
-
}): ServiceConfig;
|
|
288
|
+
export declare function tscBuild(options?: Omit<TscBuildConfig, "kind">): TscBuildConfig;
|
|
289
|
+
export declare function scriptBuild(
|
|
290
|
+
script: string,
|
|
291
|
+
options?: Omit<ScriptBuildConfig, "kind" | "script">
|
|
292
|
+
): ScriptBuildConfig;
|
|
293
|
+
export declare function stepsBuild(options?: Omit<StepsBuildConfig, "kind">): StepsBuildConfig;
|
|
294
|
+
export declare function nextBuild(options?: Omit<NextBuildConfig, "kind">): NextBuildConfig;
|
|
295
|
+
export declare function nodeApp(options: NodeAppOptions): ServiceConfig;
|
|
296
|
+
export declare function nextApp(options: NextAppOptions): ServiceConfig;
|
|
221
297
|
export declare function clerkSessionProfile(options?: {
|
|
222
298
|
apiBase?: string;
|
|
223
299
|
needsAuth?: boolean;
|