playwright-order-manager 0.1.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.
- package/CHANGELOG.md +20 -0
- package/README.md +240 -0
- package/bin/run.js +133 -0
- package/dist/constants/index.d.ts +72 -0
- package/dist/constants/index.d.ts.map +1 -0
- package/dist/constants/index.js +93 -0
- package/dist/constants/index.js.map +1 -0
- package/dist/core/OrderedExecution.d.ts +52 -0
- package/dist/core/OrderedExecution.d.ts.map +1 -0
- package/dist/core/OrderedExecution.js +253 -0
- package/dist/core/OrderedExecution.js.map +1 -0
- package/dist/core/OrderedReportParser.d.ts +38 -0
- package/dist/core/OrderedReportParser.d.ts.map +1 -0
- package/dist/core/OrderedReportParser.js +169 -0
- package/dist/core/OrderedReportParser.js.map +1 -0
- package/dist/core/OrderedSummary.d.ts +20 -0
- package/dist/core/OrderedSummary.d.ts.map +1 -0
- package/dist/core/OrderedSummary.js +747 -0
- package/dist/core/OrderedSummary.js.map +1 -0
- package/dist/fixtures/index.d.ts +30 -0
- package/dist/fixtures/index.d.ts.map +1 -0
- package/dist/fixtures/index.js +212 -0
- package/dist/fixtures/index.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/runner/TestOrderManager.d.ts +62 -0
- package/dist/runner/TestOrderManager.d.ts.map +1 -0
- package/dist/runner/TestOrderManager.js +490 -0
- package/dist/runner/TestOrderManager.js.map +1 -0
- package/dist/types/index.d.ts +215 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +6 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +65 -0
- package/templates/playwright.merge.config.ts +57 -0
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.TestOrderManager = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const os = __importStar(require("os"));
|
|
40
|
+
const child_process_1 = require("child_process");
|
|
41
|
+
const constants_1 = require("../constants");
|
|
42
|
+
const OrderedExecution_1 = require("../core/OrderedExecution");
|
|
43
|
+
const OrderedReportParser_1 = require("../core/OrderedReportParser");
|
|
44
|
+
const OrderedSummary_1 = require("../core/OrderedSummary");
|
|
45
|
+
// =============================================================================
|
|
46
|
+
// INTERNAL HELPERS
|
|
47
|
+
// =============================================================================
|
|
48
|
+
/**
|
|
49
|
+
* Merges env vars and a RunConfig object into a ResolvedConfig.
|
|
50
|
+
* RunConfig values take priority over env vars.
|
|
51
|
+
* Env vars take priority over hardcoded defaults.
|
|
52
|
+
*
|
|
53
|
+
* Priority order (highest → lowest):
|
|
54
|
+
* RunConfig object → env vars → RunnerConstants.DEFAULTS
|
|
55
|
+
*/
|
|
56
|
+
function resolveConfig(userConfig) {
|
|
57
|
+
const env = process.env;
|
|
58
|
+
const orderMode = (userConfig?.orderMode ??
|
|
59
|
+
env['ORDER_MODE'] ??
|
|
60
|
+
constants_1.RunnerConstants.DEFAULTS.ORDER_MODE);
|
|
61
|
+
const failurePolicy = (userConfig?.failurePolicy ??
|
|
62
|
+
env['FAILURE_POLICY'] ??
|
|
63
|
+
constants_1.RunnerConstants.DEFAULTS.FAILURE_POLICY);
|
|
64
|
+
const reportRoot = userConfig?.reportRoot ??
|
|
65
|
+
env['ORDERED_REPORT_ROOT'] ??
|
|
66
|
+
constants_1.RunnerConstants.DEFAULTS.REPORT_ROOT;
|
|
67
|
+
const playwrightConfigPath = userConfig?.playwrightConfigPath ??
|
|
68
|
+
env['PLAYWRIGHT_CONFIG'] ??
|
|
69
|
+
'playwright.config.ts';
|
|
70
|
+
const mergeConfigPath = userConfig?.mergeConfigPath ??
|
|
71
|
+
env['PLAYWRIGHT_MERGE_CONFIG'] ??
|
|
72
|
+
'playwright.merge.config.ts';
|
|
73
|
+
// project can be a string, array, or comma-separated env var
|
|
74
|
+
let project = [];
|
|
75
|
+
if (userConfig?.project) {
|
|
76
|
+
project = Array.isArray(userConfig.project)
|
|
77
|
+
? userConfig.project
|
|
78
|
+
: [userConfig.project];
|
|
79
|
+
}
|
|
80
|
+
else if (env['PLAYWRIGHT_PROJECT']) {
|
|
81
|
+
project = env['PLAYWRIGHT_PROJECT'].split(',').map((p) => p.trim());
|
|
82
|
+
}
|
|
83
|
+
const extraArgs = userConfig?.extraArgs ?? [];
|
|
84
|
+
return {
|
|
85
|
+
playwrightConfigPath,
|
|
86
|
+
mergeConfigPath,
|
|
87
|
+
reportRoot,
|
|
88
|
+
orderMode,
|
|
89
|
+
failurePolicy,
|
|
90
|
+
project,
|
|
91
|
+
extraArgs,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Ensures a directory exists, creating it recursively if needed.
|
|
96
|
+
*/
|
|
97
|
+
function ensureDir(dirPath) {
|
|
98
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Logs a message with a [pw-order] prefix.
|
|
102
|
+
* Using a prefix makes our output easy to distinguish from Playwright's output.
|
|
103
|
+
*/
|
|
104
|
+
function log(message) {
|
|
105
|
+
console.log(`[pw-order] ${message}`);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Logs an error with a [pw-order] prefix.
|
|
109
|
+
*/
|
|
110
|
+
function logError(message) {
|
|
111
|
+
console.error(`[pw-order] ERROR: ${message}`);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Returns the absolute path to the Playwright CLI binary.
|
|
115
|
+
* We always use the local installation (node_modules/.bin/playwright)
|
|
116
|
+
* rather than a global one — ensures we use the version the project depends on.
|
|
117
|
+
*/
|
|
118
|
+
function getPlaywrightBin() {
|
|
119
|
+
return path.resolve(process.cwd(), 'node_modules', '.bin', os.platform() === 'win32' ? 'playwright.cmd' : 'playwright');
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Spawns a child process and returns a promise that resolves
|
|
123
|
+
* with the exit code when the process finishes.
|
|
124
|
+
*
|
|
125
|
+
* stdout and stderr are piped to the parent process in real time
|
|
126
|
+
* so the user sees Playwright's output as it happens.
|
|
127
|
+
*
|
|
128
|
+
* @param command - The executable to run
|
|
129
|
+
* @param args - Arguments to pass to the executable
|
|
130
|
+
* @param env - Additional environment variables to inject
|
|
131
|
+
*/
|
|
132
|
+
function spawnProcess(command, args, env = {}) {
|
|
133
|
+
return new Promise((resolve, reject) => {
|
|
134
|
+
const child = (0, child_process_1.spawn)(command, args, {
|
|
135
|
+
stdio: 'inherit', // pipe stdout/stderr straight to terminal
|
|
136
|
+
env: {
|
|
137
|
+
...process.env, // inherit everything from the parent
|
|
138
|
+
...env, // then add/override our extras
|
|
139
|
+
},
|
|
140
|
+
shell: false, // never use shell — avoids platform quoting issues
|
|
141
|
+
});
|
|
142
|
+
child.on('close', (code) => resolve(code ?? 1));
|
|
143
|
+
child.on('error', (err) => reject(new Error(`Failed to spawn ${command}: ${err.message}`)));
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Builds the Playwright CLI args for a discovery run (--list).
|
|
148
|
+
* We set --reporter=json and point it at a temp file so we can
|
|
149
|
+
* parse the discovered tests after the process exits.
|
|
150
|
+
*/
|
|
151
|
+
function buildDiscoveryArgs(config, discoveryJsonPath) {
|
|
152
|
+
const args = [
|
|
153
|
+
'test',
|
|
154
|
+
'--list',
|
|
155
|
+
'--config', config.playwrightConfigPath,
|
|
156
|
+
`--reporter=json`,
|
|
157
|
+
];
|
|
158
|
+
for (const project of config.project) {
|
|
159
|
+
args.push('--project', project);
|
|
160
|
+
}
|
|
161
|
+
args.push(...config.extraArgs);
|
|
162
|
+
return args;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Builds the Playwright CLI args for executing a single bucket.
|
|
166
|
+
*
|
|
167
|
+
* We pass the test file paths as positional arguments so Playwright
|
|
168
|
+
* only runs the tests that belong to this bucket.
|
|
169
|
+
*/
|
|
170
|
+
function buildBucketArgs(config, bucket, executionJsonPath) {
|
|
171
|
+
// Collect unique file paths for tests in this bucket
|
|
172
|
+
const files = [...new Set(bucket.tests.map((t) => t.file))];
|
|
173
|
+
const args = [
|
|
174
|
+
'test',
|
|
175
|
+
'--config', config.playwrightConfigPath,
|
|
176
|
+
`--reporter=json`,
|
|
177
|
+
];
|
|
178
|
+
for (const project of config.project) {
|
|
179
|
+
args.push('--project', project);
|
|
180
|
+
}
|
|
181
|
+
// Add each file as a positional argument
|
|
182
|
+
args.push(...files);
|
|
183
|
+
args.push(...config.extraArgs);
|
|
184
|
+
return args;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Aggregates an array of ExecutedTestResult into bucket-level counts.
|
|
188
|
+
*/
|
|
189
|
+
function aggregateResults(results) {
|
|
190
|
+
return results.reduce((acc, r) => ({
|
|
191
|
+
passed: acc.passed + (r.status === 'passed' ? 1 : 0),
|
|
192
|
+
failed: acc.failed + (r.status === 'failed' || r.status === 'timedOut' ? 1 : 0),
|
|
193
|
+
skipped: acc.skipped + (r.status === 'skipped' ? 1 : 0),
|
|
194
|
+
totalDuration: acc.totalDuration + r.duration,
|
|
195
|
+
}), { passed: 0, failed: 0, skipped: 0, totalDuration: 0 });
|
|
196
|
+
}
|
|
197
|
+
// =============================================================================
|
|
198
|
+
// CORE RUNNER CLASS
|
|
199
|
+
// =============================================================================
|
|
200
|
+
class TestOrderManager {
|
|
201
|
+
// ---------------------------------------------------------------------------
|
|
202
|
+
// PHASE 1 — DISCOVERY
|
|
203
|
+
// ---------------------------------------------------------------------------
|
|
204
|
+
/**
|
|
205
|
+
* Runs `playwright --list` to discover all tests matching the config.
|
|
206
|
+
* Sets ORDERED_DISCOVERY=true so our fixture captures test metadata.
|
|
207
|
+
* Returns the discovered tests parsed from the discovery JSON file.
|
|
208
|
+
*/
|
|
209
|
+
static async discover(config) {
|
|
210
|
+
log('Starting discovery phase...');
|
|
211
|
+
const discoveryFilePath = path.resolve(process.cwd(), config.reportRoot, constants_1.RunnerConstants.DEFAULTS.DISCOVERY_FILENAME);
|
|
212
|
+
// Clean up any previous discovery file so we start fresh
|
|
213
|
+
ensureDir(path.dirname(discoveryFilePath));
|
|
214
|
+
if (fs.existsSync(discoveryFilePath)) {
|
|
215
|
+
fs.unlinkSync(discoveryFilePath);
|
|
216
|
+
}
|
|
217
|
+
// Write to a temp JSON file — Playwright's --list with --reporter=json
|
|
218
|
+
// doesn't write to disk by default, our fixture handles the actual write
|
|
219
|
+
const discoveryArgs = buildDiscoveryArgs(config, discoveryFilePath);
|
|
220
|
+
log(`Running: playwright ${discoveryArgs.join(' ')}`);
|
|
221
|
+
const exitCode = await spawnProcess(getPlaywrightBin(), discoveryArgs, {
|
|
222
|
+
ORDERED_DISCOVERY: 'true',
|
|
223
|
+
ORDERED_REPORT_ROOT: config.reportRoot,
|
|
224
|
+
});
|
|
225
|
+
// --list exits with 0 even if no tests found, but non-zero means a config error
|
|
226
|
+
if (exitCode !== 0) {
|
|
227
|
+
throw new Error(`Discovery failed with exit code ${exitCode}. ` +
|
|
228
|
+
`Check your playwright.config.ts for errors.`);
|
|
229
|
+
}
|
|
230
|
+
// Read and parse the discovery file written by our fixture
|
|
231
|
+
if (!fs.existsSync(discoveryFilePath)) {
|
|
232
|
+
log('Warning: no discovery file found. Did you import test from playwright-order-manager in your test files?');
|
|
233
|
+
return [];
|
|
234
|
+
}
|
|
235
|
+
const raw = JSON.parse(fs.readFileSync(discoveryFilePath, 'utf8'));
|
|
236
|
+
const tests = OrderedReportParser_1.OrderedReportParser.parseDiscoveryReport(raw);
|
|
237
|
+
log(`Discovered ${tests.length} tests across ${config.project.length || 'all'} projects`);
|
|
238
|
+
return tests;
|
|
239
|
+
}
|
|
240
|
+
// ---------------------------------------------------------------------------
|
|
241
|
+
// PHASE 2 — PLANNING
|
|
242
|
+
// ---------------------------------------------------------------------------
|
|
243
|
+
/**
|
|
244
|
+
* Takes discovered tests and builds the ordered bucket plan.
|
|
245
|
+
* Logs the plan so the user can see exactly what will run and in what order.
|
|
246
|
+
*/
|
|
247
|
+
static plan(tests, config) {
|
|
248
|
+
log(`Planning execution order (mode: ${config.orderMode})...`);
|
|
249
|
+
const buckets = OrderedExecution_1.OrderedExecution.buildBuckets({
|
|
250
|
+
tests,
|
|
251
|
+
orderMode: config.orderMode,
|
|
252
|
+
});
|
|
253
|
+
log(`Execution plan: ${buckets.length} bucket(s)`);
|
|
254
|
+
buckets.forEach((bucket, index) => {
|
|
255
|
+
const critical = bucket.critical ? ' [critical]' : '';
|
|
256
|
+
log(` #${index + 1} ${bucket.label}${critical} — ${bucket.tests.length} tests`);
|
|
257
|
+
});
|
|
258
|
+
return buckets;
|
|
259
|
+
}
|
|
260
|
+
// ---------------------------------------------------------------------------
|
|
261
|
+
// PHASE 3 — EXECUTION (one bucket at a time)
|
|
262
|
+
// ---------------------------------------------------------------------------
|
|
263
|
+
/**
|
|
264
|
+
* Executes a single bucket by spawning Playwright and parsing the results.
|
|
265
|
+
*
|
|
266
|
+
* Returns a BucketRunResult containing:
|
|
267
|
+
* - record: The completed BucketExecutionRecord to add to the summary
|
|
268
|
+
* - shouldAbort: Whether the failure policy says we must stop the run
|
|
269
|
+
*/
|
|
270
|
+
static async executeBucket(bucket, bucketIndex, totalBuckets, config) {
|
|
271
|
+
const num = bucketIndex + 1;
|
|
272
|
+
log(`\nExecuting bucket #${num}/${totalBuckets}: ${bucket.label} (${bucket.tests.length} tests)`);
|
|
273
|
+
const startedAt = new Date().toISOString();
|
|
274
|
+
// Path where Playwright writes its JSON report for this bucket
|
|
275
|
+
const executionJsonPath = path.resolve(process.cwd(), config.reportRoot, `bucket-${num}-${bucket.key}.json`);
|
|
276
|
+
const bucketArgs = buildBucketArgs(config, bucket, executionJsonPath);
|
|
277
|
+
log(`Running: playwright ${bucketArgs.join(' ')}`);
|
|
278
|
+
const exitCode = await spawnProcess(getPlaywrightBin(), bucketArgs, {
|
|
279
|
+
ORDERED_REPORT_ROOT: config.reportRoot,
|
|
280
|
+
// Tell Playwright to write its JSON report to our path
|
|
281
|
+
PLAYWRIGHT_JSON_OUTPUT_NAME: executionJsonPath,
|
|
282
|
+
});
|
|
283
|
+
const finishedAt = new Date().toISOString();
|
|
284
|
+
// Parse results from the JSON report Playwright wrote
|
|
285
|
+
let results = [];
|
|
286
|
+
if (fs.existsSync(executionJsonPath)) {
|
|
287
|
+
try {
|
|
288
|
+
const raw = JSON.parse(fs.readFileSync(executionJsonPath, 'utf8'));
|
|
289
|
+
results = OrderedReportParser_1.OrderedReportParser.parseExecutionReport(raw);
|
|
290
|
+
// Attach tags from the original bucket plan to each result
|
|
291
|
+
// so the HTML report can show them per test
|
|
292
|
+
results = results.map((result) => {
|
|
293
|
+
const originalTest = bucket.tests.find((t) => t.title === result.title && t.file === result.file);
|
|
294
|
+
return {
|
|
295
|
+
...result,
|
|
296
|
+
tags: originalTest?.tags ?? [],
|
|
297
|
+
};
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
catch (err) {
|
|
301
|
+
logError(`Failed to parse execution report for bucket ${bucket.label}: ${err.message}`);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
logError(`No execution report found for bucket ${bucket.label}. Tests may not have run.`);
|
|
306
|
+
}
|
|
307
|
+
// Aggregate results into bucket-level counts
|
|
308
|
+
const counts = aggregateResults(results);
|
|
309
|
+
const bucketStatus = counts.failed > 0 ? 'failed' : 'passed';
|
|
310
|
+
const record = {
|
|
311
|
+
key: bucket.key,
|
|
312
|
+
label: bucket.label,
|
|
313
|
+
critical: bucket.critical,
|
|
314
|
+
totalTests: bucket.tests.length,
|
|
315
|
+
passed: counts.passed,
|
|
316
|
+
failed: counts.failed,
|
|
317
|
+
skipped: counts.skipped,
|
|
318
|
+
duration: counts.totalDuration,
|
|
319
|
+
status: bucketStatus,
|
|
320
|
+
startedAt,
|
|
321
|
+
finishedAt,
|
|
322
|
+
results,
|
|
323
|
+
};
|
|
324
|
+
// Log bucket result
|
|
325
|
+
log(`Bucket #${num} complete: ` +
|
|
326
|
+
`${counts.passed} passed, ${counts.failed} failed, ${counts.skipped} skipped`);
|
|
327
|
+
// Determine if we should abort based on failure policy
|
|
328
|
+
const shouldAbort = TestOrderManager.shouldAbortRun(record, config.failurePolicy);
|
|
329
|
+
if (shouldAbort) {
|
|
330
|
+
logError(`Aborting run after bucket #${num} (${bucket.label}) — ` +
|
|
331
|
+
`failure policy: ${config.failurePolicy}`);
|
|
332
|
+
}
|
|
333
|
+
return { record, shouldAbort };
|
|
334
|
+
}
|
|
335
|
+
// ---------------------------------------------------------------------------
|
|
336
|
+
// FAILURE POLICY
|
|
337
|
+
// ---------------------------------------------------------------------------
|
|
338
|
+
/**
|
|
339
|
+
* Determines whether the run should be aborted after a bucket completes.
|
|
340
|
+
*
|
|
341
|
+
* - 'critical' → abort only if this specific bucket is marked critical AND failed
|
|
342
|
+
* - 'immediate' → abort on any failure, regardless of critical flag
|
|
343
|
+
* - 'continue' → never abort, always run all remaining buckets
|
|
344
|
+
*/
|
|
345
|
+
static shouldAbortRun(record, policy) {
|
|
346
|
+
if (record.status !== 'failed')
|
|
347
|
+
return false;
|
|
348
|
+
switch (policy) {
|
|
349
|
+
case 'critical':
|
|
350
|
+
return record.critical;
|
|
351
|
+
case 'immediate':
|
|
352
|
+
return true;
|
|
353
|
+
case 'continue':
|
|
354
|
+
return false;
|
|
355
|
+
default: {
|
|
356
|
+
const check = policy;
|
|
357
|
+
throw new Error(`Unknown failure policy: ${check}`);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
// ---------------------------------------------------------------------------
|
|
362
|
+
// PHASE 4 — FULL ORCHESTRATED RUN
|
|
363
|
+
// ---------------------------------------------------------------------------
|
|
364
|
+
/**
|
|
365
|
+
* Runs the complete ordered test suite.
|
|
366
|
+
*
|
|
367
|
+
* This is the main entry point — called by bin/run.js (CLI usage)
|
|
368
|
+
* or directly by users who import TestOrderManager programmatically.
|
|
369
|
+
*
|
|
370
|
+
* @param userConfig - Optional RunConfig for programmatic use.
|
|
371
|
+
* All fields fall back to env vars then defaults.
|
|
372
|
+
*
|
|
373
|
+
* @returns The process exit code: 0 for success, 1 for failure.
|
|
374
|
+
* When called from bin/run.js, we call process.exit() directly.
|
|
375
|
+
* When called programmatically, we return the code so the caller
|
|
376
|
+
* can decide what to do with it.
|
|
377
|
+
*
|
|
378
|
+
* @example CLI usage (via bin/run.js):
|
|
379
|
+
* ```
|
|
380
|
+
* npx pw-order --project=chromium
|
|
381
|
+
* ```
|
|
382
|
+
*
|
|
383
|
+
* @example Programmatic usage:
|
|
384
|
+
* ```typescript
|
|
385
|
+
* import { TestOrderManager } from 'playwright-order-manager';
|
|
386
|
+
*
|
|
387
|
+
* const exitCode = await TestOrderManager.run({
|
|
388
|
+
* orderMode: 'priority',
|
|
389
|
+
* failurePolicy: 'continue',
|
|
390
|
+
* project: 'chromium',
|
|
391
|
+
* });
|
|
392
|
+
* ```
|
|
393
|
+
*/
|
|
394
|
+
static async run(userConfig) {
|
|
395
|
+
const startedAt = new Date().toISOString();
|
|
396
|
+
const config = resolveConfig(userConfig);
|
|
397
|
+
log('='.repeat(60));
|
|
398
|
+
log('playwright-order-manager');
|
|
399
|
+
log('='.repeat(60));
|
|
400
|
+
log(`Order mode: ${config.orderMode}`);
|
|
401
|
+
log(`Failure policy: ${config.failurePolicy}`);
|
|
402
|
+
log(`Report root: ${config.reportRoot}`);
|
|
403
|
+
log(`Config: ${config.playwrightConfigPath}`);
|
|
404
|
+
if (config.project.length > 0) {
|
|
405
|
+
log(`Projects: ${config.project.join(', ')}`);
|
|
406
|
+
}
|
|
407
|
+
log('='.repeat(60));
|
|
408
|
+
// Ensure report root exists before anything else
|
|
409
|
+
ensureDir(path.resolve(process.cwd(), config.reportRoot));
|
|
410
|
+
let allBucketRecords = [];
|
|
411
|
+
let exitCode = 0;
|
|
412
|
+
try {
|
|
413
|
+
// ── Phase 1: Discover ──────────────────────────────────────────
|
|
414
|
+
const tests = await TestOrderManager.discover(config);
|
|
415
|
+
if (tests.length === 0) {
|
|
416
|
+
log('No tests discovered. Exiting.');
|
|
417
|
+
return 0;
|
|
418
|
+
}
|
|
419
|
+
// ── Phase 2: Plan ──────────────────────────────────────────────
|
|
420
|
+
const buckets = TestOrderManager.plan(tests, config);
|
|
421
|
+
if (buckets.length === 0) {
|
|
422
|
+
log('No buckets to execute. Exiting.');
|
|
423
|
+
return 0;
|
|
424
|
+
}
|
|
425
|
+
// ── Phase 3: Execute ───────────────────────────────────────────
|
|
426
|
+
// We split into three phases: runFirst → middle → runLast
|
|
427
|
+
// The runLast phase always executes even if middle buckets failed,
|
|
428
|
+
// because runLast is typically cleanup and must always run.
|
|
429
|
+
const { runFirst, middle, runLast } = OrderedExecution_1.OrderedExecution.groupBuckets(buckets);
|
|
430
|
+
let aborted = false;
|
|
431
|
+
// runFirst phase
|
|
432
|
+
for (const bucket of runFirst) {
|
|
433
|
+
const result = await TestOrderManager.executeBucket(bucket, allBucketRecords.length, buckets.length, config);
|
|
434
|
+
allBucketRecords.push(result.record);
|
|
435
|
+
if (result.shouldAbort) {
|
|
436
|
+
aborted = true;
|
|
437
|
+
exitCode = 1;
|
|
438
|
+
break;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
// middle phase — skip if aborted in runFirst
|
|
442
|
+
if (!aborted) {
|
|
443
|
+
for (const bucket of middle) {
|
|
444
|
+
const result = await TestOrderManager.executeBucket(bucket, allBucketRecords.length, buckets.length, config);
|
|
445
|
+
allBucketRecords.push(result.record);
|
|
446
|
+
if (result.record.status === 'failed')
|
|
447
|
+
exitCode = 1;
|
|
448
|
+
if (result.shouldAbort) {
|
|
449
|
+
aborted = true;
|
|
450
|
+
break;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
// runLast phase — ALWAYS executes, even after abort
|
|
455
|
+
// This ensures cleanup tests always run
|
|
456
|
+
for (const bucket of runLast) {
|
|
457
|
+
const result = await TestOrderManager.executeBucket(bucket, allBucketRecords.length, buckets.length, config);
|
|
458
|
+
allBucketRecords.push(result.record);
|
|
459
|
+
if (result.record.status === 'failed')
|
|
460
|
+
exitCode = 1;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
catch (err) {
|
|
464
|
+
logError(err.message);
|
|
465
|
+
exitCode = 1;
|
|
466
|
+
}
|
|
467
|
+
// ── Phase 4: Summarise ─────────────────────────────────────────────
|
|
468
|
+
try {
|
|
469
|
+
const summary = OrderedSummary_1.OrderedSummary.buildSummary(allBucketRecords, startedAt, config.orderMode, config.failurePolicy);
|
|
470
|
+
const { jsonPath, htmlPath } = OrderedSummary_1.OrderedSummary.write(summary, path.resolve(process.cwd(), config.reportRoot));
|
|
471
|
+
log('='.repeat(60));
|
|
472
|
+
log(`Run complete`);
|
|
473
|
+
log(` Total: ${summary.totals.tests} tests`);
|
|
474
|
+
log(` Passed: ${summary.totals.passed}`);
|
|
475
|
+
log(` Failed: ${summary.totals.failed}`);
|
|
476
|
+
log(` Skipped: ${summary.totals.skipped}`);
|
|
477
|
+
log(` Result: ${summary.success ? 'PASSED' : 'FAILED'}`);
|
|
478
|
+
log(` JSON: ${jsonPath}`);
|
|
479
|
+
log(` HTML: ${htmlPath}`);
|
|
480
|
+
log('='.repeat(60));
|
|
481
|
+
}
|
|
482
|
+
catch (err) {
|
|
483
|
+
logError(`Failed to write summary: ${err.message}`);
|
|
484
|
+
exitCode = 1;
|
|
485
|
+
}
|
|
486
|
+
return exitCode;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
exports.TestOrderManager = TestOrderManager;
|
|
490
|
+
//# sourceMappingURL=TestOrderManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TestOrderManager.js","sourceRoot":"","sources":["../../src/runner/TestOrderManager.ts"],"names":[],"mappings":"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"}
|