chore: roll playwright 5/9 (#394)

This commit is contained in:
Pavel Feldman 2025-05-09 18:01:17 -07:00 committed by GitHub
parent c28b480b51
commit 445170a76b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 88 additions and 149 deletions

39
package-lock.json generated
View File

@ -11,8 +11,7 @@
"dependencies": { "dependencies": {
"@modelcontextprotocol/sdk": "^1.11.0", "@modelcontextprotocol/sdk": "^1.11.0",
"commander": "^13.1.0", "commander": "^13.1.0",
"playwright": "1.53.0-alpha-1746218818000", "playwright": "1.53.0-alpha-1746832516000",
"yaml": "^2.7.1",
"zod-to-json-schema": "^3.24.4" "zod-to-json-schema": "^3.24.4"
}, },
"bin": { "bin": {
@ -21,7 +20,7 @@
"devDependencies": { "devDependencies": {
"@eslint/eslintrc": "^3.2.0", "@eslint/eslintrc": "^3.2.0",
"@eslint/js": "^9.19.0", "@eslint/js": "^9.19.0",
"@playwright/test": "1.53.0-alpha-1746218818000", "@playwright/test": "1.53.0-alpha-1746832516000",
"@stylistic/eslint-plugin": "^3.0.1", "@stylistic/eslint-plugin": "^3.0.1",
"@types/node": "^22.13.10", "@types/node": "^22.13.10",
"@typescript-eslint/eslint-plugin": "^8.26.1", "@typescript-eslint/eslint-plugin": "^8.26.1",
@ -287,13 +286,13 @@
} }
}, },
"node_modules/@playwright/test": { "node_modules/@playwright/test": {
"version": "1.53.0-alpha-1746218818000", "version": "1.53.0-alpha-1746832516000",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.53.0-alpha-1746218818000.tgz", "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.53.0-alpha-1746832516000.tgz",
"integrity": "sha512-J05FD0oOCVbjbp4IjQi5tOPKywchi5EENS9jRjgkA5N9jd/+BaZ3jT8HlLMIgALdk/eLsprQa7vh9h45Q1FOPA==", "integrity": "sha512-Sec+6uzpA4MfwmQqJFBFVazffynqVwLO5swDxG7WoqgpUdn9gQX4K4tDG64SV6f4nOpwdM5LKTasPSXu02nn/Q==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"playwright": "1.53.0-alpha-1746218818000" "playwright": "1.53.0-alpha-1746832516000"
}, },
"bin": { "bin": {
"playwright": "cli.js" "playwright": "cli.js"
@ -3299,12 +3298,12 @@
} }
}, },
"node_modules/playwright": { "node_modules/playwright": {
"version": "1.53.0-alpha-1746218818000", "version": "1.53.0-alpha-1746832516000",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.53.0-alpha-1746218818000.tgz", "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.53.0-alpha-1746832516000.tgz",
"integrity": "sha512-mVIjtdqIawIqWVyvCaLmV6XTALCT4oWWrbMjoHyyWRln3jQjnm3RUO9LkaINz+Yh88O3FkuY6RfjGXPXeFeJ4Q==", "integrity": "sha512-kcC1B2XJr4VaDAcVzi61SbYGkodq1QIqQXuPieXsNgZZ7cEKWzO2sI42yp2yie6wlCx0oLkSS2Q6jWSRVRLeaw==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"playwright-core": "1.53.0-alpha-1746218818000" "playwright-core": "1.53.0-alpha-1746832516000"
}, },
"bin": { "bin": {
"playwright": "cli.js" "playwright": "cli.js"
@ -3317,9 +3316,9 @@
} }
}, },
"node_modules/playwright-core": { "node_modules/playwright-core": {
"version": "1.53.0-alpha-1746218818000", "version": "1.53.0-alpha-1746832516000",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.53.0-alpha-1746218818000.tgz", "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.53.0-alpha-1746832516000.tgz",
"integrity": "sha512-iaIZmhO/psGssWpxIprJkFrn2h4xFjgL0jZsKGtReAMZ/XhlqMUJxtSitwWM4BV+wxJIptsZD0s5Ml2KU62Z3w==", "integrity": "sha512-4O98y4zV0rOP6CepMLC/VGuzqGaR1sS9AVh+i0CghWMQHM/8bxPJI8W38QndO0JU0V5nBD6j7DQeNt1mJ+CZ+g==",
"license": "Apache-2.0", "license": "Apache-2.0",
"bin": { "bin": {
"playwright-core": "cli.js" "playwright-core": "cli.js"
@ -4350,18 +4349,6 @@
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"license": "ISC" "license": "ISC"
}, },
"node_modules/yaml": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz",
"integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==",
"license": "ISC",
"bin": {
"yaml": "bin.mjs"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/yocto-queue": { "node_modules/yocto-queue": {
"version": "0.1.0", "version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",

View File

@ -37,14 +37,13 @@
"dependencies": { "dependencies": {
"@modelcontextprotocol/sdk": "^1.11.0", "@modelcontextprotocol/sdk": "^1.11.0",
"commander": "^13.1.0", "commander": "^13.1.0",
"playwright": "1.53.0-alpha-1746218818000", "playwright": "1.53.0-alpha-1746832516000",
"yaml": "^2.7.1",
"zod-to-json-schema": "^3.24.4" "zod-to-json-schema": "^3.24.4"
}, },
"devDependencies": { "devDependencies": {
"@eslint/eslintrc": "^3.2.0", "@eslint/eslintrc": "^3.2.0",
"@eslint/js": "^9.19.0", "@eslint/js": "^9.19.0",
"@playwright/test": "1.53.0-alpha-1746218818000", "@playwright/test": "1.53.0-alpha-1746832516000",
"@stylistic/eslint-plugin": "^3.0.1", "@stylistic/eslint-plugin": "^3.0.1",
"@types/node": "^22.13.10", "@types/node": "^22.13.10",
"@typescript-eslint/eslint-plugin": "^8.26.1", "@typescript-eslint/eslint-plugin": "^8.26.1",

View File

@ -99,7 +99,7 @@ export async function configFromCLIOptions(cliOptions: CLIOptions): Promise<Conf
}; };
if (browserName === 'chromium') if (browserName === 'chromium')
(launchOptions as any).webSocketPort = await findFreePort(); (launchOptions as any).cdpPort = await findFreePort();
const contextOptions: BrowserContextOptions | undefined = cliOptions.device ? devices[cliOptions.device] : undefined; const contextOptions: BrowserContextOptions | undefined = cliOptions.device ? devices[cliOptions.device] : undefined;

View File

@ -15,20 +15,18 @@
*/ */
import * as playwright from 'playwright'; import * as playwright from 'playwright';
import yaml from 'yaml';
type PageOrFrameLocator = playwright.Page | playwright.FrameLocator;
export class PageSnapshot { export class PageSnapshot {
private _frameLocators: PageOrFrameLocator[] = []; private _page: playwright.Page;
private _text!: string; private _text!: string;
constructor() { constructor(page: playwright.Page) {
this._page = page;
} }
static async create(page: playwright.Page): Promise<PageSnapshot> { static async create(page: playwright.Page): Promise<PageSnapshot> {
const snapshot = new PageSnapshot(); const snapshot = new PageSnapshot(page);
await snapshot._build(page); await snapshot._build();
return snapshot; return snapshot;
} }
@ -36,8 +34,8 @@ export class PageSnapshot {
return this._text; return this._text;
} }
private async _build(page: playwright.Page) { private async _build() {
const yamlDocument = await this._snapshotFrame(page); const yamlDocument = await (this._page as any)._snapshotForAI();
this._text = [ this._text = [
`- Page Snapshot`, `- Page Snapshot`,
'```yaml', '```yaml',
@ -46,56 +44,7 @@ export class PageSnapshot {
].join('\n'); ].join('\n');
} }
private async _snapshotFrame(frame: playwright.Page | playwright.FrameLocator) {
const frameIndex = this._frameLocators.push(frame) - 1;
const snapshotString = await frame.locator('body').ariaSnapshot({ ref: true, emitGeneric: true });
const snapshot = yaml.parseDocument(snapshotString);
const visit = async (node: any): Promise<unknown> => {
if (yaml.isPair(node)) {
await Promise.all([
visit(node.key).then(k => node.key = k),
visit(node.value).then(v => node.value = v)
]);
} else if (yaml.isSeq(node) || yaml.isMap(node)) {
node.items = await Promise.all(node.items.map(visit));
} else if (yaml.isScalar(node)) {
if (typeof node.value === 'string') {
const value = node.value;
if (frameIndex > 0)
node.value = value.replace('[ref=', `[ref=f${frameIndex}`);
if (value.startsWith('iframe ')) {
const ref = value.match(/\[ref=(.*)\]/)?.[1];
if (ref) {
try {
const childSnapshot = await this._snapshotFrame(frame.frameLocator(`aria-ref=${ref}`));
return snapshot.createPair(node.value, childSnapshot);
} catch (error) {
return snapshot.createPair(node.value, '<could not take iframe snapshot>');
}
}
}
}
}
return node;
};
await visit(snapshot.contents);
return snapshot;
}
refLocator(ref: string): playwright.Locator { refLocator(ref: string): playwright.Locator {
let frame = this._frameLocators[0]; return this._page.locator(`aria-ref=${ref}`);
const match = ref.match(/^f(\d+)(.*)/);
if (match) {
const frameIndex = parseInt(match[1], 10);
frame = this._frameLocators[frameIndex];
ref = match[2];
}
if (!frame)
throw new Error(`Frame does not exist. Provide ref from the most current snapshot.`);
return frame.locator(`aria-ref=${ref}`);
} }
} }

View File

@ -21,7 +21,7 @@ test('cdp server', async ({ cdpEndpoint, startClient, server }) => {
expect(await client.callTool({ expect(await client.callTool({
name: 'browser_navigate', name: 'browser_navigate',
arguments: { url: server.HELLO_WORLD }, arguments: { url: server.HELLO_WORLD },
})).toContainTextContent(`- generic [ref=s1e2]: Hello, world!`); })).toContainTextContent(`- generic [ref=e1]: Hello, world!`);
}); });
test('cdp server reuse tab', async ({ cdpEndpoint, startClient }) => { test('cdp server reuse tab', async ({ cdpEndpoint, startClient }) => {
@ -48,7 +48,7 @@ test('cdp server reuse tab', async ({ cdpEndpoint, startClient }) => {
- Page Title: - Page Title:
- Page Snapshot - Page Snapshot
\`\`\`yaml \`\`\`yaml
- generic [ref=s1e2]: hello world - generic [ref=e1]: hello world
\`\`\` \`\`\`
`); `);
}); });
@ -70,5 +70,5 @@ test('should throw connection error and allow re-connecting', async ({ cdpEndpoi
expect(await client.callTool({ expect(await client.callTool({
name: 'browser_navigate', name: 'browser_navigate',
arguments: { url: server.PREFIX }, arguments: { url: server.PREFIX },
})).toContainTextContent(`- generic [ref=s1e2]: Hello, world!`); })).toContainTextContent(`- generic [ref=e1]: Hello, world!`);
}); });

View File

@ -31,7 +31,7 @@ await page.goto('${server.HELLO_WORLD}');
- Page Title: Title - Page Title: Title
- Page Snapshot - Page Snapshot
\`\`\`yaml \`\`\`yaml
- generic [ref=s1e2]: Hello, world! - generic [ref=e1]: Hello, world!
\`\`\` \`\`\`
` `
); );
@ -52,7 +52,7 @@ test('browser_click', async ({ client, server }) => {
name: 'browser_click', name: 'browser_click',
arguments: { arguments: {
element: 'Submit button', element: 'Submit button',
ref: 's1e3', ref: 'e2',
}, },
})).toHaveTextContent(` })).toHaveTextContent(`
- Ran Playwright code: - Ran Playwright code:
@ -65,7 +65,7 @@ await page.getByRole('button', { name: 'Submit' }).click();
- Page Title: Title - Page Title: Title
- Page Snapshot - Page Snapshot
\`\`\`yaml \`\`\`yaml
- button "Submit" [ref=s2e3] - button "Submit" [ref=e2]
\`\`\` \`\`\`
`); `);
}); });
@ -88,7 +88,7 @@ test('browser_select_option', async ({ client, server }) => {
name: 'browser_select_option', name: 'browser_select_option',
arguments: { arguments: {
element: 'Select', element: 'Select',
ref: 's1e3', ref: 'e2',
values: ['bar'], values: ['bar'],
}, },
})).toHaveTextContent(` })).toHaveTextContent(`
@ -102,7 +102,7 @@ await page.getByRole('combobox').selectOption(['bar']);
- Page Title: Title - Page Title: Title
- Page Snapshot - Page Snapshot
\`\`\`yaml \`\`\`yaml
- combobox [ref=s2e3]: - combobox [ref=e2]:
- option "Foo" - option "Foo"
- option "Bar" [selected] - option "Bar" [selected]
\`\`\` \`\`\`
@ -128,7 +128,7 @@ test('browser_select_option (multiple)', async ({ client, server }) => {
name: 'browser_select_option', name: 'browser_select_option',
arguments: { arguments: {
element: 'Select', element: 'Select',
ref: 's1e3', ref: 'e2',
values: ['bar', 'baz'], values: ['bar', 'baz'],
}, },
})).toHaveTextContent(` })).toHaveTextContent(`
@ -142,10 +142,10 @@ await page.getByRole('listbox').selectOption(['bar', 'baz']);
- Page Title: Title - Page Title: Title
- Page Snapshot - Page Snapshot
\`\`\`yaml \`\`\`yaml
- listbox [ref=s2e3]: - listbox [ref=e2]:
- option "Foo" [ref=s2e4] - option "Foo" [ref=e3]
- option "Bar" [selected] [ref=s2e5] - option "Bar" [selected] [ref=e4]
- option "Baz" [selected] [ref=s2e6] - option "Baz" [selected] [ref=e5]
\`\`\` \`\`\`
`); `);
}); });
@ -168,7 +168,7 @@ test('browser_type', async ({ client, server }) => {
name: 'browser_type', name: 'browser_type',
arguments: { arguments: {
element: 'textbox', element: 'textbox',
ref: 's1e3', ref: 'e2',
text: 'Hi!', text: 'Hi!',
submit: true, submit: true,
}, },
@ -194,7 +194,7 @@ test('browser_type (slowly)', async ({ client, server }) => {
name: 'browser_type', name: 'browser_type',
arguments: { arguments: {
element: 'textbox', element: 'textbox',
ref: 's1e3', ref: 'e2',
text: 'Hi!', text: 'Hi!',
submit: true, submit: true,
slowly: true, slowly: true,

View File

@ -24,13 +24,13 @@ test('alert dialog', async ({ client, server }) => {
expect(await client.callTool({ expect(await client.callTool({
name: 'browser_navigate', name: 'browser_navigate',
arguments: { url: server.PREFIX }, arguments: { url: server.PREFIX },
})).toContainTextContent('- button "Button" [ref=s1e3]'); })).toContainTextContent('- button "Button" [ref=e2]');
expect(await client.callTool({ expect(await client.callTool({
name: 'browser_click', name: 'browser_click',
arguments: { arguments: {
element: 'Button', element: 'Button',
ref: 's1e3', ref: 'e2',
}, },
})).toHaveTextContent(`- Ran Playwright code: })).toHaveTextContent(`- Ran Playwright code:
\`\`\`js \`\`\`js
@ -58,7 +58,7 @@ await page.getByRole('button', { name: 'Button' }).click();
- Page Title: - Page Title:
- Page Snapshot - Page Snapshot
\`\`\`yaml \`\`\`yaml
- button "Button" [ref=s2e3] - button "Button" [ref=e2]
\`\`\` \`\`\`
`); `);
}); });
@ -76,13 +76,13 @@ test('two alert dialogs', async ({ client, server }) => {
expect(await client.callTool({ expect(await client.callTool({
name: 'browser_navigate', name: 'browser_navigate',
arguments: { url: server.PREFIX }, arguments: { url: server.PREFIX },
})).toContainTextContent('- button "Button" [ref=s1e3]'); })).toContainTextContent('- button "Button" [ref=e2]');
expect(await client.callTool({ expect(await client.callTool({
name: 'browser_click', name: 'browser_click',
arguments: { arguments: {
element: 'Button', element: 'Button',
ref: 's1e3', ref: 'e2',
}, },
})).toHaveTextContent(`- Ran Playwright code: })).toHaveTextContent(`- Ran Playwright code:
\`\`\`js \`\`\`js
@ -114,13 +114,13 @@ test('confirm dialog (true)', async ({ client, server }) => {
expect(await client.callTool({ expect(await client.callTool({
name: 'browser_navigate', name: 'browser_navigate',
arguments: { url: server.PREFIX }, arguments: { url: server.PREFIX },
})).toContainTextContent('- button "Button" [ref=s1e3]'); })).toContainTextContent('- button "Button" [ref=e2]');
expect(await client.callTool({ expect(await client.callTool({
name: 'browser_click', name: 'browser_click',
arguments: { arguments: {
element: 'Button', element: 'Button',
ref: 's1e3', ref: 'e2',
}, },
})).toContainTextContent(`### Modal state })).toContainTextContent(`### Modal state
- ["confirm" dialog with message "Confirm"]: can be handled by the "browser_handle_dialog" tool`); - ["confirm" dialog with message "Confirm"]: can be handled by the "browser_handle_dialog" tool`);
@ -136,7 +136,7 @@ test('confirm dialog (true)', async ({ client, server }) => {
expect(result).toContainTextContent('// <internal code to handle "confirm" dialog>'); expect(result).toContainTextContent('// <internal code to handle "confirm" dialog>');
expect(result).toContainTextContent(`- Page Snapshot expect(result).toContainTextContent(`- Page Snapshot
\`\`\`yaml \`\`\`yaml
- generic [ref=s2e2]: "true" - generic [ref=e1]: "true"
\`\`\``); \`\`\``);
}); });
@ -151,13 +151,13 @@ test('confirm dialog (false)', async ({ client, server }) => {
expect(await client.callTool({ expect(await client.callTool({
name: 'browser_navigate', name: 'browser_navigate',
arguments: { url: server.PREFIX }, arguments: { url: server.PREFIX },
})).toContainTextContent('- button "Button" [ref=s1e3]'); })).toContainTextContent('- button "Button" [ref=e2]');
expect(await client.callTool({ expect(await client.callTool({
name: 'browser_click', name: 'browser_click',
arguments: { arguments: {
element: 'Button', element: 'Button',
ref: 's1e3', ref: 'e2',
}, },
})).toContainTextContent(`### Modal state })).toContainTextContent(`### Modal state
- ["confirm" dialog with message "Confirm"]: can be handled by the "browser_handle_dialog" tool`); - ["confirm" dialog with message "Confirm"]: can be handled by the "browser_handle_dialog" tool`);
@ -171,7 +171,7 @@ test('confirm dialog (false)', async ({ client, server }) => {
expect(result).toContainTextContent(`- Page Snapshot expect(result).toContainTextContent(`- Page Snapshot
\`\`\`yaml \`\`\`yaml
- generic [ref=s2e2]: "false" - generic [ref=e1]: "false"
\`\`\``); \`\`\``);
}); });
@ -186,13 +186,13 @@ test('prompt dialog', async ({ client, server }) => {
expect(await client.callTool({ expect(await client.callTool({
name: 'browser_navigate', name: 'browser_navigate',
arguments: { url: server.PREFIX }, arguments: { url: server.PREFIX },
})).toContainTextContent('- button "Button" [ref=s1e3]'); })).toContainTextContent('- button "Button" [ref=e2]');
expect(await client.callTool({ expect(await client.callTool({
name: 'browser_click', name: 'browser_click',
arguments: { arguments: {
element: 'Button', element: 'Button',
ref: 's1e3', ref: 'e2',
}, },
})).toContainTextContent(`### Modal state })).toContainTextContent(`### Modal state
- ["prompt" dialog with message "Prompt"]: can be handled by the "browser_handle_dialog" tool`); - ["prompt" dialog with message "Prompt"]: can be handled by the "browser_handle_dialog" tool`);
@ -207,6 +207,6 @@ test('prompt dialog', async ({ client, server }) => {
expect(result).toContainTextContent(`- Page Snapshot expect(result).toContainTextContent(`- Page Snapshot
\`\`\`yaml \`\`\`yaml
- generic [ref=s2e2]: Answer - generic [ref=e1]: Answer
\`\`\``); \`\`\``);
}); });

View File

@ -29,8 +29,9 @@ test('browser_file_upload', async ({ client, localOutputPath, server }) => {
arguments: { url: server.PREFIX }, arguments: { url: server.PREFIX },
})).toContainTextContent(` })).toContainTextContent(`
\`\`\`yaml \`\`\`yaml
- button "Choose File" [ref=s1e3] - generic [ref=e1]:
- button "Button" [ref=s1e4] - button "Choose File" [ref=e2]
- button "Button" [ref=e3]
\`\`\``); \`\`\``);
{ {
@ -48,7 +49,7 @@ The tool "browser_file_upload" can only be used when there is related modal stat
name: 'browser_click', name: 'browser_click',
arguments: { arguments: {
element: 'Textbox', element: 'Textbox',
ref: 's1e3', ref: 'e2',
}, },
})).toContainTextContent(`### Modal state })).toContainTextContent(`### Modal state
- [File chooser]: can be handled by the "browser_file_upload" tool`); - [File chooser]: can be handled by the "browser_file_upload" tool`);
@ -67,8 +68,9 @@ The tool "browser_file_upload" can only be used when there is related modal stat
expect(response).not.toContainTextContent('### Modal state'); expect(response).not.toContainTextContent('### Modal state');
expect(response).toContainTextContent(` expect(response).toContainTextContent(`
\`\`\`yaml \`\`\`yaml
- button "Choose File" [ref=s3e3] - generic [ref=e1]:
- button "Button" [ref=s3e4] - button "Choose File" [ref=e2]
- button "Button" [ref=e3]
\`\`\``); \`\`\``);
} }
@ -77,7 +79,7 @@ The tool "browser_file_upload" can only be used when there is related modal stat
name: 'browser_click', name: 'browser_click',
arguments: { arguments: {
element: 'Textbox', element: 'Textbox',
ref: 's3e3', ref: 'e2',
}, },
}); });
@ -89,7 +91,7 @@ The tool "browser_file_upload" can only be used when there is related modal stat
name: 'browser_click', name: 'browser_click',
arguments: { arguments: {
element: 'Button', element: 'Button',
ref: 's4e4', ref: 'e3',
}, },
}); });
@ -111,12 +113,12 @@ test('clicking on download link emits download', async ({ startClient, localOutp
expect(await client.callTool({ expect(await client.callTool({
name: 'browser_navigate', name: 'browser_navigate',
arguments: { url: server.PREFIX }, arguments: { url: server.PREFIX },
})).toContainTextContent('- link "Download" [ref=s1e3]'); })).toContainTextContent('- link "Download" [ref=e2]');
await client.callTool({ await client.callTool({
name: 'browser_click', name: 'browser_click',
arguments: { arguments: {
element: 'Download link', element: 'Download link',
ref: 's1e3', ref: 'e2',
}, },
}); });
await expect.poll(() => client.callTool({ name: 'browser_snapshot', arguments: {} })).toContainTextContent(` await expect.poll(() => client.callTool({ name: 'browser_snapshot', arguments: {} })).toContainTextContent(`

View File

@ -24,19 +24,21 @@ test('stitched aria frames', async ({ client }) => {
}, },
})).toContainTextContent(` })).toContainTextContent(`
\`\`\`yaml \`\`\`yaml
- heading "Hello" [level=1] [ref=s1e3] - generic [ref=e1]:
- iframe [ref=s1e4]: - heading "Hello" [level=1] [ref=e2]
- button "World" [ref=f1s1e3] - iframe [ref=e3]:
- main [ref=f1s1e4]: - generic [ref=f1e1]:
- iframe [ref=f1s1e5]: - button "World" [ref=f1e2]
- paragraph [ref=f2s1e3]: Nested - main [ref=f1e3]:
- iframe [ref=f1e4]:
- paragraph [ref=f2e2]: Nested
\`\`\``); \`\`\``);
expect(await client.callTool({ expect(await client.callTool({
name: 'browser_click', name: 'browser_click',
arguments: { arguments: {
element: 'World', element: 'World',
ref: 'f1s1e3', ref: 'f1e2',
}, },
})).toContainTextContent(`// Click World`); })).toContainTextContent(`// Click World`);
}); });

