@nsxbet/playwright-orchestrator 0.2.0

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 (59) hide show
  1. package/README.md +161 -0
  2. package/bin/run.js +5 -0
  3. package/dist/commands/assign.d.ts +23 -0
  4. package/dist/commands/assign.d.ts.map +1 -0
  5. package/dist/commands/assign.js +256 -0
  6. package/dist/commands/assign.js.map +1 -0
  7. package/dist/commands/extract-timing.d.ts +40 -0
  8. package/dist/commands/extract-timing.d.ts.map +1 -0
  9. package/dist/commands/extract-timing.js +196 -0
  10. package/dist/commands/extract-timing.js.map +1 -0
  11. package/dist/commands/list-tests.d.ts +16 -0
  12. package/dist/commands/list-tests.d.ts.map +1 -0
  13. package/dist/commands/list-tests.js +98 -0
  14. package/dist/commands/list-tests.js.map +1 -0
  15. package/dist/commands/merge-timing.d.ts +19 -0
  16. package/dist/commands/merge-timing.d.ts.map +1 -0
  17. package/dist/commands/merge-timing.js +217 -0
  18. package/dist/commands/merge-timing.js.map +1 -0
  19. package/dist/core/ckk-algorithm.d.ts +38 -0
  20. package/dist/core/ckk-algorithm.d.ts.map +1 -0
  21. package/dist/core/ckk-algorithm.js +192 -0
  22. package/dist/core/ckk-algorithm.js.map +1 -0
  23. package/dist/core/estimate.d.ts +72 -0
  24. package/dist/core/estimate.d.ts.map +1 -0
  25. package/dist/core/estimate.js +142 -0
  26. package/dist/core/estimate.js.map +1 -0
  27. package/dist/core/grep-pattern.d.ts +61 -0
  28. package/dist/core/grep-pattern.d.ts.map +1 -0
  29. package/dist/core/grep-pattern.js +104 -0
  30. package/dist/core/grep-pattern.js.map +1 -0
  31. package/dist/core/index.d.ts +9 -0
  32. package/dist/core/index.d.ts.map +1 -0
  33. package/dist/core/index.js +9 -0
  34. package/dist/core/index.js.map +1 -0
  35. package/dist/core/lpt-algorithm.d.ts +28 -0
  36. package/dist/core/lpt-algorithm.d.ts.map +1 -0
  37. package/dist/core/lpt-algorithm.js +80 -0
  38. package/dist/core/lpt-algorithm.js.map +1 -0
  39. package/dist/core/slugify.d.ts +13 -0
  40. package/dist/core/slugify.d.ts.map +1 -0
  41. package/dist/core/slugify.js +19 -0
  42. package/dist/core/slugify.js.map +1 -0
  43. package/dist/core/test-discovery.d.ts +46 -0
  44. package/dist/core/test-discovery.d.ts.map +1 -0
  45. package/dist/core/test-discovery.js +192 -0
  46. package/dist/core/test-discovery.js.map +1 -0
  47. package/dist/core/timing-store.d.ts +90 -0
  48. package/dist/core/timing-store.d.ts.map +1 -0
  49. package/dist/core/timing-store.js +280 -0
  50. package/dist/core/timing-store.js.map +1 -0
  51. package/dist/core/types.d.ts +241 -0
  52. package/dist/core/types.d.ts.map +1 -0
  53. package/dist/core/types.js +54 -0
  54. package/dist/core/types.js.map +1 -0
  55. package/dist/index.d.ts +9 -0
  56. package/dist/index.d.ts.map +1 -0
  57. package/dist/index.js +9 -0
  58. package/dist/index.js.map +1 -0
  59. package/package.json +70 -0
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Longest Processing Time First (LPT) algorithm for load balancing
3
+ *
4
+ * This greedy algorithm assigns jobs to workers by:
5
+ * 1. Sorting jobs by duration (descending)
6
+ * 2. Assigning each job to the worker with the smallest current load
7
+ *
8
+ * Time complexity: O(n log n) for sorting + O(n log k) for assignment = O(n log n)
9
+ * where n = number of files, k = number of shards
10
+ *
11
+ * @param files - Files with their durations
12
+ * @param numShards - Number of shards to distribute across
13
+ * @returns Shard assignments with expected durations
14
+ */
15
+ export function assignWithLPT(files, numShards) {
16
+ // Initialize shards
17
+ const shards = Array.from({ length: numShards }, (_, i) => ({
18
+ shardIndex: i + 1, // 1-based index
19
+ files: [],
20
+ expectedDuration: 0,
21
+ }));
22
+ if (files.length === 0) {
23
+ return shards;
24
+ }
25
+ // Sort files by duration descending (longest first)
26
+ const sortedFiles = [...files].sort((a, b) => b.duration - a.duration);
27
+ // Assign each file to the shard with the smallest current load
28
+ for (const file of sortedFiles) {
29
+ // Find shard with minimum load
30
+ let minShard = shards[0];
31
+ for (const shard of shards) {
32
+ if (minShard && shard.expectedDuration < minShard.expectedDuration) {
33
+ minShard = shard;
34
+ }
35
+ }
36
+ // Assign file to this shard
37
+ if (minShard) {
38
+ minShard.files.push(file.file);
39
+ minShard.expectedDuration += file.duration;
40
+ }
41
+ }
42
+ return shards;
43
+ }
44
+ /**
45
+ * Convert shard assignments to the format expected by the CLI output
46
+ */
47
+ export function formatAssignResult(assignments, estimatedFiles) {
48
+ const shards = {};
49
+ const expectedDurations = {};
50
+ let totalFiles = 0;
51
+ for (const assignment of assignments) {
52
+ shards[assignment.shardIndex] = assignment.files;
53
+ expectedDurations[assignment.shardIndex] = assignment.expectedDuration;
54
+ totalFiles += assignment.files.length;
55
+ }
56
+ return {
57
+ shards,
58
+ expectedDurations,
59
+ totalFiles,
60
+ estimatedFiles,
61
+ };
62
+ }
63
+ /**
64
+ * Calculate the balance metric (max/min ratio) for the assignment
65
+ *
66
+ * A perfectly balanced assignment would have a ratio of 1.0
67
+ * The target is to keep this below 1.2 (20% difference)
68
+ */
69
+ export function calculateBalanceRatio(assignments) {
70
+ const durations = assignments
71
+ .map((a) => a.expectedDuration)
72
+ .filter((d) => d > 0);
73
+ if (durations.length === 0) {
74
+ return 1.0;
75
+ }
76
+ const max = Math.max(...durations);
77
+ const min = Math.min(...durations);
78
+ return min > 0 ? max / min : 1.0;
79
+ }
80
+ //# sourceMappingURL=lpt-algorithm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lpt-algorithm.js","sourceRoot":"","sources":["../../src/core/lpt-algorithm.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,aAAa,CAC3B,KAAyB,EACzB,SAAiB;IAEjB,oBAAoB;IACpB,MAAM,MAAM,GAAsB,KAAK,CAAC,IAAI,CAC1C,EAAE,MAAM,EAAE,SAAS,EAAE,EACrB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QACT,UAAU,EAAE,CAAC,GAAG,CAAC,EAAE,gBAAgB;QACnC,KAAK,EAAE,EAAE;QACT,gBAAgB,EAAE,CAAC;KACpB,CAAC,CACH,CAAC;IAEF,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,oDAAoD;IACpD,MAAM,WAAW,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC;IAEvE,+DAA+D;IAC/D,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,+BAA+B;QAC/B,IAAI,QAAQ,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACzB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,IAAI,QAAQ,IAAI,KAAK,CAAC,gBAAgB,GAAG,QAAQ,CAAC,gBAAgB,EAAE,CAAC;gBACnE,QAAQ,GAAG,KAAK,CAAC;YACnB,CAAC;QACH,CAAC;QAED,4BAA4B;QAC5B,IAAI,QAAQ,EAAE,CAAC;YACb,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC/B,QAAQ,CAAC,gBAAgB,IAAI,IAAI,CAAC,QAAQ,CAAC;QAC7C,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAChC,WAA8B,EAC9B,cAAwB;IAExB,MAAM,MAAM,GAA6B,EAAE,CAAC;IAC5C,MAAM,iBAAiB,GAA2B,EAAE,CAAC;IACrD,IAAI,UAAU,GAAG,CAAC,CAAC;IAEnB,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;QACrC,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC;QACjD,iBAAiB,CAAC,UAAU,CAAC,UAAU,CAAC,GAAG,UAAU,CAAC,gBAAgB,CAAC;QACvE,UAAU,IAAI,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC;IACxC,CAAC;IAED,OAAO;QACL,MAAM;QACN,iBAAiB;QACjB,UAAU;QACV,cAAc;KACf,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,WAA8B;IAClE,MAAM,SAAS,GAAG,WAAW;SAC1B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC;SAC9B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAExB,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO,GAAG,CAAC;IACb,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC;IACnC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC;IAEnC,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;AACnC,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Slugify a string for use in cache keys
3
+ *
4
+ * Converts to lowercase, replaces spaces and special characters with hyphens,
5
+ * and removes consecutive hyphens.
6
+ *
7
+ * @example
8
+ * slugify("Mobile Chrome") // "mobile-chrome"
9
+ * slugify("feature/ABC-123") // "feature-abc-123"
10
+ * slugify("refs/heads/main") // "refs-heads-main"
11
+ */
12
+ export declare function slugify(input: string): string;
13
+ //# sourceMappingURL=slugify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slugify.d.ts","sourceRoot":"","sources":["../../src/core/slugify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAM7C"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Slugify a string for use in cache keys
3
+ *
4
+ * Converts to lowercase, replaces spaces and special characters with hyphens,
5
+ * and removes consecutive hyphens.
6
+ *
7
+ * @example
8
+ * slugify("Mobile Chrome") // "mobile-chrome"
9
+ * slugify("feature/ABC-123") // "feature-abc-123"
10
+ * slugify("refs/heads/main") // "refs-heads-main"
11
+ */
12
+ export function slugify(input) {
13
+ return input
14
+ .toLowerCase()
15
+ .replace(/[^a-z0-9]+/g, '-') // Replace non-alphanumeric with hyphens
16
+ .replace(/^-+|-+$/g, '') // Remove leading/trailing hyphens
17
+ .replace(/-+/g, '-'); // Remove consecutive hyphens
18
+ }
19
+ //# sourceMappingURL=slugify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slugify.js","sourceRoot":"","sources":["../../src/core/slugify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,UAAU,OAAO,CAAC,KAAa;IACnC,OAAO,KAAK;SACT,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,wCAAwC;SACpE,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,kCAAkC;SAC1D,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,6BAA6B;AACvD,CAAC"}
@@ -0,0 +1,46 @@
1
+ import type { DiscoveredTest } from './types.js';
2
+ /**
3
+ * Discover tests by running Playwright with --list flag
4
+ *
5
+ * @param testDir - Path to test directory
6
+ * @param project - Optional Playwright project name
7
+ * @returns List of discovered tests
8
+ */
9
+ export declare function discoverTests(testDir: string, project?: string): DiscoveredTest[];
10
+ /**
11
+ * Parse Playwright --list JSON output
12
+ *
13
+ * @param jsonOutput - Raw JSON output from Playwright --list
14
+ * @returns List of discovered tests
15
+ */
16
+ export declare function parsePlaywrightListOutput(jsonOutput: string): DiscoveredTest[];
17
+ /**
18
+ * Discover tests by scanning test files directly (fallback method)
19
+ *
20
+ * This parses test files to find test definitions when Playwright --list isn't available.
21
+ * Uses regex to find test() and it() calls.
22
+ *
23
+ * @param testDir - Path to test directory
24
+ * @param globPattern - Glob pattern for test files
25
+ * @returns List of discovered tests
26
+ */
27
+ export declare function discoverTestsFromFiles(testDir: string, globPattern?: string): DiscoveredTest[];
28
+ /**
29
+ * Parse test definitions from source code
30
+ *
31
+ * Extracts test() and it() calls with their describe() context.
32
+ * This is a simple regex-based parser that handles common patterns.
33
+ *
34
+ * @param source - Source code content
35
+ * @param fileName - Name of the source file
36
+ * @returns List of discovered tests
37
+ */
38
+ export declare function parseTestsFromSource(source: string, fileName: string): DiscoveredTest[];
39
+ /**
40
+ * Group tests by file
41
+ *
42
+ * @param tests - List of discovered tests
43
+ * @returns Map of file name to tests
44
+ */
45
+ export declare function groupTestsByFile(tests: DiscoveredTest[]): Map<string, DiscoveredTest[]>;
46
+ //# sourceMappingURL=test-discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-discovery.d.ts","sourceRoot":"","sources":["../../src/core/test-discovery.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,cAAc,EAGf,MAAM,YAAY,CAAC;AAGpB;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,GACf,cAAc,EAAE,CAsBlB;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,MAAM,GACjB,cAAc,EAAE,CAsBlB;AA8CD;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,WAAW,GAAE,MAAuB,GACnC,cAAc,EAAE,CAalB;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,cAAc,EAAE,CA0DlB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,cAAc,EAAE,GACtB,GAAG,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC,CAU/B"}
@@ -0,0 +1,192 @@
1
+ import { execSync } from 'node:child_process';
2
+ import * as fs from 'node:fs';
3
+ import * as path from 'node:path';
4
+ import { glob } from 'glob';
5
+ import { buildTestId } from './types.js';
6
+ /**
7
+ * Discover tests by running Playwright with --list flag
8
+ *
9
+ * @param testDir - Path to test directory
10
+ * @param project - Optional Playwright project name
11
+ * @returns List of discovered tests
12
+ */
13
+ export function discoverTests(testDir, project) {
14
+ const projectFlag = project ? `--project="${project}"` : '';
15
+ const cmd = `npx playwright test --list --reporter=json ${projectFlag}`.trim();
16
+ try {
17
+ const output = execSync(cmd, {
18
+ cwd: testDir,
19
+ encoding: 'utf-8',
20
+ maxBuffer: 50 * 1024 * 1024, // 50MB buffer for large test suites
21
+ stdio: ['pipe', 'pipe', 'pipe'],
22
+ });
23
+ return parsePlaywrightListOutput(output);
24
+ }
25
+ catch (error) {
26
+ // Playwright might exit with non-zero even for --list if there are issues
27
+ const execError = error;
28
+ if (execError.stdout) {
29
+ return parsePlaywrightListOutput(execError.stdout);
30
+ }
31
+ throw error;
32
+ }
33
+ }
34
+ /**
35
+ * Parse Playwright --list JSON output
36
+ *
37
+ * @param jsonOutput - Raw JSON output from Playwright --list
38
+ * @returns List of discovered tests
39
+ */
40
+ export function parsePlaywrightListOutput(jsonOutput) {
41
+ const tests = [];
42
+ try {
43
+ const data = JSON.parse(jsonOutput);
44
+ for (const suite of data.suites) {
45
+ extractTestsFromSuite(suite, [], tests);
46
+ }
47
+ }
48
+ catch {
49
+ // Try parsing line by line if JSON is malformed (older Playwright versions)
50
+ // or if output contains additional text
51
+ const jsonMatch = jsonOutput.match(/\{[\s\S]*\}/);
52
+ if (jsonMatch) {
53
+ const data = JSON.parse(jsonMatch[0]);
54
+ for (const suite of data.suites) {
55
+ extractTestsFromSuite(suite, [], tests);
56
+ }
57
+ }
58
+ }
59
+ return tests;
60
+ }
61
+ /**
62
+ * Recursively extract tests from a Playwright suite
63
+ */
64
+ function extractTestsFromSuite(suite, parentTitles, tests) {
65
+ const currentTitles = suite.title && suite.title !== ''
66
+ ? [...parentTitles, suite.title]
67
+ : parentTitles;
68
+ // Process specs (actual tests)
69
+ if (suite.specs) {
70
+ for (const spec of suite.specs) {
71
+ const titlePath = [...currentTitles, spec.title];
72
+ const file = getRelativeFilePath(spec.file || suite.file);
73
+ tests.push({
74
+ file,
75
+ title: spec.title,
76
+ titlePath,
77
+ testId: buildTestId(file, titlePath),
78
+ });
79
+ }
80
+ }
81
+ // Process nested suites
82
+ if (suite.suites) {
83
+ for (const nestedSuite of suite.suites) {
84
+ extractTestsFromSuite(nestedSuite, currentTitles, tests);
85
+ }
86
+ }
87
+ }
88
+ /**
89
+ * Get relative file path from absolute path
90
+ */
91
+ function getRelativeFilePath(filePath) {
92
+ // Extract just the filename for test IDs
93
+ return path.basename(filePath);
94
+ }
95
+ /**
96
+ * Discover tests by scanning test files directly (fallback method)
97
+ *
98
+ * This parses test files to find test definitions when Playwright --list isn't available.
99
+ * Uses regex to find test() and it() calls.
100
+ *
101
+ * @param testDir - Path to test directory
102
+ * @param globPattern - Glob pattern for test files
103
+ * @returns List of discovered tests
104
+ */
105
+ export function discoverTestsFromFiles(testDir, globPattern = '**/*.spec.ts') {
106
+ const tests = [];
107
+ const files = glob.sync(globPattern, { cwd: testDir, absolute: true });
108
+ for (const filePath of files) {
109
+ const content = fs.readFileSync(filePath, 'utf-8');
110
+ const fileName = path.basename(filePath);
111
+ const fileTests = parseTestsFromSource(content, fileName);
112
+ tests.push(...fileTests);
113
+ }
114
+ return tests;
115
+ }
116
+ /**
117
+ * Parse test definitions from source code
118
+ *
119
+ * Extracts test() and it() calls with their describe() context.
120
+ * This is a simple regex-based parser that handles common patterns.
121
+ *
122
+ * @param source - Source code content
123
+ * @param fileName - Name of the source file
124
+ * @returns List of discovered tests
125
+ */
126
+ export function parseTestsFromSource(source, fileName) {
127
+ const tests = [];
128
+ // Match describe blocks and test/it calls
129
+ // This is a simplified parser - for full accuracy, use Playwright --list
130
+ const describeRegex = /(?:test\.)?describe\s*\(\s*['"`]([^'"`]+)['"`]/g;
131
+ const testRegex = /(?:test|it)\s*\(\s*['"`]([^'"`]+)['"`]/g;
132
+ // Find all describe blocks with their positions
133
+ const describes = [];
134
+ // Extract all describe blocks
135
+ for (const match of source.matchAll(describeRegex)) {
136
+ // Find matching closing brace (simplified - counts braces)
137
+ const start = match.index ?? 0;
138
+ let braceCount = 0;
139
+ let end = start;
140
+ let foundOpen = false;
141
+ for (let i = start; i < source.length; i++) {
142
+ if (source[i] === '{') {
143
+ braceCount++;
144
+ foundOpen = true;
145
+ }
146
+ else if (source[i] === '}') {
147
+ braceCount--;
148
+ if (foundOpen && braceCount === 0) {
149
+ end = i;
150
+ break;
151
+ }
152
+ }
153
+ }
154
+ describes.push({ title: match[1] ?? '', start, end });
155
+ }
156
+ // Find all tests
157
+ for (const match of source.matchAll(testRegex)) {
158
+ const testTitle = match[1] ?? '';
159
+ const testPos = match.index ?? 0;
160
+ // Find which describe blocks contain this test
161
+ const titlePath = [];
162
+ for (const desc of describes) {
163
+ if (testPos > desc.start && testPos < desc.end) {
164
+ titlePath.push(desc.title);
165
+ }
166
+ }
167
+ titlePath.push(testTitle);
168
+ tests.push({
169
+ file: fileName,
170
+ title: testTitle,
171
+ titlePath,
172
+ testId: buildTestId(fileName, titlePath),
173
+ });
174
+ }
175
+ return tests;
176
+ }
177
+ /**
178
+ * Group tests by file
179
+ *
180
+ * @param tests - List of discovered tests
181
+ * @returns Map of file name to tests
182
+ */
183
+ export function groupTestsByFile(tests) {
184
+ const grouped = new Map();
185
+ for (const test of tests) {
186
+ const existing = grouped.get(test.file) || [];
187
+ existing.push(test);
188
+ grouped.set(test.file, existing);
189
+ }
190
+ return grouped;
191
+ }
192
+ //# sourceMappingURL=test-discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-discovery.js","sourceRoot":"","sources":["../../src/core/test-discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAM5B,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAC3B,OAAe,EACf,OAAgB;IAEhB,MAAM,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC,cAAc,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5D,MAAM,GAAG,GACP,8CAA8C,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;IAErE,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,EAAE;YAC3B,GAAG,EAAE,OAAO;YACZ,QAAQ,EAAE,OAAO;YACjB,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,oCAAoC;YACjE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;SAChC,CAAC,CAAC;QAEH,OAAO,yBAAyB,CAAC,MAAM,CAAC,CAAC;IAC3C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,0EAA0E;QAC1E,MAAM,SAAS,GAAG,KAA6C,CAAC;QAChE,IAAI,SAAS,CAAC,MAAM,EAAE,CAAC;YACrB,OAAO,yBAAyB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACrD,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,yBAAyB,CACvC,UAAkB;IAElB,MAAM,KAAK,GAAqB,EAAE,CAAC;IAEnC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAyB,CAAC;QAE5D,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChC,qBAAqB,CAAC,KAAK,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,4EAA4E;QAC5E,wCAAwC;QACxC,MAAM,SAAS,GAAG,UAAU,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QAClD,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAyB,CAAC;YAC9D,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBAChC,qBAAqB,CAAC,KAAK,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;YAC1C,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,SAAS,qBAAqB,CAC5B,KAA0B,EAC1B,YAAsB,EACtB,KAAuB;IAEvB,MAAM,aAAa,GACjB,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,KAAK,EAAE;QAC/B,CAAC,CAAC,CAAC,GAAG,YAAY,EAAE,KAAK,CAAC,KAAK,CAAC;QAChC,CAAC,CAAC,YAAY,CAAC;IAEnB,+BAA+B;IAC/B,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAChB,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAC/B,MAAM,SAAS,GAAG,CAAC,GAAG,aAAa,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;YACjD,MAAM,IAAI,GAAG,mBAAmB,CAAC,IAAI,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC;YAE1D,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI;gBACJ,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,SAAS;gBACT,MAAM,EAAE,WAAW,CAAC,IAAI,EAAE,SAAS,CAAC;aACrC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,wBAAwB;IACxB,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACjB,KAAK,MAAM,WAAW,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;YACvC,qBAAqB,CAAC,WAAW,EAAE,aAAa,EAAE,KAAK,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,mBAAmB,CAAC,QAAgB;IAC3C,yCAAyC;IACzC,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AACjC,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,sBAAsB,CACpC,OAAe,EACf,cAAsB,cAAc;IAEpC,MAAM,KAAK,GAAqB,EAAE,CAAC;IAEnC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IAEvE,KAAK,MAAM,QAAQ,IAAI,KAAK,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACnD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACzC,MAAM,SAAS,GAAG,oBAAoB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QAC1D,KAAK,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC;IAC3B,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,oBAAoB,CAClC,MAAc,EACd,QAAgB;IAEhB,MAAM,KAAK,GAAqB,EAAE,CAAC;IAEnC,0CAA0C;IAC1C,yEAAyE;IACzE,MAAM,aAAa,GAAG,iDAAiD,CAAC;IACxE,MAAM,SAAS,GAAG,yCAAyC,CAAC;IAE5D,gDAAgD;IAChD,MAAM,SAAS,GAAoD,EAAE,CAAC;IAEtE,8BAA8B;IAC9B,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;QACnD,2DAA2D;QAC3D,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC;QAC/B,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,IAAI,GAAG,GAAG,KAAK,CAAC;QAChB,IAAI,SAAS,GAAG,KAAK,CAAC;QAEtB,KAAK,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3C,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;gBACtB,UAAU,EAAE,CAAC;gBACb,SAAS,GAAG,IAAI,CAAC;YACnB,CAAC;iBAAM,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;gBAC7B,UAAU,EAAE,CAAC;gBACb,IAAI,SAAS,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;oBAClC,GAAG,GAAG,CAAC,CAAC;oBACR,MAAM;gBACR,CAAC;YACH,CAAC;QACH,CAAC;QAED,SAAS,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,iBAAiB;IACjB,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAC/C,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC;QAEjC,+CAA+C;QAC/C,MAAM,SAAS,GAAa,EAAE,CAAC;QAC/B,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;YAC7B,IAAI,OAAO,GAAG,IAAI,CAAC,KAAK,IAAI,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBAC/C,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;QACD,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAE1B,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,SAAS;YAChB,SAAS;YACT,MAAM,EAAE,WAAW,CAAC,QAAQ,EAAE,SAAS,CAAC;SACzC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAC9B,KAAuB;IAEvB,MAAM,OAAO,GAAG,IAAI,GAAG,EAA4B,CAAC;IAEpD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAC9C,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACnC,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,90 @@
1
+ import type { ShardTimingArtifact, TestShardTimingArtifact, TimingData, TimingDataV1, TimingDataV2 } from './types.js';
2
+ /**
3
+ * Default EMA smoothing factor (alpha)
4
+ * Higher values give more weight to recent measurements
5
+ */
6
+ export declare const DEFAULT_EMA_ALPHA = 0.3;
7
+ /**
8
+ * Default number of days after which to prune old entries
9
+ */
10
+ export declare const DEFAULT_PRUNE_DAYS = 30;
11
+ /**
12
+ * Load timing data from a JSON file
13
+ *
14
+ * Supports both v1 (file-level) and v2 (test-level) formats.
15
+ *
16
+ * @param filePath - Path to the timing data JSON file
17
+ * @returns Timing data, or empty data if file doesn't exist
18
+ */
19
+ export declare function loadTimingData(filePath: string): TimingData;
20
+ /**
21
+ * Save timing data to a JSON file
22
+ */
23
+ export declare function saveTimingData(filePath: string, data: TimingData): void;
24
+ /**
25
+ * Calculate Exponential Moving Average for duration
26
+ *
27
+ * Formula: newDuration = α * measuredDuration + (1 - α) * oldDuration
28
+ *
29
+ * @param oldDuration - Previous duration value
30
+ * @param newDuration - New measured duration
31
+ * @param alpha - Smoothing factor (0-1), higher = more weight on new value
32
+ */
33
+ export declare function calculateEMA(oldDuration: number, newDuration: number, alpha?: number): number;
34
+ /**
35
+ * Merge new timing measurements into existing timing data using EMA (v1 - file-level)
36
+ *
37
+ * @param existing - Existing timing data (v1)
38
+ * @param newMeasurements - New measurements from shard artifacts
39
+ * @param alpha - EMA smoothing factor
40
+ * @returns Updated timing data
41
+ */
42
+ export declare function mergeTimingData(existing: TimingData, newMeasurements: ShardTimingArtifact[], alpha?: number): TimingDataV1;
43
+ /**
44
+ * Merge new timing measurements into existing timing data using EMA (v2 - test-level)
45
+ *
46
+ * @param existing - Existing timing data (v2)
47
+ * @param newMeasurements - New measurements from shard artifacts
48
+ * @param alpha - EMA smoothing factor
49
+ * @returns Updated timing data
50
+ */
51
+ export declare function mergeTestTimingData(existing: TimingDataV2 | null, newMeasurements: TestShardTimingArtifact[], alpha?: number): TimingDataV2;
52
+ /**
53
+ * Prune old entries from timing data (v1 - file-level)
54
+ *
55
+ * Removes entries that:
56
+ * 1. Haven't been run in more than `days` days
57
+ * 2. No longer exist in the current test files (if provided)
58
+ *
59
+ * @param data - Timing data to prune
60
+ * @param days - Number of days after which to remove entries
61
+ * @param currentFiles - Optional list of current test files (to remove deleted tests)
62
+ * @returns Pruned timing data
63
+ */
64
+ export declare function pruneTimingData(data: TimingData, days?: number, currentFiles?: string[]): TimingData;
65
+ /**
66
+ * Prune old entries from timing data (v2 - test-level)
67
+ *
68
+ * @param data - Timing data to prune
69
+ * @param days - Number of days after which to remove entries
70
+ * @param currentTestIds - Optional list of current test IDs (to remove deleted tests)
71
+ * @returns Pruned timing data
72
+ */
73
+ export declare function pruneTestTimingData(data: TimingDataV2, days?: number, currentTestIds?: string[]): TimingDataV2;
74
+ /**
75
+ * Get duration for a file from timing data (v1)
76
+ *
77
+ * @param data - Timing data
78
+ * @param file - File name
79
+ * @returns Duration in ms, or undefined if not found
80
+ */
81
+ export declare function getFileDuration(data: TimingData, file: string): number | undefined;
82
+ /**
83
+ * Get duration for a test from timing data (v2)
84
+ *
85
+ * @param data - Timing data (v2)
86
+ * @param testId - Test ID
87
+ * @returns Duration in ms, or undefined if not found
88
+ */
89
+ export declare function getTestDuration(data: TimingDataV2, testId: string): number | undefined;
90
+ //# sourceMappingURL=timing-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timing-store.d.ts","sourceRoot":"","sources":["../../src/core/timing-store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,mBAAmB,EACnB,uBAAuB,EAEvB,UAAU,EACV,YAAY,EACZ,YAAY,EACb,MAAM,YAAY,CAAC;AASpB;;;GAGG;AACH,eAAO,MAAM,iBAAiB,MAAM,CAAC;AAErC;;GAEG;AACH,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAErC;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,CA4B3D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI,CAGvE;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,KAAK,GAAE,MAA0B,GAChC,MAAM,CAER;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,UAAU,EACpB,eAAe,EAAE,mBAAmB,EAAE,EACtC,KAAK,GAAE,MAA0B,GAChC,YAAY,CAqCd;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,YAAY,GAAG,IAAI,EAC7B,eAAe,EAAE,uBAAuB,EAAE,EAC1C,KAAK,GAAE,MAA0B,GAChC,YAAY,CAmCd;AAkDD;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,UAAU,EAChB,IAAI,GAAE,MAA2B,EACjC,YAAY,CAAC,EAAE,MAAM,EAAE,GACtB,UAAU,CAgCZ;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,YAAY,EAClB,IAAI,GAAE,MAA2B,EACjC,cAAc,CAAC,EAAE,MAAM,EAAE,GACxB,YAAY,CA4Bd;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,MAAM,GACX,MAAM,GAAG,SAAS,CAcpB;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,YAAY,EAClB,MAAM,EAAE,MAAM,GACb,MAAM,GAAG,SAAS,CAEpB"}