Accessibility testing
Skill almasumdev/awesome-mobile-testing-agent-skills/.github/skills/ui/accessibility-testing
Agent skills for unit, widget, UI, and end-to-end testing of mobile apps across platforms.
npx -y skills add almasumdev/awesome-mobile-testing-agent-skills --skill accessibility-testingAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Expert guidance on automated and manual accessibility testing for mobile apps — Espresso AccessibilityChecks, XCTest accessibility audits, Flutter a11y guidelines, RN a11y assertions. Use when adding a11y coverage or when asked how to catch accessibility regressions in CI.
SKILL.md
5.2 KB, as published. Nobody here has run it
Accessibility Testing
Instructions
Accessibility bugs are defects, not polish items. A tap target that is 24 dp square, an icon button with no content description, or a form field unreachable by VoiceOver is a shipped regression. Cover them with automated checks in CI plus a small set of manual heuristics for each critical flow.
1. What Automation Can Catch
Automated scanners reliably catch:
- Missing content descriptions / accessibility labels on interactive elements.
- Contrast ratios below WCAG AA for known text colors.
- Touch targets below the platform minimum (48 dp Android, 44 pt iOS).
- Duplicate or confusing focus order (platform-dependent).
- Form fields without labels.
They do not catch: whether the label makes sense, whether the reading order is logical, whether animations trigger vestibular issues. That is the manual pass.
2. Android — Espresso / Compose
Enable AccessibilityChecks for the whole suite:
@BeforeClass @JvmStatic fun enableA11yChecks() {
AccessibilityChecks.enable().setRunChecksFromRootView(true)
}
For Compose, use SemanticsMatcher and assertContentDescriptionEquals:
composeRule.onNodeWithTag("pay")
.assertContentDescriptionEquals("Pay 19.99 USD")
.assert(hasClickAction())
For Views, AccessibilityNodeInfo assertions are surfaced automatically by AccessibilityChecks — a failing check fails the test.
3. iOS — XCTest Accessibility Audit
iOS 17+ ships a native accessibility audit:
func test_checkout_isAccessible() throws {
let app = XCUIApplication(); app.launch()
app.buttons["openCheckout"].tap()
try app.performAccessibilityAudit() // fails on any violation
}
Scope audits per screen, not per entire app launch — failures are easier to read. For SwiftUI unit-level checks, assert .accessibilityLabel, .accessibilityHint, and .accessibilityTraits on the rendered view hierarchy.
4. Flutter — flutter_test Guidelines
testWidgets('Checkout meets tap-target guidelines', (tester) async {
await tester.pumpWidget(const AppShell(child: CheckoutScreen()));
final handle = tester.ensureSemantics();
await expectLater(tester, meetsGuideline(androidTapTargetGuideline));
await expectLater(tester, meetsGuideline(iOSTapTargetGuideline));
await expectLater(tester, meetsGuideline(textContrastGuideline));
await expectLater(tester, meetsGuideline(labeledTapTargetGuideline));
handle.dispose();
});
Use Semantics(label: ...) wrappers in production code for icon-only widgets.
5. React Native
import { render } from '@testing-library/react-native';
test('Pay button has accessible label', () => {
const { getByRole } = render(<CheckoutScreen />);
const btn = getByRole('button', { name: /pay/i });
expect(btn).toBeTruthy();
expect(btn.props.accessibilityLabel).toBeDefined();
});
For contrast and tap size, rely on design-system tokens that enforce minimums at build time, plus a periodic manual sweep — RN does not have a first-class runtime a11y auditor.
6. Manual Heuristics
For every critical flow, before release:
- Screen reader sweep. Enable TalkBack / VoiceOver; complete the flow without looking at the screen. Every focusable element must announce a meaningful label.
- Dynamic type. Set the OS text size to the largest supported; verify no clipped labels, truncated buttons, or overlapping views.
- Contrast. Spot-check with a contrast checker on non-token surfaces (marketing screens, onboarding).
- Keyboard / switch control (iPadOS, Android with keyboard). The app must be usable without touch on large-screen surfaces.
- Reduce motion. Turn on "Reduce motion" / "Remove animations"; make sure the flow still works and is not disorienting.
7. Linting at Build Time
- Android Lint rules:
ContentDescription,LabelFor,ClickableViewAccessibility. - SwiftLint / custom rule to forbid
Image(systemName:)inside aButtonwithout.accessibilityLabel. - Dart:
flutter analyze+ custom lints (missing_contentdescription-style rules viadart_code_metrics). - RN:
eslint-plugin-react-native-a11y.
Enable these in CI so regressions fail before tests even run.
8. Reporting Violations
Upload the a11y audit JSON (Android) / audit output (iOS) as a CI artifact. When a test fails, the report must name: element, rule, and how to fix (content description / larger target / higher contrast).
9. Checklist
-
AccessibilityChecks.enable()/performAccessibilityAudit()/ Flutter guideline expectations wrap every UI test suite. - Icon-only buttons have labels enforced by lint, not code review.
- Dynamic type, screen reader, and reduce-motion manual sweeps are documented per critical flow.
- Contrast is tested at the design-token level, not on every screen.
- Platform-minimum tap targets (48 dp / 44 pt) are enforced.
- A11y violations fail the build the same as functional test failures.