playwright-e2e-mcp 0.9.0 → 0.10.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.
Files changed (41) hide show
  1. package/README.md +18 -3
  2. package/dist/apps/index.d.ts +29 -0
  3. package/dist/apps/index.js +52 -0
  4. package/dist/apps/index.js.map +1 -0
  5. package/dist/apps/test-report-html.d.ts +15 -0
  6. package/dist/apps/test-report-html.js +430 -0
  7. package/dist/apps/test-report-html.js.map +1 -0
  8. package/dist/index.js +2 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/oauth.d.ts +12 -2
  11. package/dist/oauth.js +44 -6
  12. package/dist/oauth.js.map +1 -1
  13. package/dist/server.js +17 -0
  14. package/dist/server.js.map +1 -1
  15. package/dist/tools/audit-tests.js +24 -6
  16. package/dist/tools/audit-tests.js.map +1 -1
  17. package/dist/tools/compare-visual-state.js +7 -1
  18. package/dist/tools/compare-visual-state.js.map +1 -1
  19. package/dist/tools/generate-e2e-test.js +27 -12
  20. package/dist/tools/generate-e2e-test.js.map +1 -1
  21. package/dist/tools/quarantine.js +7 -1
  22. package/dist/tools/quarantine.js.map +1 -1
  23. package/dist/tools/shared.d.ts +10 -0
  24. package/dist/tools/shared.js +15 -0
  25. package/dist/tools/shared.js.map +1 -1
  26. package/dist/tools/structured.d.ts +2 -0
  27. package/dist/tools/structured.js +4 -2
  28. package/dist/tools/structured.js.map +1 -1
  29. package/dist/tools/suggest-fix.js +6 -1
  30. package/dist/tools/suggest-fix.js.map +1 -1
  31. package/dist/types/index.d.ts +9 -0
  32. package/dist/utils/client-metadata.d.ts +46 -0
  33. package/dist/utils/client-metadata.js +174 -0
  34. package/dist/utils/client-metadata.js.map +1 -0
  35. package/dist/utils/confirm.d.ts +68 -0
  36. package/dist/utils/confirm.js +120 -0
  37. package/dist/utils/confirm.js.map +1 -0
  38. package/examples/github-actions/playwright-e2e.yml +1 -1
  39. package/package.json +1 -1
  40. package/skill/playwright-e2e-mcp/SKILL.md +6 -3
  41. package/skill/playwright-e2e-mcp/references/setup.md +1 -1
package/README.md CHANGED
@@ -273,8 +273,8 @@ Running and fixing your own tests needs your project, so use the local install f
273
273
  | --- | --- |
274
274
  | Skill only, any agent | `npx skills add xsignon-secure/E2E` |
