README
extend-to-be-announced
Utility for asserting ARIA live regions.
Validating ARIA live regions with @testing-library
and jest-dom
requires developers to consider implementation details.
Current solutions are prone to false positives.
In test below it is not clearly visible that Loading...
is not actually announced.
Assistive technologies are only expected to announce updates of ARIA live regions with polite
as politeness setting.
render(<div role="status">Loading...</div>);
// Loading should be announced ❌
const statusContainer = screen.getByRole('status');
expect(statusContainer).toHaveTextContent('Loading...');
// Not detected by assistive technologies since content of
// live container was not updated
Instead developers should check that messages are rendered into existing Aria Live Containers.
const { rerender } = render(<div role="status"></div>);
// Status container should be present
const statusContainer = screen.getByRole('status');
// Status container should initially be empty
expect(statusContainer).toBeEmptyDOMElement();
// Update content of live region
rerender(<div role="status">Loading...</div>);
// Loading should be announced ✅
expect(statusContainer).toHaveTextContent('Loading...');
toBeAnnounced
can be used to hide such implementation detail from tests.
const { rerender } = render(<div role="status"></div>);
rerender(<div role="status">Loading...</div>);
expect('Loading...').toBeAnnounced('polite');
Installation
extend-to-be-announced
should be included in development dependencies.
yarn add --dev extend-to-be-announced
Usage
Test setup
Import registration entrypoint in your test setup.
import 'extend-to-be-announced/register';
For setting up registration options use register(options)
method instead.
import { register } from 'extend-to-be-announced';
register({
/** Indicates whether live regions inside `ShadowRoot`s should be tracked. Defaults to false. */
includeShadowDom: true,
});
Assertions
toBeAnnounced
Assert whether given message was announced by ARIA live region. Accepts string or regexp as matcher value.
expect('Loading...').toBeAnnounced();
expect(/loading/i).toBeAnnounced();
expect('Error occured...').toBeAnnounced();
expect(/error occured/i).toBeAnnounced();
Politeness setting of announcement can be optionally asserted.
expect('Loading...').toBeAnnounced('polite');
expect('Error occured...').toBeAnnounced('assertive');
Examples
Render#1 | <div role="status"></div>
Render#2 | <div role="status">Loading</div>
PASS ✅ | expect('Loading').toBeAnnounced('polite');
Render#1 | <div role="alert">Error</div>
PASS ✅ | expect('Error').toBeAnnounced('assertive');
Render#1 | <div></div>
Render#2 | <div role="alert">Error</div>
PASS ✅ | expect('Error').toBeAnnounced();
Render#1 | <div role="status">Loading</div>
FAIL ❌ | expect('Loading').toBeAnnounced();
Render#1 | <div></div>
Render#2 | <div role="status">Loading</div>
FAIL ❌ | expect('Loading').toBeAnnounced();
With register({ includeShadowDom: true })
:
Render#1 | <div role="status">
| #shadow-root
| <div></div>
| </div>
|
Render#2 | <div role="status">
| #shadow-root
| <div>Loading</div>
| </div>
|
PASS ✅ | expect('Loading').toBeAnnounced()
Utilities
getAnnouncements
Get all announcements as Map<string, PolitenessSetting>
.
import { getAnnouncements } from 'extend-to-be-announced';
getAnnouncements();
> Map {
> "Status message" => "polite",
> "Alert message" => "assertive",
> }
clearAnnouncements
Clear all captured announcements.
import { clearAnnouncements } from 'extend-to-be-announced';
clearAnnouncements();
Support
Feature | Status |
---|---|
role |
✅ |
aria-live |
✅ |
aria-atomic |
❌ 👷 |
aria-busy |
❌ |
aria-relevant |
❌ |