openspec-playwright 0.3.41 → 0.3.43

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
@@ -35,7 +35,7 @@ Claude Code — E2E workflow is driven by `/opsx:e2e` command using a browser ex
35
35
  ```bash
36
36
  openspec-pw init # Initialize integration (one-time setup; add --seed to overwrite existing seed.spec.ts)
37
37
  openspec-pw update # Update CLI and commands to latest version
38
- openspec-pw doctor # Check prerequisites
38
+ openspec-pw doctor # Check prerequisites + app server diagnostics
39
39
  openspec-pw audit # Audit tests for orphaned specs and issues
40
40
  openspec-pw migrate # Migrate old test files to new structure
41
41
  openspec-pw explore # Explore routes in parallel with Playwright
@@ -94,6 +94,7 @@ openspec-pw uninstall # Remove integration from the project
94
94
  1. Detects Claude Code in the project
95
95
  2. Installs E2E command (`/opsx:e2e`) for Claude Code
96
96
  3. Generates `tests/playwright/seed.spec.ts`, `auth.setup.ts`, `credentials.yaml`, `app-knowledge.md`
97
+ 4. Generates `playwright.config.ts` with automatic dev script and port detection (Vite/Next/Nuxt/Astro, `.env`, and `--port`)
97
98
 
98
99
  > **Note**: After running `openspec-pw init`, manually install Playwright browsers: `npx playwright install --with-deps`
99
100
 
@@ -119,6 +120,28 @@ Run through these steps in order when using the E2E workflow for the first time:
119
120
  |------|---------|-------------|
120
121
  | A. Install gstack | `git clone --single-branch --depth 1 https://github.com/garrytan/gstack.git ~/.claude/skills/gstack && cd ~/.claude/skills/gstack && ./setup` | Requires Bun: `curl -fsSL https://bun.sh/install \| bash` |
121
122
 
123
+ ## App Server Detection
124
+
125
+ Generated `playwright.config.ts` automatically detects the app URL in this order:
126
+
127
+ 1. `BASE_URL` environment variable
128
+ 2. port flags in `package.json` scripts, e.g. `vite --port 5125`
129
+ 3. `vite.config.*` `server.port`
130
+ 4. `.env.local`, `.env.development`, `.env` (`PLAYWRIGHT_PORT`, `E2E_PORT`, `VITE_PORT`, `PORT`)
131
+ 5. framework defaults: Vite `5173`, Astro `4321`, Next/Nuxt `3000`
132
+ 6. fallback: `http://localhost:3000`
133
+
134
+ Run `openspec-pw doctor` to see the detected dev script and base URL:
135
+
136
+ ```text
137
+ ─── App Server ───
138
+ ✓ dev-script: npm run dev:all
139
+ ✓ base-url: http://localhost:5125 (vite.config.ts)
140
+ ⚠ reachable: fetch failed (diagnostic only; Playwright webServer may start it)
141
+ ```
142
+
143
+ If your project already has `playwright.config.ts`, `openspec-pw init` will not overwrite it. It prints patch hints for missing `webServer`, `testDir`, `storageState`, and setup-project wiring.
144
+
122
145
  ## Authentication
123
146
 
124
147
  If your app requires login, set up credentials once, then all tests run authenticated automatically.
@@ -127,7 +150,9 @@ If your app requires login, set up credentials once, then all tests run authenti
127
150
  # 1. Edit credentials
128
151
  vim tests/playwright/credentials.yaml
129
152
 
130
- # 2. Set environment variables
153
+ # 2. Enable auth and set environment variables
154
+ export E2E_AUTH_REQUIRED=true
155
+ export E2E_AUTH_METHOD=api # or ui
131
156
  export E2E_USERNAME=your-email@example.com
132
157
  export E2E_PASSWORD=your-password
133
158
 
@@ -3,7 +3,7 @@ import { createRequire } from "node:module";
3
3
  import { join } from "path";
4
4
  import { execFileSync } from "child_process";
5
5
  import chalk from "chalk";
6
- import { isPlaywrightMcpInstalled, needsShell } from "../shared/index.js";
6
+ import { detectAppServer, isPlaywrightMcpInstalled, needsShell } from "../shared/index.js";
7
7
  export async function doctor(options = {}) {
8
8
  const checks = [];
9
9
  const projectRoot = process.cwd();
@@ -121,7 +121,32 @@ export async function doctor(options = {}) {
121
121
  ok: hasSeed,
122
122
  message: hasSeed ? "found" : "not found (optional)",
123
123
  });
