@elench/testkit 0.1.17 → 0.1.19

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.
Files changed (53) hide show
  1. package/README.md +76 -16
  2. package/bin/testkit.mjs +1 -1
  3. package/lib/bundler/index.mjs +95 -0
  4. package/lib/bundler/index.test.mjs +79 -0
  5. package/lib/cli/args.mjs +57 -0
  6. package/lib/cli/args.test.mjs +62 -0
  7. package/lib/cli/index.mjs +114 -0
  8. package/lib/config/index.mjs +294 -0
  9. package/lib/config/index.test.mjs +12 -0
  10. package/lib/config/model.mjs +422 -0
  11. package/lib/config/model.test.mjs +193 -0
  12. package/lib/database/fingerprint.mjs +61 -0
  13. package/lib/database/fingerprint.test.mjs +93 -0
  14. package/lib/{database.mjs → database/index.mjs} +45 -160
  15. package/lib/database/naming.mjs +47 -0
  16. package/lib/database/naming.test.mjs +39 -0
  17. package/lib/database/state.mjs +52 -0
  18. package/lib/database/state.test.mjs +66 -0
  19. package/lib/index.mjs +1 -0
  20. package/lib/k6/checks.mjs +1 -0
  21. package/lib/k6/dal-suite.mjs +1 -0
  22. package/lib/k6/dal.mjs +1 -0
  23. package/lib/k6/http.mjs +1 -0
  24. package/lib/k6/index.mjs +30 -0
  25. package/lib/k6/suite.mjs +1 -0
  26. package/lib/reporters/playwright.mjs +125 -0
  27. package/lib/reporters/playwright.test.mjs +73 -0
  28. package/lib/{runner.mjs → runner/index.mjs} +252 -835
  29. package/lib/runner/metadata.mjs +55 -0
  30. package/lib/runner/metadata.test.mjs +52 -0
  31. package/lib/runner/planning.mjs +270 -0
  32. package/lib/runner/planning.test.mjs +127 -0
  33. package/lib/runner/results.mjs +285 -0
  34. package/lib/runner/results.test.mjs +144 -0
  35. package/lib/runner/state.mjs +71 -0
  36. package/lib/runner/state.test.mjs +64 -0
  37. package/lib/runner/template.mjs +320 -0
  38. package/lib/runner/template.test.mjs +150 -0
  39. package/lib/runtime/index.mjs +191 -0
  40. package/lib/runtime-src/k6/checks.js +39 -0
  41. package/lib/runtime-src/k6/dal-suite.js +33 -0
  42. package/lib/runtime-src/k6/dal.js +32 -0
  43. package/lib/runtime-src/k6/http.js +134 -0
  44. package/lib/runtime-src/k6/suite.js +55 -0
  45. package/lib/telemetry/index.mjs +43 -0
  46. package/lib/timing/index.mjs +73 -0
  47. package/lib/timing/index.test.mjs +64 -0
  48. package/package.json +18 -3
  49. package/infra/neon-down.sh +0 -18
  50. package/infra/neon-up.sh +0 -124
  51. package/lib/cli.mjs +0 -132
  52. package/lib/config.mjs +0 -666
  53. package/lib/exec.mjs +0 -20
