@dionlarson/playwright-orchestrator-core 1.3.2 → 1.3.4

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.
@@ -1,3 +1,4 @@
1
+ import { writeFileSync } from 'node:fs';
1
2
  export default class TestResultReporter {
2
3
  testResults = [];
3
4
  testCases = [];
@@ -58,6 +59,13 @@ export default class TestResultReporter {
58
59
  retry,
59
60
  })),
60
61
  };
61
- console.log(JSON.stringify(output));
62
+ const outputFile = process.env.PLAYWRIGHT_ORCHESTRATOR_RESULT_FILE;
63
+ if (outputFile) {
64
+ writeFileSync(outputFile, JSON.stringify(output));
65
+ }
66
+ else {
67
+ // Fallback to stdout if no file specified
68
+ console.log(JSON.stringify(output));
69
+ }
62
70
  }
63
71
  }
@@ -12,7 +12,6 @@ export declare class TestRunner {
12
12
  private runTestsUntilAvailable;
13
13
  private removePreviousReports;
14
14
  private runTest;
15
- private parseTestResult;
16
15
  private buildParams;
17
16
  private createTempConfig;
18
17
  }
@@ -1,37 +1,19 @@
1
1
  import { createHash } from 'node:crypto';
2
2
  import child_process, { spawn } from 'node:child_process';
3
3
  import { promisify } from 'node:util';
4
- import { rm, writeFile } from 'node:fs/promises';
4
+ import { mkdir, readFile, rm, writeFile } from 'node:fs/promises';
5
5
  import { TestExecutionReporter } from './reporters/test-execution-reporter.js';
6
6
  import path from 'node:path';
7
7
  import * as uuid from 'uuid';
8
8
  const exec = promisify(child_process.exec);
9
- function spawnWithOutput(command, args, env) {
9
+ function spawnPassthrough(command, env) {
10
10
  return new Promise((resolve, reject) => {
11
- const proc = spawn(command, args, {
11
+ const proc = spawn(command, {
12
12
  env,
13
13
  shell: true,
14
- stdio: ['inherit', 'pipe', 'inherit'] // stdin inherit, stdout pipe, stderr inherit
15
- });
16
- let stdout = '';
17
- proc.stdout?.on('data', (data) => {
18
- const str = data.toString();
19
- stdout += str;
20
- // Stream output but filter out the JSON reporter output
21
- if (!str.trim().startsWith('{')) {
22
- process.stdout.write(data);
23
- }
24
- });
25
- proc.on('close', (code) => {
26
- if (code === 0) {
27
- resolve(stdout);
28
- }
29
- else {
30
- const error = new Error(`Process exited with code ${code}`);
31
- error.stdout = stdout;
32
- reject(error);
33
- }
14
+ stdio: 'inherit' // Full passthrough - all output goes directly to terminal
34
15
  });
16
+ proc.on('close', (code) => resolve(code ?? 1));
35
17
  proc.on('error', reject);
36
18
  });
37
19
  }
@@ -88,45 +70,55 @@ export class TestRunner {
88
70
  }
89
71
  async removePreviousReports() {
90
72
  await rm(`./${this.outputFolder}`, { recursive: true, force: true });
73
+ await mkdir(`./${this.outputFolder}`, { recursive: true });
91
74
  }
92
75
  async runTest(test, config) {
93
76
  const testPosition = `${test.file}:${test.position}`;
94
77
  const testName = `[${test.project}] > ${testPosition}`;
95
78
  const testHash = createHash('md5').update(testName).digest('hex');
79
+ const resultFile = `${this.outputFolder}/${testHash}.result.json`;
96
80
  const args = [testPosition, ...this.buildParams(test, config, testHash).split(' ')];
97
81
  const env = {
98
82
  ...process.env,
99
83
  PLAYWRIGHT_BLOB_OUTPUT_FILE: `${this.outputFolder}/${testHash}.zip`,
84
+ PLAYWRIGHT_ORCHESTRATOR_RESULT_FILE: resultFile,
100
85
  };
86
+ const fullCommand = `npx playwright test ${args.join(' ')}`;
87
+ const exitCode = await spawnPassthrough(fullCommand, env);
88
+ let testResult;
101
89
  try {
102
- const stdout = await spawnWithOutput('npx', ['playwright', 'test', ...args], env);
90
+ const resultJson = await readFile(resultFile, 'utf-8');
91
+ testResult = JSON.parse(resultJson);
92
+ await rm(resultFile, { force: true });
93
+ }
94
+ catch (e) {
95
+ console.error(`[orchestrator] Failed to read test result for [${test.project}] ${test.file}:${test.position}`, e);
96
+ throw e;
97
+ }
98
+ if (exitCode === 0) {
99
+ console.log(`[orchestrator] Test passed: [${test.project}] ${test.file}:${test.position}`);
103
100
  this.reporter.finishTest(test);
104
101
  await this.adapter.finishTest({
105
102
  runId: this.runId,
106
103
  test,
107
- testResult: this.parseTestResult(stdout),
104
+ testResult,
108
105
  config,
109
106
  });
110
107
  }
111
- catch (error) {
112
- if (!error.stdout)
113
- throw error;
108
+ else {
109
+ console.log(`[orchestrator] Test failed: [${test.project}] ${test.file}:${test.position}`);
114
110
  this.reporter.failTest(test);
115
111
  await this.adapter.failTest({
116
112
  runId: this.runId,
117
113
  test,
118
- testResult: this.parseTestResult(error.stdout),
114
+ testResult,
119
115
  config,
120
116
  });
121
117
  }
122
118
  }
123
- parseTestResult(stdout) {
124
- return JSON.parse(stdout);
125
- }
126
119
  buildParams(test, config, testHash) {
127
120
  const args = [...config.args];
128
121
  args.push('--workers', '1');
129
- args.push('--reporter', 'blob,@dionlarson/playwright-orchestrator-core/test-result-reporter');
130
122
  args.push('--project', `"${test.project}"`);
131
123
  args.push('--output', `"${this.outputFolder}/${testHash}"`);
132
124
  if (config.configFile) {
@@ -137,10 +129,22 @@ export class TestRunner {
137
129
  async createTempConfig(file) {
138
130
  if (!file)
139
131
  return;
140
- // Remove webServer from the config. Not supported in the orchestrator
132
+ // Modify config: remove webServer, add our reporters while preserving existing ones
141
133
  const content = `
142
134
  import config from '${path.resolve(file)}';
135
+
136
+ // Remove webServer - not supported in orchestrator (server should already be running)
143
137
  delete config.webServer;
138
+
139
+ // Add our reporters while preserving existing reporters from config
140
+ const existingReporters = Array.isArray(config.reporter) ? config.reporter :
141
+ config.reporter ? [[config.reporter]] : [];
142
+ config.reporter = [
143
+ ...existingReporters,
144
+ ['blob'],
145
+ ['@dionlarson/playwright-orchestrator-core/test-result-reporter'],
146
+ ];
147
+
144
148
  export default config;`;
145
149
  const tempFile = `.playwright-${uuid.v7()}.config.tmp.ts`;
146
150
  await writeFile(tempFile, content);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dionlarson/playwright-orchestrator-core",
3
- "version": "1.3.2",
3
+ "version": "1.3.4",
4
4
  "description": "Core lib and cli for Playwright test orchestration",
5
5
  "keywords": [
6
6
  "playwright",