GetByRole in Playwright –Many of us might be using page.getByRole in PlayWright but I doubt everyone is fully aware of its benefits. GetByRole
is a double-edged sword, which not only makes your tests robust but also ensures a certain level of accessibility compliance in the application. It’s a two-in-one utility in PlayWright that finds elements while simultaneously validating the use of correct ARIA roles.
What is WAI-ARIA roles?
WAI-ARIA (Web Accessibility Initiative – Accessible Rich Internet Applications) 1.2 is a technical specification that provides guidelines for making web content and applications more accessible to people with special abilities. It helps assistive technologies like screen readers to function effectively. HTML alone doesn’t always provide sufficient information for assistive technologies, so WAI-ARIA suggests to add roles, properties, and states to make dynamic content understandable to screen readers.
Interesting, right?
So when you write a locator as below, it not only locates the Buy With Credit Card
button, but it also ensures that screen readers will be able to understand this as button, and will read it correctly.
await page.getByRole('button', { name: 'Buy With Credit Card' });
In this article, I will highlight the advanced usage of the Playwright GetByRole locator strategy Additionally, I’ll help you to identify situations where GetByRole
should be avoided.
[Read, Why I avoid ID, CSS attributes as Selector in my automated tests]
[Read, how to print the element attributes in PlayWright]
The ARIA Roles in HTML
As per the WAI-ARIA Roles guidelines, it is recommended to developers to use native HTML elements like <button>
, <input>
, <select>
, etc., because they inherently support accessibility features.
For PlayWright users, the native HTML elements will work as per their role suggested by WAI-ARIA guidelines.
For native HTML elements, the getByRole works even if their HTML representation does not contain role attribute.
With the help of following table, you would be able to clearly understand what are the native elements in HTML and their corresponding role as per the WAI-ARIA Role guidelines.
PlayWright’s getByRole Implementation
PlayWright Implementation of GetByRole
method.
The roles are specified as “alert”|”alertdialog”|”application”|”article”| ..etc.
The attribute which getByRole
supports are checked?: boolean;
disabled?: boolean;
exact?: boolean;
expanded?: boolean;
includeHidden?: boolean;
level?: number;
name?: string|RegExp;
pressed?: boolean;
selected?: boolean;
getByRole(role: "alert"|"alertdialog"|"application"|"article"|"banner"|"blockquote"|"button"|"caption"|"cell"|"checkbox"|"code"|"columnheader"|"combobox"|"complementary"|"contentinfo"|"definition"|"deletion"|"dialog"|"directory"|"document"|"emphasis"|"feed"|"figure"|"form"|"generic"|"grid"|"gridcell"|"group"|"heading"|"img"|"insertion"|"link"|"list"|"listbox"|"listitem"|"log"|"main"|"marquee"|"math"|"meter"|"menu"|"menubar"|"menuitem"|"menuitemcheckbox"|"menuitemradio"|"navigation"|"none"|"note"|"option"|"paragraph"|"presentation"|"progressbar"|"radio"|"radiogroup"|"region"|"row"|"rowgroup"|"rowheader"|"scrollbar"|"search"|"searchbox"|"separator"|"slider"|"spinbutton"|"status"|"strong"|"subscript"|"superscript"|"switch"|"tab"|"table"|"tablist"|"tabpanel"|"term"|"textbox"|"time"|"timer"|"toolbar"|"tooltip"|"tree"|"treegrid"|"treeitem", options?: {
checked?: boolean;
disabled?: boolean;
exact?: boolean;
expanded?: boolean;
includeHidden?: boolean;
level?: number;
name?: string|RegExp;
pressed?: boolean;
selected?: boolean;
}): Locator;
,
getByRole in PlayWright for Native HTML Elements
A button with does not have attribute role
but still it can’t identified by getByRole
in PlayWright as button
is an example of native html element.
<div className="mb-6">
<label className="block mb-2 text-sm font-medium text-gray-700">
Button:
</label>
<button className="px-4 py-2 bg-blue-500 text-white rounded">Click Here</button>
</div>
await page.getByRole('button', {name: 'Click Here'}).click();
await expect(page.getByRole('button', {name: 'Clicked'})).toBeVisible();
An input check which is having an attribute as aria-checked="true"
can also be identified in PlayWright getByRole as
await expect(page.getByRole('checkbox', {selected: true })).toBeVisible();
Another example of list:
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
const item1 = await page.getByRole('listitem', { name: 'Item 1' });
const item2 = await page.getByRole('listitem', { name: 'Item 2' });
const item3 = await page.getByRole('listitem', { name: 'Item 3' });
GetByRole in PlayWright for Non-Native Elements
Often, developers use non-native elements to design user interface.
One of the common example of usage of non-native element is div
. A button can also be designed as div
by having something like:
<div onclick="toggleButton(this)">Click Me</div>
This creates a confusion for PlayWright users to understand whether getByRole
will work in this case or not.
The answer is NO, the div is designed to work as button but it is not a native element as suggested by WAI-ARIA. For this div, if we write page.getByRole('button', {name: 'Click Me'})
will result in failure.
As per the guidelines of WAI-ARIA, developer should specify the role of the div. The screen readers will be able to identify is as button only if specifies role
as <div onclick="toggleButton(this)" role="button">Click Me</div>
Playwright can locate elements using the getByRole function if a role is defined.
How to understand when to use getByRole?
To make it easier for Playwright users to understand when to use the getByRole function, consider this:
- For native elements, getByRole will work regardless of whether the role attribute is present.
- For non-native elements, getByRole will only work if a role attribute is specified.
Isn’t it easy now to understand when to use getByRole?
When to avoid getByRole?
getByRole should be avoided only if a non-native element without role is present in HTML. As explained above, the non-native elements won’t be located by getByRole. In this case, it is recommended to use other method like page.locator
() , page.getByText()
, etc.
Additionally, GetByRole should be avoided when you are planning to run tests against different languages.
Other benefits of GetByRole
Thought it can’t be completely replaced for accessibility testing, but having locator finding strategy using getByRole at least ensures that screen-readers will work for the given html element. So it is recommended for PlayWright users to prefer getByRole
and in case it does not work for any element, a suggestion can be made to developers to fix the HTML to have attributes like role
and others as per WAI-ARIA guidelines.
Impact on Test Execution Speed by usage of GetByRole in PlayWright
The following screenshot shows my basic test execution using both getByRole and CSS locator by ID. If you look at the execution time on the right-hand side of each line, you’ll see there’s no significant difference between the two methods: getByRole took 145 ms, while the locator by ID took around 147 ms. Both methods perform equally well, so I don’t see any slowness introduced by the getByRole method, as some have claimed.
However, a more detailed comparison is needed to understand how these methods behave on a complex, dynamic page.
Thank you for reading this post, don't forget to subscribe!