diff --git a/.claude/skills/dev/roll.md b/.claude/skills/dev/roll.md index 5341c96..2480512 100644 --- a/.claude/skills/dev/roll.md +++ b/.claude/skills/dev/roll.md @@ -2,11 +2,14 @@ ## Steps -1. **Update Playwright packages** in `package.json`: +1. **Obtain latest Playwright version** + `npm info playwright@next version` + +2. **Update Playwright packages** in `package.json`: - Update `playwright` (dependency) and `@playwright/test` (devDependency) to the target version. - Run `npm install` to update `package-lock.json`. -2. **Run the update script** to sync skills and README: +3. **Run the update script** to sync skills and README: ```bash node scripts/update.js ``` diff --git a/.gitignore b/.gitignore index e43d0b1..e5c0047 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ node_modules/ .vscode/ /test-results/ -/.playwright-cli/ \ No newline at end of file +/.playwright-cli/ +# Ignore self-skill which is a build artifact +.claude/skills/playwright-cli/ diff --git a/README.md b/README.md index e8d719e..59f3e2c 100644 --- a/README.md +++ b/README.md @@ -271,6 +271,31 @@ You can also take a snapshot on demand using `playwright-cli snapshot` command. If `--filename` is not provided, a new snapshot file is created with a timestamp. Default to automatic file naming, use `--filename=` when artifact is a part of the workflow result. +### Targeting elements + +By default, use refs from the snapshot to interact with page elements. + +```bash +# get snapshot with refs +playwright-cli snapshot + +# interact using a ref +playwright-cli click e15 +``` + +You can also use css or role selectors, for example when explicitly asked for it. + +```bash +# css selector +playwright-cli click "#main > button.submit" + +# role selector +playwright-cli click "role=button[name=Submit]" + +# chaining css and role selectors +playwright-cli click "#footer >> role=button[name=Submit]" +``` + ### Sessions ```bash @@ -284,11 +309,16 @@ playwright-cli kill-all # forcefully kill all browser processes ### Local installation -In some cases you might want to install playwright-cli locally. If running the globally available `playwright-cli` binary fails, use `npx playwright-cli` to run the commands. For example: +If global `playwright-cli` command is not available, try a local version via `npx playwright-cli`: + +```bash +npx --no-install playwright-cli --version +``` + +When local version is available, use `npx playwright-cli` in all commands. Otherwise, install `playwright-cli` as a global command: ```bash -npx playwright-cli open https://example.com -npx playwright-cli click e1 +npm install -g @playwright/cli@latest ``` ## Configuration file @@ -488,6 +518,7 @@ Playwright CLI will load config from `.playwright/cli.config.json` by default so The installed skill includes detailed reference guides for common tasks: +* **Running and Debugging Playwright tests** — run, debug and manage Playwright test suites * **Request mocking** — intercept and mock network requests * **Running Playwright code** — execute arbitrary Playwright scripts * **Browser session management** — manage multiple browser sessions diff --git a/package-lock.json b/package-lock.json index e925106..e3edcff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,13 +10,13 @@ "license": "Apache-2.0", "dependencies": { "minimist": "^1.2.5", - "playwright": "1.59.0-alpha-1771104257000" + "playwright": "1.59.0-alpha-1773608981000" }, "bin": { "playwright-cli": "playwright-cli.js" }, "devDependencies": { - "@playwright/test": "1.59.0-alpha-1771104257000", + "@playwright/test": "1.59.0-alpha-1773608981000", "@types/node": "^25.2.1" }, "engines": { @@ -24,13 +24,13 @@ } }, "node_modules/@playwright/test": { - "version": "1.59.0-alpha-1771104257000", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.59.0-alpha-1771104257000.tgz", - "integrity": "sha512-0zUPgLuSbyO2xtA+FdEWejFpA5tYU1dINMj2D6KGbB7dgxW8V/4bOrpYS38hizSrzpdSiuRcIK7UgiNFxEeK3A==", + "version": "1.59.0-alpha-1773608981000", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.59.0-alpha-1773608981000.tgz", + "integrity": "sha512-px+GAf8KIaMcPsCUPG3+xqPRSIPHgnizH7ygUjo6OXT1AigXTNCsIIVrPY3C5GjouM2MI4CQOkIKcSEjO84ZTg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright": "1.59.0-alpha-1771104257000" + "playwright": "1.59.0-alpha-1773608981000" }, "bin": { "playwright": "cli.js" @@ -73,12 +73,12 @@ } }, "node_modules/playwright": { - "version": "1.59.0-alpha-1771104257000", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.59.0-alpha-1771104257000.tgz", - "integrity": "sha512-6SCMMMJaDRsSqiKVLmb2nhtLES7iTYawTWWrQK6UdIGNzXi8lka4sLKRec3L4DnTWwddAvCuRn8035dhNiHzbg==", + "version": "1.59.0-alpha-1773608981000", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.59.0-alpha-1773608981000.tgz", + "integrity": "sha512-nb+BzawNj48eH6NdxecsysLuhCAB/p18FG7LLJp3MBfRGUkCAFtax0CFo/BhD+r0V4+0EW7llPK0p4cJQEIwUQ==", "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.59.0-alpha-1771104257000" + "playwright-core": "1.59.0-alpha-1773608981000" }, "bin": { "playwright": "cli.js" @@ -91,9 +91,9 @@ } }, "node_modules/playwright-core": { - "version": "1.59.0-alpha-1771104257000", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.59.0-alpha-1771104257000.tgz", - "integrity": "sha512-YiXup3pnpQUCBMSIW5zx8CErwRx4K6O5Kojkw2BzJui8MazoMUDU6E3xGsb1kzFviEAE09LFQ+y1a0RhIJQ5SA==", + "version": "1.59.0-alpha-1773608981000", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.59.0-alpha-1773608981000.tgz", + "integrity": "sha512-w6E5Q0Wleek3Wp7gtlSPGXuKeQ5eg6QPPJNNwgMHQRpkxgqOwgN2mX7x6Z52HJE10HFC88U5HQzOLMbag928Lg==", "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" diff --git a/package.json b/package.json index 3bbb372..90ecb2f 100644 --- a/package.json +++ b/package.json @@ -18,12 +18,12 @@ "test": "playwright test" }, "devDependencies": { - "@playwright/test": "1.59.0-alpha-1771104257000", + "@playwright/test": "1.59.0-alpha-1773608981000", "@types/node": "^25.2.1" }, "dependencies": { "minimist": "^1.2.5", - "playwright": "1.59.0-alpha-1771104257000" + "playwright": "1.59.0-alpha-1773608981000" }, "bin": { "playwright-cli": "playwright-cli.js" diff --git a/playwright-cli.js b/playwright-cli.js index 5f04336..6ea172f 100755 --- a/playwright-cli.js +++ b/playwright-cli.js @@ -15,4 +15,7 @@ * limitations under the License. */ -require('playwright/lib/cli/client/program'); +const { program } = require('playwright-core/lib/tools/cli-client/program'); +const packageJson = require('./package.json'); + +program({ embedderVersion: packageJson.version }); diff --git a/skills/playwright-cli/SKILL.md b/skills/playwright-cli/SKILL.md index 11bad2b..4865d33 100644 --- a/skills/playwright-cli/SKILL.md +++ b/skills/playwright-cli/SKILL.md @@ -1,7 +1,7 @@ --- name: playwright-cli -description: Automates browser interactions for web testing, form filling, screenshots, and data extraction. Use when the user needs to navigate websites, interact with web pages, fill forms, take screenshots, test web applications, or extract information from web pages. -allowed-tools: Bash(playwright-cli:*) +description: Automate browser interactions, test web pages and work with Playwright tests. +allowed-tools: Bash(playwright-cli:*) Bash(npx:*) Bash(npm:*) --- # Browser Automation with playwright-cli @@ -196,6 +196,31 @@ You can also take a snapshot on demand using `playwright-cli snapshot` command. If `--filename` is not provided, a new snapshot file is created with a timestamp. Default to automatic file naming, use `--filename=` when artifact is a part of the workflow result. +## Targeting elements + +By default, use refs from the snapshot to interact with page elements. + +```bash +# get snapshot with refs +playwright-cli snapshot + +# interact using a ref +playwright-cli click e15 +``` + +You can also use css or role selectors, for example when explicitly asked for it. + +```bash +# css selector +playwright-cli click "#main > button.submit" + +# role selector +playwright-cli click "role=button[name=Submit]" + +# chaining css and role selectors +playwright-cli click "#footer >> role=button[name=Submit]" +``` + ## Browser Sessions ```bash @@ -214,13 +239,18 @@ playwright-cli close-all playwright-cli kill-all ``` -## Local installation +## Installation + +If global `playwright-cli` command is not available, try a local version via `npx playwright-cli`: + +```bash +npx --no-install playwright-cli --version +``` -In some cases user might want to install playwright-cli locally. If running globally available `playwright-cli` binary fails, use `npx playwright-cli` to run the commands. For example: +When local version is available, use `npx playwright-cli` in all commands. Otherwise, install `playwright-cli` as a global command: ```bash -npx playwright-cli open https://example.com -npx playwright-cli click e1 +npm install -g @playwright/cli@latest ``` ## Example: Form submission @@ -269,6 +299,7 @@ playwright-cli close ## Specific tasks +* **Running and Debugging Playwright tests** [references/playwright-tests.md](references/playwright-tests.md) * **Request mocking** [references/request-mocking.md](references/request-mocking.md) * **Running Playwright code** [references/running-code.md](references/running-code.md) * **Browser session management** [references/session-management.md](references/session-management.md) diff --git a/skills/playwright-cli/references/playwright-tests.md b/skills/playwright-cli/references/playwright-tests.md new file mode 100644 index 0000000..1be8c70 --- /dev/null +++ b/skills/playwright-cli/references/playwright-tests.md @@ -0,0 +1,35 @@ +# Running Playwright Tests + +To run Playwright tests, use the `npx playwright test` command, or a package manager script. To avoid opening the interactive html report, use `PLAYWRIGHT_HTML_OPEN=never` environment variable. + +```bash +# Run all tests +PLAYWRIGHT_HTML_OPEN=never npx playwright test + +# Run all tests through a custom npm script +PLAYWRIGHT_HTML_OPEN=never npm run special-test-command +``` + +# Debugging Playwright Tests + +To debug a failing test, run it with Playwright as usual, but set `PWPAUSE=cli` environment variable. This command will pause the test at the point of failure, and print the debugging instructions. + +**IMPORTANT**: run the command in the background and check the output until "Debugging Instructions" is printed. + +Once instructions are printed, use `playwright-cli` to explore the page. Debugging instructions include a browser name that should be used in `playwright-cli` to attach to the page under test. + +```bash +# Run the test +PLAYWRIGHT_HTML_OPEN=never PWPAUSE=cli npx playwright test +# ... + +# Explore the page and interact if needed +playwright-cli --session=test open --attach=test-worker-abcdef +playwright-cli --session=test snapshot +playwright-cli --session=test click e14 +``` + +Keep the test running in the background while you explore and look for a fix. After fixing the test, stop the background test run. + +Every action you perform with `playwright-cli` generates corresponding Playwright TypeScript code. +This code appears in the output and can be copied directly into the test. Most of the time, a specific locator or an expectation should be updated, but it could also be a bug in the app. Use your judgement. diff --git a/skills/playwright-cli/references/running-code.md b/skills/playwright-cli/references/running-code.md index 7d6d22f..8b35e9a 100644 --- a/skills/playwright-cli/references/running-code.md +++ b/skills/playwright-cli/references/running-code.md @@ -87,7 +87,7 @@ playwright-cli run-code "async page => { # Wait for specific element playwright-cli run-code "async page => { - await page.waitForSelector('.loading', { state: 'hidden' }); + await page.locator('.loading').waitFor({ state: 'hidden' }); }" # Wait for function to return true @@ -97,7 +97,7 @@ playwright-cli run-code "async page => { # Wait with timeout playwright-cli run-code "async page => { - await page.waitForSelector('.result', { timeout: 10000 }); + await page.locator('.result').waitFor({ timeout: 10000 }); }" ``` @@ -122,10 +122,9 @@ playwright-cli run-code "async page => { ```bash # Handle file download playwright-cli run-code "async page => { - const [download] = await Promise.all([ - page.waitForEvent('download'), - page.click('a.download-link') - ]); + const downloadPromise = page.waitForEvent('download'); + await page.getByRole('link', { name: 'Download' }).click(); + const download = await downloadPromise; await download.saveAs('./downloaded-file.pdf'); return download.suggestedFilename(); }" @@ -197,7 +196,7 @@ playwright-cli run-code "async page => { # Try-catch in run-code playwright-cli run-code "async page => { try { - await page.click('.maybe-missing', { timeout: 1000 }); + await page.getByRole('button', { name: 'Submit' }).click({ timeout: 1000 }); return 'clicked'; } catch (e) { return 'element not found'; @@ -211,9 +210,9 @@ playwright-cli run-code "async page => { # Login and save state playwright-cli run-code "async page => { await page.goto('https://example.com/login'); - await page.fill('input[name=email]', 'user@example.com'); - await page.fill('input[name=password]', 'secret'); - await page.click('button[type=submit]'); + await page.getByRole('textbox', { name: 'Email' }).fill('user@example.com'); + await page.getByRole('textbox', { name: 'Password' }).fill('secret'); + await page.getByRole('button', { name: 'Sign in' }).click(); await page.waitForURL('**/dashboard'); await page.context().storageState({ path: 'auth.json' }); return 'Login successful';