An In-Depth Understanding of getByRole in Playwright

Priyanshu S Avatar

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.

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.

HTML native elements with role.
Native HTML elements and their role as per https://www.w3.org/TR/wai-aria/#role_definitions

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.

Screenshot showing execution speed for getByRole and css locator

Your subscription encourages me to write more insightful articles.

Subscribe to my newsletter and explore Quality Assurance beyond just manual and automation testing!

We don’t spam! Read our privacy policy for more info.

Thank you for reading this post, don’t forget to subscribe!

Priyanshu S Avatar