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
11 changes: 7 additions & 4 deletions packages/playwright-core/src/tools/backend/tab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import url from 'url';

import { EventEmitter } from 'events';
import { asLocator } from '../../utils/isomorphic/locatorGenerators';
import { locatorOrSelectorAsSelector } from '../../utils/isomorphic/locatorParser';
import { ManualPromise } from '../../utils/isomorphic/manualPromise';
import { debug } from '../../utilsBundle';

Expand Down Expand Up @@ -438,10 +439,12 @@ export class Tab extends EventEmitter<TabEventsInterface> {
await this._initializedPromise;
return Promise.all(params.map(async param => {
if (param.selector) {
const locator = this.page.locator(param.selector);
if (!await locator.isVisible())
throw new Error(`Selector ${param.selector} does not match any elements.`);
return { locator, resolved: asLocator('javascript', param.selector) };
const selector = locatorOrSelectorAsSelector('javascript', param.selector, this.context.config.testIdAttribute || 'data-testid');
const handle = await this.page.$(selector);
if (!handle)
throw new Error(`"${param.selector}" does not match any elements.`);
handle.dispose().catch(() => {});
return { locator: this.page.locator(selector), resolved: asLocator('javascript', selector) };
} else {
try {
let locator = this.page.locator(`aria-ref=${param.ref}`);
Expand Down
10 changes: 5 additions & 5 deletions packages/playwright-core/src/tools/cli-client/skill/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,17 +222,17 @@ playwright-cli snapshot
playwright-cli click e15
```

You can also use css or role selectors, for example when explicitly asked for it.
You can also use css selectors or Playwright locators.

```bash
# css selector
playwright-cli click "#main > button.submit"

# role selector
playwright-cli click "role=button[name=Submit]"
# role locator
playwright-cli click "getByRole('button', { name: 'Submit' })"

# chaining css and role selectors
playwright-cli click "#footer >> role=button[name=Submit]"
# test id
playwright-cli click "getByTestId('submit-button')"
```

## Browser Sessions
Expand Down
18 changes: 9 additions & 9 deletions tests/mcp/cli-core.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,31 +226,31 @@ await page.locator('button').click();
\`\`\``);
});

test('click button with role selector', async ({ cli, server }) => {
test('click button with role locator', async ({ cli, server }) => {
server.setContent('/', `<button>Submit</button>`, 'text/html');

const { snapshot } = await cli('open', server.PREFIX);
expect(snapshot).toContain(`- button "Submit" [ref=e2]`);

const { output, snapshot: clickSnapshot } = await cli('click', 'role=button');
const { output, snapshot: clickSnapshot } = await cli('click', 'getByRole("button", { name: "Submit" })');
expect(clickSnapshot).toBeTruthy();
expect(output).toContain(`### Ran Playwright code
\`\`\`js
await page.locator('role=button').click();
await page.getByRole('button', { name: 'Submit' }).click();
\`\`\``);
});

test('click button with mixed css + role selector', async ({ cli, server }) => {
server.setContent('/', `<div id=main><button>Submit</button></div>`, 'text/html');
test('click button with test id locator', async ({ cli, server }) => {
server.setContent('/', `<div data-testid=main><button>Submit</button></div>`, 'text/html');

const { snapshot } = await cli('open', server.PREFIX);
expect(snapshot).toContain(`- button "Submit" [ref=e3]`);

const { output, snapshot: clickSnapshot } = await cli('click', '#main >> role=button');
const { output, snapshot: clickSnapshot } = await cli('click', 'getByTestId("main").getByRole("button")');
expect(clickSnapshot).toBeTruthy();
expect(output).toContain(`### Ran Playwright code
\`\`\`js
await page.locator('#main').locator('role=button').click();
await page.getByTestId('main').getByRole('button').click();
\`\`\``);
});

Expand All @@ -261,7 +261,7 @@ test('click button with wrong css selector', async ({ cli, server }) => {
expect(snapshot).toContain(`- button "Submit" [ref=e2]`);

const { output } = await cli('click', '#target');
expect(output).toContain(`Error: Selector #target does not match any elements.`);
expect(output).toContain(`"#target" does not match any elements.`);
});

test('partial snapshot', async ({ cli, server }) => {
Expand All @@ -277,7 +277,7 @@ test('partial snapshot', async ({ cli, server }) => {
expect(strictError).toContain(`strict mode violation`);

const { output: noMatchError } = await cli('snapshot', '#target');
expect(noMatchError).toContain(`Selector "#target" does not match any element`);
expect(noMatchError).toContain(`"#target" does not match any element`);
});

test('snapshot depth', async ({ cli, server }) => {
Expand Down
Loading