124
- const allOk = checks.filter((c) => !c.ok && c.category !== "Seed Test").length === 0;
124
+ // App server detection (diagnostic only not a prerequisite)
125
+ const app = detectAppServer(projectRoot);
126
+ checks.push({
127
+ category: "App Server",
128
+ name: "dev-script",
129
+ ok: Boolean(app.devCommand),
130
+ message: app.devCommand
131
+ ? `${app.devCommand}${app.scriptCommand ? ` (${app.scriptCommand})` : ""}`
132
+ : "not detected (configure webServer manually)",
133
+ });
134
+ checks.push({
135
+ category: "App Server",
136
+ name: "base-url",
137
+ ok: true,
138
+ message: `${app.baseUrl} (${app.baseUrlSource})`,
139
+ });
140
+ const reachable = await checkUrl(app.baseUrl);
141
+ checks.push({
142
+ category: "App Server",
143
+ name: "reachable",
144
+ ok: reachable.ok,
145
+ message: reachable.ok
146
+ ? `responded ${reachable.status ?? "ok"}`
147
+ : `${reachable.message} (diagnostic only; Playwright webServer may start it)`,
148
+ });
149
+ const allOk = checks.filter((c) => !c.ok && c.category !== "Seed Test" && c.category !== "App Server").length === 0;
125
150
  if (options.json) {
126
151
  console.log(JSON.stringify({ ok: allOk, checks }, null, 2));
127
152
  if (!allOk)
@@ -139,7 +164,7 @@ export async function doctor(options = {}) {
139
164
  if (check.ok) {
140
165
  console.log(chalk.green(` ✓ ${check.name}: ${check.message}`));
141
166
  }
142
- else if (check.category === "Seed Test" || check.category === "Vision Check") {
167
+ else if (check.category === "Seed Test" || check.category === "App Server" || check.category === "Vision Check") {
143
168
  console.log(chalk.yellow(` ⚠ ${check.name}: ${check.message}`));
144
169
  }
145
170
  else {
@@ -157,4 +182,23 @@ export async function doctor(options = {}) {
157
182
  process.exit(1);
158
183
  }
159
184
  }
185
+ async function checkUrl(url) {
186
+ try {
187
+ const res = await fetch(url, {
188
+ method: "GET",
189
+ signal: AbortSignal.timeout(2000),
190
+ });
191
+ return {
192
+ ok: res.status < 500,
193
+ status: res.status,
194
+ message: `responded ${res.status}`,
195
+ };
196
+ }
197
+ catch (err) {
198
+ return {
199
+ ok: false,
200
+ message: err instanceof Error ? err.message : "not reachable",
201
+ };
202
+ }
203
+ }
160
204
  //# sourceMappingURL=doctor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
@@ -205,6 +205,7 @@ export async function generatePlaywrightConfig(projectRoot) {
205
205
  const configDest = join(projectRoot, "playwright.config.ts");
206
206
  if (existsSync(configDest)) {
207
207
  console.log(chalk.gray(" - playwright.config.ts already exists, skipping"));
208
+ suggestPlaywrightConfigPatch(configDest);
208
209
  return;
209
210
  }
210
211
  if (existsSync(configSrc)) {
@@ -216,6 +217,29 @@ export async function generatePlaywrightConfig(projectRoot) {
216
217
  console.log(chalk.gray(" - Playwright config template not found in package"));
217
218
  }
218
219
  }
220
+ function suggestPlaywrightConfigPatch(configPath) {
221
+ const config = readFileSync(configPath, "utf-8");
222
+ const suggestions = [];
223
+ if (!config.includes("webServer")) {
224
+ suggestions.push("add webServer so Playwright can start/stop your app automatically");
225
+ }
226
+ if (!config.includes("tests/playwright") && !config.includes("testDir")) {
227
+ suggestions.push("set testDir to tests/playwright");
228
+ }
229
+ if (!config.includes("storageState")) {
230
+ suggestions.push("optionally wire storageState from playwright/.auth/user.json for authenticated tests");
231
+ }
232
+ if (!config.includes("dependencies") || !config.includes("setup")) {
233
+ suggestions.push("add a setup project for auth.setup.ts when login is required");
234
+ }
235
+ if (suggestions.length === 0)
236
+ return;
237
+ console.log(chalk.yellow(" ⚠ Existing config was not modified. Recommended checks:"));
238
+ for (const suggestion of suggestions) {
239
+ console.log(chalk.gray(` - ${suggestion}`));
240
+ }
241
+ console.log(chalk.gray(" Compare with: openspec-pw init in a temporary project, or copy from templates/playwright.config.ts"));
242
+ }
219
243
  function hasCmd(bin, args, name, silent = false) {
220
244
  try {
221
245
  execFileSync(bin, args, { stdio: "pipe", shell: needsShell });
@@ -1 +1 @@
1
- {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ export interface PackageJson {
2
+ scripts?: Record<string, string>;
3
+ dependencies?: Record<string, string>;
4
+ devDependencies?: Record<string, string>;
5
+ }
6
+ export interface AppServerDetection {
7
+ projectRoot: string;
8
+ npmRoot: string;
9
+ packageJsonPath: string;
10
+ scripts: Record<string, string>;
11
+ scriptName?: string;
12
+ scriptCommand?: string;
13
+ devCommand?: string;
14
+ baseUrl: string;
15
+ baseUrlSource: string;
16
+ port?: number;
17
+ portSource?: string;
18
+ }
19
+ export declare function findNpmRoot(projectRoot: string, maxDepth?: number): string;
20
+ export declare function chooseDevScript(scripts: Record<string, string>): string | undefined;
21
+ export declare function parsePort(text: string): number | undefined;
22
+ export declare function detectAppServer(projectRoot: string, env?: NodeJS.ProcessEnv): AppServerDetection;
@@ -0,0 +1,210 @@
1
+ import { existsSync, readFileSync, readdirSync } from "fs";
2
+ import { join } from "path";
3
+ function readPackageJson(path) {
4
+ try {
5
+ return JSON.parse(readFileSync(path, "utf-8"));
6
+ }
7
+ catch {
8
+ return null;
9
+ }
10
+ }
11
+ function hasRunnableScript(pkg) {
12
+ const scripts = pkg.scripts ?? {};
13
+ return Boolean(scripts["dev:all"] || scripts.dev || scripts.start || scripts.serve || scripts.preview);
14
+ }
15
+ export function findNpmRoot(projectRoot, maxDepth = 5) {
16
+ function search(dir, depth) {
17
+ if (depth > maxDepth)
18
+ return null;
19
+ const pkgPath = join(dir, "package.json");
20
+ if (existsSync(pkgPath)) {
21
+ const pkg = readPackageJson(pkgPath);
22
+ if (pkg && hasRunnableScript(pkg))
23
+ return dir;
24
+ }
25
+ try {
26
+ const entries = readdirSync(dir, { withFileTypes: true });
27
+ for (const entry of entries) {
28
+ if (!entry.isDirectory() || entry.name.startsWith(".") || entry.name === "node_modules")
29
+ continue;
30
+ const found = search(join(dir, entry.name), depth + 1);
31
+ if (found)
32
+ return found;
33
+ }
34
+ }
35
+ catch {
36
+ // ignore unreadable directories
37
+ }
38
+ return null;
39
+ }
40
+ return search(projectRoot, 0) ?? projectRoot;
41
+ }
42
+ export function chooseDevScript(scripts) {
43
+ if (scripts["dev:all"])
44
+ return "dev:all";
45
+ if (scripts.dev)
46
+ return "dev";
47
+ if (scripts.start)
48
+ return "start";
49
+ if (scripts.serve)
50
+ return "serve";
51
+ if (scripts.preview)
52
+ return "preview";
53
+ return undefined;
54
+ }
55
+ export function parsePort(text) {
56
+ const patterns = [
57
+ /(?:^|\s)(?:--port|-p)\s+([0-9]{2,5})(?:\s|$)/,
58
+ /(?:^|\s)--port=([0-9]{2,5})(?:\s|$)/,
59
+ /(?:^|\s)(?:PORT|VITE_PORT|PLAYWRIGHT_PORT|E2E_PORT)=([0-9]{2,5})(?:\s|$)/,
60
+ /port\s*:\s*([0-9]{2,5})/,
61
+ ];
62
+ for (const pattern of patterns) {
63
+ const match = text.match(pattern);
64
+ if (match) {
65
+ const port = Number(match[1]);
66
+ if (port > 0 && port <= 65535)
67
+ return port;
68
+ }
69
+ }
70
+ return undefined;
71
+ }
72
+ function parseEnvPort(content) {
73
+ const lines = content.split(/\r?\n/);
74
+ for (const key of ["PLAYWRIGHT_PORT", "E2E_PORT", "VITE_PORT", "PORT"]) {
75
+ for (const line of lines) {
76
+ const match = line.match(new RegExp(`^\\s*${key}\\s*=\\s*["']?([0-9]{2,5})["']?\\s*$`));
77
+ if (match) {
78
+ const port = Number(match[1]);
79
+ if (port > 0 && port <= 65535)
80
+ return port;
81
+ }
82
+ }
83
+ }
84
+ return undefined;
85
+ }
86
+ function detectPortFromEnv(env) {
87
+ for (const key of ["PLAYWRIGHT_PORT", "E2E_PORT", "VITE_PORT", "PORT"]) {
88
+ const value = env[key];
89
+ if (!value)
90
+ continue;
91
+ const port = Number(value);
92
+ if (Number.isInteger(port) && port > 0 && port <= 65535) {
93
+ return { port, source: `${key} env` };
94
+ }
95
+ }
96
+ return undefined;
97
+ }
98
+ function detectPortFromEnvFiles(npmRoot) {
99
+ for (const file of [".env.local", ".env.development", ".env"]) {
100
+ const path = join(npmRoot, file);
101
+ if (!existsSync(path))
102
+ continue;
103
+ const port = parseEnvPort(readFileSync(path, "utf-8"));
104
+ if (port)
105
+ return { port, source: file };
106
+ }
107
+ return undefined;
108
+ }
109
+ function detectVitePort(npmRoot) {
110
+ for (const file of ["vite.config.ts", "vite.config.mts", "vite.config.js", "vite.config.mjs", "vite.config.cjs"]) {
111
+ const path = join(npmRoot, file);
112
+ if (!existsSync(path))
113
+ continue;
114
+ const port = parsePort(readFileSync(path, "utf-8"));
115
+ if (port)
116
+ return { port, source: file };
117
+ }
118
+ return undefined;
119
+ }
120
+ function detectSeedBaseUrl(projectRoot) {
121
+ const seedSpec = join(projectRoot, "tests", "playwright", "seed.spec.ts");
122
+ if (!existsSync(seedSpec))
123
+ return undefined;
124
+ const content = readFileSync(seedSpec, "utf-8");
125
+ const match = content.match(/BASE_URL\s*=\s*process\.env\.BASE_URL\s*\|\|\s*['"]([^'"]+)['"]/);
126
+ if (match) {
127
+ const baseUrl = match[1];
128
+ // Skip seed defaults like '/' that are relative to Playwright use.baseURL
129
+ if (baseUrl.startsWith("http://") || baseUrl.startsWith("https://")) {
130
+ return { baseUrl, source: "seed.spec.ts" };
131
+ }
132
+ }
133
+ return undefined;
134
+ }
135
+ function dependencyExists(pkg, name) {
136
+ return Boolean(pkg.dependencies?.[name] || pkg.devDependencies?.[name]);
137
+ }
138
+ function frameworkDefaultPort(pkg, command = "") {
139
+ if (command.includes("vite") || dependencyExists(pkg, "vite"))
140
+ return { port: 5173, source: "vite default" };
141
+ if (command.includes("astro") || dependencyExists(pkg, "astro"))
142
+ return { port: 4321, source: "astro default" };
143
+ if (command.includes("next") || dependencyExists(pkg, "next"))
144
+ return { port: 3000, source: "next default" };
145
+ if (command.includes("nuxt") || dependencyExists(pkg, "nuxt"))
146
+ return { port: 3000, source: "nuxt default" };
147
+ return undefined;
148
+ }
149
+ export function detectAppServer(projectRoot, env = process.env) {
150
+ const npmRoot = findNpmRoot(projectRoot);
151
+ const packageJsonPath = join(npmRoot, "package.json");
152
+ const pkg = readPackageJson(packageJsonPath) ?? {};
153
+ const scripts = pkg.scripts ?? {};
154
+ const scriptName = chooseDevScript(scripts);
155
+ const scriptCommand = scriptName ? scripts[scriptName] : undefined;
156
+ const devCommand = scriptName
157
+ ? npmRoot === projectRoot
158
+ ? `npm run ${scriptName}`
159
+ : `cd "${npmRoot}" && npm run ${scriptName}`
160
+ : undefined;
161
+ if (env.BASE_URL) {
162
+ return {
163
+ projectRoot,
164
+ npmRoot,
165
+ packageJsonPath,
166
+ scripts,
167
+ scriptName,
168
+ scriptCommand,
169
+ devCommand,
170
+ baseUrl: env.BASE_URL,
171
+ baseUrlSource: "BASE_URL env",
172
+ };
173
+ }
174
+ const portDetection = detectPortFromEnv(env) ??
175
+ (scriptCommand ? (() => {
176
+ const port = parsePort(scriptCommand);
177
+ return port ? { port, source: `package.json scripts.${scriptName}` } : undefined;
178
+ })() : undefined) ??
179
+ detectVitePort(npmRoot) ??
180
+ detectPortFromEnvFiles(npmRoot) ??
181
+ frameworkDefaultPort(pkg, scriptCommand);
182
+ if (portDetection) {
183
+ return {
184
+ projectRoot,
185
+ npmRoot,
186
+ packageJsonPath,
187
+ scripts,
188
+ scriptName,
189
+ scriptCommand,
190
+ devCommand,
191
+ baseUrl: `http://localhost:${portDetection.port}`,
192
+ baseUrlSource: portDetection.source,
193
+ port: portDetection.port,
194
+ portSource: portDetection.source,
195
+ };
196
+ }
197
+ const seed = detectSeedBaseUrl(projectRoot);
198
+ return {
199
+ projectRoot,
200
+ npmRoot,
201
+ packageJsonPath,
202
+ scripts,
203
+ scriptName,
204
+ scriptCommand,
205
+ devCommand,
206
+ baseUrl: seed?.baseUrl ?? "http://localhost:3000",
207
+ baseUrlSource: seed?.source ?? "default",
208
+ };
209
+ }
210
+ //# sourceMappingURL=app-detect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-detect.js","sourceRoot":"","sources":["../../src/shared/app-detect.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,5 @@
1
1
  export { SHARED_FILE_NAMES, TIMEOUT } from "./constants.js";
2
2
  export { isPlaywrightMcpInstalled, ensurePlaywrightMcp, removePlaywrightMcp, } from "./mcp.js";
3
3
  export { needsShell } from "./platform.js";
4
+ export { detectAppServer, findNpmRoot, chooseDevScript, parsePort, } from "./app-detect.js";
5
+ export type { AppServerDetection } from "./app-detect.js";
@@ -1,4 +1,5 @@
1
1
  export { SHARED_FILE_NAMES, TIMEOUT } from "./constants.js";
2
2
  export { isPlaywrightMcpInstalled, ensurePlaywrightMcp, removePlaywrightMcp, } from "./mcp.js";
3
3
  export { needsShell } from "./platform.js";
4
+ export { detectAppServer, findNpmRoot, chooseDevScript, parsePort, } from "./app-detect.js";
4
5
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/shared/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EACL,wBAAwB,EACxB,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/shared/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EACL,wBAAwB,EACxB,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EACL,eAAe,EACf,WAAW,EACX,eAAe,EACf,SAAS,GACV,MAAM,iBAAiB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openspec-playwright",
3
- "version": "0.3.41",
3
+ "version": "0.3.43",
4
4
  "description": "OpenSpec + Playwright E2E verification setup tool for Claude Code",
5
5
  "type": "module",
6
6
  "bin": {
@@ -2,32 +2,35 @@
2
2
  // This file authenticates once and saves the session state to .auth/user.json
3
3
  // All subsequent tests reuse this state — no repeated logins needed.
4
4
  //
5
- // Setup:
5
+ // Setup (only if your app requires login):
6
6
  // 1. Set credentials: export E2E_USERNAME=xxx E2E_PASSWORD=yyy
7
- // 2. Run: npx playwright test --project=setup
8
- // (if UI login: browser opens log in manually once)
9
- // 3. Credentials are saved tests auto-use the saved session
7
+ // 2. Enable auth: export E2E_AUTH_REQUIRED=true
8
+ // 3. Choose method: export E2E_AUTH_METHOD=api # or ui
9
+ // 4. Run: npx playwright test --project=setup
10
10
  //
11
- // To switch users, update credentials and re-run step 2.
12
- //
13
- // For multi-user testing, add more setup blocks with different storageState paths.
11
+ // If E2E_AUTH_REQUIRED is not true, auth setup is skipped so public apps
12
+ // can run seed/smoke tests without credentials.
14
13
 
15
14
  import { test as setup, expect } from '@playwright/test';
16
15
  import { existsSync } from 'fs';
17
16
 
17
+ const authRequired = process.env.E2E_AUTH_REQUIRED === 'true';
18
+ const authMethod = process.env.E2E_AUTH_METHOD || 'api';
19
+
18
20
  // ─── API Login (preferred) ───────────────────────────────────────────────────
19
21
  // If your app has a login API, configure it in tests/playwright/credentials.yaml:
20
22
  // api: /api/auth/login
21
- // Then this block runs automatically.
22
23
 
23
24
  setup('authenticate via API', async ({ page }) => {
25
+ setup.skip(!authRequired || authMethod !== 'api', 'API auth not required/enabled');
26
+
24
27
  const baseUrl = process.env.BASE_URL || 'http://localhost:3000';
25
28
  const username = process.env.E2E_USERNAME;
26
29
  const password = process.env.E2E_PASSWORD;
27
30
 
28
31
  if (!username || !password) {
29
32
  throw new Error(
30
- 'E2E_USERNAME and E2E_PASSWORD environment variables are required.\n' +
33
+ 'E2E_USERNAME and E2E_PASSWORD environment variables are required when E2E_AUTH_REQUIRED=true.\n' +
31
34
  'Set them with: export E2E_USERNAME=xxx E2E_PASSWORD=yyy'
32
35
  );
33
36
  }
@@ -51,13 +54,15 @@ setup('authenticate via API', async ({ page }) => {
51
54
  // If no login API, use UI login. Update selectors to match your login page.
52
55
 
53
56
  setup('authenticate via UI', async ({ page }) => {
57
+ setup.skip(!authRequired || authMethod !== 'ui', 'UI auth not required/enabled');
58
+
54
59
  const baseUrl = process.env.BASE_URL || 'http://localhost:3000';
55
60
  const username = process.env.E2E_USERNAME;
56
61
  const password = process.env.E2E_PASSWORD;
57
62
 
58
63
  if (!username || !password) {
59
64
  throw new Error(
60
- 'E2E_USERNAME and E2E_PASSWORD environment variables are required.\n' +
65
+ 'E2E_USERNAME and E2E_PASSWORD environment variables are required when E2E_AUTH_REQUIRED=true.\n' +
61
66
  'Set them with: export E2E_USERNAME=xxx E2E_PASSWORD=yyy'
62
67
  );
63
68
  }
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { Page, Locator, expect } from '@playwright/test';
6
6
 
7
- const BASE_URL = process.env.BASE_URL || 'http://localhost:3000';
7
+ const BASE_URL = process.env.BASE_URL;
8
8
 
9
9
  export class BasePage {
10
10
  protected page: Page;
@@ -23,7 +23,7 @@ export class BasePage {
23
23
  path: string,
24
24
  options?: { waitUntil?: 'domcontentloaded' | 'load' | 'networkidle' | 'commit' },
25
25
  ) {
26
- const url = path.startsWith('http') ? path : `${BASE_URL}${path}`;
26
+ const url = path.startsWith('http') || !BASE_URL ? path : new URL(path, BASE_URL).toString();
27
27
  await this.page.goto(url, {
28
28
  waitUntil: options?.waitUntil ?? 'domcontentloaded',
29
29
  });
@@ -2,7 +2,7 @@ import { defineConfig, devices } from '@playwright/test';
2
2
  import { readFileSync, existsSync, readdirSync } from 'fs';
3
3
  import { join } from 'path';
4
4
 
5
- // ─── Detect project root (where openspec/ lives) ───
5
+ // ─── Detect project root (where package.json lives) ───
6
6
  function findProjectRoot(start: string): string {
7
7
  let dir = start;
8
8
  for (let i = 0; i < 10; i++) {
@@ -23,7 +23,8 @@ function findNpmRoot(projectRoot: string, maxDepth = 5): string {
23
23
  if (existsSync(pkgPath)) {
24
24
  try {
25
25
  const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
26
- if (pkg.scripts?.dev || pkg.scripts?.start || pkg.scripts?.serve || pkg.scripts?.preview) {
26
+ const scripts = pkg.scripts ?? {};
27
+ if (scripts['dev:all'] || scripts.dev || scripts.start || scripts.serve || scripts.preview) {
27
28
  return dir;
28
29
  }
29
30
  } catch {}
@@ -41,30 +42,119 @@ function findNpmRoot(projectRoot: string, maxDepth = 5): string {
41
42
  return search(projectRoot, 0) ?? projectRoot;
42
43
  }
43
44
 
44
- const projectRoot = findProjectRoot(__dirname);
45
+ function parsePort(text: string): number | undefined {
46
+ const patterns = [
47
+ /(?:^|\s)(?:--port|-p)\s+([0-9]{2,5})(?:\s|$)/,
48
+ /(?:^|\s)--port=([0-9]{2,5})(?:\s|$)/,
49
+ /(?:^|\s)(?:PORT|VITE_PORT|PLAYWRIGHT_PORT|E2E_PORT)=([0-9]{2,5})(?:\s|$)/,
50
+ /port\s*:\s*([0-9]{2,5})/,
51
+ ];
52
+ for (const pattern of patterns) {
53
+ const match = text.match(pattern);
54
+ if (match) {
55
+ const port = Number(match[1]);
56
+ if (port > 0 && port <= 65535) return port;
57
+ }
58
+ }
59
+ return undefined;
60
+ }
61
+
62
+ function parseEnvPort(content: string): number | undefined {
63
+ const lines = content.split(/\r?\n/);
64
+ for (const key of ['PLAYWRIGHT_PORT', 'E2E_PORT', 'VITE_PORT', 'PORT']) {
65
+ for (const line of lines) {
66
+ const match = line.match(new RegExp(`^\\s*${key}\\s*=\\s*['\"]?([0-9]{2,5})['\"]?\\s*$`));
67
+ if (match) {
68
+ const port = Number(match[1]);
69
+ if (port > 0 && port <= 65535) return port;
70
+ }
71
+ }
72
+ }
73
+ return undefined;
74
+ }
75
+
76
+ function detectPortFromEnv(): number | undefined {
77
+ for (const key of ['PLAYWRIGHT_PORT', 'E2E_PORT', 'VITE_PORT', 'PORT']) {
78
+ const value = process.env[key];
79
+ if (!value) continue;
80
+ const port = Number(value);
81
+ if (Number.isInteger(port) && port > 0 && port <= 65535) return port;
82
+ }
83
+ return undefined;
84
+ }
85
+
86
+ function detectPortFromEnvFiles(npmRoot: string): number | undefined {
87
+ for (const file of ['.env.local', '.env.development', '.env']) {
88
+ const path = join(npmRoot, file);
89
+ if (!existsSync(path)) continue;
90
+ const port = parseEnvPort(readFileSync(path, 'utf-8'));
91
+ if (port) return port;
92
+ }
93
+ return undefined;
94
+ }
95
+
96
+ function detectVitePort(npmRoot: string): number | undefined {
97
+ for (const file of ['vite.config.ts', 'vite.config.mts', 'vite.config.js', 'vite.config.mjs', 'vite.config.cjs']) {
98
+ const path = join(npmRoot, file);
99
+ if (!existsSync(path)) continue;
100
+ const port = parsePort(readFileSync(path, 'utf-8'));
101
+ if (port) return port;
102
+ }
103
+ return undefined;
104
+ }
105
+
106
+ function frameworkDefaultPort(pkg: Record<string, any>, command = ''): number | undefined {
107
+ const deps = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) };
108
+ if (command.includes('vite') || deps.vite) return 5173;
109
+ if (command.includes('astro') || deps.astro) return 4321;
110
+ if (command.includes('next') || deps.next) return 3000;
111
+ if (command.includes('nuxt') || deps.nuxt) return 3000;
112
+ return undefined;
113
+ }
114
+
115
+ const projectRoot = findProjectRoot(process.cwd());
45
116
  const npmRoot = findNpmRoot(projectRoot);
117
+ const npmPkg = join(npmRoot, 'package.json');
118
+ const pkg = existsSync(npmPkg) ? JSON.parse(readFileSync(npmPkg, 'utf-8')) : {};
119
+ const scripts = pkg.scripts ?? {};
46
120
 
47
- // ─── BASE_URL: prefer env, then seed.spec.ts, then default ───
121
+ // ─── Dev command: detect from the npm project ───
122
+ const scriptName = scripts['dev:all']
123
+ ? 'dev:all'
124
+ : scripts.dev
125
+ ? 'dev'
126
+ : scripts.start
127
+ ? 'start'
128
+ : scripts.serve
129
+ ? 'serve'
130
+ : scripts.preview
131
+ ? 'preview'
132
+ : 'dev';
133
+ let devCmd = `npm run ${scriptName}`;
134
+ if (npmRoot !== projectRoot) {
135
+ devCmd = `cd "${npmRoot}" && ${devCmd}`;
136
+ }
137
+
138
+ // ─── BASE_URL: prefer env, then detected port, then seed.spec.ts, then default ───
48
139
  const seedSpec = join(projectRoot, 'tests', 'playwright', 'seed.spec.ts');
49
- let baseUrl = process.env.BASE_URL || 'http://localhost:3000';
50
- if (existsSync(seedSpec)) {
140
+ let baseUrl = process.env.BASE_URL;
141
+ if (!baseUrl) {
142
+ const scriptPort = scripts[scriptName] ? parsePort(scripts[scriptName]) : undefined;
143
+ const port = detectPortFromEnv() ?? scriptPort ?? detectVitePort(npmRoot) ?? detectPortFromEnvFiles(npmRoot) ?? frameworkDefaultPort(pkg, scripts[scriptName]);
144
+ if (port) baseUrl = `http://localhost:${port}`;
145
+ }
146
+ if (!baseUrl && existsSync(seedSpec)) {
51
147
  const content = readFileSync(seedSpec, 'utf-8');
52
148
  const m = content.match(/BASE_URL\s*=\s*process\.env\.BASE_URL\s*\|\|\s*['"]([^'"]+)['"]/);
53
- if (m) baseUrl = m[1];
54
- }
55
-
56
- // ─── Dev command: detect from the npm project ───
57
- let devCmd = 'npm run dev';
58
- const npmPkg = join(npmRoot, 'package.json');
59
- if (existsSync(npmPkg)) {
60
- const pkg = JSON.parse(readFileSync(npmPkg, 'utf-8'));
61
- const scripts = pkg.scripts ?? {};
62
- devCmd = scripts.dev ?? scripts.start ?? scripts.serve ?? scripts.preview ?? devCmd;
63
- // Prefix with cd if npmRoot differs from projectRoot
64
- if (npmRoot !== projectRoot) {
65
- devCmd = `cd ${npmRoot} && ${devCmd}`;
149
+ if (m) {
150
+ const candidate = m[1];
151
+ if (candidate.startsWith('http://') || candidate.startsWith('https://')) baseUrl = candidate;
66
152
  }
67
153
  }
154
+ baseUrl ??= 'http://localhost:3000';
155
+
156
+ const authStatePath = join(projectRoot, 'playwright', '.auth', 'user.json');
157
+ const storageState = existsSync(authStatePath) ? authStatePath : undefined;
68
158
 
69
159
  export default defineConfig({
70
160
  testDir: join(projectRoot, 'tests', 'playwright'),
@@ -99,7 +189,7 @@ export default defineConfig({
99
189
  name: 'chromium',
100
190
  use: {
101
191
  ...devices['Desktop Chrome'],
102
- storageState: './playwright/.auth/user.json',
192
+ storageState,
103
193
  },
104
194
  dependencies: ['setup'],
105
195
  // teardown: 'teardown', // Uncomment when teardown project is enabled
@@ -6,8 +6,8 @@ import { test, expect, Page, ConsoleMessage } from '@playwright/test';
6
6
  import { existsSync } from 'fs';
7
7
  import { BasePage } from './pages/BasePage';
8
8
 
9
- // Customize these for your application
10
- const BASE_URL = process.env.BASE_URL || 'http://localhost:3000';
9
+ // Prefer Playwright config's use.baseURL; env var is still supported for one-off overrides.
10
+ const BASE_URL = process.env.BASE_URL || '/';
11
11
 
12
12
  /**
13
13
  * Page Object Pattern - extends BasePage for shared utilities
@@ -49,9 +49,12 @@ test.describe('Application smoke tests', () => {
49
49
  }
50
50
  };
51
51
  page.on('console', handler);
52
- test.afterEach(() => page.off('console', handler));
53
- await page.reload();
54
- await page.waitForLoadState('networkidle');
52
+ try {
53
+ await page.reload();
54
+ await page.waitForLoadState('networkidle');
55
+ } finally {
56
+ page.off('console', handler);
57
+ }
55
58
  // Filter out known non-critical errors
56
59
  const criticalErrors = errors.filter(
57
60
  (e) => !e.includes('favicon') && !e.includes('404')
@@ -66,7 +69,7 @@ test.describe('Application smoke tests', () => {
66
69
 
67
70
  test.describe('Environment validation', () => {
68
71
  test('BASE_URL responds 200', async ({ page }) => {
69
- const res = await page.request.get(`${BASE_URL}/`);
72
+ const res = await page.request.get(BASE_URL);
70
73
  expect(res.status(), `BASE_URL ${BASE_URL} returned ${res.status()}`).toBeLessThan(500);
71
74
  });
72
75