PluginProbe
Extendify / 3.2.1
Extendify v3.2.1
3.2.1 3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 All 127 releases
extendify / playwright.config.ts

playwright.config.ts in Extendify 3.2.1, at playwright.config.ts

150 lines 5.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
2 import { dirname, join, relative, resolve, sep } from 'node:path';
3 import { defineConfig, devices } from '@playwright/test';
4
5 const ROOT = resolve(__dirname);
6 const TEST_DIR = resolve(ROOT, 'tests/playwright');
7 const BASE_PORT = Number(process.env.BASE_PORT ?? 9400);
8 const WP_VERSION = process.env.WP_VERSION ?? 'latest';
9 const RUN_PROJECT = process.env.RUN_PROJECT;
10 const PREVIEW_URL = process.env.PREVIEW_URL;
11
12 const walkSpecs = (dir: string): string[] => {
13 const out: string[] = [];
14 for (const entry of readdirSync(dir)) {
15 const full = join(dir, entry);
16 const stat = statSync(full);
17 if (stat.isDirectory()) {
18 out.push(...walkSpecs(full));
19 continue;
20 }
21 if (entry.endsWith('.spec.ts')) out.push(full);
22 }
23 return out;
24 };
25
26 const closestBlueprint = (specPath: string): string | null => {
27 let dir = dirname(specPath);
28 while (dir.startsWith(TEST_DIR) || dir === TEST_DIR) {
29 const candidate = join(dir, 'blueprint.json');
30 if (existsSync(candidate)) return candidate;
31 if (dir === TEST_DIR) return null;
32 dir = dirname(dir);
33 }
34 return null;
35 };
36
37 const projectName = (specPath: string): string =>
38 relative(TEST_DIR, specPath)
39 .replace(/\.spec\.ts$/, '')
40 .split(sep)
41 .join('/');
42
43 // First-line `// e2e:disabled` marker — see tests/playwright/scripts/discover-playwright-projects.mjs.
44 // RUN_PROJECT explicitly opting in to a disabled spec still wins (for local debug).
45 const isDisabled = (spec: string): boolean =>
46 readFileSync(spec, 'utf8').split('\n', 1)[0].includes('e2e:disabled');
47
48 const specs = existsSync(TEST_DIR)
49 ? walkSpecs(TEST_DIR).filter(
50 (s) => !isDisabled(s) || projectName(s) === RUN_PROJECT,
51 )
52 : [];
53
54 const blueprintPort = new Map<string, number>();
55 for (const spec of specs) {
56 const blueprint = closestBlueprint(spec);
57 if (!blueprint) continue;
58 if (!blueprintPort.has(blueprint)) {
59 blueprintPort.set(blueprint, BASE_PORT + blueprintPort.size);
60 }
61 }
62
63 const projectBlueprint = new Map<string, string>();
64
65 const allProjects = specs
66 .map((spec) => {
67 const blueprint = closestBlueprint(spec);
68 const port = blueprint ? blueprintPort.get(blueprint) : undefined;
69 if (!port || !blueprint) return null;
70 const name = projectName(spec);
71 projectBlueprint.set(name, blueprint);
72 return {
73 name,
74 testMatch: relative(ROOT, spec),
75 use: {
76 ...devices['Desktop Chrome'],
77 baseURL: PREVIEW_URL ?? `http://127.0.0.1:${port}`,
78 },
79 };
80 })
81 .filter((p): p is NonNullable<typeof p> => p !== null);
82
83 const projects = RUN_PROJECT
84 ? allProjects.filter((p) => p.name === RUN_PROJECT)
85 : allProjects;
86
87 // Only spin up the webServer(s) the selected projects actually need. Spawning
88 // every blueprint's playground when only one project will run wastes boot time
89 // and burns ports.
90 const activeBlueprints = new Set(
91 projects.map((p) => projectBlueprint.get(p.name)).filter(Boolean) as string[],
92 );
93 const webServers = (PREVIEW_URL ? [] : [...blueprintPort.entries()])
94 .filter(([blueprint]) => activeBlueprints.has(blueprint))
95 .map(([blueprint, port]) => ({
96 // PHP version is pinned per-blueprint via `preferredVersions.php` — the
97 // CLI `--php` flag is silently ignored by wp-playground-cli. Pinned to
98 // 8.3 to dodge a PHP 8.5 deprecation in vendor/react/promise that
99 // breaks ?action=rest-nonce by printing inline when WP_DEBUG_DISPLAY is
100 // on. Drop the pin once react/promise ships an 8.5-compatible release.
101 command: `npx wp-playground-cli server --auto-mount --blueprint=${relative(ROOT, blueprint)} --wp=${WP_VERSION} --port=${port} --internal-cookie-store=true --login=false`,
102 url: `http://127.0.0.1:${port}`,
103 reuseExistingServer: !process.env.CI,
104 timeout: 120_000,
105 stdout: 'pipe' as const,
106 stderr: 'pipe' as const,
107 }));
108
109 // RequestUtils caches the discovered REST root to this file and reuses it
110 // whenever it is already populated, skipping rediscovery. The default path is
111 // one shared file and playground ports shift between runs, so a later run can
112 // POST to whichever server held that port before. Scope it to the process.
113 if (!process.env.STORAGE_STATE_PATH) {
114 process.env.STORAGE_STATE_PATH = resolve(
115 ROOT,
116 `artifacts/storage-states/admin-${process.pid}.json`,
117 );
118 }
119
120 // @wordpress/e2e-test-utils-playwright's RequestUtils HEADs process.env.WP_BASE_URL
121 // (default http://localhost:8889 — wp-env's default port) to find the REST root,
122 // regardless of each request context's configured baseURL. Pin it to the selected
123 // project's own site so requestUtils.login() reaches the right server.
124 if (projects.length > 0 && !process.env.WP_BASE_URL) {
125 process.env.WP_BASE_URL = new URL(projects[0].use.baseURL).origin;
126 }
127
128 export default defineConfig({
129 testDir: TEST_DIR,
130 // An `active` site has already applied its blueprint; only playground needs the poll.
131 globalSetup: PREVIEW_URL ? undefined : './tests/playwright/global-setup.ts',
132 forbidOnly: !!process.env.CI,
133 retries: process.env.CI ? 1 : 0,
134 workers: 1,
135 // 30s default is too tight for this wp-playground suite on cold CI — the
136 // reload-based save specs run ~25-30s even locally.
137 timeout: 120_000,
138 // Raise the per-assertion floor from 5s to the 15s specs already hand-patch.
139 expect: { timeout: 15_000 },
140 reporter: process.env.CI ? [['github'], ['html', { open: 'never' }]] : 'list',
141 use: {
142 trace: 'on-first-retry',
143 video: 'retain-on-failure',
144 screenshot: 'only-on-failure',
145 testIdAttribute: 'data-test',
146 },
147 webServer: webServers.length > 0 ? webServers : undefined,
148 projects,
149 });
150