Accessible role selector for browsers, jsdom, Playwright, Puppeteer, and more.
import { selectors } from '@playwright/test';
import { selectorScript } from 'role-selector/playwright-test';
// import from 'role-selector/playwright' if you're using the 'playwright' package.
// Register the role selector in Playwright
selectors.register('role', selectorScript, { contentScript: true });
// Given DOM of:
// <label for="username">User Name</label>
// <input id="username" />
// <input type="submit" value="Submit" />
// Query the text input by its role and accessible name
const userNameInput = page.locator('role=textbox[name=/user name/i]');
await userNameInput.type('My name');
// Works on any method that accepts a selector
await page.click('role=button[name=/submit/i]');
// * Experimental:
// Suggest selector to use during development
console.log(await suggestSelector(userNameInput));
// Logs: { type: 'role', selector: 'textbox[name=/user name/i]' }
Only browsers, Playwright, Puppeteer, and jsdom are supported at the time.
role-selector
npm install -D role-selector
See the examples in the test/integration
directory.
The role selector syntax roughly follows the below format:
role=ROLE_NAME[STRING_ATTRIBUTE="STRING"][NUMBER_ATTRIBUTE=NUMBER][BOOLEAN_ATTRIBUTE]
While:
ROLE_NAME
can be any of the WAI_ARIA roles.ATTRIBUTE
is one ofname
,selected
,checked
,level
,expanded
,pressed
,current
,placeholder
,disabled
, andvaluetext
.- String attributes can be represented with string literals wrapped with double quotes
"
or single quotes'
. - String attributes can also be represented with RegExps:
/regular expression/i
. - Number attributes can be represented as number literal.
- Boolean attributes can have value of
true
orfalse
. Omitting the value and the equal sign is a shorthand of=true
.
Other than the role name, the order of the attributes doesn't matter. You can also add intermediate spaces in-between for readability.
For instance, here's a selector which queries the element <h2>Hello World</h2>
.
role=heading[name=/hello world/i][level=2]
Query an element that matches the role selector. Note that the selector doesn't have the role=
or role/
prefix.
import { query } from 'role-selector';
query(document.body, 'button[name=/button/i]');
Query all the elements that match the role selector. Note that the selector doesn't have the role=
or role/
prefix.
import { queryAll } from 'role-selector';
queryAll(document.body, 'button[name=/button/i]');
Suggest a selector for the element. See promise-based suggestSelector
for more information.
import { suggestSelector } from 'role-selector/browser';
suggestSelector(document.getElementById('button'));
An object with the path of the selector script. You can register it using selectors.register
.
import { selectors } from '@playwright/test';
import { selectorScript } from 'role-selector/playwright-test';
selectors.register('role', selectorScript, { contentScript: true });
The query handler object you can use to register the selector with puppeteer.registerCustomQueryHandler
.
import puppeteer from 'puppeteer';
import { queryHandler } from 'role-selector/puppeteer';
puppeteer.registerCustomQueryHandler('role', queryHandler);
[Experimental] suggestSelector(elementHandle: ElementHandle | Promise<ElementHandle> | Locator, options?: Options): Promise<SuggestedSelector>
Given a element handle (either in Playwright or Puppeteer), returns a promise of an object describing the suggested selector to use. The object has the following signature.
interface SuggestedSelector {
type: 'css' | 'role';
selector: string;
};
You can log it when first writing your test, then replace it with the suggested selector. If the suggested selector has type
of role
, remember to prefix your selector with the registered selectorName
(defaults to role=
in Playwright and role/
in Puppeteer).
import { suggestSelector } from 'role-selector/playwright-test';
await suggestSelector(page.$('#button'));
The options has the following type.
interface Options {
strict: boolean;
};
strict
is default to true
to only suggest selector that resolves to only one element. You can disable it to suggest any selector that selects the element by passing false
.