rename accessibilitySnapshot to snapshot for shorter agent usage

The function is now exposed as `snapshot()` in the executor sandbox scope.
`accessibilitySnapshot` remains as a backward-compatible alias pointing to
the same function, so existing agents and saved commands continue to work.

Updated all code examples across skill.md, README, PLAYWRITER_AGENTS,
docs, tests, and the extension welcome page to use the shorter name.
This commit is contained in:
Tommy D. Rossi
2026-02-18 17:13:57 +01:00
parent b5c14cb68d
commit 539aeaac91
9 changed files with 44 additions and 40 deletions
+1 -1
View File
@@ -57,7 +57,7 @@ to test CLI changes without publishing:
Get-NetTCPConnection -LocalPort 19988 | ForEach-Object { Stop-Process -Id $_.OwningProcess -Force }
tsx playwriter/src/cli.ts -s 1 -e "await page.goto('https://example.com')"
tsx playwriter/src/cli.ts -s 1 -e "console.log(await accessibilitySnapshot({ page }))"
tsx playwriter/src/cli.ts -s 1 -e "console.log(await snapshot({ page }))"
tsx playwriter/src/cli.ts session new
tsx playwriter/src/cli.ts -s 1 -e "await page.click('button')"
```
+1 -1
View File
@@ -33,7 +33,7 @@
```bash
playwriter session new # creates stateful sandbox, outputs session id (e.g. 1)
playwriter -s 1 -e "await page.goto('https://example.com')"
playwriter -s 1 -e "console.log(await accessibilitySnapshot({ page }))"
playwriter -s 1 -e "console.log(await snapshot({ page }))"
playwriter -s 1 -e "await page.locator('aria-ref=e5').click()"
```
+6 -6
View File
@@ -1,9 +1,9 @@
---
title: Framer Plugin Iframe Snapshot Guide
description: Step-by-step instructions to open the Framer MCP plugin iframe and run accessibilitySnapshot on it.
description: Step-by-step instructions to open the Framer MCP plugin iframe and run snapshot on it.
prompt: |
Create a concise step-by-step guide to open the Framer plugin iframe and
verify accessibilitySnapshot on that iframe using playwriter CLI. Include the
verify snapshot on that iframe using playwriter CLI. Include the
exact Framer project URL and the plugins.framercdn iframe URL. Also document
the Command+K workflow to open the MCP plugin: press Command+K, search for MCP
in the command palette, press Enter, then wait ~1 second for the iframe to
@@ -33,7 +33,7 @@ playwriter -s 1 -e "const target = 'https://framer.com/projects/unframer-source-
- Verify the palette is open (look for the command dialog and MCP entry in the snapshot output):
```bash
playwriter -s 1 -e "console.log(await accessibilitySnapshot({ page, search: /dialog|Search…|MCP/ }));"
playwriter -s 1 -e "console.log(await snapshot({ page, search: /dialog|Search…|MCP/ }));"
```
- Search for **MCP**, press Enter, then wait about 1 second for the plugin iframe to appear.
@@ -55,17 +55,17 @@ playwriter -s 1 -e "const iframe = page.locator(\"iframe[src*='plugins.framercdn
- Run the accessibility snapshot on that iframe using `contentFrame()` (FrameLocator is auto-resolved to Frame):
```bash
playwriter -s 1 -e "const frame = await page.locator(\"iframe[src*='plugins.framercdn.com']\").contentFrame(); console.log(await accessibilitySnapshot({ page, frame }));"
playwriter -s 1 -e "const frame = await page.locator(\"iframe[src*='plugins.framercdn.com']\").contentFrame(); console.log(await snapshot({ page, frame }));"
```
- Alternative: use `page.frames()` to get the Frame directly:
```bash
playwriter -s 1 -e "const frame = page.frames().find(f => f.url().includes('plugins.framercdn.com')); console.log(await accessibilitySnapshot({ page, frame }));"
playwriter -s 1 -e "const frame = page.frames().find(f => f.url().includes('plugins.framercdn.com')); console.log(await snapshot({ page, frame }));"
```
- Validate the snapshot contains MCP UI text (confirms the panel is actually loaded):
```bash
playwriter -s 1 -e "const frame = await page.locator(\"iframe[src*='plugins.framercdn.com']\").contentFrame(); console.log(await accessibilitySnapshot({ page, frame, search: /Control Framer with MCP|Login With Google/ }));"
playwriter -s 1 -e "const frame = await page.locator(\"iframe[src*='plugins.framercdn.com']\").contentFrame(); console.log(await snapshot({ page, frame, search: /Control Framer with MCP|Login With Google/ }));"
```
## Expected iframe URL
+1 -1
View File
@@ -99,7 +99,7 @@ The **CLI with the skill** is the recommended approach. The skill file (`playwri
```bash
playwriter session new # outputs: 1
playwriter -s 1 -e "await page.goto('https://example.com')"
playwriter -s 1 -e "console.log(await accessibilitySnapshot({ page }))"
playwriter -s 1 -e "console.log(await snapshot({ page }))"
```
Alternatively, pass host and token as flags instead of env vars:
+1 -1
View File
@@ -325,7 +325,7 @@ playwriter session new
# navigate to a URL
playwriter -s 1 -e "await page.goto('https://example.com')"
# get the accessibility tree of the page
playwriter -s 1 -e "console.log(await accessibilitySnapshot({ page }))"
playwriter -s 1 -e "console.log(await snapshot({ page }))"
# click an element by its accessibility reference
playwriter -s 1 -e "await page.locator('aria-ref=e5').click()"</code></pre>
</section>
+4 -3
View File
@@ -548,7 +548,7 @@ export class PlaywrightExecutor {
},
}
const accessibilitySnapshot = async (options: {
const snapshot = async (options: {
page?: Page
/** Optional frame to scope the snapshot (e.g. from iframe.contentFrame() or page.frames()) */
frame?: Frame | FrameLocator
@@ -564,7 +564,7 @@ export class PlaywrightExecutor {
const { page: targetPage, frame, locator, search, showDiffSinceLastCall = true, interactiveOnly = false } = options
const resolvedPage = targetPage || page
if (!resolvedPage) {
throw new Error('accessibilitySnapshot requires a page')
throw new Error('snapshot requires a page')
}
// Use new in-page implementation via getAriaSnapshot
@@ -800,7 +800,8 @@ export class PlaywrightExecutor {
context,
state: this.userState,
console: customConsole,
accessibilitySnapshot,
snapshot,
accessibilitySnapshot: snapshot, // backward compat alias
refToLocator,
getCleanHTML,
getPageMarkdown,
+1
View File
@@ -6,6 +6,7 @@ describe('shouldAutoReturn', () => {
expect(shouldAutoReturn('1 + 2')).toBe(true)
expect(shouldAutoReturn('page.title()')).toBe(true)
expect(shouldAutoReturn('await page.title()')).toBe(true)
expect(shouldAutoReturn('snapshot({ page })')).toBe(true)
expect(shouldAutoReturn('accessibilitySnapshot({ page })')).toBe(true)
expect(shouldAutoReturn('context.pages().map(p => p.url())')).toBe(true)
})
+6 -6
View File
@@ -172,7 +172,7 @@ describe('Relay Core Tests', () => {
})
}, 30000)
const accessibilitySnapshotTestCases = [
const snapshotTestCases = [
{
name: 'hacker-news',
url: 'https://news.ycombinator.com/item?id=1',
@@ -185,7 +185,7 @@ describe('Relay Core Tests', () => {
},
]
for (const testCase of accessibilitySnapshotTestCases) {
for (const testCase of snapshotTestCases) {
it(`should get accessibility snapshot of ${testCase.name}`, async () => {
await client.callTool({
name: 'execute',
@@ -205,8 +205,8 @@ describe('Relay Core Tests', () => {
arguments: {
code: js`
await state.page.goto('${testCase.url}', { waitUntil: 'domcontentloaded' });
const snapshot = await accessibilitySnapshot({ page: state.page, showDiffSinceLastCall: false, interactiveOnly: true });
return snapshot;
const snap = await snapshot({ page: state.page, showDiffSinceLastCall: false, interactiveOnly: true });
return snap;
`,
},
})
@@ -228,8 +228,8 @@ describe('Relay Core Tests', () => {
name: 'execute',
arguments: {
code: js`
const snapshot = await accessibilitySnapshot({ page: state.page, showDiffSinceLastCall: false, interactiveOnly: false });
return snapshot;
const snap = await snapshot({ page: state.page, showDiffSinceLastCall: false, interactiveOnly: false });
return snap;
`,
},
})
+23 -21
View File
@@ -69,11 +69,11 @@ playwriter -s 1 -e "await page.title()"
playwriter -s 1 -e "await page.screenshot({ path: 'screenshot.png', scale: 'css' })"
# Get accessibility snapshot
playwriter -s 1 -e "await accessibilitySnapshot({ page })"
playwriter -s 1 -e "await snapshot({ page })"
# Get accessibility snapshot for a specific iframe
const frame = await page.locator('iframe').contentFrame()
await accessibilitySnapshot({ frame })
await snapshot({ frame })
```
**Multiline code:**
@@ -214,19 +214,19 @@ Each step is a separate execute call. Notice how every action is followed by a s
// 1. Open page and observe
state.myPage = context.pages().find(p => p.url() === 'about:blank') ?? await context.newPage();
await state.myPage.goto('https://framer.com/projects/my-project', { waitUntil: 'domcontentloaded' });
await accessibilitySnapshot({ page: state.myPage }).then(console.log)
await snapshot({ page: state.myPage }).then(console.log)
```
```js
// 2. Act: open command palette → observe result
await state.myPage.keyboard.press('Meta+k');
await accessibilitySnapshot({ page: state.myPage, search: /dialog|Search/ }).then(console.log)
await snapshot({ page: state.myPage, search: /dialog|Search/ }).then(console.log)
```
```js
// 3. Act: type search query → observe result
await state.myPage.keyboard.type('MCP');
await accessibilitySnapshot({ page: state.myPage, search: /MCP/ }).then(console.log)
await snapshot({ page: state.myPage, search: /MCP/ }).then(console.log)
```
```js
@@ -234,7 +234,7 @@ await accessibilitySnapshot({ page: state.myPage, search: /MCP/ }).then(console.
await state.myPage.keyboard.press('Enter');
await state.myPage.waitForTimeout(1000);
const frame = state.myPage.frames().find(f => f.url().includes('plugins.framercdn.com'));
await accessibilitySnapshot({ page: state.myPage, frame: frame || undefined }).then(console.log)
await snapshot({ page: state.myPage, frame: frame || undefined }).then(console.log)
```
**Other ways to observe action results:**
@@ -261,7 +261,7 @@ Snapshots are the primary feedback mechanism, but some actions have side effects
Always check page state after important actions (form submissions, uploads, typing). Your mental model can diverge from actual browser state:
```js
await page.keyboard.type('my text');
await accessibilitySnapshot({ page, search: /my text/ })
await snapshot({ page, search: /my text/ })
// If verifying visual layout specifically, use screenshotWithAccessibilityLabels instead
```
@@ -283,7 +283,7 @@ Locators (especially ones with `>> nth=`) can change when the page updates. Alwa
await page.locator('[id="old-id"]').click(); // element may have changed
// GOOD: get fresh snapshot, then immediately use locators from it
await accessibilitySnapshot({ page, showDiffSinceLastCall: true })
await snapshot({ page, showDiffSinceLastCall: true })
// Now use the NEW locators from this output
```
@@ -330,7 +330,7 @@ Screenshots + image analysis is expensive and slow. Only use screenshots for vis
await page.screenshot({ path: 'check.png', scale: 'css' });
// GOOD: snapshot is text — fast, cheap, searchable
await accessibilitySnapshot({ page, search: /expected text/i })
await snapshot({ page, search: /expected text/i })
// GOOD: evaluate DOM directly for content checks
const text = await page.evaluate(() => document.querySelector('.message')?.textContent);
@@ -375,10 +375,10 @@ After any action (click, submit, navigate), verify what happened. **Always prefe
```js
// Default: use snapshot with optional filtering
page.url() + '\n' + await accessibilitySnapshot({ page })
page.url() + '\n' + await snapshot({ page })
// Filter for specific content when snapshot is large
await accessibilitySnapshot({ page, search: /dialog|button|error/i })
await snapshot({ page, search: /dialog|button|error/i })
```
Only use `screenshotWithAccessibilityLabels({ page })` for **visual layout issues** (CSS bugs, spatial positioning, colors). For verifying text content, button states, or form values, snapshots are always sufficient.
@@ -388,9 +388,11 @@ If nothing changed, try `await waitForPageLoad({ page, timeout: 3000 })` or you
## accessibility snapshots
```js
await accessibilitySnapshot({ page, search?, showDiffSinceLastCall? })
await snapshot({ page, search?, showDiffSinceLastCall? })
```
`accessibilitySnapshot` is still available as an alias for backward compatibility.
- `search` - string/regex to filter results (returns first 10 matching lines)
- `showDiffSinceLastCall` - returns diff since last snapshot (default: `true`). Pass `false` to get full snapshot.
@@ -413,7 +415,7 @@ to make it unique.
If a screenshot shows ref labels like `e3`, resolve them using the last snapshot:
```js
const snapshot = await accessibilitySnapshot({ page })
const snap = await snapshot({ page })
const locator = refToLocator({ ref: 'e3' })
await page.locator(locator!).click()
```
@@ -427,13 +429,13 @@ await page.locator('role=link[name="Blog"]').click()
Search for specific elements:
```js
const snapshot = await accessibilitySnapshot({ page, search: /button|submit/i })
const snap = await snapshot({ page, search: /button|submit/i })
```
**Filtering large snapshots in JS** — when the built-in `search` isn't enough (e.g., you need multiple patterns or custom logic), filter the snapshot string directly:
```js
const snap = await accessibilitySnapshot({ page, showDiffSinceLastCall: false });
const snap = await snapshot({ page, showDiffSinceLastCall: false });
const relevant = snap.split('\n').filter(l =>
l.includes('dialog') || l.includes('error') || l.includes('button')
).join('\n');
@@ -444,9 +446,9 @@ This is much cheaper than taking a screenshot — use it as your primary debuggi
## choosing between snapshot methods
Both `accessibilitySnapshot` and `screenshotWithAccessibilityLabels` use the same ref system, so you can combine them effectively.
Both `snapshot` and `screenshotWithAccessibilityLabels` use the same ref system, so you can combine them effectively.
**Use `accessibilitySnapshot` when:**
**Use `snapshot` when:**
- Page has simple, semantic structure (articles, forms, lists)
- You need to search for specific text or patterns
- Token usage matters (text is smaller than images)
@@ -458,11 +460,11 @@ Both `accessibilitySnapshot` and `screenshotWithAccessibilityLabels` use the sam
- DOM order doesn't match visual order
- You need to understand the visual hierarchy
**Combining both:** Use screenshot first to understand layout and identify target elements visually, then use `accessibilitySnapshot({ search: /pattern/ })` for efficient searching in subsequent calls.
**Combining both:** Use screenshot first to understand layout and identify target elements visually, then use `snapshot({ search: /pattern/ })` for efficient searching in subsequent calls.
## selector best practices
**For unknown websites**: use `accessibilitySnapshot()` - it shows what's actually interactive with stable locators.
**For unknown websites**: use `snapshot()` - it shows what's actually interactive with stable locators.
**For development** (when you have source code access), prefer stable selectors in this order:
@@ -746,7 +748,7 @@ await editor.edit({ url: matches[0].url, oldString: 'DEBUG = false', newString:
**screenshotWithAccessibilityLabels** - take a screenshot with Vimium-style visual labels overlaid on interactive elements. Shows labels, captures screenshot, then removes labels. The image and accessibility snapshot are automatically included in the response. Can be called multiple times to capture multiple screenshots. Use a timeout of **20 seconds** for complex pages.
Prefer this for pages with grids, image galleries, maps, or complex visual layouts where spatial position matters. For simple text-heavy pages, `accessibilitySnapshot` with search is faster and uses fewer tokens.
Prefer this for pages with grids, image galleries, maps, or complex visual layouts where spatial position matters. For simple text-heavy pages, `snapshot` with search is faster and uses fewer tokens.
```js
await screenshotWithAccessibilityLabels({ page });
@@ -904,7 +906,7 @@ console.log(JSON.stringify(info, null, 2));
await page.keyboard.press('Enter');
await page.waitForTimeout(2000);
const snap = await accessibilitySnapshot({ page, search: /dialog|error|message/ });
const snap = await snapshot({ page, search: /dialog|error|message/ });
const logs = await getLatestLogs({ page, search: /error/i, count: 10 });
console.log('UI:', snap);
console.log('Logs:', logs);