package/lib/cli.mjs DELETED
@@ -1,132 +0,0 @@
1
- import { cac } from "cac";
2
- import { loadConfigs, getServiceNames, isSiblingProduct } from "./config.mjs";
3
- import * as runner from "./runner.mjs";
4
-
5
- const SUITE_TYPES = new Set(["int", "integration", "e2e", "dal", "load", "all"]);
6
- const LIFECYCLE = new Set(["status", "destroy"]);
7
- const RESERVED = new Set([...SUITE_TYPES, ...LIFECYCLE]);
8
-
9
- export function run() {
10
- const cli = cac("testkit");
11
-
12
- cli
13
- .command("[first] [second] [third]", "Run test suites (int, e2e, dal, all)")
14
- .option("-s, --suite <name>", "Run specific suite(s)", { default: [] })
15
- .option("--dir <path>", "Explicit product directory")
16
- .option("--jobs <n>", "Number of isolated worker stacks for the whole run", {
17
- default: "1",
18
- })
19
- .option("--db-backend <name>", "Database backend override (neon, local)")
20
- .option("--shard <i/n>", "Run only shard i of n at suite granularity")
21
- .option("--framework <name>", "Filter by framework (k6, playwright, all)", {
22
- default: "all",
23
- })
24
- .action(async (first, second, third, options) => {
25
- // Resolve: service filter, suite type, and --dir.
26
- //
27
- // From product dir:
28
- // testkit → all services, all types
29
- // testkit int -s health → all services, int, health
30
- // testkit avocado_api int → one service, int
31
- // testkit avocado_api → one service, all types
32
- //
33
- // From workspace root:
34
- // testkit --dir outreach int → all services, int
35
- // testkit --dir avocado avocado_api int → one service, int
36
- //
37
- // Legacy (sibling dir as first arg):
38
- // testkit outreach int → --dir outreach, int
39
-
40
- let service = null;
41
- let type = null;
42
-
43
- // If first arg is a sibling dir with a manifest, treat it as --dir
44
- if (first && !RESERVED.has(first) && !options.dir && isSiblingProduct(first)) {
45
- options.dir = first;
46
- first = second;
47
- second = third;
48
- third = undefined;
49
- }
50
-
51
- // Now resolve service vs type from remaining args
52
- const serviceNames = new Set(getServiceNames(options.dir));
53
-
54
- if (first && serviceNames.has(first)) {
55
- service = first;
56
- type = second || null;
57
- } else if (first && RESERVED.has(first)) {
58
- type = first;
59
- } else if (first) {
60
- // Unknown arg — might be a service name that doesn't exist
61
- throw new Error(
62
- `Unknown argument "${first}". Expected a service name (${[...serviceNames].join(", ") || "none found"}) ` +
63
- `or suite type (int, e2e, dal, all).`
64
- );
65
- }
66
-
67
- const allConfigs = loadConfigs({ dir: options.dir, dbBackend: options.dbBackend });
68
- const configs = service
69
- ? allConfigs.filter((config) => config.name === service)
70
- : allConfigs;
71
- if (service && configs.length === 0) {
72
- const available = allConfigs.map((config) => config.name).join(", ");
73
- throw new Error(`Service "${service}" not found. Available: ${available}`);
74
- }
75
-
76
- // Lifecycle commands
77
- if (type === "status" || type === "destroy") {
78
- for (const config of configs) {
79
- if (configs.length > 1) console.log(`\n── ${config.name} ──`);
80
- if (type === "status") runner.showStatus(config);
81
- else await runner.destroy(config);
82
- }
83
- return;
84
- }
85
-
86
- if (!["all", "k6", "playwright"].includes(options.framework)) {
87
- throw new Error(
88
- `Unknown framework "${options.framework}". Expected one of: all, k6, playwright.`
89
- );
90
- }
91
-
92
- const jobs = Number.parseInt(String(options.jobs), 10);
93
- if (!Number.isInteger(jobs) || jobs <= 0) {
94
- throw new Error(`Invalid --jobs value "${options.jobs}". Expected a positive integer.`);
95
- }
96
-
97
- let shard = null;
98
- if (options.shard) {
99
- const match = String(options.shard).match(/^(\d+)\/(\d+)$/);
100
- if (!match) {
101
- throw new Error(
102
- `Invalid --shard value "${options.shard}". Expected the form "i/n", e.g. 1/3.`
103
- );
104
- }
105
- const index = Number.parseInt(match[1], 10);
106
- const total = Number.parseInt(match[2], 10);
107
- if (index <= 0 || total <= 0 || index > total) {
108
- throw new Error(
109
- `Invalid --shard value "${options.shard}". Expected 1 <= i <= n.`
110
- );
111
- }
112
- shard = { index, total };
113
- }
114
-
115
- const suiteType = type || "all";
116
- const suiteNames = Array.isArray(options.suite) ? options.suite : [options.suite].filter(Boolean);
117
- await runner.runAll(
118
- configs,
119
- suiteType,
120
- suiteNames,
121
- {
122
- ...options,
123
- jobs,
124
- shard,
125
- },
126
- allConfigs
127
- );
128
- });
129
-
130
- cli.help();
131
- cli.parse();
132
- }