@nsxbet/playwright-orchestrator 0.6.3 → 0.8.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/README.md CHANGED
@@ -25,29 +25,48 @@ This orchestrator:
25
25
 
26
26
  Result: All shards finish at roughly the same time.
27
27
 
28
+ ### Test-Level Distribution
29
+
30
+ Unlike other solutions that only distribute at the **file level**, this orchestrator supports **test-level distribution**. This matters when you have files with many tests of varying durations - distributing individual tests achieves much better balance than distributing entire files.
31
+
32
+ ```
33
+ File-level: login.spec.ts (50 tests, 10min) → all go to shard 1
34
+ Test-level: login.spec.ts tests → spread across shards 1-4
35
+ ```
36
+
37
+ Test-level distribution requires the reporter AND a test fixture to filter tests at runtime. See [Setup](#setup) below.
38
+
28
39
  ## Quick Start
29
40
 
30
41
  ```bash
31
42
  # Install
32
43
  bun add -D @nsxbet/playwright-orchestrator
33
44
 
34
- # Discover tests (uses Playwright --list for accurate discovery)
35
- playwright-orchestrator list-tests --test-dir ./e2e --project "Mobile Chrome"
45
+ # Generate test list
46
+ bunx playwright test --list --reporter=json --project "Mobile Chrome" > test-list.json
36
47
 
37
- # Assign tests to shards (with timing data)
38
- playwright-orchestrator assign \
39
- --test-dir ./e2e \
48
+ # Assign tests to shards
49
+ bunx playwright-orchestrator assign \
50
+ --test-list ./test-list.json \
40
51
  --timing-file ./timing-data.json \
41
- --shards 4 \
42
- --project "Mobile Chrome" # Recommended for accurate test discovery
52
+ --shards 4 > assignment.json
53
+
54
+ # Extract each shard's tests to separate files
55
+ jq '.shards."1"' assignment.json > shard-1.json
56
+ jq '.shards."2"' assignment.json > shard-2.json
57
+ jq '.shards."3"' assignment.json > shard-3.json
58
+ jq '.shards."4"' assignment.json > shard-4.json
43
59
 
44
- # Extract timing from report
45
- playwright-orchestrator extract-timing \
60
+ # Run tests for a specific shard (fixture filters based on ORCHESTRATOR_SHARD_FILE)
61
+ ORCHESTRATOR_SHARD_FILE=shard-1.json bunx playwright test --project "Mobile Chrome"
62
+
63
+ # Extract timing from report after tests complete
64
+ bunx playwright-orchestrator extract-timing \
46
65
  --report-file ./playwright-report/results.json \
47
66
  --output-file ./shard-1-timing.json
48
67
 
49
- # Merge timing data
50
- playwright-orchestrator merge-timing \
68
+ # Merge timing data from all shards
69
+ bunx playwright-orchestrator merge-timing \
51
70
  --existing ./timing-data.json \
52
71
  --new ./shard-1-timing.json ./shard-2-timing.json \
53
72
  --output ./timing-data.json
@@ -70,9 +89,11 @@ playwright-orchestrator merge-timing \
70
89
  2. **Run Tests**: Each shard reads its files from `needs.orchestrate.outputs`
71
90
  3. **Merge**: Collect timing from all shards, update history with EMA
72
91
 
73
- ## Reporter Setup
92
+ ## Setup
93
+
94
+ For test-level distribution to work, you need **two things**:
74
95
 
75
- Add the reporter to your `playwright.config.ts`:
96
+ ### 1. Reporter (in `playwright.config.ts`)
76
97
 
77
98
  ```typescript
78
99
  import { defineConfig } from "@playwright/test";
@@ -82,7 +103,33 @@ export default defineConfig({
82
103
  });
83
104
  ```
84
105
 
85
- The reporter reads `ORCHESTRATOR_SHARD_FILE` env var to filter tests for the current shard.
106
+ ### 2. Test Fixture (in your test setup file)
107
+
108
+ Wrap your base test with `withOrchestratorFilter`:
109
+
110
+ ```typescript
111
+ // e2e/setup.ts
112
+ import { test as base } from "@playwright/test";
113
+ import { withOrchestratorFilter } from "@nsxbet/playwright-orchestrator/fixture";
114
+
115
+ export const test = withOrchestratorFilter(base);
116
+ export { expect } from "@playwright/test";
117
+ ```
118
+
119
+ Then use this `test` in your spec files:
120
+
121
+ ```typescript
122
+ // e2e/login.spec.ts
123
+ import { test, expect } from "./setup";
124
+
125
+ test("should login", async ({ page }) => {
126
+ // ...
127
+ });
128
+ ```
129
+
130
+ The reporter and fixture work together:
131
+ - **Reporter**: Reads `ORCHESTRATOR_SHARD_FILE` env var to know which tests belong to this shard
132
+ - **Fixture**: Skips tests that don't belong to the current shard at runtime
86
133
 
87
134
  ## Local Testing
88
135
 
@@ -143,9 +190,9 @@ jobs:
143
190
  - uses: NSXBet/playwright-orchestrator/.github/actions/orchestrate@v0
144
191
  id: orchestrate
145
192
  with:
146
- test-list: test-list.json # Use pre-generated list (recommended)
193
+ test-list: test-list.json # Required: pre-generated list
194
+ timing-file: timing-data.json # Required: timing data
147
195
  shards: 4
148
- timing-file: timing-data.json
149
196
 
150
197
  # Phase 2: Run tests (parallel matrix)
151
198
  e2e:
@@ -176,17 +223,14 @@ See [docs/external-integration.md](./docs/external-integration.md) for complete
176
223
 
177
224
  ## CLI Commands
178
225
 
179
- | Command | Description |
180
- | ---------------- | -------------------------------------------------------------------------------- |
181
- | `list-tests` | Discover tests in a project (uses Playwright `--list`) |
182
- | `assign` | Distribute tests across shards (uses Playwright `--list` for accurate discovery) |
183
- | `extract-timing` | Extract timing from Playwright report |
184
- | `merge-timing` | Merge timing data with EMA smoothing |
226
+ | Command | Description |
227
+ | ---------------- | ---------------------------------------- |
228
+ | `assign` | Distribute tests across shards |
229
+ | `extract-timing` | Extract timing from Playwright report |
230
+ | `merge-timing` | Merge timing data with EMA smoothing |
185
231
 
186
232
  Run `playwright-orchestrator <command> --help` for details.
187
233
 
188
- **Important**: The `--project` flag is recommended for both `list-tests` and `assign` commands to ensure accurate test discovery, especially for parameterized tests (e.g., `test.each`).
189
-
190
234
  ## Development
191
235
 
192
236
  ```bash
@@ -235,6 +279,18 @@ Test scenarios covered in `examples/monorepo/`:
235
279
 
236
280
  See [AGENTS.md](./AGENTS.md) for AI assistant instructions.
237
281
 
282
+ ## Cache Strategy
283
+
284
+ GitHub Actions cache is branch-scoped, which creates challenges for sharing timing data between PRs and main. We recommend a **promote-on-merge** pattern:
285
+
286
+ 1. Each PR branch saves to its own cache key
287
+ 2. PRs restore from their own cache, falling back to main
288
+ 3. When a PR is merged, a workflow promotes the PR's cache to main
289
+
290
+ This avoids race conditions between concurrent PRs while ensuring main always has the latest timing data.
291
+
292
+ See [Cache Strategy for PRs](./docs/external-integration.md#cache-strategy-for-prs) for implementation details.
293
+
238
294
  ## License
239
295
 
240
296
  MIT
package/dist/fixture.d.ts CHANGED
@@ -6,10 +6,21 @@
6
6
  *
7
7
  * Usage in your test setup file (e.g., tests/setup.ts):
8
8
  * ```typescript
9
- * import { test } from '@playwright/test';
10
- * import { setupOrchestratorFilter } from '@nsxbet/playwright-orchestrator/fixture';
9
+ * import { test as base } from '@playwright/test';
10
+ * import { withOrchestratorFilter } from '@nsxbet/playwright-orchestrator/fixture';
11
11
  *
12
- * setupOrchestratorFilter(test);
12
+ * // Create extended test with orchestrator filtering
13
+ * export const test = withOrchestratorFilter(base);
14
+ * export { expect } from '@playwright/test';
15
+ * ```
16
+ *
17
+ * Then in your test files:
18
+ * ```typescript
19
+ * import { test, expect } from './setup';
20
+ *
21
+ * test('my test', async ({ page }) => {
22
+ * // ...
23
+ * });
13
24
  * ```
14
25
  *
15
26
  * Environment variables:
@@ -20,6 +31,35 @@
20
31
  */
21
32
  import type { TestType } from '@playwright/test';
22
33
  /**
34
+ * Creates an extended test with orchestrator filtering as an auto-fixture.
35
+ * This ensures tests not in the current shard are skipped.
36
+ *
37
+ * IMPORTANT: Use this function to create your test object, then export it.
38
+ * All test files should import the extended test, not the base test.
39
+ *
40
+ * @param test - The base test object from @playwright/test
41
+ * @returns Extended test with orchestrator filtering
42
+ *
43
+ * @example
44
+ * ```typescript
45
+ * // In setup.ts
46
+ * import { test as base } from '@playwright/test';
47
+ * import { withOrchestratorFilter } from '@nsxbet/playwright-orchestrator/fixture';
48
+ *
49
+ * export const test = withOrchestratorFilter(base);
50
+ *
51
+ * // In your.spec.ts
52
+ * import { test } from './setup';
53
+ * test('example', async ({ page }) => { ... });
54
+ * ```
55
+ */
56
+ export declare function withOrchestratorFilter<T extends object, W extends object>(test: TestType<T, W>): TestType<T & {
57
+ _orchestratorFilter: undefined;
58
+ }, W>;
59
+ /**
60
+ * @deprecated Use `withOrchestratorFilter` instead. This function uses beforeEach
61
+ * which only works for the first test file processed, not subsequent files.
62
+ *
23
63
  * Sets up the orchestrator filter as a beforeEach hook.
24
64
  * This will skip tests that are not in the current shard.
25
65
  *
@@ -1 +1 @@
1
- {"version":3,"file":"fixture.d.ts","sourceRoot":"","sources":["../src/fixture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAuDjD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,EACxE,IAAI,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,GACnB,IAAI,CAoCN;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5C,GAAG,OAAO,CAUV"}
1
+ {"version":3,"file":"fixture.d.ts","sourceRoot":"","sources":["../src/fixture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAuDjD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,EACvE,IAAI,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,GACnB,QAAQ,CAAC,CAAC,GAAG;IAAE,mBAAmB,EAAE,SAAS,CAAA;CAAE,EAAE,CAAC,CAAC,CAwDrD;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,EACxE,IAAI,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,GACnB,IAAI,CAoCN;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5C,GAAG,OAAO,CAUV"}
package/dist/fixture.js CHANGED
@@ -6,10 +6,21 @@
6
6
  *
7
7
  * Usage in your test setup file (e.g., tests/setup.ts):
8
8
  * ```typescript
9
- * import { test } from '@playwright/test';
10
- * import { setupOrchestratorFilter } from '@nsxbet/playwright-orchestrator/fixture';
9
+ * import { test as base } from '@playwright/test';
10
+ * import { withOrchestratorFilter } from '@nsxbet/playwright-orchestrator/fixture';
11
11
  *
12
- * setupOrchestratorFilter(test);
12
+ * // Create extended test with orchestrator filtering
13
+ * export const test = withOrchestratorFilter(base);
14
+ * export { expect } from '@playwright/test';
15
+ * ```
16
+ *
17
+ * Then in your test files:
18
+ * ```typescript
19
+ * import { test, expect } from './setup';
20
+ *
21
+ * test('my test', async ({ page }) => {
22
+ * // ...
23
+ * });
13
24
  * ```
14
25
  *
15
26
  * Environment variables:
@@ -59,6 +70,67 @@ function loadShardFile() {
59
70
  }
60
71
  }
61
72
  /**
73
+ * Creates an extended test with orchestrator filtering as an auto-fixture.
74
+ * This ensures tests not in the current shard are skipped.
75
+ *
76
+ * IMPORTANT: Use this function to create your test object, then export it.
77
+ * All test files should import the extended test, not the base test.
78
+ *
79
+ * @param test - The base test object from @playwright/test
80
+ * @returns Extended test with orchestrator filtering
81
+ *
82
+ * @example
83
+ * ```typescript
84
+ * // In setup.ts
85
+ * import { test as base } from '@playwright/test';
86
+ * import { withOrchestratorFilter } from '@nsxbet/playwright-orchestrator/fixture';
87
+ *
88
+ * export const test = withOrchestratorFilter(base);
89
+ *
90
+ * // In your.spec.ts
91
+ * import { test } from './setup';
92
+ * test('example', async ({ page }) => { ... });
93
+ * ```
94
+ */
95
+ export function withOrchestratorFilter(test) {
96
+ return test.extend({
97
+ // @ts-expect-error - Playwright's auto fixture typing is complex
98
+ _orchestratorFilter: [
99
+ async (
100
+ // biome-ignore lint/correctness/noEmptyPattern: Playwright requires empty destructuring
101
+ {}, use, testInfo) => {
102
+ const allowedTestIds = loadShardFile();
103
+ if (allowedTestIds) {
104
+ // CRITICAL: Use project.testDir for consistent path resolution with test-discovery
105
+ // No fallback to process.cwd() - this causes path mismatch bugs
106
+ const testDir = testInfo.project.testDir;
107
+ if (!testDir) {
108
+ throw new Error('[Orchestrator Fixture] Could not determine project testDir. ' +
109
+ 'Ensure your playwright.config.ts has projects configured with testDir.');
110
+ }
111
+ const testId = buildTestIdFromRuntime(testInfo.file, testInfo.titlePath, {
112
+ projectName: testInfo.project.name,
113
+ baseDir: testDir,
114
+ });
115
+ const isAllowed = allowedTestIds.has(testId);
116
+ // Debug: Write to stderr for visibility in CI logs
117
+ if (process.env.ORCHESTRATOR_DEBUG === '1') {
118
+ process.stderr.write(`[Fixture] testDir=${testInfo.project.testDir} | testId=${testId} | allowed=${isAllowed}\n`);
119
+ }
120
+ if (!isAllowed) {
121
+ test.skip(true, 'Not in shard');
122
+ }
123
+ }
124
+ await use();
125
+ },
126
+ { auto: true },
127
+ ],
128
+ });
129
+ }
130
+ /**
131
+ * @deprecated Use `withOrchestratorFilter` instead. This function uses beforeEach
132
+ * which only works for the first test file processed, not subsequent files.
133
+ *
62
134
  * Sets up the orchestrator filter as a beforeEach hook.
63
135
  * This will skip tests that are not in the current shard.
64
136
  *
@@ -1 +1 @@
1
- {"version":3,"file":"fixture.js","sourceRoot":"","sources":["../src/fixture.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fixture.js","sourceRoot":"","sources":["../src/fixture.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nsxbet/playwright-orchestrator",
3
- "version": "0.6.3",
3
+ "version": "0.8.0",
4
4
  "description": "Intelligent Playwright test distribution across CI shards using historical timing data",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -12,6 +12,9 @@
12
12
  ],
13
13
  "fixture": [
14
14
  "./dist/fixture.d.ts"
15
+ ],
16
+ "core": [
17
+ "./dist/core/index.d.ts"
15
18
  ]
16
19
  }
17
20
  },
@@ -30,6 +33,11 @@
30
33
  "types": "./dist/fixture.d.ts",
31
34
  "import": "./dist/fixture.js",
32
35
  "require": "./dist/fixture.js"
36
+ },
37
+ "./core": {
38
+ "types": "./dist/core/index.d.ts",
39
+ "import": "./dist/core/index.js",
40
+ "require": "./dist/core/index.js"
33
41
  }
34
42
  },
35
43
  "bin": {
@@ -1,16 +0,0 @@
1
- import { Command } from '@oclif/core';
2
- export default class ListTests extends Command {
3
- static description: string;
4
- static examples: string[];
5
- static flags: {
6
- 'test-dir': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
7
- project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
8
- 'output-format': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
9
- 'glob-pattern': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
10
- 'use-fallback': import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
- verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
- };
13
- run(): Promise<void>;
14
- private outputResult;
15
- }
16
- //# sourceMappingURL=list-tests.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"list-tests.d.ts","sourceRoot":"","sources":["../../src/commands/list-tests.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAS,MAAM,aAAa,CAAC;AAQ7C,MAAM,CAAC,OAAO,OAAO,SAAU,SAAQ,OAAO;IAC5C,OAAgB,WAAW,SACiD;IAE5E,OAAgB,QAAQ,WAGtB;IAEF,OAAgB,KAAK;;;;;;;MA6BnB;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IAwC1B,OAAO,CAAC,YAAY;CA4BrB"}
@@ -1,98 +0,0 @@
1
- import * as path from 'node:path';
2
- import { Command, Flags } from '@oclif/core';
3
- import { discoverTests, discoverTestsFromFiles, groupTestsByFile, } from '../core/index.js';
4
- export default class ListTests extends Command {
5
- static description = 'Discover all tests in a Playwright project using --list or file parsing';
6
- static examples = [
7
- '<%= config.bin %> list-tests --test-dir ./src/test/e2e',
8
- '<%= config.bin %> list-tests --test-dir ./e2e --project "Mobile Chrome" --output-format json',
9
- ];
10
- static flags = {
11
- 'test-dir': Flags.string({
12
- char: 'd',
13
- description: 'Path to test directory',
14
- required: true,
15
- }),
16
- project: Flags.string({
17
- char: 'p',
18
- description: 'Playwright project name',
19
- }),
20
- 'output-format': Flags.string({
21
- char: 'f',
22
- description: 'Output format',
23
- default: 'json',
24
- options: ['json', 'text'],
25
- }),
26
- 'glob-pattern': Flags.string({
27
- description: 'Glob pattern for test files (used for fallback discovery)',
28
- default: '**/*.spec.ts',
29
- }),
30
- 'use-fallback': Flags.boolean({
31
- description: 'Use file parsing instead of Playwright --list',
32
- default: false,
33
- }),
34
- verbose: Flags.boolean({
35
- char: 'v',
36
- description: 'Show verbose output',
37
- default: false,
38
- }),
39
- };
40
- async run() {
41
- const { flags } = await this.parse(ListTests);
42
- const testDir = path.resolve(flags['test-dir']);
43
- if (flags.verbose) {
44
- this.log(`Discovering tests in ${testDir}...`);
45
- }
46
- let tests;
47
- try {
48
- if (flags['use-fallback']) {
49
- // Use file parsing
50
- tests = discoverTestsFromFiles(testDir, flags['glob-pattern']);
51
- if (flags.verbose) {
52
- this.log('Using file parsing for test discovery');
53
- }
54
- }
55
- else {
56
- // Use Playwright --list
57
- tests = discoverTests(testDir, flags.project);
58
- if (flags.verbose) {
59
- this.log('Using Playwright --list for test discovery');
60
- }
61
- }
62
- }
63
- catch {
64
- // Fallback to file parsing if Playwright --list fails
65
- if (flags.verbose) {
66
- this.warn('Playwright --list failed, falling back to file parsing');
67
- }
68
- tests = discoverTestsFromFiles(testDir, flags['glob-pattern']);
69
- }
70
- if (flags.verbose) {
71
- this.log(`Discovered ${tests.length} tests`);
72
- }
73
- this.outputResult(tests, flags['output-format'], flags.verbose);
74
- }
75
- outputResult(tests, format, verbose = false) {
76
- if (format === 'json') {
77
- this.log(JSON.stringify(tests));
78
- }
79
- else {
80
- // Text format - group by file
81
- const grouped = groupTestsByFile(tests);
82
- this.log('\n=== Discovered Tests ===\n');
83
- for (const [file, fileTests] of grouped) {
84
- this.log(`${file}:`);
85
- for (const test of fileTests) {
86
- const titlePath = test.titlePath.join(' > ');
87
- this.log(` - ${titlePath}`);
88
- if (verbose) {
89
- this.log(` ID: ${test.testId}`);
90
- }
91
- }
92
- this.log('');
93
- }
94
- this.log(`Total: ${tests.length} tests in ${grouped.size} files`);
95
- }
96
- }
97
- }
98
- //# sourceMappingURL=list-tests.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"list-tests.js","sourceRoot":"","sources":["../../src/commands/list-tests.ts"],"names":[],"mappings":"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"}