playwright-e2e-mcp 0.8.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.
- package/README.md +39 -9
- package/dist/apps/index.d.ts +29 -0
- package/dist/apps/index.js +52 -0
- package/dist/apps/index.js.map +1 -0
- package/dist/apps/test-report-html.d.ts +15 -0
- package/dist/apps/test-report-html.js +430 -0
- package/dist/apps/test-report-html.js.map +1 -0
- package/dist/cli/upload.d.ts +6 -5
- package/dist/cli/upload.js +20 -17
- package/dist/cli/upload.js.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/oauth.d.ts +12 -2
- package/dist/oauth.js +44 -6
- package/dist/oauth.js.map +1 -1
- package/dist/server.js +17 -0
- package/dist/server.js.map +1 -1
- package/dist/tools/analyze-history.js +9 -9
- package/dist/tools/analyze-history.js.map +1 -1
- package/dist/tools/audit-tests.js +24 -6
- package/dist/tools/audit-tests.js.map +1 -1
- package/dist/tools/compare-visual-state.js +7 -1
- package/dist/tools/compare-visual-state.js.map +1 -1
- package/dist/tools/generate-e2e-test.js +27 -12
- package/dist/tools/generate-e2e-test.js.map +1 -1
- package/dist/tools/quarantine.js +7 -1
- package/dist/tools/quarantine.js.map +1 -1
- package/dist/tools/shared.d.ts +10 -0
- package/dist/tools/shared.js +15 -0
- package/dist/tools/shared.js.map +1 -1
- package/dist/tools/structured.d.ts +2 -0
- package/dist/tools/structured.js +4 -2
- package/dist/tools/structured.js.map +1 -1
- package/dist/tools/suggest-fix.js +6 -1
- package/dist/tools/suggest-fix.js.map +1 -1
- package/dist/types/index.d.ts +9 -0
- package/dist/utils/client-metadata.d.ts +46 -0
- package/dist/utils/client-metadata.js +174 -0
- package/dist/utils/client-metadata.js.map +1 -0
- package/dist/utils/confirm.d.ts +68 -0
- package/dist/utils/confirm.js +120 -0
- package/dist/utils/confirm.js.map +1 -0
- package/dist/utils/history-client.d.ts +32 -0
- package/dist/utils/{pro-client.js → history-client.js} +27 -20
- package/dist/utils/history-client.js.map +1 -0
- package/examples/github-actions/playwright-e2e.yml +5 -4
- package/package.json +1 -1
- package/skill/playwright-e2e-mcp/SKILL.md +8 -3
- package/skill/playwright-e2e-mcp/references/setup.md +2 -2
- package/dist/utils/pro-client.d.ts +0 -29
- package/dist/utils/pro-client.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-metadata.js","sourceRoot":"","sources":["../../src/utils/client-metadata.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ask the person before a tool changes files in their project.
|
|
3
|
+
*
|
|
4
|
+
* Tools that write test code or project state (suggest-fix `apply`,
|
|
5
|
+
* generate-e2e-test, quarantine add/remove, compare-visual-state `baseline`)
|
|
6
|
+
* call `ctx.confirmWrite()` right before the write, with the exact change
|
|
7
|
+
* they are about to make. When the client can show a form (MCP elicitation),
|
|
8
|
+
* the server answers the call with an `input_required` result (the
|
|
9
|
+
* 2026-07-28 multi-round-trip pattern; the SDK turns it into a classic
|
|
10
|
+
* elicitation request for 2025 clients). The client shows the change, the
|
|
11
|
+
* person says yes or no, and the client retries the call with the answer.
|
|
12
|
+
*
|
|
13
|
+
* The approval is bound to the change: the question's key is a hash of the
|
|
14
|
+
* tool, title and detail, so if the retried call would write something
|
|
15
|
+
* different it asks again instead of reusing an old "yes".
|
|
16
|
+
*
|
|
17
|
+
* PW_MCP_CONFIRM_WRITES:
|
|
18
|
+
* auto (default) ask when the client supports elicitation; otherwise
|
|
19
|
+
* write as before and say no one was asked
|
|
20
|
+
* always ask, and refuse to write when the client cannot ask
|
|
21
|
+
* off never ask
|
|
22
|
+
*/
|
|
23
|
+
import type { InputRequiredResult } from '@modelcontextprotocol/server';
|
|
24
|
+
export type ConfirmMode = 'auto' | 'always' | 'off';
|
|
25
|
+
/** What the tool is about to do, shown to the person. */
|
|
26
|
+
export interface WriteConfirmation {
|
|
27
|
+
/** One line: "Apply this fix to tests/cart.spec.ts:42?" */
|
|
28
|
+
title: string;
|
|
29
|
+
/** The change itself (a diff, the file to be written, the entry to add). */
|
|
30
|
+
detail: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* - `approved`: the person said yes.
|
|
34
|
+
* - `declined`: the person said no (or cancelled): do not write.
|
|
35
|
+
* - `not-asked`: confirmation is off, or the client cannot ask: write as before.
|
|
36
|
+
*/
|
|
37
|
+
export type ConfirmOutcome = 'approved' | 'declined' | 'not-asked';
|
|
38
|
+
export type ConfirmWrite = (request: WriteConfirmation) => Promise<ConfirmOutcome>;
|
|
39
|
+
/**
|
|
40
|
+
* Thrown by `confirmWrite` when the person has to be asked. It carries the
|
|
41
|
+
* `input_required` result; the server returns it instead of a tool result.
|
|
42
|
+
* Tools must let it through (guard() rethrows it).
|
|
43
|
+
*/
|
|
44
|
+
export declare class ConfirmationPending extends Error {
|
|
45
|
+
readonly result: InputRequiredResult;
|
|
46
|
+
constructor(result: InputRequiredResult);
|
|
47
|
+
}
|
|
48
|
+
export declare function confirmMode(value?: string | undefined): ConfirmMode;
|
|
49
|
+
/** Longest change shown in the question; clients show it as plain text. */
|
|
50
|
+
export declare const MAX_DETAIL_CHARS = 4000;
|
|
51
|
+
/** Whether declared client capabilities include form-mode elicitation. */
|
|
52
|
+
export declare function supportsFormElicitation(capabilities: unknown): boolean;
|
|
53
|
+
/** The input key for one exact change: a new change gets a new question. */
|
|
54
|
+
export declare function confirmationKey(tool: string, request: WriteConfirmation): string;
|
|
55
|
+
export interface ConfirmerOptions {
|
|
56
|
+
tool: string;
|
|
57
|
+
/** Retried-call answers (`ctx.mcpReq.inputResponses`). */
|
|
58
|
+
inputResponses?: Record<string, unknown>;
|
|
59
|
+
/** Per-request envelope (2026-07-28) or undefined on 2025 connections. */
|
|
60
|
+
envelope?: Record<string, unknown>;
|
|
61
|
+
/** Capabilities from the 2025 initialize handshake. */
|
|
62
|
+
sessionCapabilities?: unknown;
|
|
63
|
+
mode?: ConfirmMode;
|
|
64
|
+
}
|
|
65
|
+
/** Build the `confirmWrite` a tool call gets in its context. */
|
|
66
|
+
export declare function createConfirmWrite(options: ConfirmerOptions): ConfirmWrite;
|
|
67
|
+
/** The line tools add to a result when the person was or was not asked. */
|
|
68
|
+
export declare function confirmationNote(outcome: ConfirmOutcome): string | undefined;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ask the person before a tool changes files in their project.
|
|
3
|
+
*
|
|
4
|
+
* Tools that write test code or project state (suggest-fix `apply`,
|
|
5
|
+
* generate-e2e-test, quarantine add/remove, compare-visual-state `baseline`)
|
|
6
|
+
* call `ctx.confirmWrite()` right before the write, with the exact change
|
|
7
|
+
* they are about to make. When the client can show a form (MCP elicitation),
|
|
8
|
+
* the server answers the call with an `input_required` result (the
|
|
9
|
+
* 2026-07-28 multi-round-trip pattern; the SDK turns it into a classic
|
|
10
|
+
* elicitation request for 2025 clients). The client shows the change, the
|
|
11
|
+
* person says yes or no, and the client retries the call with the answer.
|
|
12
|
+
*
|
|
13
|
+
* The approval is bound to the change: the question's key is a hash of the
|
|
14
|
+
* tool, title and detail, so if the retried call would write something
|
|
15
|
+
* different it asks again instead of reusing an old "yes".
|
|
16
|
+
*
|
|
17
|
+
* PW_MCP_CONFIRM_WRITES:
|
|
18
|
+
* auto (default) ask when the client supports elicitation; otherwise
|
|
19
|
+
* write as before and say no one was asked
|
|
20
|
+
* always ask, and refuse to write when the client cannot ask
|
|
21
|
+
* off never ask
|
|
22
|
+
*/
|
|
23
|
+
import { createHash } from 'node:crypto';
|
|
24
|
+
import { CLIENT_CAPABILITIES_META_KEY, inputRequired, inputResponse } from '@modelcontextprotocol/server';
|
|
25
|
+
import { PlaywrightMcpError } from '../types/index.js';
|
|
26
|
+
/**
|
|
27
|
+
* Thrown by `confirmWrite` when the person has to be asked. It carries the
|
|
28
|
+
* `input_required` result; the server returns it instead of a tool result.
|
|
29
|
+
* Tools must let it through (guard() rethrows it).
|
|
30
|
+
*/
|
|
31
|
+
export class ConfirmationPending extends Error {
|
|
32
|
+
result;
|
|
33
|
+
constructor(result) {
|
|
34
|
+
super('waiting for the person to confirm a file change');
|
|
35
|
+
this.name = 'ConfirmationPending';
|
|
36
|
+
this.result = result;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export function confirmMode(value = process.env.PW_MCP_CONFIRM_WRITES) {
|
|
40
|
+
const normalized = (value ?? '').trim().toLowerCase();
|
|
41
|
+
if (normalized === 'off' || normalized === '0' || normalized === 'false')
|
|
42
|
+
return 'off';
|
|
43
|
+
if (normalized === 'always' || normalized === 'require' || normalized === 'required')
|
|
44
|
+
return 'always';
|
|
45
|
+
return 'auto';
|
|
46
|
+
}
|
|
47
|
+
/** Longest change shown in the question; clients show it as plain text. */
|
|
48
|
+
export const MAX_DETAIL_CHARS = 4_000;
|
|
49
|
+
/** Whether declared client capabilities include form-mode elicitation. */
|
|
50
|
+
export function supportsFormElicitation(capabilities) {
|
|
51
|
+
if (!capabilities || typeof capabilities !== 'object')
|
|
52
|
+
return false;
|
|
53
|
+
const elicitation = capabilities.elicitation;
|
|
54
|
+
if (!elicitation || typeof elicitation !== 'object')
|
|
55
|
+
return false;
|
|
56
|
+
const modes = elicitation;
|
|
57
|
+
// `{}` (2025-06-18) means form mode; a client that lists modes must list form.
|
|
58
|
+
if ('form' in modes || 'url' in modes)
|
|
59
|
+
return 'form' in modes;
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
/** The input key for one exact change: a new change gets a new question. */
|
|
63
|
+
export function confirmationKey(tool, request) {
|
|
64
|
+
const digest = createHash('sha256').update(`${tool}\n${request.title}\n${request.detail}`).digest('hex');
|
|
65
|
+
return `confirm_write_${digest.slice(0, 20)}`;
|
|
66
|
+
}
|
|
67
|
+
function questionText(tool, request) {
|
|
68
|
+
const detail = request.detail.length > MAX_DETAIL_CHARS
|
|
69
|
+
? `${request.detail.slice(0, MAX_DETAIL_CHARS)}\n… (${request.detail.length - MAX_DETAIL_CHARS} more characters)`
|
|
70
|
+
: request.detail;
|
|
71
|
+
return `${request.title}\n\n${detail}\n\n(${tool} asks before changing files in your project. Set PW_MCP_CONFIRM_WRITES=off to stop asking.)`;
|
|
72
|
+
}
|
|
73
|
+
/** Build the `confirmWrite` a tool call gets in its context. */
|
|
74
|
+
export function createConfirmWrite(options) {
|
|
75
|
+
return async (request) => {
|
|
76
|
+
const mode = options.mode ?? confirmMode();
|
|
77
|
+
if (mode === 'off')
|
|
78
|
+
return 'not-asked';
|
|
79
|
+
const key = confirmationKey(options.tool, request);
|
|
80
|
+
const answer = inputResponse(options.inputResponses, key);
|
|
81
|
+
if (answer.kind === 'elicit') {
|
|
82
|
+
return answer.action === 'accept' && answer.content?.confirm === true ? 'approved' : 'declined';
|
|
83
|
+
}
|
|
84
|
+
const capabilities = options.envelope?.[CLIENT_CAPABILITIES_META_KEY] ?? options.sessionCapabilities;
|
|
85
|
+
if (!supportsFormElicitation(capabilities)) {
|
|
86
|
+
if (mode === 'always') {
|
|
87
|
+
throw new PlaywrightMcpError(`Not written: ${request.title.replace(/\?$/, '')} needs your confirmation, and this client cannot ask`, 'INVALID_INPUT', {
|
|
88
|
+
hint: 'PW_MCP_CONFIRM_WRITES=always refuses file changes in clients without elicitation. Use a client that supports it, or set PW_MCP_CONFIRM_WRITES=auto.',
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return 'not-asked';
|
|
92
|
+
}
|
|
93
|
+
throw new ConfirmationPending(inputRequired({
|
|
94
|
+
inputRequests: {
|
|
95
|
+
[key]: inputRequired.elicit({
|
|
96
|
+
message: questionText(options.tool, request),
|
|
97
|
+
requestedSchema: {
|
|
98
|
+
type: 'object',
|
|
99
|
+
properties: {
|
|
100
|
+
confirm: {
|
|
101
|
+
type: 'boolean',
|
|
102
|
+
title: 'Make this change',
|
|
103
|
+
description: 'Yes writes the change. No leaves your files as they are.',
|
|
104
|
+
default: false,
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
required: ['confirm'],
|
|
108
|
+
},
|
|
109
|
+
}),
|
|
110
|
+
},
|
|
111
|
+
}));
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/** The line tools add to a result when the person was or was not asked. */
|
|
115
|
+
export function confirmationNote(outcome) {
|
|
116
|
+
if (outcome === 'approved')
|
|
117
|
+
return '> ✅ You confirmed this change.';
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=confirm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confirm.js","sourceRoot":"","sources":["../../src/utils/confirm.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared history client: CI runs from every machine in one history, kept
|
|
3
|
+
* by a history server the team hosts itself (history-server/ in this repo,
|
|
4
|
+
* free and MIT like everything else).
|
|
5
|
+
*
|
|
6
|
+
* Strictly opt-in. Nothing here makes a network call unless
|
|
7
|
+
* PW_MCP_HISTORY_TOKEN is set; without it the server behaves exactly as
|
|
8
|
+
* before. PW_MCP_HISTORY_URL points at the team's history server. There is
|
|
9
|
+
* deliberately no built-in default URL: the token only ever goes where the
|
|
10
|
+
* user pointed it. PW_MCP_PRO_KEY / PW_MCP_PRO_URL / PW_MCP_PRO_PROJECT,
|
|
11
|
+
* the names from 0.7 and 0.8, still work.
|
|
12
|
+
*/
|
|
13
|
+
import type { HistoryEntry } from './run-history.js';
|
|
14
|
+
export interface HistorySettings {
|
|
15
|
+
key: string;
|
|
16
|
+
url: string;
|
|
17
|
+
}
|
|
18
|
+
/** The shared history settings, or undefined when none are set (the normal case). */
|
|
19
|
+
export declare function historySettings(env?: NodeJS.ProcessEnv): HistorySettings | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* The project name runs are filed under: PW_MCP_HISTORY_PROJECT, else the
|
|
22
|
+
* GitHub repository (owner/name, from CI or the origin remote), else the
|
|
23
|
+
* folder name. The same rule on CI and laptops, so both see one history.
|
|
24
|
+
*/
|
|
25
|
+
export declare function historyProjectName(root: string, env?: NodeJS.ProcessEnv): Promise<string>;
|
|
26
|
+
export declare function uploadRuns(settings: HistorySettings, project: string, runs: HistoryEntry[]): Promise<{
|
|
27
|
+
stored: number;
|
|
28
|
+
skipped: number;
|
|
29
|
+
}>;
|
|
30
|
+
export declare function fetchRuns(settings: HistorySettings, project: string, limit: number): Promise<HistoryEntry[]>;
|
|
31
|
+
/** Local and cloud runs together, oldest first, without duplicates. */
|
|
32
|
+
export declare function mergeRuns(local: HistoryEntry[], cloud: HistoryEntry[], last: number): HistoryEntry[];
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Shared history client: CI runs from every machine in one history, kept
|
|
3
|
+
* by a history server the team hosts itself (history-server/ in this repo,
|
|
4
|
+
* free and MIT like everything else).
|
|
3
5
|
*
|
|
4
6
|
* Strictly opt-in. Nothing here makes a network call unless
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* PW_MCP_HISTORY_TOKEN is set; without it the server behaves exactly as
|
|
8
|
+
* before. PW_MCP_HISTORY_URL points at the team's history server. There is
|
|
9
|
+
* deliberately no built-in default URL: the token only ever goes where the
|
|
10
|
+
* user pointed it. PW_MCP_PRO_KEY / PW_MCP_PRO_URL / PW_MCP_PRO_PROJECT,
|
|
11
|
+
* the names from 0.7 and 0.8, still work.
|
|
9
12
|
*/
|
|
10
13
|
import { execFile } from 'node:child_process';
|
|
11
14
|
import path from 'node:path';
|
|
@@ -13,15 +16,19 @@ import { PlaywrightMcpError } from '../types/index.js';
|
|
|
13
16
|
import { parseHistory } from './run-history.js';
|
|
14
17
|
const PROJECT_RE = /^[A-Za-z0-9][\w./-]{0,99}$/;
|
|
15
18
|
const UPLOAD_BATCH = 100;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
const pick = (env, name, legacy) => {
|
|
20
|
+
const value = env[name]?.trim() || env[legacy]?.trim();
|
|
21
|
+
return value || undefined;
|
|
22
|
+
};
|
|
23
|
+
/** The shared history settings, or undefined when none are set (the normal case). */
|
|
24
|
+
export function historySettings(env = process.env) {
|
|
25
|
+
const key = pick(env, 'PW_MCP_HISTORY_TOKEN', 'PW_MCP_PRO_KEY');
|
|
19
26
|
if (!key)
|
|
20
27
|
return undefined;
|
|
21
|
-
const url = (env
|
|
28
|
+
const url = (pick(env, 'PW_MCP_HISTORY_URL', 'PW_MCP_PRO_URL') ?? '').replace(/\/+$/, '');
|
|
22
29
|
if (!url) {
|
|
23
|
-
throw new PlaywrightMcpError('
|
|
24
|
-
hint:
|
|
30
|
+
throw new PlaywrightMcpError('PW_MCP_HISTORY_TOKEN is set but PW_MCP_HISTORY_URL is not', 'INVALID_INPUT', {
|
|
31
|
+
hint: "Set PW_MCP_HISTORY_URL to your team's history server, or unset PW_MCP_HISTORY_TOKEN.",
|
|
25
32
|
});
|
|
26
33
|
}
|
|
27
34
|
let parsed;
|
|
@@ -29,11 +36,11 @@ export function proSettings(env = process.env) {
|
|
|
29
36
|
parsed = new URL(url);
|
|
30
37
|
}
|
|
31
38
|
catch {
|
|
32
|
-
throw new PlaywrightMcpError(`
|
|
39
|
+
throw new PlaywrightMcpError(`PW_MCP_HISTORY_URL is not a URL: ${url}`, 'INVALID_INPUT');
|
|
33
40
|
}
|
|
34
41
|
const local = parsed.hostname === 'localhost' || parsed.hostname === '127.0.0.1';
|
|
35
42
|
if (parsed.protocol !== 'https:' && !(local && parsed.protocol === 'http:')) {
|
|
36
|
-
throw new PlaywrightMcpError('
|
|
43
|
+
throw new PlaywrightMcpError('PW_MCP_HISTORY_URL must use https', 'INVALID_INPUT', { hint: 'The token is sent with every request.' });
|
|
37
44
|
}
|
|
38
45
|
return { key, url };
|
|
39
46
|
}
|
|
@@ -43,12 +50,12 @@ function git(args, cwd) {
|
|
|
43
50
|
});
|
|
44
51
|
}
|
|
45
52
|
/**
|
|
46
|
-
* The project name runs are filed under:
|
|
53
|
+
* The project name runs are filed under: PW_MCP_HISTORY_PROJECT, else the
|
|
47
54
|
* GitHub repository (owner/name, from CI or the origin remote), else the
|
|
48
55
|
* folder name. The same rule on CI and laptops, so both see one history.
|
|
49
56
|
*/
|
|
50
|
-
export async function
|
|
51
|
-
const candidates = [env.PW_MCP_PRO_PROJECT, env.GITHUB_REPOSITORY];
|
|
57
|
+
export async function historyProjectName(root, env = process.env) {
|
|
58
|
+
const candidates = [env.PW_MCP_HISTORY_PROJECT, env.PW_MCP_PRO_PROJECT, env.GITHUB_REPOSITORY];
|
|
52
59
|
const remote = await git(['remote', 'get-url', 'origin'], root);
|
|
53
60
|
const match = remote ? /[:/]([^/:]+\/[^/]+?)(?:\.git)?$/.exec(remote) : null;
|
|
54
61
|
candidates.push(match?.[1], path.basename(root));
|
|
@@ -70,13 +77,13 @@ async function call(settings, method, pathAndQuery, body) {
|
|
|
70
77
|
});
|
|
71
78
|
}
|
|
72
79
|
catch (error) {
|
|
73
|
-
throw new PlaywrightMcpError(`
|
|
74
|
-
hint: 'Check the network and
|
|
80
|
+
throw new PlaywrightMcpError(`The history server is unreachable (${settings.url}): ${error.message}`, 'UNKNOWN', {
|
|
81
|
+
hint: 'Check the network and PW_MCP_HISTORY_URL; local history still works.',
|
|
75
82
|
});
|
|
76
83
|
}
|
|
77
84
|
const data = (await response.json().catch(() => ({})));
|
|
78
85
|
if (!response.ok) {
|
|
79
|
-
throw new PlaywrightMcpError(`
|
|
86
|
+
throw new PlaywrightMcpError(`History server: ${data.error ?? `HTTP ${response.status}`}`, response.status === 401 ? 'INVALID_INPUT' : 'UNKNOWN', {
|
|
80
87
|
hint: data.hint,
|
|
81
88
|
});
|
|
82
89
|
}
|
|
@@ -111,4 +118,4 @@ export function mergeRuns(local, cloud, last) {
|
|
|
111
118
|
}
|
|
112
119
|
return out.sort((a, b) => a.at.localeCompare(b.at)).slice(-last);
|
|
113
120
|
}
|
|
114
|
-
//# sourceMappingURL=
|
|
121
|
+
//# sourceMappingURL=history-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history-client.js","sourceRoot":"","sources":["../../src/utils/history-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -38,7 +38,7 @@ jobs:
|
|
|
38
38
|
|
|
39
39
|
- name: Run Playwright E2E diagnosis action
|
|
40
40
|
id: e2e
|
|
41
|
-
uses: xsignon-secure/E2E@v0.
|
|
41
|
+
uses: xsignon-secure/E2E@v0.10.0
|
|
42
42
|
with:
|
|
43
43
|
# Directory containing playwright.config.* (default is workspace root)
|
|
44
44
|
project-root: .
|
|
@@ -64,9 +64,10 @@ jobs:
|
|
|
64
64
|
# Heal guard: block test changes that pass by checking less (deleted assertions, skipped tests, .only)
|
|
65
65
|
# guard: true
|
|
66
66
|
|
|
67
|
-
#
|
|
68
|
-
#
|
|
69
|
-
#
|
|
67
|
+
# Shared team history (optional, free): upload runs to your self-hosted history server
|
|
68
|
+
# (history-server/ in xsignon-secure/E2E)
|
|
69
|
+
# history-token: ${{ secrets.PW_MCP_HISTORY_TOKEN }}
|
|
70
|
+
# history-url: https://history.example.com
|
|
70
71
|
|
|
71
72
|
# Fail step when tests fail (default: true)
|
|
72
73
|
fail-on-failure: true
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "playwright-e2e-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "MCP server and agent skill that run, diagnose and fix failing Playwright tests (TypeScript and pytest): CI report diagnosis, trace analysis, verified locator fixes, flaky verdicts, breaking commits, heal guard, accessibility and Web Vitals audits.",
|
|
5
5
|
"author": "xsignon-secure (https://github.com/xsignon-secure)",
|
|
6
6
|
"mcpName": "io.github.xsignon-secure/E2E",
|
|
@@ -13,7 +13,7 @@ and concrete next steps. It can also propose and apply a verified fix for a brok
|
|
|
13
13
|
locator, inspect pages behind a login, run long suites in the background and keep
|
|
14
14
|
a local history of every run.
|
|
15
15
|
|
|
16
|
-
This skill is written for playwright-e2e-mcp 0.
|
|
16
|
+
This skill is written for playwright-e2e-mcp 0.10.0 and works with 0.2.0 or
|
|
17
17
|
newer. If `suggest-fix`, `get-run-status` or `analyze-history` is missing, the
|
|
18
18
|
server is older than 0.2.0: use the steps that do not need those tools and tell
|
|
19
19
|
the user to update it. `diagnose-flaky`'s per-test table and `isolate` option
|
|
@@ -25,7 +25,12 @@ history views and strict-mode fixes in `suggest-fix` arrived in 0.5.0;
|
|
|
25
25
|
`save-login`, `check-test-change` and `quarantine` arrived in 0.7.0; the
|
|
26
26
|
`switchTab` page step, `blockWrites`, recovery of crashed runs and
|
|
27
27
|
pytest-playwright projects (`run-test`, `get-failure`, `list-tests`) arrived in
|
|
28
|
-
0.8.0
|
|
28
|
+
0.8.0; the free self-hosted history server (`PW_MCP_HISTORY_URL` /
|
|
29
|
+
`PW_MCP_HISTORY_TOKEN`, replacing the old Pro settings, which still work) arrived
|
|
30
|
+
in 0.9.0; asking before changing files, the interactive test report (MCP Apps)
|
|
31
|
+
and sign-in with Client ID Metadata Documents arrived in 0.10.0. If a tool that
|
|
32
|
+
writes returns `declined: true`, the user said no: do not retry the write, show
|
|
33
|
+
them the proposed change instead. If `doctor` says a newer version is out, pass its upgrade command on to
|
|
29
34
|
the user.
|
|
30
35
|
|
|
31
36
|
## Before you start
|
|
@@ -281,7 +286,7 @@ with the commit it tested. `analyze-history` views:
|
|
|
281
286
|
`selector` for one region) returns the accessibility snapshot and a
|
|
282
287
|
`toMatchAriaSnapshot` assertion to paste into a spec.
|
|
283
288
|
- **Set up CI:** when the user wants the same diagnosis on every pull request,
|
|
284
|
-
point them to the GitHub Action (`uses: xsignon-secure/E2E@v0.
|
|
289
|
+
point them to the GitHub Action (`uses: xsignon-secure/E2E@v0.10.0`) or the
|
|
285
290
|
`npx -y playwright-e2e-mcp ci` command in `references/setup.md`. It writes the
|
|
286
291
|
run, flaky verdicts and fix diffs to the job summary and one PR comment.
|
|
287
292
|
- **Accessibility:** `audit-accessibility` with `url` runs axe-core against
|
|
@@ -83,7 +83,7 @@ Set these in the server's `env` block. None of them are secrets except
|
|
|
83
83
|
| `PW_MCP_STORAGE_STATE` | none | Default Playwright storageState JSON (inside the project) for the page tools, so signed-in pages open logged in |
|
|
84
84
|
| `PW_MCP_SHUFFLE_SEEDS` | random | Seeds for `diagnose-flaky`'s `order` pass (comma separated), to replay reported orders |
|
|
85
85
|
| `PW_MCP_LOGIN_ENV` | — | Extra variables `save-login` may type through `{{env:NAME}}`, comma separated (default: only `E2E_*`, `TEST_*`, `PW_*`, `PLAYWRIGHT_*`, `LOGIN_*`) |
|
|
86
|
-
| `
|
|
86
|
+
| `PW_MCP_HISTORY_URL` / `PW_MCP_HISTORY_TOKEN` | — | Optional, free: the team's self-hosted history server (`history-server/` in the repo). CI runs uploaded with `upload` show up in `analyze-history` (`source: both`). Unset = no network calls. Old names `PW_MCP_PRO_KEY` / `PW_MCP_PRO_URL` still work |
|
|
87
87
|
| `PW_MCP_BLOCK_WRITES` | off | `1` makes the page tools abort POST, PUT, PATCH and DELETE requests that no mock or HAR answers (0.8.0+) |
|
|
88
88
|
| `PW_MCP_PYTHON` | project venv, then `python3` | The Python used for pytest-playwright projects (0.8.0+) |
|
|
89
89
|
| `PW_MCP_PROTOCOL` | both | `legacy` stops offering the 2026-07-28 MCP revision (0.8.0+) |
|
|
@@ -119,7 +119,7 @@ Exit code 0 means passed, 1 tests failed, 2 the run itself failed. On GitHub
|
|
|
119
119
|
Actions it also writes to the job summary. As an Action:
|
|
120
120
|
|
|
121
121
|
```yaml
|
|
122
|
-
- uses: xsignon-secure/E2E@v0.
|
|
122
|
+
- uses: xsignon-secure/E2E@v0.10.0
|
|
123
123
|
with:
|
|
124
124
|
flaky-runs: 3
|
|
125
125
|
suggest: 2
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pro Cloud client: shared CI run history for teams that subscribe to Pro.
|
|
3
|
-
*
|
|
4
|
-
* Strictly opt-in. Nothing here makes a network call unless
|
|
5
|
-
* PW_MCP_PRO_KEY is set; without it the server behaves exactly as before.
|
|
6
|
-
* The key is the license key from the Pro subscription; PW_MCP_PRO_URL
|
|
7
|
-
* points at the Pro Cloud deployment. There is deliberately no built-in
|
|
8
|
-
* default URL: the key only ever goes where the user pointed it.
|
|
9
|
-
*/
|
|
10
|
-
import type { HistoryEntry } from './run-history.js';
|
|
11
|
-
export interface ProSettings {
|
|
12
|
-
key: string;
|
|
13
|
-
url: string;
|
|
14
|
-
}
|
|
15
|
-
/** The Pro settings, or undefined when Pro is not configured (the normal case). */
|
|
16
|
-
export declare function proSettings(env?: NodeJS.ProcessEnv): ProSettings | undefined;
|
|
17
|
-
/**
|
|
18
|
-
* The project name runs are filed under: PW_MCP_PRO_PROJECT, else the
|
|
19
|
-
* GitHub repository (owner/name, from CI or the origin remote), else the
|
|
20
|
-
* folder name. The same rule on CI and laptops, so both see one history.
|
|
21
|
-
*/
|
|
22
|
-
export declare function proProjectName(root: string, env?: NodeJS.ProcessEnv): Promise<string>;
|
|
23
|
-
export declare function uploadRuns(settings: ProSettings, project: string, runs: HistoryEntry[]): Promise<{
|
|
24
|
-
stored: number;
|
|
25
|
-
skipped: number;
|
|
26
|
-
}>;
|
|
27
|
-
export declare function fetchRuns(settings: ProSettings, project: string, limit: number): Promise<HistoryEntry[]>;
|
|
28
|
-
/** Local and cloud runs together, oldest first, without duplicates. */
|
|
29
|
-
export declare function mergeRuns(local: HistoryEntry[], cloud: HistoryEntry[], last: number): HistoryEntry[];
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pro-client.js","sourceRoot":"","sources":["../../src/utils/pro-client.ts"],"names":[],"mappings":"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"}
|