@elench/testkit 0.1.26 → 0.1.27
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 +103 -82
- package/lib/bundler/index.mjs +46 -7
- package/lib/cli/index.mjs +3 -32
- package/lib/config/discovery.mjs +209 -54
- package/lib/config/discovery.test.mjs +57 -28
- package/lib/config/index.mjs +297 -154
- package/lib/config/setup-loader.mjs +98 -0
- package/lib/index.d.ts +1 -0
- package/lib/package.test.mjs +5 -0
- package/lib/runner/template.mjs +1 -1
- package/lib/runtime-src/k6/http.js +1 -0
- package/lib/runtime-src/k6/suite.js +66 -23
- package/lib/setup/index.d.ts +104 -0
- package/lib/setup/index.mjs +292 -0
- package/lib/setup/runtime.mjs +79 -0
- package/package.json +5 -1
- package/lib/config/model.mjs +0 -320
- package/lib/config/model.test.mjs +0 -163
- package/lib/runtime-manager/index.mjs +0 -190
package/lib/config/discovery.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import path from "path";
|
|
3
3
|
|
|
4
|
+
const TESTKIT_DIRNAME = "__testkit__";
|
|
4
5
|
const DISCOVERY_RULES = [
|
|
5
6
|
{ suffix: ".int.testkit.ts", type: "integration", framework: "k6" },
|
|
6
7
|
{ suffix: ".e2e.testkit.ts", type: "e2e", framework: "k6" },
|
|
@@ -27,80 +28,98 @@ const IGNORED_DIRS = new Set([
|
|
|
27
28
|
"test-results",
|
|
28
29
|
]);
|
|
29
30
|
|
|
30
|
-
export function
|
|
31
|
-
const
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
);
|
|
35
|
-
const groupedByService = Object.fromEntries(
|
|
36
|
-
serviceEntries.map(([serviceName]) => [serviceName, {}])
|
|
37
|
-
);
|
|
38
|
-
const discoveredFiles = discoverFiles(productDir);
|
|
31
|
+
export function discoverProject(productDir, explicitServices = {}) {
|
|
32
|
+
const { suiteFiles, legacyFiles } = discoverFiles(productDir);
|
|
33
|
+
const groupedByService = {};
|
|
34
|
+
const services = {};
|
|
39
35
|
const unowned = [];
|
|
40
36
|
const ambiguous = [];
|
|
37
|
+
const discoveredSuites = [];
|
|
41
38
|
|
|
42
|
-
for (const filePath of
|
|
39
|
+
for (const filePath of suiteFiles) {
|
|
43
40
|
const rule = inferRule(filePath);
|
|
44
41
|
if (!rule) continue;
|
|
45
42
|
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
.map((serviceRule) => serviceRule.name);
|
|
49
|
-
|
|
50
|
-
if (matches.length === 0) {
|
|
43
|
+
const owners = inferOwners(filePath, explicitServices);
|
|
44
|
+
if (owners.length === 0) {
|
|
51
45
|
unowned.push(filePath);
|
|
52
46
|
continue;
|
|
53
47
|
}
|
|
54
|
-
|
|
55
|
-
if (matches.length > 1) {
|
|
48
|
+
if (owners.length > 1) {
|
|
56
49
|
ambiguous.push({
|
|
57
50
|
filePath,
|
|
58
|
-
serviceNames:
|
|
51
|
+
serviceNames: owners.map((owner) => owner.name).sort((left, right) => left.localeCompare(right)),
|
|
59
52
|
});
|
|
60
53
|
continue;
|
|
61
54
|
}
|
|
62
55
|
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
const relativeToService = relativeToServiceRoot(
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
56
|
+
const owner = owners[0];
|
|
57
|
+
services[owner.name] = mergeServiceDiscovery(services[owner.name], owner);
|
|
58
|
+
const relativeToService = relativeToServiceRoot(owner, filePath);
|
|
59
|
+
const suiteRef = deriveSuiteRef(relativeToService, rule.suffix);
|
|
60
|
+
discoveredSuites.push({
|
|
61
|
+
serviceName: owner.name,
|
|
62
|
+
type: rule.type,
|
|
63
|
+
framework: rule.framework,
|
|
64
|
+
filePath,
|
|
65
|
+
suitePath: suiteRef.suitePath,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (legacyFiles.length > 0 || unowned.length > 0 || ambiguous.length > 0) {
|
|
70
|
+
throw buildDiscoveryError(legacyFiles, unowned, ambiguous);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
for (const entry of discoveredSuites) {
|
|
74
|
+
const grouped = groupedByService[entry.serviceName] || {};
|
|
75
|
+
const suitesForType = grouped[entry.type] || [];
|
|
76
|
+
const suiteKey = entry.suitePath.join("/");
|
|
69
77
|
let suite = suitesForType.find(
|
|
70
|
-
(candidate) => candidate.
|
|
78
|
+
(candidate) => candidate._suiteKey === suiteKey && candidate.framework === entry.framework
|
|
71
79
|
);
|
|
72
80
|
|
|
73
81
|
if (!suite) {
|
|
74
82
|
suite = {
|
|
75
|
-
name:
|
|
83
|
+
name: null,
|
|
76
84
|
files: [],
|
|
77
|
-
framework:
|
|
85
|
+
framework: entry.framework,
|
|
86
|
+
_suiteKey: suiteKey,
|
|
87
|
+
_suitePath: entry.suitePath,
|
|
78
88
|
};
|
|
79
89
|
suitesForType.push(suite);
|
|
80
|
-
grouped[
|
|
90
|
+
grouped[entry.type] = suitesForType;
|
|
91
|
+
groupedByService[entry.serviceName] = grouped;
|
|
81
92
|
}
|
|
82
93
|
|
|
83
|
-
suite.files.push(filePath);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (unowned.length > 0 || ambiguous.length > 0) {
|
|
87
|
-
throw buildDiscoveryError(unowned, ambiguous);
|
|
94
|
+
suite.files.push(entry.filePath);
|
|
88
95
|
}
|
|
89
96
|
|
|
90
97
|
for (const grouped of Object.values(groupedByService)) {
|
|
91
98
|
for (const suites of Object.values(grouped)) {
|
|
99
|
+
const suiteNames = disambiguateSuiteNames(suites);
|
|
92
100
|
for (const suite of suites) {
|
|
101
|
+
suite.name = suiteNames.get(suite._suiteKey);
|
|
93
102
|
suite.files.sort((left, right) => left.localeCompare(right));
|
|
103
|
+
delete suite._suiteKey;
|
|
104
|
+
delete suite._suitePath;
|
|
94
105
|
}
|
|
95
106
|
suites.sort((left, right) => left.name.localeCompare(right.name));
|
|
96
107
|
}
|
|
97
108
|
}
|
|
98
109
|
|
|
99
|
-
return
|
|
110
|
+
return {
|
|
111
|
+
services,
|
|
112
|
+
suitesByService: groupedByService,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function discoverSuites(productDir, explicitServices = {}) {
|
|
117
|
+
return discoverProject(productDir, explicitServices).suitesByService;
|
|
100
118
|
}
|
|
101
119
|
|
|
102
120
|
function discoverFiles(productDir) {
|
|
103
|
-
const
|
|
121
|
+
const suiteFiles = [];
|
|
122
|
+
const legacyFiles = [];
|
|
104
123
|
const queue = [productDir];
|
|
105
124
|
|
|
106
125
|
while (queue.length > 0) {
|
|
@@ -119,48 +138,184 @@ function discoverFiles(productDir) {
|
|
|
119
138
|
if (!entry.isFile()) continue;
|
|
120
139
|
|
|
121
140
|
const relativePath = normalizePath(path.relative(productDir, absolutePath));
|
|
122
|
-
if (inferRule(relativePath))
|
|
141
|
+
if (!inferRule(relativePath)) continue;
|
|
142
|
+
if (relativePath.split("/").includes(TESTKIT_DIRNAME)) {
|
|
143
|
+
suiteFiles.push(relativePath);
|
|
144
|
+
} else {
|
|
145
|
+
legacyFiles.push(relativePath);
|
|
146
|
+
}
|
|
123
147
|
}
|
|
124
148
|
}
|
|
125
149
|
|
|
126
|
-
return
|
|
150
|
+
return {
|
|
151
|
+
suiteFiles: suiteFiles.sort((left, right) => left.localeCompare(right)),
|
|
152
|
+
legacyFiles: legacyFiles.sort((left, right) => left.localeCompare(right)),
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function inferOwners(filePath, explicitServices) {
|
|
157
|
+
const serviceRules = Object.entries(explicitServices).flatMap(([name, config]) =>
|
|
158
|
+
buildServiceRules(name, config)
|
|
159
|
+
);
|
|
160
|
+
if (serviceRules.length === 0) {
|
|
161
|
+
return [
|
|
162
|
+
{
|
|
163
|
+
name: "app",
|
|
164
|
+
source: "implicit-root",
|
|
165
|
+
cwdPrefix: ".",
|
|
166
|
+
},
|
|
167
|
+
];
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const owningRules = serviceRules.filter((rule) => ownsFile(rule, filePath));
|
|
171
|
+
if (owningRules.length === 0) {
|
|
172
|
+
return [];
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const maxDepth = Math.max(...owningRules.map((rule) => rule.depth));
|
|
176
|
+
return owningRules.filter((rule) => rule.depth === maxDepth);
|
|
127
177
|
}
|
|
128
178
|
|
|
129
|
-
function
|
|
130
|
-
const
|
|
179
|
+
function disambiguateSuiteNames(suites) {
|
|
180
|
+
const used = new Map();
|
|
181
|
+
const resolved = new Map();
|
|
182
|
+
|
|
183
|
+
for (const suite of suites) {
|
|
184
|
+
const pathSegments = suite._suitePath;
|
|
185
|
+
let candidate = "";
|
|
186
|
+
|
|
187
|
+
for (let depth = 1; depth <= pathSegments.length; depth += 1) {
|
|
188
|
+
candidate = pathSegments.slice(-depth).join("-");
|
|
189
|
+
const existing = used.get(candidate);
|
|
190
|
+
if (!existing) {
|
|
191
|
+
used.set(candidate, suite._suiteKey);
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
if (existing === suite._suiteKey) break;
|
|
195
|
+
candidate = "";
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (!candidate) {
|
|
199
|
+
candidate = pathSegments.join("-");
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
resolved.set(suite._suiteKey, candidate);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (resolved.size !== suites.length) {
|
|
206
|
+
for (const suite of suites) {
|
|
207
|
+
if (!resolved.has(suite._suiteKey)) {
|
|
208
|
+
resolved.set(suite._suiteKey, suite._suitePath.join("-"));
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (new Set(resolved.values()).size !== suites.length) {
|
|
214
|
+
const counts = new Map();
|
|
215
|
+
for (const suite of suites) {
|
|
216
|
+
const base = suite._suitePath.join("-");
|
|
217
|
+
const count = counts.get(base) || 0;
|
|
218
|
+
counts.set(base, count + 1);
|
|
219
|
+
resolved.set(suite._suiteKey, count === 0 ? base : `${base}-${count + 1}`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return resolved;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function buildServiceRules(serviceName, serviceConfig) {
|
|
131
227
|
const cwd = normalizePath(serviceConfig?.local?.cwd || ".");
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
228
|
+
const discoveryRoots = Array.isArray(serviceConfig?.discovery?.roots)
|
|
229
|
+
? serviceConfig.discovery.roots
|
|
230
|
+
: [cwd];
|
|
231
|
+
|
|
232
|
+
return discoveryRoots.map((root) => {
|
|
233
|
+
const normalizedRoot = normalizePath(root || ".");
|
|
234
|
+
return {
|
|
235
|
+
name: serviceName,
|
|
236
|
+
source: "cwd",
|
|
237
|
+
cwdPrefix: cwd === "." ? null : cwd,
|
|
238
|
+
matchPrefix: normalizedRoot === "." ? null : normalizedRoot,
|
|
239
|
+
depth: normalizedRoot === "." ? 0 : normalizedRoot.split("/").filter(Boolean).length,
|
|
240
|
+
};
|
|
241
|
+
});
|
|
137
242
|
}
|
|
138
243
|
|
|
139
244
|
function ownsFile(serviceRule, filePath) {
|
|
140
|
-
if (
|
|
141
|
-
if (serviceRule.
|
|
245
|
+
if (serviceRule.depth === 0) return true;
|
|
246
|
+
if (serviceRule.matchPrefix && hasPrefix(filePath, serviceRule.matchPrefix)) return true;
|
|
142
247
|
return false;
|
|
143
248
|
}
|
|
144
249
|
|
|
145
250
|
function relativeToServiceRoot(serviceRule, filePath) {
|
|
146
|
-
if (hasPrefix(filePath, serviceRule.testPrefix)) {
|
|
147
|
-
return path.posix.relative(serviceRule.testPrefix, filePath);
|
|
148
|
-
}
|
|
149
251
|
if (serviceRule.cwdPrefix && hasPrefix(filePath, serviceRule.cwdPrefix)) {
|
|
150
252
|
return path.posix.relative(serviceRule.cwdPrefix, filePath);
|
|
151
253
|
}
|
|
152
254
|
return filePath;
|
|
153
255
|
}
|
|
154
256
|
|
|
155
|
-
function
|
|
257
|
+
function deriveSuiteRef(relativePath, suffix) {
|
|
156
258
|
const parts = relativePath.split("/").filter(Boolean);
|
|
157
|
-
|
|
158
|
-
|
|
259
|
+
const testkitIndex = parts.indexOf(TESTKIT_DIRNAME);
|
|
260
|
+
if (testkitIndex === -1) {
|
|
261
|
+
const fallback = path.posix.basename(relativePath, suffix);
|
|
262
|
+
return {
|
|
263
|
+
suitePath: [fallback],
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const before = parts.slice(0, testkitIndex);
|
|
268
|
+
const after = parts.slice(testkitIndex + 1);
|
|
269
|
+
if (after.length === 0) {
|
|
270
|
+
const fallback = path.posix.basename(relativePath, suffix);
|
|
271
|
+
return {
|
|
272
|
+
suitePath: [fallback],
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (after.length === 1) {
|
|
277
|
+
if (before.length === 0) {
|
|
278
|
+
return {
|
|
279
|
+
suitePath: [path.posix.basename(after[0], suffix)],
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
return {
|
|
283
|
+
suitePath: before,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return {
|
|
288
|
+
suitePath: [...before, after[0]],
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function mergeServiceDiscovery(existing, owner) {
|
|
293
|
+
if (!existing) {
|
|
294
|
+
return {
|
|
295
|
+
name: owner.name,
|
|
296
|
+
inferredLocalCwd: owner.cwdPrefix || ".",
|
|
297
|
+
source: owner.source,
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return {
|
|
302
|
+
...existing,
|
|
303
|
+
inferredLocalCwd:
|
|
304
|
+
existing.inferredLocalCwd === "." ? owner.cwdPrefix || "." : existing.inferredLocalCwd,
|
|
305
|
+
};
|
|
159
306
|
}
|
|
160
307
|
|
|
161
|
-
function buildDiscoveryError(unowned, ambiguous) {
|
|
308
|
+
function buildDiscoveryError(legacyFiles, unowned, ambiguous) {
|
|
162
309
|
const lines = ["Filesystem discovery failed for one or more .testkit.ts files."];
|
|
163
310
|
|
|
311
|
+
if (legacyFiles.length > 0) {
|
|
312
|
+
lines.push("");
|
|
313
|
+
lines.push("Legacy test files outside __testkit__:");
|
|
314
|
+
for (const filePath of legacyFiles) {
|
|
315
|
+
lines.push(`- ${filePath}`);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
164
319
|
if (unowned.length > 0) {
|
|
165
320
|
lines.push("");
|
|
166
321
|
lines.push("Unowned test files:");
|
|
@@ -178,7 +333,7 @@ function buildDiscoveryError(unowned, ambiguous) {
|
|
|
178
333
|
}
|
|
179
334
|
|
|
180
335
|
lines.push("");
|
|
181
|
-
lines.push('Expected test files to live under "
|
|
336
|
+
lines.push('Expected test files to live under a "__testkit__" directory within a service root.');
|
|
182
337
|
return new Error(lines.join("\n"));
|
|
183
338
|
}
|
|
184
339
|
|
|
@@ -2,7 +2,7 @@ import fs from "fs";
|
|
|
2
2
|
import os from "os";
|
|
3
3
|
import path from "path";
|
|
4
4
|
import { afterEach, describe, expect, it } from "vitest";
|
|
5
|
-
import { discoverSuites } from "./discovery.mjs";
|
|
5
|
+
import { discoverProject, discoverSuites } from "./discovery.mjs";
|
|
6
6
|
|
|
7
7
|
const cleanups = [];
|
|
8
8
|
|
|
@@ -13,13 +13,13 @@ afterEach(() => {
|
|
|
13
13
|
});
|
|
14
14
|
|
|
15
15
|
describe("filesystem-discovery", () => {
|
|
16
|
-
it("discovers
|
|
16
|
+
it("discovers colocated __testkit__ suites by service root", () => {
|
|
17
17
|
const productDir = fs.mkdtempSync(path.join(os.tmpdir(), "testkit-discovery-"));
|
|
18
18
|
cleanups.push(() => fs.rmSync(productDir, { recursive: true, force: true }));
|
|
19
19
|
|
|
20
|
-
writeFile(productDir, "
|
|
21
|
-
writeFile(productDir, "
|
|
22
|
-
writeFile(productDir, "frontend/
|
|
20
|
+
writeFile(productDir, "src/api/routes/__testkit__/auth/me.int.testkit.ts");
|
|
21
|
+
writeFile(productDir, "src/api/routes/__testkit__/health/ready.int.testkit.ts");
|
|
22
|
+
writeFile(productDir, "frontend/app/__testkit__/homepage/homepage.pw.testkit.ts");
|
|
23
23
|
|
|
24
24
|
const suites = discoverSuites(productDir, {
|
|
25
25
|
api: {
|
|
@@ -37,61 +37,90 @@ describe("filesystem-discovery", () => {
|
|
|
37
37
|
expect(suites.api.integration).toEqual([
|
|
38
38
|
{
|
|
39
39
|
name: "auth",
|
|
40
|
-
files: ["
|
|
40
|
+
files: ["src/api/routes/__testkit__/auth/me.int.testkit.ts"],
|
|
41
41
|
framework: "k6",
|
|
42
42
|
},
|
|
43
43
|
{
|
|
44
44
|
name: "health",
|
|
45
|
-
files: ["
|
|
45
|
+
files: ["src/api/routes/__testkit__/health/ready.int.testkit.ts"],
|
|
46
46
|
framework: "k6",
|
|
47
47
|
},
|
|
48
48
|
]);
|
|
49
49
|
expect(suites.frontend.e2e).toEqual([
|
|
50
50
|
{
|
|
51
51
|
name: "homepage",
|
|
52
|
-
files: ["frontend/
|
|
52
|
+
files: ["frontend/app/__testkit__/homepage/homepage.pw.testkit.ts"],
|
|
53
53
|
framework: "playwright",
|
|
54
54
|
},
|
|
55
55
|
]);
|
|
56
56
|
});
|
|
57
57
|
|
|
58
|
-
it("
|
|
58
|
+
it("infers the suite from the directory that owns __testkit__", () => {
|
|
59
59
|
const productDir = fs.mkdtempSync(path.join(os.tmpdir(), "testkit-discovery-"));
|
|
60
60
|
cleanups.push(() => fs.rmSync(productDir, { recursive: true, force: true }));
|
|
61
61
|
|
|
62
|
-
writeFile(productDir, "
|
|
62
|
+
writeFile(productDir, "src/services/search/__testkit__/query/validation.int.testkit.ts");
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
cwd: ".",
|
|
69
|
-
},
|
|
64
|
+
const project = discoverProject(productDir, {
|
|
65
|
+
api: {
|
|
66
|
+
local: {
|
|
67
|
+
cwd: ".",
|
|
70
68
|
},
|
|
71
|
-
}
|
|
72
|
-
)
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
expect(project.services.api).toMatchObject({
|
|
72
|
+
name: "api",
|
|
73
|
+
inferredLocalCwd: ".",
|
|
74
|
+
});
|
|
75
|
+
expect(project.suitesByService.api.integration[0]).toMatchObject({
|
|
76
|
+
name: "query",
|
|
77
|
+
files: ["src/services/search/__testkit__/query/validation.int.testkit.ts"],
|
|
78
|
+
framework: "k6",
|
|
79
|
+
});
|
|
73
80
|
});
|
|
74
81
|
|
|
75
|
-
it("
|
|
82
|
+
it("prefers the deepest matching service root", () => {
|
|
76
83
|
const productDir = fs.mkdtempSync(path.join(os.tmpdir(), "testkit-discovery-"));
|
|
77
84
|
cleanups.push(() => fs.rmSync(productDir, { recursive: true, force: true }));
|
|
78
85
|
|
|
79
|
-
writeFile(productDir, "frontend/
|
|
86
|
+
writeFile(productDir, "frontend/app/__testkit__/billing/lifecycle.pw.testkit.ts");
|
|
87
|
+
|
|
88
|
+
const project = discoverProject(productDir, {
|
|
89
|
+
app: {
|
|
90
|
+
local: {
|
|
91
|
+
cwd: ".",
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
frontend: {
|
|
95
|
+
local: {
|
|
96
|
+
cwd: "frontend",
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
expect(project.suitesByService.app).toBeUndefined();
|
|
102
|
+
expect(project.suitesByService.frontend.e2e[0]).toMatchObject({
|
|
103
|
+
name: "billing",
|
|
104
|
+
files: ["frontend/app/__testkit__/billing/lifecycle.pw.testkit.ts"],
|
|
105
|
+
framework: "playwright",
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("fails on legacy files outside __testkit__", () => {
|
|
110
|
+
const productDir = fs.mkdtempSync(path.join(os.tmpdir(), "testkit-discovery-"));
|
|
111
|
+
cleanups.push(() => fs.rmSync(productDir, { recursive: true, force: true }));
|
|
112
|
+
|
|
113
|
+
writeFile(productDir, "tests/api/integration/health.int.testkit.ts");
|
|
80
114
|
|
|
81
115
|
expect(() =>
|
|
82
116
|
discoverSuites(productDir, {
|
|
83
|
-
|
|
84
|
-
local: {
|
|
85
|
-
cwd: "frontend",
|
|
86
|
-
},
|
|
87
|
-
},
|
|
88
|
-
web: {
|
|
117
|
+
api: {
|
|
89
118
|
local: {
|
|
90
|
-
cwd: "
|
|
119
|
+
cwd: ".",
|
|
91
120
|
},
|
|
92
121
|
},
|
|
93
122
|
})
|
|
94
|
-
).toThrow("
|
|
123
|
+
).toThrow("Legacy test files outside __testkit__");
|
|
95
124
|
});
|
|
96
125
|
});
|
|
97
126
|
|