View File

@ -30,7 +30,7 @@ test('test reopen browser', async ({ client, server }) => {
expect(await client.callTool({ expect(await client.callTool({
name: 'browser_navigate', name: 'browser_navigate',
arguments: { url: server.HELLO_WORLD }, arguments: { url: server.HELLO_WORLD },
})).toContainTextContent(`- generic [ref=s1e2]: Hello, world!`); })).toContainTextContent(`- generic [ref=e1]: Hello, world!`);
}); });
test('executable path', async ({ startClient, server }) => { test('executable path', async ({ startClient, server }) => {

View File

@ -34,7 +34,7 @@ test('browser_network_requests', async ({ client, server }) => {
name: 'browser_click', name: 'browser_click',
arguments: { arguments: {
element: 'Click me button', element: 'Click me button',
ref: 's1e3', ref: 'e2',
}, },
}); });

View File

@ -36,7 +36,7 @@ test('save as pdf', async ({ client, mcpBrowser, server }) => {
expect(await client.callTool({ expect(await client.callTool({
name: 'browser_navigate', name: 'browser_navigate',
arguments: { url: server.HELLO_WORLD }, arguments: { url: server.HELLO_WORLD },
})).toContainTextContent(`- generic [ref=s1e2]: Hello, world!`); })).toContainTextContent(`- generic [ref=e1]: Hello, world!`);
const response = await client.callTool({ const response = await client.callTool({
name: 'browser_pdf_save', name: 'browser_pdf_save',
@ -55,7 +55,7 @@ test('save as pdf (filename: output.pdf)', async ({ startClient, mcpBrowser, ser
expect(await client.callTool({ expect(await client.callTool({
name: 'browser_navigate', name: 'browser_navigate',
arguments: { url: server.HELLO_WORLD }, arguments: { url: server.HELLO_WORLD },
})).toContainTextContent(`- generic [ref=s1e2]: Hello, world!`); })).toContainTextContent(`- generic [ref=e1]: Hello, world!`);
expect(await client.callTool({ expect(await client.callTool({
name: 'browser_pdf_save', name: 'browser_pdf_save',

View File

@ -46,13 +46,13 @@ test('browser_take_screenshot (element)', async ({ client, server }) => {
expect(await client.callTool({ expect(await client.callTool({
name: 'browser_navigate', name: 'browser_navigate',
arguments: { url: server.HELLO_WORLD }, arguments: { url: server.HELLO_WORLD },
})).toContainTextContent(`[ref=s1e2]`); })).toContainTextContent(`[ref=e1]`);
expect(await client.callTool({ expect(await client.callTool({
name: 'browser_take_screenshot', name: 'browser_take_screenshot',
arguments: { arguments: {
element: 'hello button', element: 'hello button',
ref: 's1e2', ref: 'e1',
}, },
})).toEqual({ })).toEqual({
content: [ content: [

View File

@ -97,7 +97,7 @@ test('sse transport via public API', async ({ server }) => {
expect(await client.callTool({ expect(await client.callTool({
name: 'browser_navigate', name: 'browser_navigate',
arguments: { url: server.HELLO_WORLD }, arguments: { url: server.HELLO_WORLD },
})).toContainTextContent(`- generic [ref=s1e2]: Hello, world!`); })).toContainTextContent(`- generic [ref=e1]: Hello, world!`);
await client.close(); await client.close();
mcpServer.close(); mcpServer.close();
}); });

View File

@ -63,7 +63,7 @@ test('create new tab', async ({ client }) => {
- Page Title: Tab one - Page Title: Tab one
- Page Snapshot - Page Snapshot
\`\`\`yaml \`\`\`yaml
- generic [ref=s1e2]: Body one - generic [ref=e1]: Body one
\`\`\``); \`\`\``);
expect(await createTab(client, 'Tab two', 'Body two')).toHaveTextContent(` expect(await createTab(client, 'Tab two', 'Body two')).toHaveTextContent(`
@ -82,7 +82,7 @@ test('create new tab', async ({ client }) => {
- Page Title: Tab two - Page Title: Tab two
- Page Snapshot - Page Snapshot
\`\`\`yaml \`\`\`yaml
- generic [ref=s1e2]: Body two - generic [ref=e1]: Body two
\`\`\``); \`\`\``);
}); });
@ -110,7 +110,7 @@ test('select tab', async ({ client }) => {
- Page Title: Tab one - Page Title: Tab one
- Page Snapshot - Page Snapshot
\`\`\`yaml \`\`\`yaml
- generic [ref=s2e2]: Body one - generic [ref=e1]: Body one
\`\`\``); \`\`\``);
}); });
@ -137,7 +137,7 @@ test('close tab', async ({ client }) => {
- Page Title: Tab one - Page Title: Tab one
- Page Snapshot - Page Snapshot
\`\`\`yaml \`\`\`yaml
- generic [ref=s2e2]: Body one - generic [ref=e1]: Body one
\`\`\``); \`\`\``);
}); });

View File

@ -40,14 +40,14 @@ test('browser_wait_for(text)', async ({ client, server }) => {
name: 'browser_click', name: 'browser_click',
arguments: { arguments: {
element: 'Click me', element: 'Click me',
ref: 's1e3', ref: 'e2',
}, },
}); });
expect(await client.callTool({ expect(await client.callTool({
name: 'browser_wait_for', name: 'browser_wait_for',
arguments: { text: 'Text to appear' }, arguments: { text: 'Text to appear' },
})).toContainTextContent(`- generic [ref=s3e4]: Text to appear`); })).toContainTextContent(`- generic [ref=e3]: Text to appear`);
}); });
test('browser_wait_for(textGone)', async ({ client, server }) => { test('browser_wait_for(textGone)', async ({ client, server }) => {
@ -74,12 +74,12 @@ test('browser_wait_for(textGone)', async ({ client, server }) => {
name: 'browser_click', name: 'browser_click',
arguments: { arguments: {
element: 'Click me', element: 'Click me',
ref: 's1e3', ref: 'e2',
}, },
}); });
expect(await client.callTool({ expect(await client.callTool({
name: 'browser_wait_for', name: 'browser_wait_for',
arguments: { textGone: 'Text to disappear' }, arguments: { textGone: 'Text to disappear' },
})).toContainTextContent(`- generic [ref=s3e4]: Text to appear`); })).toContainTextContent(`- generic [ref=e3]: Text to appear`);
}); });