microsoft / playwright

Playwright is a framework for Web Testing and Automation. It allows testing Chromium, Firefox and WebKit with a single API.
https://playwright.dev
Apache License 2.0
65.85k stars 3.58k forks source link

[Feature] Aria methods and assertions #13517

Open kevin940726 opened 2 years ago

kevin940726 commented 2 years ago

Originally posted in https://github.com/microsoft/playwright/pull/12999#issuecomment-1092536668.

Now that we have all these accessible attributes helpers, is it worth making them available under locator and assertions as well?

For instance, we want to know whether an element is expanded or not:

const button = page.locator('role=button[name=Expand me]');
const isExpanded = await button.expanded(); // `true` or `false`
await expect(button).toBeExpanded(); // Error if the button is not expanded

I think it's only natural to make them available both via querying and accessing.

Currently, we only have page.accessibility, but that uses browsers' API and it's platform-specific, different from the JS implementation injected into the browsers.

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):

And for assertions:

c.c. @dgozman

frontsideair commented 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.

thewilkybarkid commented 2 years ago

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.

frontsideair commented 1 year ago

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.

alexkrolick commented 1 year ago

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

ManuelLR commented 1 year ago

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)
}
jacobrask commented 1 year ago

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.

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
jnurthen commented 1 year ago

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.

ling1726 commented 5 months ago

@dgozman Is there a timeline for the following matchers?

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

dgozman commented 5 months ago

See also #18332 for a more specific issue covering toHaveAccessibleName and toHaveAccessibleDescription.