Use executors to test screen reader interactions
Learn how to use executors to automate screen reader gestures, capture spoken output, and add accessibility assertions.
Screen Reader Automation is currently in the Beta phase and is available on Android and iOS devices under the Ultimate plan. To get access, contact BrowserStack Support. For more details on the Ultimate plan, check the pricing page.
With BrowserStack App Accessibility, you can automate screen reader accessibility testing by simulating screen reader interactions, capturing screen reader output, and validating accessibility metadata directly within your test scripts. This guide helps you get started with setting up and using Screen Reader Automation on Android and iOS.
How screen reader automation works
BrowserStack provides the browserstack_executor command, which gives you granular control over the screen reader environment within your tests. It is a custom extension that lets your test scripts send commands to control the screen reader on real BrowserStack devices.
The command can be used only with Appium. However, it is language-agnostic and can be used in any Appium-supported language to run tests on BrowserStack real devices.
This feature provides the following capabilities:
- Programmatic control: Enable and disable the screen reader directly from your test scripts.
- Gesture simulation: Programmatically simulate common accessibility gestures, such as moving between elements, activating an element, or scrolling.
- Real output capture: Capture the screen reader’s actual spoken output as plain text.
- Assertions: Use the captured spoken output to add assertions in your test scripts, so your app meets accessibility standards.
The following video provides an overview of the Screen Reader Automation executor’s capabilities:
Supported platforms and screen readers
You can automate screen reader accessibility testing on the following platforms and their corresponding screen readers:
| Platform | Screen Reader |
|---|---|
| Android | TalkBack |
| iOS | VoiceOver |
Set up screen reader automation
To set up screen reader automation, execute interactions, and add assertions, select your platform and follow the corresponding steps.
Implement screen reader automation
Integrate the browserstack_executor command into your test scripts to enable or disable the screen reader, simulate screen reader gestures, or capture spoken output.
Enable or disable the screen reader
Use the screenReader action to enable or disable TalkBack.
- To enable TalkBack:
driver.execute_script("browserstack_executor: {\"action\":\"screenReader\",\"arguments\": {\"enable\" : \"true\"}}"); - To disable TalkBack:
driver.execute_script("browserstack_executor: {\"action\":\"screenReader\",\"arguments\": {\"enable\" : \"false\"}}");
Simulate screen reader gestures
Use the screenReaderGesture action to simulate common screen reader gestures, such as navigate, activate, or scroll.
- To simulate a navigate next gesture:
driver.execute_script("browserstack_executor: {\"action\":\"screenReaderGesture\",\"arguments\": {\"gesture\" : \"navigate_next\"}}"); - To simulate an activate gesture:
driver.execute_script("browserstack_executor: {\"action\":\"screenReaderGesture\",\"arguments\": {\"gesture\" : \"activate_item\"}}"); - To simulate a scroll down gesture:
driver.execute_script("browserstack_executor: {\"action\":\"screenReaderGesture\",\"arguments\": {\"gesture\" : \"scroll_down\"}}");
List of supported gestures
The following gestures are supported for TalkBack automation:
Gestures supported on both Android and iOS use the same argument names, so you can reuse them across platforms. Gestures supported on iOS only aren’t available on Android.
| Gesture | Argument |
|---|---|
| Move focus to next element | "navigate_next" |
| Move focus to previous element | "navigate_previous" |
| Activate focused element | "activate_item" |
| Scroll down | "scroll_down" |
| Scroll up | "scroll_up" |
| Navigate back | "back" |
| Return to home screen | "home" |
Capture spoken output
Use the screenReaderSpokenDescription action to capture the spoken output of a specific UI element. Identify the element in one of the following ways:
-
resourceId: the resource ID of the element. -
rect: the coordinates of the element’s bounding box.
Use coordinates when the element has no resource ID. Elements often have no resource ID in apps built with Jetpack Compose, where a semantics tree describes the UI instead. If you don’t specify either identifier, the command returns the spoken output for all elements captured by the screen reader.
- To capture the spoken output by resource ID:
driver.execute_script("browserstack_executor: {\"action\":\"screenReaderSpokenDescription\",\"arguments\": {\"resourceId\" : \"<your-element-resource-id>\"}}") - To capture the spoken output by coordinates:
driver.execute_script("browserstack_executor: {\"action\":\"screenReaderSpokenDescription\",\"arguments\": {\"rect\" : {\"x\": <x-coordinate>, \"y\": <y-coordinate>, \"width\": <width>, \"height\": <height>}}}")
You can’t pass an XPath expression to the browserstack_executor command. XPath is an Appium locator, not an Android accessibility attribute, so the screen reader can’t resolve XPath. To target an element you locate by XPath, read the element’s coordinates in your test script. Pass those coordinates in the rect argument.
The command groups the spoken output by the identifier you use. The following example shows the output when you use both identifiers to target the same element:
{
"spoken_description": {
"by_resource_id": {
"com.example.app:id/sign_in": ["Sign In, Button, Double-tap to activate"]
},
"by_rect": {
"70 1171 1010 1297": ["Sign In, Button, Double-tap to activate"]
}
}
}
Output you request by resource ID appears under by_resource_id. Output you request by coordinates appears under by_rect, listed under the element’s bounds in the form left top right bottom. You can log this output, use it for assertions, or save it to a file for offline review.
If you pass neither identifier, the command returns the spoken output for every captured element, listed under both by_resource_id and by_rect. You get the same full output when you pass a resource ID for an element that has no accessibility metadata. Use the output to debug missing accessibility labels or an incorrect focus order.
Add accessibility assertions
With the captured screen reader data, you can add assertions to your test scripts. This lets you verify critical accessibility aspects:
- Focusability: Verify that all relevant UI elements receive focus and are reachable by the screen reader.
- Spoken output verification: Check that elements expose the correct accessibility metadata to screen readers, such as labels, roles, and hints, and that the actual spoken output matches your expected accessibility label or announcement.
- Traversal order: Record the screen reader traversal sequence. Compare it to the Accessibility Tree or a visual test to confirm the focus order follows a logical reading flow.
Enable assertions
You can enable assertions in your test scripts by using the browserstack_executor command with the screenReaderSpokenDescription action to capture the spoken output of a specific UI element and verify it against your expected values.
To enable assertions using resourceId:
driver.execute_script("browserstack_executor: {\"action\":\"screenReaderSpokenDescription\",\"arguments\": {\"resourceId\" : \"<your-element-resource-id>\"}}");
You can also enable assertions with rect by passing the element’s coordinates.
Example assertion
-
Spoken output verification:
The following example captures the spoken output of an element by its resource ID and asserts that the output matches the expected description:print("Getting spoken text of element\n") out = driver.execute_script("browserstack_executor: {\"action\":\"screenReaderSpokenDescription\",\"arguments\": {\"resourceId\" : \"<your-element-resource-id>\"}}"); expected_description = "Master Switch, ON" actual_description = out['spoken_description']['by_resource_id']['<your-element-resource-id>'][0] if actual_description == expected_description puts "Assertion Passed: Spoken description is correct." else raise "Assertion Failed: Expected '#{expected_description}', but got '#{actual_description}'" end
To assert on the output for an element you captured by its coordinates, use by_rect instead, for example out['spoken_description']['by_rect']['<left> <top> <right> <bottom>'][0]. Take the left top right bottom values from the captured output, as shown in Capture spoken output.
We're sorry to hear that. Please share your feedback so we can do better
Contact our Support team for immediate help while we work on improving our docs.
We're continuously improving our docs. We'd love to know what you liked
We're sorry to hear that. Please share your feedback so we can do better
Contact our Support team for immediate help while we work on improving our docs.
We're continuously improving our docs. We'd love to know what you liked
Thank you for your valuable feedback!