275
275
  | MCP Registry | `io.github.xsignon-secure/E2E` ([listing](https://registry.modelcontextprotocol.io/)); registry-aware clients find it there |
276
- | Straight from GitHub, no npm | `npx -y github:xsignon-secure/E2E#v0.9.0` (pin a release tag) |
277
- | Release tarball | `npm install -D https://github.com/xsignon-secure/E2E/releases/download/v0.9.0/playwright-e2e-mcp-0.9.0.tgz` |
276
+ | Straight from GitHub, no npm | `npx -y github:xsignon-secure/E2E#v0.10.0` (pin a release tag) |
277
+ | Release tarball | `npm install -D https://github.com/xsignon-secure/E2E/releases/download/v0.10.0/playwright-e2e-mcp-0.10.0.tgz` |
278
278
  | Docker | `docker run -i --rm -v "$PWD:/work" ghcr.io/xsignon-secure/playwright-e2e-mcp` (published on each release; see [Development](docs/development.md#docker)) |
279
279
  | Local checkout | `"command": "node", "args": ["/path/to/E2E/dist/index.js"]` |
280
280
 
@@ -338,6 +338,18 @@ in the project, else `python3` / `python`.
338
338
  pip install pytest-playwright && playwright install chromium
339
339
  ```
340
340
 
341
+ ## What's new in 0.10
342
+
343
+ - **Asks before changing your files.** Applying a fix, writing a new test, quarantining a test or
344
+ replacing a visual baseline now shows you the exact change and waits for your yes, in clients
345
+ that support MCP questions (elicitation). No writes nothing. `PW_MCP_CONFIRM_WRITES` sets the
346
+ policy (`auto`, `always`, `off`).
347
+ - **Interactive test report** in Claude, ChatGPT, Cursor and other MCP Apps clients: counts,
348
+ a filterable list of failures, expected vs. received, and one-click re-run or "Ask to fix".
349
+ Other clients show the text result as before. `PW_MCP_APPS=0` turns it off.
350
+ - **Newer sign-in for the hosted endpoint:** OAuth clients can identify with a Client ID
351
+ Metadata Document (the MCP default since 2025-11-25); dynamic registration keeps working.
352
+
341
353
  ## What's new in 0.9
342
354
 
343
355
  - **Everything is free, including team history.** The CI history service that used to be a
@@ -481,7 +493,7 @@ steps:
481
493
  - uses: actions/setup-node@v6
482
494
  with: { node-version: 24 }
483
495
  - run: npm ci && npx playwright install --with-deps chromium
484
- - uses: xsignon-secure/E2E@v0.9.0
496
+ - uses: xsignon-secure/E2E@v0.10.0
485
497
  with:
486
498
  flaky-runs: 3 # 0 skips the flaky verdict
487
499
  suggest: 2 # suggest-fix diffs for the first 2 failures
@@ -525,6 +537,8 @@ npx -y playwright-e2e-mcp guard --base origin/main # exit 1 on BLOCK; --strict
525
537
  | `PW_MCP_OUTPUT_SCHEMAS` | on | `0` leaves the output schemas out of the tool list to save context. Results still carry `structuredContent` (see [Structured results](docs/tools.md#structured-results)) |
526
538
  | `PW_MCP_PROTOCOL` | both | `legacy` stops offering the stateless 2026-07-28 MCP revision, for a client that trips over it. By default 2026 clients get it and 2025 clients get the old handshake |
527
539
  | `PW_MCP_NO_UPDATE_CHECK` | off | `1` stops `doctor` from asking npm whether a newer version is out (same as `doctor --offline`) |
540
+ | `PW_MCP_CONFIRM_WRITES` | `auto` | Ask before a tool changes your files (`suggest-fix` apply, `audit-tests` fix, a new test from `generate-e2e-test`, quarantine add/remove, replacing a visual baseline). `auto` asks when the client can show a question (MCP elicitation) and writes as before when it can't; `always` refuses to write when the client can't ask; `off` never asks. The question shows the exact diff, and a yes only covers that diff |
541
+ | `PW_MCP_APPS` | `1` | Show an interactive test report next to `run-test`, `get-run-status` and `get-failure` results in clients that support MCP Apps (Claude, ChatGPT, Cursor). The report filters failures, shows expected vs. received, and re-runs or asks to fix a test with one click. `0` turns it off; other clients show the text result as before |
528
542
  | `PW_MCP_SKILLS` | on | `0` stops serving the bundled agent skill over the MCP Skills extension (`skill://playwright-e2e-mcp/SKILL.md`) |
529
543
  | `PW_MCP_STORAGE_STATE` | — | Default `storageState` file (inside the project) for the page tools |
530
544
  | `PW_MCP_PYTHON` | project venv, then `python3` | The Python that runs a pytest-playwright suite |
@@ -538,6 +552,7 @@ npx -y playwright-e2e-mcp guard --base origin/main # exit 1 on BLOCK; --strict
538
552
  | `PW_MCP_ALLOWED_HOSTS` | localhost + Vercel hostnames when there is no token | HTTP bridge only: comma-separated `Host` allowlist; `*` accepts any |
539
553
  | `PW_MCP_MAX_FAILED_AUTH` | `20` | HTTP bridge only: wrong tokens or access keys one client address may send in 15 minutes before it gets `429` |
540
554
  | `PW_MCP_OAUTH_REDIRECT_HOSTS` | any https host | HTTP bridge only: comma-separated hosts OAuth apps may return to, e.g. `claude.ai,chatgpt.com`; `.example.com` covers subdomains; localhost always works |
555
+ | `PW_MCP_OAUTH_CIMD` | `1` | HTTP bridge only: accept OAuth clients that identify with a Client ID Metadata Document (an https `client_id`, the MCP default since 2025-11-25); `0` accepts only dynamically registered clients |
541
556
  | `PW_MCP_TRUST_PROXY` | off (on for Vercel) | HTTP bridge only: `1` trusts `X-Real-IP` / `X-Forwarded-For` from a reverse proxy in front, so the sign-in limit counts per client, not per proxy |
542
557
  | `PW_MCP_PASSTHROUGH_ENV` | — | HTTP bridge only: comma-separated extra variables passed to test runs (e.g. `BASE_URL`) |
543
558
  | `PW_MCP_MAX_CHILDREN` | `4` | HTTP bridge only: how many test runs and browser probes may run at once |
@@ -0,0 +1,29 @@
1
+ /**
2
+ * MCP Apps (SEP-1865, extension `io.modelcontextprotocol/ui`): an
3
+ * interactive test report that Claude, ChatGPT, Cursor and other MCP Apps
4
+ * hosts render next to the run-test, get-run-status and get-failure results.
5
+ *
6
+ * The tools say which view to show in their `_meta.ui.resourceUri`; the
7
+ * host reads the `ui://` resource, renders it in a sandboxed iframe and
8
+ * hands it the tool result. Hosts that do not support MCP Apps ignore the
9
+ * metadata and show the text result exactly as before, so nothing changes
10
+ * for them.
11
+ *
12
+ * The view makes no network requests (it declares no CSP domains) and only
13
+ * calls this server's own tools through the host.
14
+ *
15
+ * Set PW_MCP_APPS=0 to turn it off.
16
+ */
17
+ import type { McpServer } from '@modelcontextprotocol/server';
18
+ /** The MCP Apps resource MIME type (`text/html;profile=mcp-app`). */
19
+ export declare const MCP_APP_MIME_TYPE = "text/html;profile=mcp-app";
20
+ /** Older hosts read the view from this flat key (`ui/resourceUri`). */
21
+ export declare const LEGACY_RESOURCE_URI_KEY = "ui/resourceUri";
22
+ export declare const TEST_REPORT_URI = "ui://playwright-e2e-mcp/test-report.html";
23
+ /** Tools whose results the report view can show. */
24
+ export declare const REPORT_TOOLS: ReadonlySet<string>;
25
+ export declare function appsEnabled(): boolean;
26
+ /** The `_meta` a tool declares so MCP Apps hosts show the report, or undefined. */
27
+ export declare function appMetaFor(toolName: string): Record<string, unknown> | undefined;
28
+ /** Register the report view resource. A no-op when PW_MCP_APPS=0. */
29
+ export declare function registerApps(server: McpServer): void;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * MCP Apps (SEP-1865, extension `io.modelcontextprotocol/ui`): an
3
+ * interactive test report that Claude, ChatGPT, Cursor and other MCP Apps
4
+ * hosts render next to the run-test, get-run-status and get-failure results.
5
+ *
6
+ * The tools say which view to show in their `_meta.ui.resourceUri`; the
7
+ * host reads the `ui://` resource, renders it in a sandboxed iframe and
8
+ * hands it the tool result. Hosts that do not support MCP Apps ignore the
9
+ * metadata and show the text result exactly as before, so nothing changes
10
+ * for them.
11
+ *
12
+ * The view makes no network requests (it declares no CSP domains) and only
13
+ * calls this server's own tools through the host.
14
+ *
15
+ * Set PW_MCP_APPS=0 to turn it off.
16
+ */
17
+ import { TEST_REPORT_HTML } from './test-report-html.js';
18
+ /** The MCP Apps resource MIME type (`text/html;profile=mcp-app`). */
19
+ export const MCP_APP_MIME_TYPE = 'text/html;profile=mcp-app';
20
+ /** Older hosts read the view from this flat key (`ui/resourceUri`). */
21
+ export const LEGACY_RESOURCE_URI_KEY = 'ui/resourceUri';
22
+ export const TEST_REPORT_URI = 'ui://playwright-e2e-mcp/test-report.html';
23
+ /** Tools whose results the report view can show. */
24
+ export const REPORT_TOOLS = new Set(['run-test', 'get-run-status', 'get-failure']);
25
+ export function appsEnabled() {
26
+ return process.env.PW_MCP_APPS !== '0';
27
+ }
28
+ /** The `_meta` a tool declares so MCP Apps hosts show the report, or undefined. */
29
+ export function appMetaFor(toolName) {
30
+ if (!appsEnabled() || !REPORT_TOOLS.has(toolName))
31
+ return undefined;
32
+ return { ui: { resourceUri: TEST_REPORT_URI }, [LEGACY_RESOURCE_URI_KEY]: TEST_REPORT_URI };
33
+ }
34
+ /** Rendering hints for the host: a border, and no outside origins at all. */
35
+ const RESOURCE_UI_META = {
36
+ prefersBorder: true,
37
+ csp: { connectDomains: [], resourceDomains: [] },
38
+ };
39
+ /** Register the report view resource. A no-op when PW_MCP_APPS=0. */
40
+ export function registerApps(server) {
41
+ if (!appsEnabled())
42
+ return;
43
+ server.registerResource('test-report', TEST_REPORT_URI, {
44
+ title: 'Interactive test report',
45
+ description: 'The view MCP Apps hosts show for run-test, get-run-status and get-failure results.',
46
+ mimeType: MCP_APP_MIME_TYPE,
47
+ _meta: { ui: RESOURCE_UI_META },
48
+ }, async () => ({
49
+ contents: [{ uri: TEST_REPORT_URI, mimeType: MCP_APP_MIME_TYPE, text: TEST_REPORT_HTML, _meta: { ui: RESOURCE_UI_META } }],
50
+ }));
51
+ }
52
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/apps/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD,qEAAqE;AACrE,MAAM,CAAC,MAAM,iBAAiB,GAAG,2BAA2B,CAAC;AAE7D,uEAAuE;AACvE,MAAM,CAAC,MAAM,uBAAuB,GAAG,gBAAgB,CAAC;AAExD,MAAM,CAAC,MAAM,eAAe,GAAG,0CAA0C,CAAC;AAE1E,oDAAoD;AACpD,MAAM,CAAC,MAAM,YAAY,GAAwB,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,gBAAgB,EAAE,aAAa,CAAC,CAAC,CAAC;AAExG,MAAM,UAAU,WAAW;IACzB,OAAO,OAAO,CAAC,GAAG,CAAC,WAAW,KAAK,GAAG,CAAC;AACzC,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,UAAU,CAAC,QAAgB;IACzC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC;QAAE,OAAO,SAAS,CAAC;IACpE,OAAO,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE,eAAe,EAAE,EAAE,CAAC,uBAAuB,CAAC,EAAE,eAAe,EAAE,CAAC;AAC9F,CAAC;AAED,6EAA6E;AAC7E,MAAM,gBAAgB,GAAG;IACvB,aAAa,EAAE,IAAI;IACnB,GAAG,EAAE,EAAE,cAAc,EAAE,EAAE,EAAE,eAAe,EAAE,EAAE,EAAE;CACjD,CAAC;AAEF,qEAAqE;AACrE,MAAM,UAAU,YAAY,CAAC,MAAiB;IAC5C,IAAI,CAAC,WAAW,EAAE;QAAE,OAAO;IAC3B,MAAM,CAAC,gBAAgB,CACrB,aAAa,EACb,eAAe,EACf;QACE,KAAK,EAAE,yBAAyB;QAChC,WAAW,EAAE,oFAAoF;QACjG,QAAQ,EAAE,iBAAiB;QAC3B,KAAK,EAAE,EAAE,EAAE,EAAE,gBAAgB,EAAE;KAChC,EACD,KAAK,IAAI,EAAE,CAAC,CAAC;QACX,QAAQ,EAAE,CAAC,EAAE,GAAG,EAAE,eAAe,EAAE,QAAQ,EAAE,iBAAiB,EAAE,IAAI,EAAE,gBAAgB,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,gBAAgB,EAAE,EAAE,CAAC;KAC3H,CAAC,CACH,CAAC;AACJ,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * The interactive test report view (MCP Apps, SEP-1865).
3
+ *
4
+ * One self-contained HTML page with no external requests: the host loads it
5
+ * in a sandboxed iframe and talks to it with JSON-RPC over postMessage. The
6
+ * page speaks the small part of the MCP Apps protocol it needs directly
7
+ * (ui/initialize, tool-input, tool-result, tools/call, ui/message,
8
+ * size-changed), so it ships no framework and no bundle.
9
+ *
10
+ * Everything from the tool result is written with textContent, never as
11
+ * HTML: test titles and error messages come from the project under test.
12
+ *
13
+ * Kept as a TypeScript string so `tsc` ships it in dist/ with the server.
14
+ */
15
+ export declare const TEST_REPORT_HTML: string;
@@ -0,0 +1,430 @@
1
+ /**
2
+ * The interactive test report view (MCP Apps, SEP-1865).
3
+ *
4
+ * One self-contained HTML page with no external requests: the host loads it
5
+ * in a sandboxed iframe and talks to it with JSON-RPC over postMessage. The
6
+ * page speaks the small part of the MCP Apps protocol it needs directly
7
+ * (ui/initialize, tool-input, tool-result, tools/call, ui/message,
8
+ * size-changed), so it ships no framework and no bundle.
9
+ *
10
+ * Everything from the tool result is written with textContent, never as
11
+ * HTML: test titles and error messages come from the project under test.
12
+ *
13
+ * Kept as a TypeScript string so `tsc` ships it in dist/ with the server.
14
+ */
15
+ export const TEST_REPORT_HTML = String.raw `<!doctype html>
16
+ <html lang="en">
17
+ <head>
18
+ <meta charset="utf-8">
19
+ <meta name="viewport" content="width=device-width, initial-scale=1">
20
+ <title>Playwright test report</title>
21
+ <style>
22
+ :root {
23
+ --bg: var(--color-background-primary, #ffffff);
24
+ --bg2: var(--color-background-secondary, #f5f6f8);
25
+ --fg: var(--color-text-primary, #1d2125);
26
+ --fg2: var(--color-text-secondary, #5b636b);
27
+ --line: var(--color-border-primary, #dfe2e6);
28
+ --ok: var(--color-text-success, #1f7a3d);
29
+ --bad: var(--color-text-danger, #b42318);
30
+ --warn: var(--color-text-warning, #9a6700);
31
+ --okbg: var(--color-background-success, #e7f6ec);
32
+ --badbg: var(--color-background-danger, #fdecea);
33
+ --warnbg: var(--color-background-warning, #fff4d6);
34
+ --radius: var(--border-radius-md, 8px);
35
+ --sans: var(--font-sans, system-ui, -apple-system, "Segoe UI", sans-serif);
36
+ --mono: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
37
+ }
38
+ :root[data-theme="dark"] {
39
+ --bg: var(--color-background-primary, #17191c);
40
+ --bg2: var(--color-background-secondary, #212429);
41
+ --fg: var(--color-text-primary, #e8eaed);
42
+ --fg2: var(--color-text-secondary, #a2a9b1);
43
+ --line: var(--color-border-primary, #33373d);
44
+ --ok: var(--color-text-success, #6fd08c);
45
+ --bad: var(--color-text-danger, #ff8a80);
46
+ --warn: var(--color-text-warning, #f2c94c);
47
+ --okbg: var(--color-background-success, #17301f);
48
+ --badbg: var(--color-background-danger, #3a1d1b);
49
+ --warnbg: var(--color-background-warning, #3a3117);
50
+ }
51
+ * { box-sizing: border-box; }
52
+ html, body { margin: 0; background: var(--bg); color: var(--fg); font: 14px/1.45 var(--sans); }
53
+ main { padding: 14px 16px 16px; }
54
+ h1 { font-size: 15px; margin: 0 0 10px; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
55
+ .badge { font-size: 12px; font-weight: 600; padding: 2px 8px; border-radius: 999px; }
56
+ .badge.ok { background: var(--okbg); color: var(--ok); }
57
+ .badge.bad { background: var(--badbg); color: var(--bad); }
58
+ .badge.warn { background: var(--warnbg); color: var(--warn); }
59
+ .stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(84px, 1fr)); gap: 8px; margin-bottom: 12px; }
60
+ .stat { background: var(--bg2); border-radius: var(--radius); padding: 8px 10px; }
61
+ .stat b { display: block; white-space: nowrap; font-size: 18px; font-variant-numeric: tabular-nums; }
62
+ .stat span { color: var(--fg2); font-size: 12px; }
63
+ .stat.failed b { color: var(--bad); }
64
+ .stat.passed b { color: var(--ok); }
65
+ .stat.flaky b { color: var(--warn); }
66
+ .bar { display: flex; height: 6px; border-radius: 3px; overflow: hidden; background: var(--bg2); margin-bottom: 12px; }
67
+ .bar i { display: block; }
68
+ .toolbar { display: flex; gap: 8px; margin-bottom: 8px; }
69
+ input[type=search] { flex: 1; min-width: 0; padding: 6px 10px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--bg); color: var(--fg); font: inherit; }
70
+ ul { list-style: none; margin: 0; padding: 0; }
71
+ li.failure { border: 1px solid var(--line); border-radius: var(--radius); margin-bottom: 8px; overflow: hidden; }
72
+ li.failure > button.head { all: unset; cursor: pointer; display: block; width: 100%; padding: 8px 10px; box-sizing: border-box; }
73
+ li.failure > button.head:focus-visible { outline: 2px solid var(--color-ring-primary, #3b82f6); outline-offset: -2px; }
74
+ .title { font-weight: 600; word-break: break-word; }
75
+ .where { color: var(--fg2); font: 12px var(--mono); word-break: break-all; }
76
+ .kind { font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--bad); margin-left: 6px; }
77
+ .body { padding: 0 10px 10px; display: none; }
78
+ li.open .body { display: block; }
79
+ pre { margin: 6px 0; padding: 8px; background: var(--bg2); border-radius: 6px; font: 12px/1.4 var(--mono); white-space: pre-wrap; word-break: break-word; max-height: 260px; overflow: auto; }
80
+ .cmp { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
81
+ .cmp div > span { font-size: 12px; color: var(--fg2); }
82
+ @media (max-width: 480px) { .cmp { grid-template-columns: 1fr; } }
83
+ .actions { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 6px; }
84
+ button.act { font: inherit; font-size: 13px; padding: 5px 10px; border-radius: var(--radius); border: 1px solid var(--line); background: var(--bg); color: var(--fg); cursor: pointer; }
85
+ button.act.primary { background: var(--fg); color: var(--bg); border-color: var(--fg); }
86
+ button.act:disabled { opacity: .55; cursor: default; }
87
+ .muted { color: var(--fg2); }
88
+ .note { font-size: 12px; color: var(--fg2); margin-top: 10px; }
89
+ .empty { padding: 18px; text-align: center; color: var(--fg2); background: var(--bg2); border-radius: var(--radius); }
90
+ .spin { display: inline-block; width: 10px; height: 10px; border: 2px solid var(--fg2); border-right-color: transparent; border-radius: 50%; animation: s 0.8s linear infinite; }
91
+ @keyframes s { to { transform: rotate(360deg); } }
92
+ @media (prefers-reduced-motion: reduce) { .spin { animation: none; } }
93
+ </style>
94
+ </head>
95
+ <body>
96
+ <main id="root"><p class="muted"><span class="spin"></span> Waiting for the test results…</p></main>
97
+ <script>
98
+ (function () {
99
+ "use strict";
100
+ var root = document.getElementById("root");
101
+ var nextId = 1;
102
+ var pending = {};
103
+ var lastInput = {};
104
+ var hostCaps = {};
105
+ var openai = window.openai;
106
+
107
+ // ---- JSON-RPC over postMessage (MCP Apps) ----
108
+ function post(msg) { window.parent.postMessage(msg, "*"); }
109
+ function request(method, params) {
110
+ var id = nextId++;
111
+ return new Promise(function (resolve, reject) {
112
+ pending[id] = { resolve: resolve, reject: reject };
113
+ post({ jsonrpc: "2.0", id: id, method: method, params: params || {} });
114
+ });
115
+ }
116
+ function notify(method, params) { post({ jsonrpc: "2.0", method: method, params: params || {} }); }
117
+
118
+ window.addEventListener("message", function (event) {
119
+ if (event.source !== window.parent) return;
120
+ var msg = event.data;
121
+ if (!msg || msg.jsonrpc !== "2.0") return;
122
+ if (msg.id !== undefined && !msg.method) {
123
+ var p = pending[msg.id];
124
+ if (!p) return;
125
+ delete pending[msg.id];
126
+ if (msg.error) p.reject(new Error(msg.error.message || "request failed"));
127
+ else p.resolve(msg.result);
128
+ return;
129
+ }
130
+ if (msg.method === "ui/notifications/tool-input") { lastInput = (msg.params && msg.params.arguments) || {}; return; }
131
+ if (msg.method === "ui/notifications/tool-result") { render(msg.params || {}); return; }
132
+ if (msg.method === "ui/notifications/tool-cancelled") { message("The tool call was cancelled."); return; }
133
+ if (msg.method === "ui/notifications/host-context-changed") { applyContext(msg.params || {}); return; }
134
+ if (msg.method === "ui/resource-teardown") { post({ jsonrpc: "2.0", id: msg.id, result: {} }); return; }
135
+ if (msg.method === "ping" && msg.id !== undefined) { post({ jsonrpc: "2.0", id: msg.id, result: {} }); }
136
+ });
137
+
138
+ function applyContext(ctx) {
139
+ if (ctx.theme === "dark" || ctx.theme === "light") document.documentElement.setAttribute("data-theme", ctx.theme);
140
+ var vars = ctx.styles && ctx.styles.variables;
141
+ if (vars) Object.keys(vars).forEach(function (k) { if (vars[k]) document.documentElement.style.setProperty(k, vars[k]); });
142
+ }
143
+
144
+ function callTool(name, args) {
145
+ if (openai && typeof openai.callTool === "function") return openai.callTool(name, args);
146
+ return request("tools/call", { name: name, arguments: args || {} });
147
+ }
148
+ function canCallTools() { return !!(openai && openai.callTool) || !!hostCaps.serverTools; }
149
+ function sendMessage(text) {
150
+ if (openai && typeof openai.sendFollowUpMessage === "function") return openai.sendFollowUpMessage({ prompt: text });
151
+ return request("ui/message", { role: "user", content: [{ type: "text", text: text }] });
152
+ }
153
+ function canMessage() { return !!(openai && openai.sendFollowUpMessage) || !!hostCaps.message; }
154
+
155
+ // ---- DOM helpers (textContent only) ----
156
+ function el(tag, cls, text) {
157
+ var node = document.createElement(tag);
158
+ if (cls) node.className = cls;
159
+ if (text !== undefined && text !== null) node.textContent = String(text);
160
+ return node;
161
+ }
162
+ function clear() { while (root.firstChild) root.removeChild(root.firstChild); }
163
+ function message(text) { clear(); root.appendChild(el("p", "muted", text)); }
164
+ function where(f) { return f.file + (f.line ? ":" + f.line : ""); }
165
+ function duration(ms) {
166
+ if (typeof ms !== "number") return "";
167
+ if (ms < 1000) return Math.round(ms) + " ms";
168
+ var s = ms / 1000;
169
+ return s < 60 ? s.toFixed(1) + " s" : Math.floor(s / 60) + "m " + Math.round(s % 60) + "s";
170
+ }
171
+ function button(label, cls, onClick) {
172
+ var b = el("button", "act" + (cls ? " " + cls : ""), label);
173
+ b.type = "button";
174
+ b.addEventListener("click", function () {
175
+ if (b.disabled) return;
176
+ b.disabled = true;
177
+ var before = b.textContent;
178
+ b.textContent = "…";
179
+ Promise.resolve().then(onClick).catch(function (err) {
180
+ b.title = String(err && err.message || err);
181
+ }).then(function () { b.disabled = false; b.textContent = before; });
182
+ });
183
+ return b;
184
+ }
185
+
186
+ // ---- views ----
187
+ function render(result) {
188
+ var data = result.structuredContent;
189
+ if (!data && result.content) {
190
+ // Hosts that drop structuredContent: show the Markdown text.
191
+ clear();
192
+ var text = result.content.filter(function (c) { return c.type === "text"; }).map(function (c) { return c.text; }).join("\n\n");
193
+ root.appendChild(el("pre", null, text || "No result."));
194
+ return;
195
+ }
196
+ data = data || {};
197
+ if (data.error) return renderError(data.error);
198
+ if (data.run) return renderRun(data);
199
+ if (data.failure) return renderSingleFailure(data);
200
+ if (data.status === "running" && data.runId) return renderRunning(data);
201
+ message(data.ok ? "Done." : "The tool reported a problem; see the text reply.");
202
+ }
203
+
204
+ function renderError(error) {
205
+ clear();
206
+ var h = el("h1", null, "Could not run the tests");
207
+ h.appendChild(el("span", "badge bad", error.kind || "ERROR"));
208
+ root.appendChild(h);
209
+ root.appendChild(el("pre", null, error.message || ""));
210
+ if (error.hint) root.appendChild(el("p", "muted", error.hint));
211
+ }
212
+
213
+ function renderRunning(data) {
214
+ clear();
215
+ var h = el("h1", null, "Tests are running");
216
+ h.appendChild(el("span", "badge warn", data.runId));
217
+ root.appendChild(h);
218
+ var p = el("p", "muted");
219
+ p.appendChild(el("span", "spin"));
220
+ p.appendChild(document.createTextNode(" This report updates when the run finishes."));
221
+ root.appendChild(p);
222
+ if (!canCallTools()) return;
223
+ var poll = function () {
224
+ callTool("get-run-status", { runId: data.runId, waitSeconds: 20 }).then(function (res) {
225
+ var sc = (res && res.structuredContent) || {};
226
+ if (sc.status === "running" && !sc.run) setTimeout(poll, 500);
227
+ else render(res);
228
+ }).catch(function () { setTimeout(poll, 5000); });
229
+ };
230
+ setTimeout(poll, 500);
231
+ }
232
+
233
+ function renderRun(data) {
234
+ var run = data.run;
235
+ clear();
236
+ var total = run.passed + run.failed + run.flaky + run.skipped;
237
+ var h = el("h1", null, "Playwright test report");
238
+ var verdict = run.failed > 0 ? ["bad", run.failed + " failed"] : run.flaky > 0 ? ["warn", "flaky"] : total === 0 ? ["warn", "no tests ran"] : ["ok", "all passed"];
239
+ h.appendChild(el("span", "badge " + verdict[0], verdict[1]));
240
+ if (run.partial) h.appendChild(el("span", "badge warn", "stopped early"));
241
+ if (data.status === "cancelled") h.appendChild(el("span", "badge warn", "cancelled"));
242
+ root.appendChild(h);
243
+
244
+ var stats = el("div", "stats");
245
+ [["passed", run.passed], ["failed", run.failed], ["flaky", run.flaky], ["skipped", run.skipped]].forEach(function (s) {
246
+ var box = el("div", "stat " + s[0]);
247
+ box.appendChild(el("b", null, s[1]));
248
+ box.appendChild(el("span", null, s[0]));
249
+ stats.appendChild(box);
250
+ });
251
+ var time = el("div", "stat");
252
+ time.appendChild(el("b", null, duration(run.durationMs)));
253
+ time.appendChild(el("span", null, "duration"));
254
+ stats.appendChild(time);
255
+ root.appendChild(stats);
256
+
257
+ if (total > 0) {
258
+ var bar = el("div", "bar");
259
+ bar.setAttribute("role", "img");
260
+ bar.setAttribute("aria-label", run.passed + " passed, " + run.failed + " failed, " + run.flaky + " flaky, " + run.skipped + " skipped");
261
+ [["passed", "var(--ok)"], ["failed", "var(--bad)"], ["flaky", "var(--warn)"], ["skipped", "var(--line)"]].forEach(function (s) {
262
+ if (!run[s[0]]) return;
263
+ var seg = el("i");
264
+ seg.style.width = (100 * run[s[0]] / total) + "%";
265
+ seg.style.background = s[1];
266
+ bar.appendChild(seg);
267
+ });
268
+ root.appendChild(bar);
269
+ }
270
+
271
+ if (!run.failures.length) {
272
+ root.appendChild(el("div", "empty", run.failed > 0 ? "Failures were not listed. Ask for get-failure." : "No failures."));
273
+ } else {
274
+ var toolbar = el("div", "toolbar");
275
+ var search = el("input");
276
+ search.type = "search";
277
+ search.placeholder = "Filter failures by title, file or error";
278
+ search.setAttribute("aria-label", "Filter failures");
279
+ toolbar.appendChild(search);
280
+ if (run.failures.length > 1 && canMessage()) {
281
+ toolbar.appendChild(button("Fix all", "primary", function () {
282
+ return sendMessage("Please fix the " + run.failures.length + " failing Playwright tests from the last run. Start with get-failure for each one, then suggest-fix.");
283
+ }));
284
+ }
285
+ root.appendChild(toolbar);
286
+ var list = el("ul");
287
+ run.failures.forEach(function (f, i) { list.appendChild(failureItem(f, i + 1, run.failures.length === 1)); });
288
+ root.appendChild(list);
289
+ search.addEventListener("input", function () {
290
+ var q = search.value.trim().toLowerCase();
291
+ Array.prototype.forEach.call(list.children, function (li) {
292
+ li.style.display = !q || li.getAttribute("data-text").indexOf(q) >= 0 ? "" : "none";
293
+ });
294
+ });
295
+ if (run.failuresTruncated) root.appendChild(el("p", "note", "Only the first failures are listed; the text reply has the rest."));
296
+ }
297
+ if (run.quarantined) root.appendChild(el("p", "note", run.quarantined + " failing test(s) are quarantined and do not fail the run."));
298
+ var rerun = rerunArgs();
299
+ if (rerun && canCallTools()) {
300
+ var actions = el("div", "actions");
301
+ actions.appendChild(button("Run again", null, function () {
302
+ message("Running the tests again…");
303
+ return callTool("run-test", rerun).then(render);
304
+ }));
305
+ root.appendChild(actions);
306
+ }
307
+ }
308
+
309
+ function rerunArgs() {
310
+ var keep = {};
311
+ ["testFiles", "grep", "browser", "config", "projectRoot", "retries", "workers", "lastFailed", "timeoutMs", "testTimeoutMs"].forEach(function (k) {
312
+ if (lastInput[k] !== undefined) keep[k] = lastInput[k];
313
+ });
314
+ return keep;
315
+ }
316
+
317
+ function failureItem(f, index, open) {
318
+ var li = el("li", "failure" + (open ? " open" : ""));
319
+ li.setAttribute("data-text", (f.title + " " + f.file + " " + f.message).toLowerCase());
320
+ var head = el("button", "head");
321
+ head.type = "button";
322
+ head.setAttribute("aria-expanded", open ? "true" : "false");
323
+ var t = el("div", "title", f.title);
324
+ t.appendChild(el("span", "kind", f.kind));
325
+ head.appendChild(t);
326
+ head.appendChild(el("div", "where", where(f) + (f.project ? " · " + f.project : "")));
327
+ li.appendChild(head);
328
+ var body = el("div", "body");
329
+ body.appendChild(el("pre", null, f.message));
330
+ var details = el("div");
331
+ body.appendChild(details);
332
+ var actions = el("div", "actions");
333
+ if (canCallTools()) {
334
+ actions.appendChild(button("Show details", null, function () {
335
+ return callTool("get-failure", { index: index }).then(function (res) {
336
+ var sc = (res && res.structuredContent) || {};
337
+ while (details.firstChild) details.removeChild(details.firstChild);
338
+ fillDetails(details, sc.failure, res);
339
+ });
340
+ }));
341
+ actions.appendChild(button("Re-run this test", null, function () {
342
+ message("Running " + where(f) + "…");
343
+ return callTool("run-test", { testFiles: [where(f)] }).then(render);
344
+ }));
345
+ }
346
+ if (canMessage()) {
347
+ actions.appendChild(button("Ask to fix", "primary", function () {
348
+ return sendMessage("Fix the failing Playwright test \"" + f.title + "\" at " + where(f) + ". Call get-failure with index " + index + " first, then suggest-fix.");
349
+ }));
350
+ }
351
+ if (actions.firstChild) body.appendChild(actions);
352
+ li.appendChild(body);
353
+ head.addEventListener("click", function () {
354
+ var isOpen = li.classList.toggle("open");
355
+ head.setAttribute("aria-expanded", isOpen ? "true" : "false");
356
+ });
357
+ return li;
358
+ }
359
+
360
+ function fillDetails(target, failure, res) {
361
+ if (failure && (failure.expected || failure.actual)) {
362
+ var cmp = el("div", "cmp");
363
+ var a = el("div"); a.appendChild(el("span", null, "Expected")); a.appendChild(el("pre", null, failure.expected || ""));
364
+ var b = el("div"); b.appendChild(el("span", null, "Received")); b.appendChild(el("pre", null, failure.actual || ""));
365
+ cmp.appendChild(a); cmp.appendChild(b);
366
+ target.appendChild(cmp);
367
+ }
368
+ var text = ((res && res.content) || []).filter(function (c) { return c.type === "text"; }).map(function (c) { return c.text; }).join("\n\n");
369
+ if (text) target.appendChild(el("pre", null, text));
370
+ }
371
+
372
+ function renderSingleFailure(data) {
373
+ clear();
374
+ var f = data.failure;
375
+ var h = el("h1", null, "Failure " + (data.index || 1) + (data.total ? " of " + data.total : ""));
376
+ h.appendChild(el("span", "badge bad", f.kind));
377
+ root.appendChild(h);
378
+ root.appendChild(el("div", "title", f.title));
379
+ root.appendChild(el("div", "where", where(f)));
380
+ var box = el("div");
381
+ box.appendChild(el("pre", null, f.message));
382
+ fillDetails(box, { expected: f.expected, actual: f.actual }, null);
383
+ root.appendChild(box);
384
+ var actions = el("div", "actions");
385
+ if (canCallTools() && data.total && data.total > 1) {
386
+ var i = data.index || 1;
387
+ if (i > 1) actions.appendChild(button("Previous", null, function () { return callTool("get-failure", { index: i - 1 }).then(render); }));
388
+ if (i < data.total) actions.appendChild(button("Next", null, function () { return callTool("get-failure", { index: i + 1 }).then(render); }));
389
+ }
390
+ if (canMessage()) {
391
+ actions.appendChild(button("Ask to fix", "primary", function () {
392
+ return sendMessage("Fix the failing Playwright test \"" + f.title + "\" at " + where(f) + " with suggest-fix.");
393
+ }));
394
+ }
395
+ if (actions.firstChild) root.appendChild(actions);
396
+ }
397
+
398
+ // ---- size reporting ----
399
+ function reportSize() {
400
+ var h = Math.ceil(document.documentElement.getBoundingClientRect().height);
401
+ notify("ui/notifications/size-changed", { width: Math.ceil(window.innerWidth), height: h });
402
+ }
403
+
404
+ // ---- start ----
405
+ if (openai) {
406
+ // ChatGPT's window.openai bridge: the result is already there.
407
+ if (openai.toolInput) lastInput = openai.toolInput;
408
+ if (openai.toolOutput) render({ structuredContent: openai.toolOutput });
409
+ window.addEventListener("openai:set_globals", function () {
410
+ if (window.openai.toolOutput) render({ structuredContent: window.openai.toolOutput });
411
+ });
412
+ return;
413
+ }
414
+ request("ui/initialize", {
415
+ appInfo: { name: "playwright-e2e-mcp-report", version: "1.0.0" },
416
+ appCapabilities: {},
417
+ protocolVersion: "2026-01-26"
418
+ }).then(function (init) {
419
+ hostCaps = (init && init.hostCapabilities) || {};
420
+ applyContext((init && init.hostContext) || {});
421
+ notify("ui/notifications/initialized", {});
422
+ if (typeof ResizeObserver === "function") new ResizeObserver(reportSize).observe(document.body);
423
+ reportSize();
424
+ }).catch(function () { /* not inside an MCP Apps host */ });
425
+ })();
426
+ </script>
427
+ </body>
428
+ </html>
429
+ `;
430
+ //# sourceMappingURL=test-report-html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-report-html.js","sourceRoot":"","sources":["../../src/apps/test-report-html.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8ZzC,CAAC"}
package/dist/index.js CHANGED
@@ -93,6 +93,8 @@ async function main() {
93
93
  ' PW_MCP_PYTHON Python for pytest-playwright projects (default: project venv, python3)',
94
94
  ' PW_MCP_LOGIN_ENV extra variables save-login may type ({{env:NAME}}), comma separated',
95
95
  ' PW_MCP_PROTOCOL legacy = do not offer the 2026-07-28 MCP revision',
96
+ ' PW_MCP_CONFIRM_WRITES auto | always | off: ask before changing files (default auto)',
97
+ ' PW_MCP_APPS=0 no interactive test report in MCP Apps clients',
96
98
  ' PW_MCP_SKILLS 0 = do not serve the bundled skill over the Skills extension',
97
99
  ' PW_MCP_NO_UPDATE_CHECK 1 = doctor does not ask npm whether a newer version is out',
98
100
  ' LOG_LEVEL / MCP_LOG_LEVEL debug | info | warn | error | silent (default: info)',
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}