Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/extension/manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "Playwright Extension",
"version": "0.2.1",
"version": "0.3.0",
"description": "Connect your browser to AI agents through Playwright MCP server and CLI. Enables AI-driven web testing, debugging, and automation.",
"permissions": [
"debugger",
Expand Down
2 changes: 1 addition & 1 deletion packages/extension/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@playwright/extension",
"version": "0.2.1",
"version": "0.3.0",
"description": "Playwright Browser Extension",
"private": true,
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion packages/html-reporter/src/chip.css
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
background-color: var(--color-canvas-subtle);
padding: 0 8px;
border-bottom: none;
margin-top: 12px;
margin: 12px 0 0;
color: inherit;
font: inherit;
font-weight: 600;
Expand Down
7 changes: 5 additions & 2 deletions packages/html-reporter/src/chip.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,13 @@ test('body render prop is rendered', async ({ mount }) => {
await expect(component.getByText('Chip children')).toBeVisible();
});

test('chip without setExpanded is not a button', async ({ mount }) => {
test('chip without setExpanded is a heading', async ({ mount }) => {
const component = await mount<typeof NotExpandable>('chip/NotExpandable');
await expect(component.getByRole('button')).toHaveCount(0);
await expect(component.getByText('Body')).toBeVisible();
await expect(component).toMatchAriaSnapshot(`
- heading "Title" [level=2]
- region: Body
`);
});

test('expand collapse with the keyboard', async ({ mount, page }) => {
Expand Down
4 changes: 2 additions & 2 deletions packages/html-reporter/src/chip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ export const Chip: React.FC<{
onClick={() => setExpanded(!expanded)}
title={title}>
{headerContent}
</button> : <div className='chip-header' title={title}>
</button> : <h2 className='chip-header' title={title}>
{headerContent}
</div>}
</h2>}
{(!setExpanded || expanded) && <div id={id} role='region' className={clsx('chip-body', noInsets && 'chip-body-no-insets')}>
{children}
{body && body()}
Expand Down
2 changes: 1 addition & 1 deletion packages/playwright-core/src/tools/cli-client/output.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ export class TextOutput implements Output {
attach(session: string, pid: number | undefined, endpoint: string | undefined, toolResult: string): void {
if (endpoint) {
console.log(`### Session \`${session}\` created, attached to \`${endpoint}\`.`);
console.log(`Run commands with: playwright-cli --s=${session} <command>`);
console.log(`Run commands with: playwright-cli -s=${session} <command>`);
console.log('');
} else {
console.log(`### Browser \`${session}\` opened with pid ${pid}.`);
Expand Down
8 changes: 8 additions & 0 deletions packages/playwright-core/src/tools/mcp/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,17 @@ export type CLIOptions = {
viewportSize?: ViewportSize;
};

export const defaultCodegenLanguage: 'typescript' | 'python' | 'java' | 'csharp' =
process.env.PW_LANG_NAME === 'python' || process.env.PW_LANG_NAME === 'java' || process.env.PW_LANG_NAME === 'csharp'
? process.env.PW_LANG_NAME
: 'typescript';

const defaultConfig: MergedConfig = {
browser: {
launchOptions: {},
contextOptions: {},
},
codegen: defaultCodegenLanguage,
timeouts: {
action: 5000,
navigation: 60000,
Expand Down Expand Up @@ -406,6 +412,8 @@ export function configFromEnv(env?: NodeJS.ProcessEnv): Config & { configFile?:
options.cdpEndpoint = envToString(e.PLAYWRIGHT_MCP_CDP_ENDPOINT);
options.cdpHeader = headerParser(envToString(e.PLAYWRIGHT_MCP_CDP_HEADERS));
options.cdpTimeout = numberParser(e.PLAYWRIGHT_MCP_CDP_TIMEOUT);
if (e.PLAYWRIGHT_MCP_CODEGEN)
options.codegen = enumParser<'typescript' | 'python' | 'java' | 'csharp' | 'none'>('--codegen', ['none', 'typescript', 'python', 'java', 'csharp'], e.PLAYWRIGHT_MCP_CODEGEN);
options.config = envToString(e.PLAYWRIGHT_MCP_CONFIG);
if (e.PLAYWRIGHT_MCP_CONSOLE_LEVEL)
options.consoleLevel = enumParser<'error' | 'warning' | 'info' | 'debug'>('--console-level', ['error', 'warning', 'info', 'debug'], e.PLAYWRIGHT_MCP_CONSOLE_LEVEL);
Expand Down
4 changes: 2 additions & 2 deletions packages/playwright-core/src/tools/mcp/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import { Option as ProgramOption } from 'commander';
import * as mcpServer from '../utils/mcp/server';
import { commaSeparatedList, dotenvFileLoader, enumParser, headerParser, numberParser, resolutionParser, resolveCLIConfigForMCP, semicolonSeparatedList } from './config';
import { commaSeparatedList, defaultCodegenLanguage, dotenvFileLoader, enumParser, headerParser, numberParser, resolutionParser, resolveCLIConfigForMCP, semicolonSeparatedList } from './config';
import { setupExitWatchdog } from './watchdog';
import { createBrowserWithInfo } from './browserFactory';
import { BrowserBackend } from '../backend/browserBackend';
Expand All @@ -42,7 +42,7 @@ export function decorateMCPCommand(command: Command) {
.option('--cdp-endpoint <endpoint>', 'CDP endpoint to connect to.')
.option('--cdp-header <headers...>', 'CDP headers to send with the connect request, multiple can be specified.', headerParser)
.option('--cdp-timeout <timeout>', 'timeout in milliseconds for connecting to CDP endpoint, defaults to 30000ms', numberParser)
.option('--codegen <lang>', 'specify the language to use for code generation, possible values: "typescript", "python", "java", "csharp", "none". Default is "typescript".', enumParser.bind(null, '--codegen', ['none', 'typescript', 'python', 'java', 'csharp']))
.option('--codegen <lang>', `specify the language to use for code generation, possible values: "typescript", "python", "java", "csharp", "none". Default is "${defaultCodegenLanguage}".`, enumParser.bind(null, '--codegen', ['none', 'typescript', 'python', 'java', 'csharp']))
.option('--config <path>', 'path to the configuration file.')
.option('--console-level <level>', 'level of console messages to return: "error", "warning", "info", "debug". Each level includes the messages of more severe levels.', enumParser.bind(null, '--console-level', ['error', 'warning', 'info', 'debug']))
.option('--device <device>', 'device to emulate, for example: "iPhone 15"')
Expand Down
4 changes: 2 additions & 2 deletions tests/mcp/cli-session.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ workspace1:
await page.setContent('<title>My Page</title>');
const { output: openOutput } = await cli('attach', 'foobar');
expect(openOutput).toContain('### Session `foobar` created, attached to `foobar`.');
expect(openOutput).toContain('Run commands with: playwright-cli --s=foobar <command>');
expect(openOutput).toContain('Run commands with: playwright-cli -s=foobar <command>');
const { output: listOutput } = await cli('list', '--all');
expect(listOutput).toBe(`### Browsers
/:
Expand Down Expand Up @@ -326,7 +326,7 @@ workspace1:
await page.setContent('<title>Alias Page</title>');
const { output: openOutput } = await cli('attach', 'foobar', '--session=mybrowser');
expect(openOutput).toContain('### Session `mybrowser` created, attached to `foobar`.');
expect(openOutput).toContain('Run commands with: playwright-cli --s=mybrowser <command>');
expect(openOutput).toContain('Run commands with: playwright-cli -s=mybrowser <command>');
await cli('-s', 'mybrowser', 'close');
});

Expand Down
14 changes: 14 additions & 0 deletions tests/mcp/codegen.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,20 @@ async function navigateToForm(client: Client, server: any) {
});
}

test('codegen defaults to PW_LANG_NAME', async ({ startClient, server }) => {
const { client } = await startClient({ env: { PW_LANG_NAME: 'python' } });
expect(await navigateToForm(client, server)).toHaveResponse({
code: `page.goto("${server.PREFIX}")`,
});

expect(await client.callTool({
name: 'browser_click',
arguments: { element: 'Submit button', target: 'e2' },
})).toHaveResponse({
code: `page.get_by_role("button", name="Submit").click()`,
});
});

test('codegen python', async ({ startClient, server }) => {
const { client } = await startClient({ args: ['--codegen=python'] });
expect(await navigateToForm(client, server)).toHaveResponse({
Expand Down
4 changes: 2 additions & 2 deletions tests/playwright-test/reporter-html.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3431,7 +3431,7 @@ for (const useIntermediateMergeReport of [true, false] as const) {
await expect(page.getByRole('link', { name: 'Speedboard' })).toHaveAttribute('aria-selected', 'true');

await expect(page).toMatchAriaSnapshot(`
- text: /Slowest Tests/
- heading "Slowest Tests" [level=2]
- region:
- list:
- listitem:
Expand All @@ -3455,7 +3455,7 @@ for (const useIntermediateMergeReport of [true, false] as const) {
`);
await page.getByText('foo').first().click();
await expect(page).toMatchAriaSnapshot(`
- text: /Slowest Tests/
- heading "Slowest Tests" [level=2]
`);

await page.getByRole('link', { name: 'Failed' }).click();
Expand Down
Loading