@nsxbet/playwright-orchestrator 0.4.1 → 0.5.1
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 +54 -7
- package/dist/commands/assign.d.ts.map +1 -1
- package/dist/commands/assign.js +7 -48
- package/dist/commands/assign.js.map +1 -1
- package/dist/commands/extract-timing.d.ts +1 -12
- package/dist/commands/extract-timing.d.ts.map +1 -1
- package/dist/commands/extract-timing.js +15 -84
- package/dist/commands/extract-timing.js.map +1 -1
- package/dist/commands/merge-timing.d.ts +1 -4
- package/dist/commands/merge-timing.d.ts.map +1 -1
- package/dist/commands/merge-timing.js +11 -106
- package/dist/commands/merge-timing.js.map +1 -1
- package/dist/core/estimate.d.ts +9 -9
- package/dist/core/estimate.d.ts.map +1 -1
- package/dist/core/estimate.js +4 -4
- package/dist/core/estimate.js.map +1 -1
- package/dist/core/index.d.ts +0 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +0 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/test-discovery.d.ts.map +1 -1
- package/dist/core/test-discovery.js +7 -4
- package/dist/core/test-discovery.js.map +1 -1
- package/dist/core/timing-store.d.ts +16 -36
- package/dist/core/timing-store.d.ts.map +1 -1
- package/dist/core/timing-store.js +21 -140
- package/dist/core/timing-store.js.map +1 -1
- package/dist/core/types.d.ts +7 -67
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +1 -32
- package/dist/core/types.js.map +1 -1
- package/dist/reporter.d.ts +40 -0
- package/dist/reporter.d.ts.map +1 -0
- package/dist/reporter.js +73 -0
- package/dist/reporter.js.map +1 -0
- package/package.json +22 -1
- package/dist/core/grep-pattern.d.ts +0 -71
- package/dist/core/grep-pattern.d.ts.map +0 -1
- package/dist/core/grep-pattern.js +0 -117
- package/dist/core/grep-pattern.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as fs from 'node:fs';
|
|
2
|
-
import { createEmptyTimingData,
|
|
2
|
+
import { createEmptyTimingData, TIMING_DATA_VERSION } from './types.js';
|
|
3
3
|
/**
|
|
4
4
|
* Default EMA smoothing factor (alpha)
|
|
5
5
|
* Higher values give more weight to recent measurements
|
|
@@ -12,25 +12,18 @@ export const DEFAULT_PRUNE_DAYS = 30;
|
|
|
12
12
|
/**
|
|
13
13
|
* Load timing data from a JSON file
|
|
14
14
|
*
|
|
15
|
-
* Supports both v1 (file-level) and v2 (test-level) formats.
|
|
16
|
-
*
|
|
17
15
|
* @param filePath - Path to the timing data JSON file
|
|
18
|
-
* @returns Timing data, or empty data if file doesn't exist
|
|
16
|
+
* @returns Timing data, or empty data if file doesn't exist or is invalid
|
|
19
17
|
*/
|
|
20
18
|
export function loadTimingData(filePath) {
|
|
21
19
|
try {
|
|
22
20
|
const content = fs.readFileSync(filePath, 'utf-8');
|
|
23
21
|
const data = JSON.parse(content);
|
|
24
|
-
//
|
|
25
|
-
if (data.version === TIMING_DATA_VERSION_V1) {
|
|
26
|
-
// Return as-is for backwards compatibility
|
|
27
|
-
return data;
|
|
28
|
-
}
|
|
29
|
-
// Handle v2 format
|
|
22
|
+
// Only accept current version
|
|
30
23
|
if (data.version === TIMING_DATA_VERSION) {
|
|
31
24
|
return data;
|
|
32
25
|
}
|
|
33
|
-
// Unknown version - return empty
|
|
26
|
+
// Unknown or old version - return empty data
|
|
34
27
|
console.warn(`Timing data version mismatch: expected ${TIMING_DATA_VERSION}, got ${data.version}. Using empty data.`);
|
|
35
28
|
return createEmptyTimingData();
|
|
36
29
|
}
|
|
@@ -59,56 +52,14 @@ export function calculateEMA(oldDuration, newDuration, alpha = DEFAULT_EMA_ALPHA
|
|
|
59
52
|
return Math.round(alpha * newDuration + (1 - alpha) * oldDuration);
|
|
60
53
|
}
|
|
61
54
|
/**
|
|
62
|
-
* Merge new timing measurements into existing timing data using EMA
|
|
55
|
+
* Merge new timing measurements into existing timing data using EMA
|
|
63
56
|
*
|
|
64
|
-
* @param existing - Existing timing data (
|
|
57
|
+
* @param existing - Existing timing data (or null for fresh start)
|
|
65
58
|
* @param newMeasurements - New measurements from shard artifacts
|
|
66
59
|
* @param alpha - EMA smoothing factor
|
|
67
60
|
* @returns Updated timing data
|
|
68
61
|
*/
|
|
69
62
|
export function mergeTimingData(existing, newMeasurements, alpha = DEFAULT_EMA_ALPHA) {
|
|
70
|
-
const now = new Date().toISOString();
|
|
71
|
-
// Convert v2 to v1 if needed (lossy - just take file names)
|
|
72
|
-
const existingFiles = isTimingDataV1(existing)
|
|
73
|
-
? existing.files
|
|
74
|
-
: aggregateTestsToFiles(existing);
|
|
75
|
-
const merged = {
|
|
76
|
-
version: TIMING_DATA_VERSION_V1,
|
|
77
|
-
updatedAt: now,
|
|
78
|
-
files: { ...existingFiles },
|
|
79
|
-
};
|
|
80
|
-
for (const artifact of newMeasurements) {
|
|
81
|
-
for (const [file, duration] of Object.entries(artifact.files)) {
|
|
82
|
-
const existingData = merged.files[file];
|
|
83
|
-
if (existingData) {
|
|
84
|
-
// Apply EMA to existing data
|
|
85
|
-
merged.files[file] = {
|
|
86
|
-
duration: calculateEMA(existingData.duration, duration, alpha),
|
|
87
|
-
runs: existingData.runs + 1,
|
|
88
|
-
lastRun: now,
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
else {
|
|
92
|
-
// First measurement for this file
|
|
93
|
-
merged.files[file] = {
|
|
94
|
-
duration,
|
|
95
|
-
runs: 1,
|
|
96
|
-
lastRun: now,
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
return merged;
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* Merge new timing measurements into existing timing data using EMA (v2 - test-level)
|
|
105
|
-
*
|
|
106
|
-
* @param existing - Existing timing data (v2)
|
|
107
|
-
* @param newMeasurements - New measurements from shard artifacts
|
|
108
|
-
* @param alpha - EMA smoothing factor
|
|
109
|
-
* @returns Updated timing data
|
|
110
|
-
*/
|
|
111
|
-
export function mergeTestTimingData(existing, newMeasurements, alpha = DEFAULT_EMA_ALPHA) {
|
|
112
63
|
const now = new Date().toISOString();
|
|
113
64
|
const merged = {
|
|
114
65
|
version: TIMING_DATA_VERSION,
|
|
@@ -149,84 +100,18 @@ function extractFileFromTestId(testId) {
|
|
|
149
100
|
return parts[0] ?? '';
|
|
150
101
|
}
|
|
151
102
|
/**
|
|
152
|
-
*
|
|
153
|
-
*/
|
|
154
|
-
function aggregateTestsToFiles(data) {
|
|
155
|
-
const fileMap = new Map();
|
|
156
|
-
for (const testData of Object.values(data.tests)) {
|
|
157
|
-
const existing = fileMap.get(testData.file);
|
|
158
|
-
if (existing) {
|
|
159
|
-
existing.totalDuration += testData.duration;
|
|
160
|
-
existing.count += 1;
|
|
161
|
-
if (testData.lastRun > existing.lastRun) {
|
|
162
|
-
existing.lastRun = testData.lastRun;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
else {
|
|
166
|
-
fileMap.set(testData.file, {
|
|
167
|
-
totalDuration: testData.duration,
|
|
168
|
-
count: 1,
|
|
169
|
-
lastRun: testData.lastRun,
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
const result = {};
|
|
174
|
-
for (const [file, stats] of fileMap) {
|
|
175
|
-
result[file] = {
|
|
176
|
-
duration: stats.totalDuration,
|
|
177
|
-
runs: stats.count,
|
|
178
|
-
lastRun: stats.lastRun,
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
return result;
|
|
182
|
-
}
|
|
183
|
-
/**
|
|
184
|
-
* Prune old entries from timing data (v1 - file-level)
|
|
103
|
+
* Prune old entries from timing data
|
|
185
104
|
*
|
|
186
105
|
* Removes entries that:
|
|
187
106
|
* 1. Haven't been run in more than `days` days
|
|
188
|
-
* 2. No longer exist in the current
|
|
189
|
-
*
|
|
190
|
-
* @param data - Timing data to prune
|
|
191
|
-
* @param days - Number of days after which to remove entries
|
|
192
|
-
* @param currentFiles - Optional list of current test files (to remove deleted tests)
|
|
193
|
-
* @returns Pruned timing data
|
|
194
|
-
*/
|
|
195
|
-
export function pruneTimingData(data, days = DEFAULT_PRUNE_DAYS, currentFiles) {
|
|
196
|
-
if (isTimingDataV2(data)) {
|
|
197
|
-
return pruneTestTimingData(data, days, currentFiles);
|
|
198
|
-
}
|
|
199
|
-
const now = new Date();
|
|
200
|
-
const cutoffDate = new Date(now.getTime() - days * 24 * 60 * 60 * 1000);
|
|
201
|
-
const currentFileSet = currentFiles ? new Set(currentFiles) : null;
|
|
202
|
-
const prunedFiles = {};
|
|
203
|
-
for (const [file, timing] of Object.entries(data.files)) {
|
|
204
|
-
const lastRun = new Date(timing.lastRun);
|
|
205
|
-
// Skip if too old
|
|
206
|
-
if (lastRun < cutoffDate) {
|
|
207
|
-
continue;
|
|
208
|
-
}
|
|
209
|
-
// Skip if file no longer exists (when currentFiles is provided)
|
|
210
|
-
if (currentFileSet && !currentFileSet.has(file)) {
|
|
211
|
-
continue;
|
|
212
|
-
}
|
|
213
|
-
prunedFiles[file] = timing;
|
|
214
|
-
}
|
|
215
|
-
return {
|
|
216
|
-
...data,
|
|
217
|
-
updatedAt: new Date().toISOString(),
|
|
218
|
-
files: prunedFiles,
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
/**
|
|
222
|
-
* Prune old entries from timing data (v2 - test-level)
|
|
107
|
+
* 2. No longer exist in the current tests (if provided)
|
|
223
108
|
*
|
|
224
109
|
* @param data - Timing data to prune
|
|
225
110
|
* @param days - Number of days after which to remove entries
|
|
226
111
|
* @param currentTestIds - Optional list of current test IDs (to remove deleted tests)
|
|
227
112
|
* @returns Pruned timing data
|
|
228
113
|
*/
|
|
229
|
-
export function
|
|
114
|
+
export function pruneTimingData(data, days = DEFAULT_PRUNE_DAYS, currentTestIds) {
|
|
230
115
|
const now = new Date();
|
|
231
116
|
const cutoffDate = new Date(now.getTime() - days * 24 * 60 * 60 * 1000);
|
|
232
117
|
const currentTestSet = currentTestIds ? new Set(currentTestIds) : null;
|
|
@@ -250,31 +135,27 @@ export function pruneTestTimingData(data, days = DEFAULT_PRUNE_DAYS, currentTest
|
|
|
250
135
|
};
|
|
251
136
|
}
|
|
252
137
|
/**
|
|
253
|
-
* Get duration for a
|
|
138
|
+
* Get duration for a test from timing data
|
|
254
139
|
*
|
|
255
140
|
* @param data - Timing data
|
|
256
|
-
* @param
|
|
141
|
+
* @param testId - Test ID
|
|
257
142
|
* @returns Duration in ms, or undefined if not found
|
|
258
143
|
*/
|
|
144
|
+
export function getTestDuration(data, testId) {
|
|
145
|
+
return data.tests[testId]?.duration;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Get total duration for a file by aggregating all tests in that file
|
|
149
|
+
*
|
|
150
|
+
* @param data - Timing data
|
|
151
|
+
* @param file - File path
|
|
152
|
+
* @returns Total duration in ms, or undefined if no tests found
|
|
153
|
+
*/
|
|
259
154
|
export function getFileDuration(data, file) {
|
|
260
|
-
if (isTimingDataV1(data)) {
|
|
261
|
-
return data.files[file]?.duration;
|
|
262
|
-
}
|
|
263
|
-
// For v2 data, aggregate tests in this file
|
|
264
155
|
const fileTests = Object.entries(data.tests).filter(([, t]) => t.file === file);
|
|
265
156
|
if (fileTests.length === 0) {
|
|
266
157
|
return undefined;
|
|
267
158
|
}
|
|
268
159
|
return fileTests.reduce((sum, [, t]) => sum + t.duration, 0);
|
|
269
160
|
}
|
|
270
|
-
/**
|
|
271
|
-
* Get duration for a test from timing data (v2)
|
|
272
|
-
*
|
|
273
|
-
* @param data - Timing data (v2)
|
|
274
|
-
* @param testId - Test ID
|
|
275
|
-
* @returns Duration in ms, or undefined if not found
|
|
276
|
-
*/
|
|
277
|
-
export function getTestDuration(data, testId) {
|
|
278
|
-
return data.tests[testId]?.duration;
|
|
279
|
-
}
|
|
280
161
|
//# sourceMappingURL=timing-store.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timing-store.js","sourceRoot":"","sources":["../../src/core/timing-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"timing-store.js","sourceRoot":"","sources":["../../src/core/timing-store.ts"],"names":[],"mappings":"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"}
|
package/dist/core/types.d.ts
CHANGED
|
@@ -1,16 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Timing data for a single test
|
|
3
|
-
*/
|
|
4
|
-
export interface FileTimingData {
|
|
5
|
-
/** Duration in milliseconds */
|
|
6
|
-
duration: number;
|
|
7
|
-
/** Number of times this file has been measured */
|
|
8
|
-
runs: number;
|
|
9
|
-
/** ISO timestamp of last measurement */
|
|
10
|
-
lastRun: string;
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Timing data for a single test (v2 format - test-level)
|
|
2
|
+
* Timing data for a single test
|
|
14
3
|
*/
|
|
15
4
|
export interface TestTimingData {
|
|
16
5
|
/** Source file containing this test */
|
|
@@ -23,31 +12,16 @@ export interface TestTimingData {
|
|
|
23
12
|
lastRun: string;
|
|
24
13
|
}
|
|
25
14
|
/**
|
|
26
|
-
* Complete timing data structure stored in cache (
|
|
15
|
+
* Complete timing data structure stored in cache (test-level)
|
|
27
16
|
*/
|
|
28
|
-
export interface
|
|
29
|
-
/** Schema version
|
|
30
|
-
version: 1;
|
|
31
|
-
/** ISO timestamp of last update */
|
|
32
|
-
updatedAt: string;
|
|
33
|
-
/** Map of file names to their timing data */
|
|
34
|
-
files: Record<string, FileTimingData>;
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Complete timing data structure stored in cache (v2 - test-level)
|
|
38
|
-
*/
|
|
39
|
-
export interface TimingDataV2 {
|
|
40
|
-
/** Schema version (2) */
|
|
17
|
+
export interface TimingData {
|
|
18
|
+
/** Schema version */
|
|
41
19
|
version: 2;
|
|
42
20
|
/** ISO timestamp of last update */
|
|
43
21
|
updatedAt: string;
|
|
44
22
|
/** Map of test IDs to their timing data */
|
|
45
23
|
tests: Record<string, TestTimingData>;
|
|
46
24
|
}
|
|
47
|
-
/**
|
|
48
|
-
* Union type for timing data (supports both versions)
|
|
49
|
-
*/
|
|
50
|
-
export type TimingData = TimingDataV1 | TimingDataV2;
|
|
51
25
|
/**
|
|
52
26
|
* Input for the shard assignment algorithm (file-level)
|
|
53
27
|
*/
|
|
@@ -113,10 +87,6 @@ export interface AssignResult {
|
|
|
113
87
|
export interface TestAssignResult {
|
|
114
88
|
/** Map of shard index to list of test IDs */
|
|
115
89
|
shards: Record<number, string[]>;
|
|
116
|
-
/** Map of shard index to grep pattern */
|
|
117
|
-
grepPatterns: Record<number, string>;
|
|
118
|
-
/** Map of shard index to test locations (file:line format) */
|
|
119
|
-
testLocations: Record<number, string[]>;
|
|
120
90
|
/** Expected duration per shard */
|
|
121
91
|
expectedDurations: Record<number, number>;
|
|
122
92
|
/** Total number of tests */
|
|
@@ -127,20 +97,9 @@ export interface TestAssignResult {
|
|
|
127
97
|
isOptimal: boolean;
|
|
128
98
|
}
|
|
129
99
|
/**
|
|
130
|
-
* Per-shard timing artifact uploaded after test run (
|
|
100
|
+
* Per-shard timing artifact uploaded after test run (test-level)
|
|
131
101
|
*/
|
|
132
102
|
export interface ShardTimingArtifact {
|
|
133
|
-
/** Shard index (1-based) */
|
|
134
|
-
shard: number;
|
|
135
|
-
/** Browser project name */
|
|
136
|
-
project: string;
|
|
137
|
-
/** Map of file names to duration in ms */
|
|
138
|
-
files: Record<string, number>;
|
|
139
|
-
}
|
|
140
|
-
/**
|
|
141
|
-
* Per-shard timing artifact uploaded after test run (test-level, v2)
|
|
142
|
-
*/
|
|
143
|
-
export interface TestShardTimingArtifact {
|
|
144
103
|
/** Shard index (1-based) */
|
|
145
104
|
shard: number;
|
|
146
105
|
/** Browser project name */
|
|
@@ -214,26 +173,15 @@ export interface PlaywrightListSpec {
|
|
|
214
173
|
}
|
|
215
174
|
/** Current schema version for timing data */
|
|
216
175
|
export declare const TIMING_DATA_VERSION = 2;
|
|
217
|
-
/** Legacy schema version */
|
|
218
|
-
export declare const TIMING_DATA_VERSION_V1 = 1;
|
|
219
176
|
/**
|
|
220
|
-
* Create an empty timing data structure
|
|
177
|
+
* Create an empty timing data structure
|
|
221
178
|
*/
|
|
222
|
-
export declare function createEmptyTimingData():
|
|
223
|
-
/**
|
|
224
|
-
* Create an empty timing data structure (v1 - file-level, for backwards compatibility)
|
|
225
|
-
*/
|
|
226
|
-
export declare function createEmptyTimingDataV1(): TimingDataV1;
|
|
179
|
+
export declare function createEmptyTimingData(): TimingData;
|
|
227
180
|
/**
|
|
228
181
|
* Build a test ID from file and title path
|
|
229
182
|
* Format: file::describe1::describe2::testTitle
|
|
230
183
|
*/
|
|
231
184
|
export declare function buildTestId(file: string, titlePath: string[]): string;
|
|
232
|
-
/**
|
|
233
|
-
* Build a test location from file and line
|
|
234
|
-
* Format: file:line (used for exact test filtering in Playwright)
|
|
235
|
-
*/
|
|
236
|
-
export declare function buildTestLocation(file: string, line: number): string;
|
|
237
185
|
/**
|
|
238
186
|
* Parse a test ID back to file and title path
|
|
239
187
|
*/
|
|
@@ -241,12 +189,4 @@ export declare function parseTestId(testId: string): {
|
|
|
241
189
|
file: string;
|
|
242
190
|
titlePath: string[];
|
|
243
191
|
};
|
|
244
|
-
/**
|
|
245
|
-
* Check if timing data is v2 (test-level)
|
|
246
|
-
*/
|
|
247
|
-
export declare function isTimingDataV2(data: TimingData): data is TimingDataV2;
|
|
248
|
-
/**
|
|
249
|
-
* Check if timing data is v1 (file-level)
|
|
250
|
-
*/
|
|
251
|
-
export declare function isTimingDataV1(data: TimingData): data is TimingDataV1;
|
|
252
192
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/core/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"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"}
|
package/dist/core/types.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
/** Current schema version for timing data */
|
|
2
2
|
export const TIMING_DATA_VERSION = 2;
|
|
3
|
-
/** Legacy schema version */
|
|
4
|
-
export const TIMING_DATA_VERSION_V1 = 1;
|
|
5
3
|
/**
|
|
6
|
-
* Create an empty timing data structure
|
|
4
|
+
* Create an empty timing data structure
|
|
7
5
|
*/
|
|
8
6
|
export function createEmptyTimingData() {
|
|
9
7
|
return {
|
|
@@ -12,16 +10,6 @@ export function createEmptyTimingData() {
|
|
|
12
10
|
tests: {},
|
|
13
11
|
};
|
|
14
12
|
}
|
|
15
|
-
/**
|
|
16
|
-
* Create an empty timing data structure (v1 - file-level, for backwards compatibility)
|
|
17
|
-
*/
|
|
18
|
-
export function createEmptyTimingDataV1() {
|
|
19
|
-
return {
|
|
20
|
-
version: TIMING_DATA_VERSION_V1,
|
|
21
|
-
updatedAt: new Date().toISOString(),
|
|
22
|
-
files: {},
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
13
|
/**
|
|
26
14
|
* Build a test ID from file and title path
|
|
27
15
|
* Format: file::describe1::describe2::testTitle
|
|
@@ -29,13 +17,6 @@ export function createEmptyTimingDataV1() {
|
|
|
29
17
|
export function buildTestId(file, titlePath) {
|
|
30
18
|
return [file, ...titlePath].join('::');
|
|
31
19
|
}
|
|
32
|
-
/**
|
|
33
|
-
* Build a test location from file and line
|
|
34
|
-
* Format: file:line (used for exact test filtering in Playwright)
|
|
35
|
-
*/
|
|
36
|
-
export function buildTestLocation(file, line) {
|
|
37
|
-
return `${file}:${line}`;
|
|
38
|
-
}
|
|
39
20
|
/**
|
|
40
21
|
* Parse a test ID back to file and title path
|
|
41
22
|
*/
|
|
@@ -46,16 +27,4 @@ export function parseTestId(testId) {
|
|
|
46
27
|
titlePath: parts.slice(1),
|
|
47
28
|
};
|
|
48
29
|
}
|
|
49
|
-
/**
|
|
50
|
-
* Check if timing data is v2 (test-level)
|
|
51
|
-
*/
|
|
52
|
-
export function isTimingDataV2(data) {
|
|
53
|
-
return data.version === 2;
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Check if timing data is v1 (file-level)
|
|
57
|
-
*/
|
|
58
|
-
export function isTimingDataV1(data) {
|
|
59
|
-
return data.version === 1;
|
|
60
|
-
}
|
|
61
30
|
//# sourceMappingURL=types.js.map
|
package/dist/core/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AA+LA,6CAA6C;AAC7C,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAErC;;GAEG;AACH,MAAM,UAAU,qBAAqB;IACnC,OAAO;QACL,OAAO,EAAE,mBAAmB;QAC5B,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,KAAK,EAAE,EAAE;KACV,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,SAAmB;IAC3D,OAAO,CAAC,IAAI,EAAE,GAAG,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,MAAc;IAIxC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACjC,OAAO;QACL,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE;QACpB,SAAS,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;KAC1B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Playwright Orchestrator Reporter
|
|
3
|
+
*
|
|
4
|
+
* A custom Playwright reporter that filters tests based on a JSON file
|
|
5
|
+
* containing test IDs. Uses exact Set.has() matching to avoid substring
|
|
6
|
+
* collisions that plague --grep approaches.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* 1. Add to playwright.config.ts:
|
|
10
|
+
* reporter: [['@nsxbet/playwright-orchestrator/reporter'], ['html']]
|
|
11
|
+
* 2. Set ORCHESTRATOR_SHARD_FILE env var to path of JSON file with test IDs
|
|
12
|
+
*
|
|
13
|
+
* Environment variables:
|
|
14
|
+
* - ORCHESTRATOR_SHARD_FILE: Path to JSON file with array of test IDs
|
|
15
|
+
* - ORCHESTRATOR_DEBUG: Set to "1" to enable debug logging
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* // shard.json
|
|
19
|
+
* ["e2e/login.spec.ts::Login::should login", "e2e/home.spec.ts::Home::should render"]
|
|
20
|
+
*
|
|
21
|
+
* // Run with filtering
|
|
22
|
+
* ORCHESTRATOR_SHARD_FILE=shard.json npx playwright test
|
|
23
|
+
*
|
|
24
|
+
* @module @nsxbet/playwright-orchestrator/reporter
|
|
25
|
+
*/
|
|
26
|
+
import type { FullConfig, Reporter, Suite, TestCase } from '@playwright/test/reporter';
|
|
27
|
+
export default class OrchestratorReporter implements Reporter {
|
|
28
|
+
private allowedTestIds;
|
|
29
|
+
private debug;
|
|
30
|
+
onBegin(_config: FullConfig, _suite: Suite): void;
|
|
31
|
+
onTestBegin(test: TestCase): void;
|
|
32
|
+
/**
|
|
33
|
+
* Build test ID from TestCase.
|
|
34
|
+
* Format: {relative-file}::{describe}::{test-title}
|
|
35
|
+
*
|
|
36
|
+
* This must match the format generated by the orchestrator.
|
|
37
|
+
*/
|
|
38
|
+
private buildTestId;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=reporter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAIH,OAAO,KAAK,EACV,UAAU,EACV,QAAQ,EACR,KAAK,EACL,QAAQ,EACT,MAAM,2BAA2B,CAAC;AAEnC,MAAM,CAAC,OAAO,OAAO,oBAAqB,YAAW,QAAQ;IAC3D,OAAO,CAAC,cAAc,CAA4B;IAClD,OAAO,CAAC,KAAK,CAA0C;IAEvD,OAAO,CAAC,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK;IAsB1C,WAAW,CAAC,IAAI,EAAE,QAAQ;IAa1B;;;;;OAKG;IACH,OAAO,CAAC,WAAW;CAMpB"}
|
package/dist/reporter.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Playwright Orchestrator Reporter
|
|
3
|
+
*
|
|
4
|
+
* A custom Playwright reporter that filters tests based on a JSON file
|
|
5
|
+
* containing test IDs. Uses exact Set.has() matching to avoid substring
|
|
6
|
+
* collisions that plague --grep approaches.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* 1. Add to playwright.config.ts:
|
|
10
|
+
* reporter: [['@nsxbet/playwright-orchestrator/reporter'], ['html']]
|
|
11
|
+
* 2. Set ORCHESTRATOR_SHARD_FILE env var to path of JSON file with test IDs
|
|
12
|
+
*
|
|
13
|
+
* Environment variables:
|
|
14
|
+
* - ORCHESTRATOR_SHARD_FILE: Path to JSON file with array of test IDs
|
|
15
|
+
* - ORCHESTRATOR_DEBUG: Set to "1" to enable debug logging
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* // shard.json
|
|
19
|
+
* ["e2e/login.spec.ts::Login::should login", "e2e/home.spec.ts::Home::should render"]
|
|
20
|
+
*
|
|
21
|
+
* // Run with filtering
|
|
22
|
+
* ORCHESTRATOR_SHARD_FILE=shard.json npx playwright test
|
|
23
|
+
*
|
|
24
|
+
* @module @nsxbet/playwright-orchestrator/reporter
|
|
25
|
+
*/
|
|
26
|
+
import * as fs from 'node:fs';
|
|
27
|
+
import * as path from 'node:path';
|
|
28
|
+
export default class OrchestratorReporter {
|
|
29
|
+
allowedTestIds = null;
|
|
30
|
+
debug = process.env.ORCHESTRATOR_DEBUG === '1';
|
|
31
|
+
onBegin(_config, _suite) {
|
|
32
|
+
const shardFile = process.env.ORCHESTRATOR_SHARD_FILE;
|
|
33
|
+
if (!shardFile || !fs.existsSync(shardFile)) {
|
|
34
|
+
if (this.debug) {
|
|
35
|
+
console.log('[Orchestrator] No shard file, running all tests');
|
|
36
|
+
}
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
const testIds = JSON.parse(fs.readFileSync(shardFile, 'utf-8'));
|
|
41
|
+
this.allowedTestIds = new Set(testIds);
|
|
42
|
+
console.log(`[Orchestrator] ${this.allowedTestIds.size} tests for this shard`);
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
console.error('[Orchestrator] Failed to load shard file:', error);
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
onTestBegin(test) {
|
|
50
|
+
if (!this.allowedTestIds)
|
|
51
|
+
return;
|
|
52
|
+
const testId = this.buildTestId(test);
|
|
53
|
+
if (!this.allowedTestIds.has(testId)) {
|
|
54
|
+
test.annotations.push({ type: 'skip', description: 'Not in shard' });
|
|
55
|
+
if (this.debug) {
|
|
56
|
+
console.log(`[Skip] ${testId}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Build test ID from TestCase.
|
|
62
|
+
* Format: {relative-file}::{describe}::{test-title}
|
|
63
|
+
*
|
|
64
|
+
* This must match the format generated by the orchestrator.
|
|
65
|
+
*/
|
|
66
|
+
buildTestId(test) {
|
|
67
|
+
const file = path
|
|
68
|
+
.relative(process.cwd(), test.location.file)
|
|
69
|
+
.replace(/\\/g, '/');
|
|
70
|
+
return [file, ...test.titlePath()].join('::');
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=reporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reporter.js","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAQlC,MAAM,CAAC,OAAO,OAAO,oBAAoB;IAC/B,cAAc,GAAuB,IAAI,CAAC;IAC1C,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,KAAK,GAAG,CAAC;IAEvD,OAAO,CAAC,OAAmB,EAAE,MAAa;QACxC,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC;QAEtD,IAAI,CAAC,SAAS,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC5C,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAC;YACjE,CAAC;YACD,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;YAChE,IAAI,CAAC,cAAc,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;YACvC,OAAO,CAAC,GAAG,CACT,kBAAkB,IAAI,CAAC,cAAc,CAAC,IAAI,uBAAuB,CAClE,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,2CAA2C,EAAE,KAAK,CAAC,CAAC;YAClE,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,WAAW,CAAC,IAAc;QACxB,IAAI,CAAC,IAAI,CAAC,cAAc;YAAE,OAAO;QAEjC,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAEtC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YACrC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,CAAC,CAAC;YACrE,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,GAAG,CAAC,UAAU,MAAM,EAAE,CAAC,CAAC;YAClC,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACK,WAAW,CAAC,IAAc;QAChC,MAAM,IAAI,GAAG,IAAI;aACd,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;aAC3C,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACvB,OAAO,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChD,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nsxbet/playwright-orchestrator",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "Intelligent Playwright test distribution across CI shards using historical timing data",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./reporter": {
|
|
15
|
+
"types": "./dist/reporter.d.ts",
|
|
16
|
+
"import": "./dist/reporter.js",
|
|
17
|
+
"require": "./dist/reporter.js"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
8
20
|
"bin": {
|
|
9
21
|
"playwright-orchestrator": "./bin/run.js"
|
|
10
22
|
},
|
|
@@ -64,7 +76,16 @@
|
|
|
64
76
|
"@biomejs/biome": "2.3.11",
|
|
65
77
|
"@changesets/changelog-github": "^0.5.2",
|
|
66
78
|
"@changesets/cli": "^2.29.8",
|
|
79
|
+
"@playwright/test": "^1.40.0",
|
|
67
80
|
"@types/node": "22.15.29",
|
|
68
81
|
"typescript": "5.9.3"
|
|
82
|
+
},
|
|
83
|
+
"peerDependencies": {
|
|
84
|
+
"@playwright/test": ">=1.20.0"
|
|
85
|
+
},
|
|
86
|
+
"peerDependenciesMeta": {
|
|
87
|
+
"@playwright/test": {
|
|
88
|
+
"optional": true
|
|
89
|
+
}
|
|
69
90
|
}
|
|
70
91
|
}
|