diff --git a/docs/src/api/class-locator.md b/docs/src/api/class-locator.md index c252b318fdd91..7a6d5957ce2de 100644 --- a/docs/src/api/class-locator.md +++ b/docs/src/api/class-locator.md @@ -239,6 +239,61 @@ When `true`, appends each element's bounding box as `[box=x,y,width,height]` to relative to the viewport, in CSS pixels, as returned by [`Element.getBoundingClientRect()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect). Defaults to `false`. +## async method: Locator.ariaSnapshotJSON +* since: v1.63 +* langs: js +- returns: <[Serializable]> + +Captures the aria snapshot of the given element as a free form JSON object. + +**Usage** + +```js +await page.getByRole('list').ariaSnapshotJSON(); +``` + +**Details** + +This method returns the same tree as [`method: Locator.ariaSnapshot`], serialized as a JSON value instead of YAML markup. +The result is a list of nodes, each node being either a plain string with static text, or an object with the following properties: +* `role` <[string]> Aria role of the element. +* `name` <[string]> Accessible name of the element, if any. +* `text` <[string]> Text content of the element, when it is the only child. +* `children` <[Array]> Child nodes and text fragments. +* Boolean and value properties for element state flags: `checked`, `disabled`, `expanded`, `active`, `invalid`, `level`, `pressed` and `selected`. +* Additional element properties, for example `url` for links and `placeholder` for text boxes. +* `ref` <[string]> Element reference for AI-optimized snapshots. +* `cursor` <[string]> Set to `"pointer"` for clickable elements in AI-optimized snapshots. +* `box` <[Object]> Bounding box of the element when [`option: Locator.ariaSnapshotJSON.boxes`] is set. + +### option: Locator.ariaSnapshotJSON.mode +* since: v1.63 +- `mode` <[AriaSnapshotMode]<"ai"|"default">> + +When set to `"ai"`, returns a snapshot optimized for AI consumption. Defaults to `"default"`. See details in [`method: Locator.ariaSnapshot`]. + +### option: Locator.ariaSnapshotJSON.timeout = %%-input-timeout-%% +* since: v1.63 + +### option: Locator.ariaSnapshotJSON.timeout = %%-input-timeout-js-%% +* since: v1.63 + +### option: Locator.ariaSnapshotJSON.signal = %%-input-signal-%% + +### option: Locator.ariaSnapshotJSON.depth +* since: v1.63 +- `depth` <[int]> + +When specified, limits the depth of the snapshot. + +### option: Locator.ariaSnapshotJSON.boxes +* since: v1.63 +- `boxes` <[boolean]> + +When `true`, includes each element's bounding box as a `box` property with `x`, `y`, `width` and `height`. Coordinates are +relative to the viewport, in CSS pixels, as returned by [`Element.getBoundingClientRect()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect). +Defaults to `false`. + ## async method: Locator.blur * since: v1.28 diff --git a/docs/src/api/class-page.md b/docs/src/api/class-page.md index 423fc97eefcef..9cb83bef41cdf 100644 --- a/docs/src/api/class-page.md +++ b/docs/src/api/class-page.md @@ -4427,6 +4427,43 @@ When `true`, appends each element's bounding box as `[box=x,y,width,height]` to relative to the viewport, in CSS pixels, as returned by [`Element.getBoundingClientRect()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect). Defaults to `false`. +## async method: Page.ariaSnapshotJSON +* since: v1.63 +* langs: js +- returns: <[Serializable]> + +Captures the aria snapshot of the page as a free form JSON object. +Returns the same tree as [`method: Page.ariaSnapshot`], serialized as a JSON value instead of YAML markup. +See [`method: Locator.ariaSnapshotJSON`] for the details of the format. + +### option: Page.ariaSnapshotJSON.mode +* since: v1.63 +- `mode` <[AriaSnapshotMode]<"ai"|"default">> + +When set to `"ai"`, returns a snapshot optimized for AI consumption: including element references like `[ref=e2]` and snapshots of ` + `); + const json = await page.ariaSnapshotJSON({ mode: 'ai' }) as NodeJSON[]; + const iframe = findNode(json, node => node.role === 'iframe'); + expect(iframe?.ref).toBeTruthy(); + const button = findNode(iframe!.children!, node => node.role === 'button'); + expect(button?.name).toBe('In frame'); + expect(button?.ref).toMatch(/^f\d+e\d+$/); +}); + +it('should limit depth', async ({ page }) => { + await page.setContent(``); + expect(await page.ariaSnapshotJSON({ depth: 1 })).toEqual([ + { + role: 'list', + children: [ + { role: 'listitem' }, + ], + }, + ]); +}); + +it('should include boxes when requested', async ({ page }) => { + await page.setContent(``); + const json = await page.ariaSnapshotJSON({ boxes: true }) as NodeJSON[]; + const button = findNode(json, node => node.role === 'button'); + expect(button?.box).toEqual({ + x: expect.any(Number), + y: expect.any(Number), + width: expect.any(Number), + height: expect.any(Number), + }); + expect(button!.box.width).toBeGreaterThan(0); + expect(button!.box.height).toBeGreaterThan(0); +}); + +it('should snapshot a locator', async ({ page }) => { + await page.setContent(` +

title

+ + `); + expect(await page.locator('ul').ariaSnapshotJSON()).toEqual([ + { + role: 'list', + children: [ + { role: 'listitem', text: 'one' }, + { role: 'listitem', text: 'two' }, + ], + }, + ]); +});