agentsclimarketplace

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.

Install
npx -y skills add almasumdev/awesome-mobile-testing-agent-skills --skill accessibility-testing

Assembled 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:

  1. Screen reader sweep. Enable TalkBack / VoiceOver; complete the flow without looking at the screen. Every focusable element must announce a meaningful label.
  2. Dynamic type. Set the OS text size to the largest supported; verify no clipped labels, truncated buttons, or overlapping views.
  3. Contrast. Spot-check with a contrast checker on non-token surfaces (marketing screens, onboarding).
  4. Keyboard / switch control (iPadOS, Android with keyboard). The app must be usable without touch on large-screen surfaces.
  5. 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 a Button without .accessibilityLabel.
  • Dart: flutter analyze + custom lints (missing_contentdescription-style rules via dart_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.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.