Open kevin940726 opened 2 years ago
It would be nice to have the accessible name selector as an option to filter, like hasText
. It would look like this:
await page.locator('role=button', { hasName: /click me/i }).click();
// translates to
await page.locator('role=button[name=/click me/i]).click();
Another idea; select by aria description:
await page.locator('role=article[description=/something/i]');
I can create separate issues if needed.
I'd find assertions for aria-invalid
and aria-errormessage
useful, maybe toBeValid
/toBeInvalid
and toHaveErrorMessage
?
I get around the former with https://github.com/PREreview/prereview.org/blob/403705b239fe088d7d2ed28e46042ed7f94324cb/integration/posting-a-prereview.spec.ts#L932, but the latter is harder as it refers to another element.
With the release of 1.27.0 my first issue is fixed, thanks for landing it! The second issue persists, however, I still can't query with accessible description using accessible selectors. @thewilkybarkid's issue is not fixed either, as far as I can tell.
It would be nice to have an assertion that can compute and compare the accessible name and description for an element, similar to the jest-dom APIs:
https://github.com/testing-library/jest-dom/blob/main/src/to-have-accessible-name.js https://github.com/testing-library/jest-dom/blob/main/src/to-have-accessible-description.js
The W3C Spec for the computation is here: https://www.w3.org/TR/accname-1.1/#mapping_additional_nd_te
Since Playwright also has access to browser internals it may be possible to turn on the AccessibilityObjectModel (AOM) experimental features, although there is spotty support for the features you'd need at the moment. https://github.com/WICG/aom
Actually, to solve this problem, I have added the following code:
import { expect, Locator } from '@playwright/test'
// We detected that not all aria labels are implemented in Playwright. https://github.com/microsoft/playwright/issues/13517
// This is currently the only attributes tested. You could add more if needed.
type ariaAttributesSupported = 'selected'|'other'
export async function isAriaAttributeValue (locator:Locator, label:ariaAttributesSupported, value: string) {
const currentValue = await locator.getAttribute(`aria-${label}`)
const res = currentValue === value
return res
}
export async function expectToHaveAriaAttributeValue (locator:Locator, label:ariaAttributesSupported, value: string, options?: Record<string, unknown>) {
return expect(locator).toHaveAttribute(`aria-${label}`, value, options)
}
I'd find assertions for
aria-invalid
andaria-errormessage
useful, maybetoBeValid
/toBeInvalid
andtoHaveErrorMessage
?I get around the former with https://github.com/PREreview/prereview.org/blob/403705b239fe088d7d2ed28e46042ed7f94324cb/integration/posting-a-prereview.spec.ts#L932, but the latter is harder as it refers to another element.
The browser accessibility tree will expose an "Invalid user entry" property which is true either if an input is invalid from native constraints validation or from aria-invalid
, similar to checked
vs aria-checked
. toBeValid
and toBeInvalid
matcher would be very useful to be able to write tests that work with either.
E.g. all of these should trigger toBeInvalid()
:
<input type="radio" aria-invalid">
<input type="radio" required>
input.setCustomValidity('error');
Example browser a11y properties
Role: radio
Invalid user entry: false
Focusable: true
Checked: true
Labeled by: label
Now that webdriver includes getComputedRole and getComputedLabel is there any chance that Playwright could support those? Providing access to the browser internal name and role would allow a huge increase in accessibility tests we could write.
@dgozman Is there a timeline for the following matchers?
toHaveName
toHaveRole
toHaveDescription
At Teams we've integrated axe-core already, but we would like more level of granularity to assert specific scenarios that should not regress. To be able to assert accessible name and role explicitly would be really helpful in tests for keyboard navigation where you'd want to press keys and also assert that each focus stop has correct name and role.
An example would be a complex UI component like a treeview, where keyboard navigation patterns can be really complex with lots of extra embedded controls like tooltips and flyout menus, we need to make sure we can have that level of granularity
See also #18332 for a more specific issue covering toHaveAccessibleName
and toHaveAccessibleDescription
.
Originally posted in https://github.com/microsoft/playwright/pull/12999#issuecomment-1092536668.
It'll be great to add support for computing aria attributes on Locator and ElementHandle to make them more feature-complete.
Proposed methods on Locator (and ElementHandle):
locator.ariaRole(): string
: Get the aria role of the element.locator.ariaName(): string
: Get the aria name of the element.locator.isChecked(): boolean
: Already available.locator.isSelected(): boolean
: Returns whether the option is selected.locator.isExpanded(): boolean
: Returns whether the element is expanded.locator.isPressed(): boolean
: Returns whether the button is being pressed.locator.isDisabled(): boolean
: Already available.locator.level(): number
: Get the level of the heading element.And for assertions:
expect(locator).toHaveRole(role: string)
: Test whether the element has the aria role.expect(locator).toHaveName(name: string | RegExp)
: Test whether the element has the aria name.expect(locator).toBeChecked()
: Already available.expect(locator).toBeSelected()
: Expect the option to be selected.expect(locator).toBeExpanded()
: Expect the element to be expanded.expect(locator).toBePressed()
: Expect the button to be pressed.expect(locator).toBeDisabled()
: Already available.expect(locator).toHaveLevel(level: number)
: Expect the heading element to have the level.c.c. @dgozman