buildanything 1.7.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (222) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +55 -0
  4. package/README.md +71 -61
  5. package/agents/ios-app-review-guardian.md +49 -0
  6. package/agents/ios-foundation-models-specialist.md +46 -0
  7. package/agents/ios-storekit-specialist.md +52 -0
  8. package/agents/ios-swift-architect.md +102 -0
  9. package/agents/ios-swift-search.md +130 -0
  10. package/agents/ios-swift-ui-design.md +104 -0
  11. package/commands/build.md +80 -176
  12. package/commands/fix.md +65 -0
  13. package/commands/setup.md +73 -0
  14. package/commands/ux-review.md +63 -0
  15. package/commands/verify.md +72 -0
  16. package/hooks/session-start +18 -1
  17. package/package.json +5 -2
  18. package/protocols/brainstorm.md +99 -0
  19. package/protocols/build-fix.md +52 -0
  20. package/protocols/cleanup.md +54 -0
  21. package/protocols/design.md +269 -0
  22. package/protocols/eval-harness.md +61 -0
  23. package/protocols/fake-data-detector.md +64 -0
  24. package/protocols/ios-context.md +235 -0
  25. package/protocols/ios-frameworks-map.md +323 -0
  26. package/protocols/ios-phase-branches.md +162 -0
  27. package/protocols/ios-preflight.md +27 -0
  28. package/protocols/metric-loop.md +93 -0
  29. package/protocols/planning.md +87 -0
  30. package/protocols/smoke-test.md +110 -0
  31. package/protocols/verify.md +67 -0
  32. package/protocols/web-phase-branches.md +201 -0
  33. package/skills/ios/_VENDORED.md +60 -0
  34. package/skills/ios/activitykit/LICENSE +131 -0
  35. package/skills/ios/activitykit/SKILL.md +505 -0
  36. package/skills/ios/activitykit/references/activitykit-patterns.md +868 -0
  37. package/skills/ios/app-intents/LICENSE +131 -0
  38. package/skills/ios/app-intents/SKILL.md +494 -0
  39. package/skills/ios/app-intents/references/appintents-advanced.md +1076 -0
  40. package/skills/ios/apple-on-device-ai/LICENSE +131 -0
  41. package/skills/ios/apple-on-device-ai/SKILL.md +505 -0
  42. package/skills/ios/apple-on-device-ai/references/coreml-conversion.md +425 -0
  43. package/skills/ios/apple-on-device-ai/references/coreml-optimization.md +344 -0
  44. package/skills/ios/apple-on-device-ai/references/foundation-models.md +508 -0
  45. package/skills/ios/apple-on-device-ai/references/mlx-swift.md +285 -0
  46. package/skills/ios/ios-26-platform/SKILL.md +53 -0
  47. package/skills/ios/ios-26-platform/references/automatic-adoption.md +161 -0
  48. package/skills/ios/ios-26-platform/references/backward-compat.md +238 -0
  49. package/skills/ios/ios-26-platform/references/liquid-glass.md +255 -0
  50. package/skills/ios/ios-26-platform/references/swiftui-apis.md +277 -0
  51. package/skills/ios/ios-26-platform/references/toolbar-navigation.md +250 -0
  52. package/skills/ios/ios-bootstrap/SKILL.md +98 -0
  53. package/skills/ios/ios-bootstrap/references/apple-docs-mcp-config.md +28 -0
  54. package/skills/ios/ios-bootstrap/references/new-project-dialog.md +41 -0
  55. package/skills/ios/ios-bootstrap/references/xcode-mcp-config.md +29 -0
  56. package/skills/ios/ios-debugger-agent/LICENSE +21 -0
  57. package/skills/ios/ios-debugger-agent/SKILL.md +58 -0
  58. package/skills/ios/ios-debugger-agent/agents/openai.yaml +4 -0
  59. package/skills/ios/ios-entitlements-generator/SKILL.md +47 -0
  60. package/skills/ios/ios-hig/SKILL.md +41 -0
  61. package/skills/ios/ios-hig/references/accessibility.md +81 -0
  62. package/skills/ios/ios-hig/references/content.md +142 -0
  63. package/skills/ios/ios-hig/references/feedback.md +123 -0
  64. package/skills/ios/ios-hig/references/interaction.md +199 -0
  65. package/skills/ios/ios-hig/references/performance-platform.md +129 -0
  66. package/skills/ios/ios-hig/references/privacy-permissions.md +181 -0
  67. package/skills/ios/ios-hig/references/visual-design.md +84 -0
  68. package/skills/ios/ios-info-plist-hardening/SKILL.md +130 -0
  69. package/skills/ios/ios-maestro-flow-author/SKILL.md +68 -0
  70. package/skills/ios/ios-maestro-flow-author/references/input-and-scroll.yaml +17 -0
  71. package/skills/ios/ios-maestro-flow-author/references/modal-and-dismiss.yaml +14 -0
  72. package/skills/ios/ios-maestro-flow-author/references/onboarding-flow.yaml +16 -0
  73. package/skills/ios/ios-maestro-flow-author/references/tab-navigation.yaml +13 -0
  74. package/skills/ios/ios-maestro-flow-author/references/tap-and-assert.yaml +9 -0
  75. package/skills/ios/swift-accessibility/LICENSE +21 -0
  76. package/skills/ios/swift-accessibility/SKILL.md +371 -0
  77. package/skills/ios/swift-accessibility/examples/before-after-appkit.md +446 -0
  78. package/skills/ios/swift-accessibility/examples/before-after-swiftui.md +441 -0
  79. package/skills/ios/swift-accessibility/examples/before-after-uikit.md +464 -0
  80. package/skills/ios/swift-accessibility/references/assistive-access.md +441 -0
  81. package/skills/ios/swift-accessibility/references/display-settings.md +491 -0
  82. package/skills/ios/swift-accessibility/references/dynamic-type.md +420 -0
  83. package/skills/ios/swift-accessibility/references/media-accessibility.md +421 -0
  84. package/skills/ios/swift-accessibility/references/motor-input.md +393 -0
  85. package/skills/ios/swift-accessibility/references/nutrition-labels.md +362 -0
  86. package/skills/ios/swift-accessibility/references/platform-specifics.md +515 -0
  87. package/skills/ios/swift-accessibility/references/semantic-structure.md +585 -0
  88. package/skills/ios/swift-accessibility/references/testing-auditing.md +507 -0
  89. package/skills/ios/swift-accessibility/references/voice-control.md +317 -0
  90. package/skills/ios/swift-accessibility/references/voiceover-swiftui.md +584 -0
  91. package/skills/ios/swift-accessibility/references/voiceover-uikit.md +519 -0
  92. package/skills/ios/swift-accessibility/references/wcag-mapping.md +167 -0
  93. package/skills/ios/swift-accessibility/resources/audit-template.swift +128 -0
  94. package/skills/ios/swift-accessibility/resources/qa-checklist.md +258 -0
  95. package/skills/ios/swift-concurrency/LICENSE +21 -0
  96. package/skills/ios/swift-concurrency/SKILL.md +171 -0
  97. package/skills/ios/swift-concurrency/references/_index.md +50 -0
  98. package/skills/ios/swift-concurrency/references/actors.md +660 -0
  99. package/skills/ios/swift-concurrency/references/async-algorithms.md +847 -0
  100. package/skills/ios/swift-concurrency/references/async-await-basics.md +266 -0
  101. package/skills/ios/swift-concurrency/references/async-sequences.md +710 -0
  102. package/skills/ios/swift-concurrency/references/core-data.md +560 -0
  103. package/skills/ios/swift-concurrency/references/glossary.md +135 -0
  104. package/skills/ios/swift-concurrency/references/linting.md +155 -0
  105. package/skills/ios/swift-concurrency/references/memory-management.md +569 -0
  106. package/skills/ios/swift-concurrency/references/migration.md +1104 -0
  107. package/skills/ios/swift-concurrency/references/performance.md +593 -0
  108. package/skills/ios/swift-concurrency/references/sendable.md +598 -0
  109. package/skills/ios/swift-concurrency/references/tasks.md +636 -0
  110. package/skills/ios/swift-concurrency/references/testing.md +592 -0
  111. package/skills/ios/swift-concurrency/references/threading.md +495 -0
  112. package/skills/ios/swift-security-expert/LICENSE +21 -0
  113. package/skills/ios/swift-security-expert/SKILL.md +470 -0
  114. package/skills/ios/swift-security-expert/references/biometric-authentication.md +565 -0
  115. package/skills/ios/swift-security-expert/references/certificate-trust.md +592 -0
  116. package/skills/ios/swift-security-expert/references/common-anti-patterns.md +690 -0
  117. package/skills/ios/swift-security-expert/references/compliance-owasp-mapping.md +537 -0
  118. package/skills/ios/swift-security-expert/references/credential-storage-patterns.md +721 -0
  119. package/skills/ios/swift-security-expert/references/cryptokit-public-key.md +505 -0
  120. package/skills/ios/swift-security-expert/references/cryptokit-symmetric.md +497 -0
  121. package/skills/ios/swift-security-expert/references/keychain-access-control.md +508 -0
  122. package/skills/ios/swift-security-expert/references/keychain-fundamentals.md +596 -0
  123. package/skills/ios/swift-security-expert/references/keychain-item-classes.md +476 -0
  124. package/skills/ios/swift-security-expert/references/keychain-sharing.md +458 -0
  125. package/skills/ios/swift-security-expert/references/migration-legacy-stores.md +727 -0
  126. package/skills/ios/swift-security-expert/references/secure-enclave.md +539 -0
  127. package/skills/ios/swift-security-expert/references/testing-security-code.md +781 -0
  128. package/skills/ios/swift-testing-expert/LICENSE +21 -0
  129. package/skills/ios/swift-testing-expert/SKILL.md +79 -0
  130. package/skills/ios/swift-testing-expert/references/_index.md +12 -0
  131. package/skills/ios/swift-testing-expert/references/async-testing-and-waiting.md +127 -0
  132. package/skills/ios/swift-testing-expert/references/expectations.md +145 -0
  133. package/skills/ios/swift-testing-expert/references/fundamentals.md +141 -0
  134. package/skills/ios/swift-testing-expert/references/migration-from-xctest.md +127 -0
  135. package/skills/ios/swift-testing-expert/references/parallelization-and-isolation.md +95 -0
  136. package/skills/ios/swift-testing-expert/references/parameterized-testing.md +284 -0
  137. package/skills/ios/swift-testing-expert/references/performance-and-best-practices.md +187 -0
  138. package/skills/ios/swift-testing-expert/references/traits-and-tags.md +114 -0
  139. package/skills/ios/swift-testing-expert/references/xcode-workflows.md +70 -0
  140. package/skills/ios/swiftdata-pro/LICENSE +21 -0
  141. package/skills/ios/swiftdata-pro/SKILL.md +102 -0
  142. package/skills/ios/swiftdata-pro/agents/openai.yaml +10 -0
  143. package/skills/ios/swiftdata-pro/assets/swiftdata-pro-icon.png +0 -0
  144. package/skills/ios/swiftdata-pro/assets/swiftdata-pro-icon.svg +29 -0
  145. package/skills/ios/swiftdata-pro/references/class-inheritance.md +104 -0
  146. package/skills/ios/swiftdata-pro/references/cloudkit.md +10 -0
  147. package/skills/ios/swiftdata-pro/references/core-rules.md +20 -0
  148. package/skills/ios/swiftdata-pro/references/indexing.md +27 -0
  149. package/skills/ios/swiftdata-pro/references/predicates.md +73 -0
  150. package/skills/ios/swiftui-design-principles/AGENTS.md +21 -0
  151. package/skills/ios/swiftui-design-principles/LICENSE +21 -0
  152. package/skills/ios/swiftui-design-principles/README.md +41 -0
  153. package/skills/ios/swiftui-design-principles/SKILL.md +605 -0
  154. package/skills/ios/swiftui-design-principles/metadata.json +10 -0
  155. package/skills/ios/swiftui-liquid-glass/LICENSE +21 -0
  156. package/skills/ios/swiftui-liquid-glass/SKILL.md +95 -0
  157. package/skills/ios/swiftui-liquid-glass/agents/openai.yaml +4 -0
  158. package/skills/ios/swiftui-liquid-glass/references/liquid-glass.md +280 -0
  159. package/skills/ios/swiftui-performance-audit/LICENSE +21 -0
  160. package/skills/ios/swiftui-performance-audit/SKILL.md +111 -0
  161. package/skills/ios/swiftui-performance-audit/agents/openai.yaml +4 -0
  162. package/skills/ios/swiftui-performance-audit/references/code-smells.md +150 -0
  163. package/skills/ios/swiftui-performance-audit/references/demystify-swiftui-performance-wwdc23.md +46 -0
  164. package/skills/ios/swiftui-performance-audit/references/optimizing-swiftui-performance-instruments.md +29 -0
  165. package/skills/ios/swiftui-performance-audit/references/profiling-intake.md +44 -0
  166. package/skills/ios/swiftui-performance-audit/references/report-template.md +47 -0
  167. package/skills/ios/swiftui-performance-audit/references/understanding-hangs-in-your-app.md +33 -0
  168. package/skills/ios/swiftui-performance-audit/references/understanding-improving-swiftui-performance.md +52 -0
  169. package/skills/ios/swiftui-pro/LICENSE +21 -0
  170. package/skills/ios/swiftui-pro/SKILL.md +108 -0
  171. package/skills/ios/swiftui-pro/agents/openai.yaml +10 -0
  172. package/skills/ios/swiftui-pro/assets/swiftui-pro-icon.png +0 -0
  173. package/skills/ios/swiftui-pro/assets/swiftui-pro-icon.svg +29 -0
  174. package/skills/ios/swiftui-pro/references/accessibility.md +13 -0
  175. package/skills/ios/swiftui-pro/references/api.md +39 -0
  176. package/skills/ios/swiftui-pro/references/data.md +43 -0
  177. package/skills/ios/swiftui-pro/references/design.md +31 -0
  178. package/skills/ios/swiftui-pro/references/hygiene.md +9 -0
  179. package/skills/ios/swiftui-pro/references/navigation.md +14 -0
  180. package/skills/ios/swiftui-pro/references/performance.md +46 -0
  181. package/skills/ios/swiftui-pro/references/swift.md +56 -0
  182. package/skills/ios/swiftui-pro/references/views.md +35 -0
  183. package/skills/ios/swiftui-ui-patterns/LICENSE +21 -0
  184. package/skills/ios/swiftui-ui-patterns/SKILL.md +100 -0
  185. package/skills/ios/swiftui-ui-patterns/agents/openai.yaml +4 -0
  186. package/skills/ios/swiftui-ui-patterns/references/app-wiring.md +201 -0
  187. package/skills/ios/swiftui-ui-patterns/references/async-state.md +96 -0
  188. package/skills/ios/swiftui-ui-patterns/references/components-index.md +50 -0
  189. package/skills/ios/swiftui-ui-patterns/references/controls.md +57 -0
  190. package/skills/ios/swiftui-ui-patterns/references/deeplinks.md +66 -0
  191. package/skills/ios/swiftui-ui-patterns/references/focus.md +90 -0
  192. package/skills/ios/swiftui-ui-patterns/references/form.md +97 -0
  193. package/skills/ios/swiftui-ui-patterns/references/grids.md +71 -0
  194. package/skills/ios/swiftui-ui-patterns/references/haptics.md +71 -0
  195. package/skills/ios/swiftui-ui-patterns/references/input-toolbar.md +51 -0
  196. package/skills/ios/swiftui-ui-patterns/references/lightweight-clients.md +93 -0
  197. package/skills/ios/swiftui-ui-patterns/references/list.md +86 -0
  198. package/skills/ios/swiftui-ui-patterns/references/loading-placeholders.md +38 -0
  199. package/skills/ios/swiftui-ui-patterns/references/macos-settings.md +71 -0
  200. package/skills/ios/swiftui-ui-patterns/references/matched-transitions.md +59 -0
  201. package/skills/ios/swiftui-ui-patterns/references/media.md +73 -0
  202. package/skills/ios/swiftui-ui-patterns/references/menu-bar.md +101 -0
  203. package/skills/ios/swiftui-ui-patterns/references/navigationstack.md +159 -0
  204. package/skills/ios/swiftui-ui-patterns/references/overlay.md +45 -0
  205. package/skills/ios/swiftui-ui-patterns/references/performance.md +62 -0
  206. package/skills/ios/swiftui-ui-patterns/references/previews.md +48 -0
  207. package/skills/ios/swiftui-ui-patterns/references/scroll-reveal.md +133 -0
  208. package/skills/ios/swiftui-ui-patterns/references/scrollview.md +87 -0
  209. package/skills/ios/swiftui-ui-patterns/references/searchable.md +71 -0
  210. package/skills/ios/swiftui-ui-patterns/references/sheets.md +155 -0
  211. package/skills/ios/swiftui-ui-patterns/references/split-views.md +72 -0
  212. package/skills/ios/swiftui-ui-patterns/references/tabview.md +114 -0
  213. package/skills/ios/swiftui-ui-patterns/references/theming.md +71 -0
  214. package/skills/ios/swiftui-ui-patterns/references/title-menus.md +93 -0
  215. package/skills/ios/swiftui-ui-patterns/references/top-bar.md +49 -0
  216. package/skills/ios/swiftui-view-refactor/LICENSE +21 -0
  217. package/skills/ios/swiftui-view-refactor/SKILL.md +207 -0
  218. package/skills/ios/swiftui-view-refactor/agents/openai.yaml +4 -0
  219. package/skills/ios/swiftui-view-refactor/references/mv-patterns.md +161 -0
  220. package/skills/ios/widgetkit/LICENSE +131 -0
  221. package/skills/ios/widgetkit/SKILL.md +502 -0
  222. package/skills/ios/widgetkit/references/widgetkit-advanced.md +871 -0
@@ -0,0 +1,507 @@
1
+ # Testing and Auditing
2
+
3
+ Covers Accessibility Inspector, SwiftUI Previews, XCTest / XCUITest, manual testing procedures, and common audit findings — for verifying Accessibility Nutrition Label readiness.
4
+
5
+ ## Contents
6
+ - [Accessibility Inspector (Xcode)](#accessibility-inspector-xcode)
7
+ - [Verifying Accessibility in Xcode](#verifying-accessibility-in-xcode)
8
+ - [XCUITest — Automated Accessibility Testing](#xcuitest--automated-accessibility-testing)
9
+ - [Manual Testing Checklist](#manual-testing-checklist)
10
+ - [Common Audit Findings](#common-audit-findings)
11
+
12
+ ---
13
+
14
+ ## Accessibility Inspector (Xcode)
15
+
16
+ The primary tool for inspecting and auditing accessibility without a real device. Available via Xcode → Open Developer Tool → Accessibility Inspector.
17
+
18
+ ### Inspection Mode
19
+
20
+ Point at any element in the Simulator or on a connected Mac app. Inspector shows:
21
+ - `accessibilityLabel`, `accessibilityHint`, `accessibilityValue`
22
+ - `accessibilityTraits` (button, header, selected, etc.)
23
+ - `accessibilityFrame` (tap target size in points)
24
+ - Container information
25
+
26
+ **Usage:** Click the crosshair icon, then hover over elements in the Simulator. Verify that every element reports the correct label and traits. Confirm tap targets are ≥ 44×44pt.
27
+
28
+ ### Audit Tab
29
+
30
+ Runs automated checks across the current screen.
31
+
32
+ ```
33
+ Accessibility Inspector → Audit → Run Audit
34
+ ```
35
+
36
+ Findings include:
37
+ - Missing labels on interactive elements
38
+ - Low color contrast (compares against WCAG thresholds)
39
+ - Touch targets below 44×44pt
40
+ - Elements with traits that contradict their role
41
+ - Decorative images exposed to accessibility tree
42
+
43
+ **Workflow:** Fix every finding before proceeding to manual testing. Treat high-severity findings as blockers.
44
+
45
+ ### Contrast Checker
46
+
47
+ ```
48
+ Accessibility Inspector → Inspection → Color tab → Use eyedropper
49
+ ```
50
+
51
+ Measures contrast ratio between two colors. Validates against:
52
+ - 4.5:1 for normal text
53
+ - 3:1 for large text and non-text interactive elements
54
+
55
+ Test every color pair: foreground/background for body text, button labels, placeholder text, and state indicators.
56
+
57
+ ### Settings Tab (Simulate Accessibility Settings)
58
+
59
+ Simulate device settings without changing actual device configuration:
60
+ - Increase Contrast
61
+ - Reduce Motion
62
+ - Bold Text
63
+ - Button Shapes
64
+ - Reduce Transparency
65
+ - Grayscale (via Simulator)
66
+ - Dynamic Type sizes
67
+
68
+ ---
69
+
70
+ ## Verifying Accessibility in Xcode
71
+
72
+ Use Xcode's built-in Canvas tools and Accessibility Inspector to test accessibility configurations without writing custom preview code. Many accessibility environment values (`colorSchemeContrast`, `accessibilityReduceMotion`, `accessibilityReduceTransparency`, `accessibilityDifferentiateWithoutColor`) are **read-only** — `.environment()` calls for these values compile but are **silently ignored** at runtime. Use Accessibility Inspector (Settings tab) or Simulator settings instead.
73
+
74
+ ### Xcode Canvas Variants
75
+
76
+ The preview canvas has a **Variants** button (grid icon) at the bottom. Click it to choose:
77
+
78
+ | Variant mode | What it shows |
79
+ |---|---|
80
+ | **Dynamic Type Variants** | Your view rendered at all 12 Dynamic Type sizes side by side — catches clipping, overlap, and truncation |
81
+ | **Color Scheme Variants** | Light and dark mode previews — catches contrast failures and invisible borders |
82
+ | **Orientation Variants** | Portrait + landscape — catches layout breaks |
83
+
84
+ This is the fastest way to visually verify Dynamic Type and Dark Mode without writing any code.
85
+
86
+ ### Xcode Canvas Device Settings
87
+
88
+ The preview canvas has a **Device Settings** button (slider icon) at the bottom. Use it to configure a single preview with:
89
+
90
+ - **Color Scheme**: light / dark
91
+ - **Dynamic Type size**: any of the 12 sizes
92
+ - **Orientation**: portrait / landscape
93
+
94
+ Combine these to test specific scenarios (e.g., dark mode + accessibility large text + landscape).
95
+
96
+ ### Accessibility Inspector — Settings Tab
97
+
98
+ For read-only accessibility settings, use Accessibility Inspector on the Simulator:
99
+
100
+ **Open:** Xcode menu → Open Developer Tool → Accessibility Inspector
101
+
102
+ **Settings tab** — toggle these on the Simulator without changing device settings:
103
+
104
+ | Setting | What it simulates |
105
+ |---|---|
106
+ | Increase Contrast | Tests `colorSchemeContrast == .increased` |
107
+ | Reduce Motion | Tests `accessibilityReduceMotion == true` |
108
+ | Bold Text | Tests `legibilityWeight == .bold` |
109
+ | Reduce Transparency | Tests `accessibilityReduceTransparency == true` |
110
+ | Button Shapes | Tests `accessibilityShowButtonShapes == true` |
111
+ | Grayscale | Tests color-only indicators (via Simulator Color Filters) |
112
+ | Dynamic Type | Adjusts text size on the Simulator |
113
+
114
+ **Workflow:** Enable each setting, then interact with the Simulator to verify your UI adapts correctly.
115
+
116
+ ### Writable environment values for `#Preview`
117
+
118
+ Only these accessibility-related values are writable and work in `#Preview` with `.environment()`:
119
+
120
+ ```swift
121
+ #Preview("Large Text") {
122
+ ProductCardView(product: .sample)
123
+ .environment(\.dynamicTypeSize, .accessibility3)
124
+ }
125
+
126
+ #Preview("Dark Mode") {
127
+ ProductCardView(product: .sample)
128
+ .environment(\.colorScheme, .dark)
129
+ }
130
+ ```
131
+
132
+ For testing adaptive layout breakpoints:
133
+
134
+ ```swift
135
+ #Preview("Before breakpoint") {
136
+ AdaptiveCardView()
137
+ .environment(\.dynamicTypeSize, .xxxLarge)
138
+ }
139
+
140
+ #Preview("After breakpoint") {
141
+ AdaptiveCardView()
142
+ .environment(\.dynamicTypeSize, .accessibility1)
143
+ }
144
+ ```
145
+
146
+ ### What to check for each setting
147
+
148
+ | Setting | Check for |
149
+ |---|---|
150
+ | Dynamic Type (large sizes) | Text clipping, overlapping elements, truncated labels without `...` affordance |
151
+ | Dark Mode | Unreadable text, invisible borders, low-contrast icons |
152
+ | Increase Contrast | Borders/separators visible, text contrast improved |
153
+ | Reduce Motion | No animations playing, state changes still visible via opacity/fade |
154
+ | Grayscale | Status indicators still distinguishable by shape/icon/text |
155
+ | Bold Text | Layout doesn't break with heavier font weights |
156
+
157
+ ---
158
+
159
+ ## XCUITest — Automated Accessibility Testing
160
+
161
+ ### Finding Elements by Accessibility Identifier
162
+
163
+ ```swift
164
+ // Set stable identifiers in production code
165
+ TextField("Search", text: $query)
166
+ .accessibilityIdentifier("searchField")
167
+
168
+ Button("Submit") { submit() }
169
+ .accessibilityIdentifier("submitButton")
170
+
171
+ // Find in UI tests
172
+ func testSearchFlow() throws {
173
+ let app = XCUIApplication()
174
+ app.launch()
175
+
176
+ let searchField = app.textFields["searchField"]
177
+ XCTAssert(searchField.exists, "Search field must exist")
178
+ XCTAssert(searchField.isEnabled, "Search field must be enabled")
179
+
180
+ searchField.tap()
181
+ searchField.typeText("accessibility")
182
+
183
+ let submitButton = app.buttons["submitButton"]
184
+ XCTAssert(submitButton.exists)
185
+ submitButton.tap()
186
+ }
187
+ ```
188
+
189
+ ### Querying by Accessibility Label
190
+
191
+ ```swift
192
+ // Find by label (matches accessibilityLabel)
193
+ let shareButton = app.buttons["Share"]
194
+ XCTAssert(shareButton.exists)
195
+
196
+ // Find by partial label
197
+ let deleteButtons = app.buttons.matching(identifier: "Delete")
198
+ XCTAssert(deleteButtons.count > 0)
199
+ ```
200
+
201
+ ### Printing the Accessibility Tree
202
+
203
+ ```swift
204
+ // Invaluable for debugging — prints full accessible element tree
205
+ func testPrintTree() {
206
+ let app = XCUIApplication()
207
+ app.launch()
208
+ print(app.debugDescription)
209
+ }
210
+ ```
211
+
212
+ ### Verifying Accessibility Properties
213
+
214
+ ```swift
215
+ func testProductCardAccessibility() throws {
216
+ let app = XCUIApplication()
217
+ app.launch()
218
+
219
+ // Verify the card is a single accessible element
220
+ let card = app.otherElements["Product Card"]
221
+ XCTAssert(card.exists)
222
+
223
+ // Verify label is meaningful
224
+ XCTAssertFalse(card.label.isEmpty, "Card must have an accessibility label")
225
+
226
+ // Verify interactive elements have labels
227
+ let favoriteButton = app.buttons["Add to favorites"]
228
+ XCTAssert(favoriteButton.exists, "Favorite button must have correct label")
229
+
230
+ // Verify button is large enough (indirectly via existence and interaction)
231
+ XCTAssert(favoriteButton.isHittable, "Favorite button must be tappable")
232
+ }
233
+ ```
234
+
235
+ ### Testing VoiceOver Navigation Flow
236
+
237
+ ```swift
238
+ func testVoiceOverReadingOrder() {
239
+ let app = XCUIApplication()
240
+ app.launchArguments = ["-UIAccessibilityEnabled", "YES"]
241
+ app.launch()
242
+
243
+ // Swipe through elements and verify order
244
+ // Note: full VoiceOver simulation is limited in XCUITest
245
+ // Use Accessibility Inspector + manual testing for complete VoiceOver verification
246
+ }
247
+ ```
248
+
249
+ ### performAccessibilityAudit() (iOS 17+ / macOS 14+ / tvOS 17+ / watchOS 10+ / visionOS 1+)
250
+
251
+ Runs Accessibility Inspector's audit engine programmatically inside XCUITest. Catches accessibility regressions automatically in CI — no manual inspection needed. Part of the `XCUIAutomation` framework.
252
+
253
+ #### API Signature
254
+
255
+ ```swift
256
+ @MainActor func performAccessibilityAudit(
257
+ for auditTypes: XCUIAccessibilityAuditType = .all,
258
+ _ issueHandler: ((XCUIAccessibilityAuditIssue) throws -> Bool)? = nil
259
+ ) throws
260
+ ```
261
+
262
+ #### Audit Types
263
+
264
+ | Type | What it checks | Platforms |
265
+ |---|---|---|
266
+ | `.contrast` | WCAG contrast ratio (4.5:1 text, 3:1 non-text) | All |
267
+ | `.elementDetection` | Elements missing from the accessibility tree | All |
268
+ | `.hitRegion` | Touch targets smaller than 44×44pt | All |
269
+ | `.sufficientElementDescription` | Missing or empty accessibility labels | All |
270
+ | `.dynamicType` | Text that doesn't scale with Dynamic Type | All |
271
+ | `.textClipped` | Text clipped or truncated at larger sizes | All |
272
+ | `.trait` | Incorrect or missing accessibility traits | All |
273
+ | `.action` | Missing or invalid accessibility actions | macOS only |
274
+ | `.parentChild` | Parent-child relationship issues in the accessibility tree | macOS only |
275
+
276
+ #### XCUIAccessibilityAuditIssue Properties
277
+
278
+ | Property | Type | Description |
279
+ |---|---|---|
280
+ | `auditType` | `XCUIAccessibilityAuditType` | The audit type that flagged this issue |
281
+ | `element` | `XCUIElement?` | The element with the issue (nil if not identifiable) |
282
+ | `compactDescription` | `String` | Short description of the issue |
283
+ | `detailedDescription` | `String` | Full description with remediation guidance |
284
+
285
+ #### Basic Usage — Run All Checks
286
+
287
+ ```swift
288
+ func testAccessibilityAudit() throws {
289
+ let app = XCUIApplication()
290
+ app.launch()
291
+
292
+ // Runs all audit types — fails test on any issue
293
+ try app.performAccessibilityAudit()
294
+ }
295
+ ```
296
+
297
+ #### Filter by Audit Type
298
+
299
+ ```swift
300
+ func testContrastAndLabels() throws {
301
+ let app = XCUIApplication()
302
+ app.launch()
303
+
304
+ // Run only contrast and label checks
305
+ try app.performAccessibilityAudit(for: [.contrast, .sufficientElementDescription])
306
+ }
307
+ ```
308
+
309
+ #### Ignore Known Issues
310
+
311
+ Use the issue handler closure to suppress known issues. Return `true` to ignore an issue, `false` to fail on it. Use `compactDescription` or `detailedDescription` for debugging.
312
+
313
+ ```swift
314
+ func testAccessibilityAuditWithExclusions() throws {
315
+ let app = XCUIApplication()
316
+ app.launch()
317
+
318
+ try app.performAccessibilityAudit(for: .all) { issue in
319
+ // Log issue details for debugging
320
+ print(issue.detailedDescription)
321
+
322
+ // Ignore contrast issues on the splash screen (uses branded colors)
323
+ if issue.auditType == .contrast,
324
+ issue.element?.identifier == "splashLogo" {
325
+ return true
326
+ }
327
+ return false
328
+ }
329
+ }
330
+ ```
331
+
332
+ #### Exclude Specific Audit Types
333
+
334
+ ```swift
335
+ func testAccessibilityAuditExcludingContrast() throws {
336
+ let app = XCUIApplication()
337
+ app.launch()
338
+
339
+ var auditTypes: XCUIAccessibilityAuditType = .all
340
+ auditTypes.remove(.contrast) // Skip contrast checks
341
+
342
+ try app.performAccessibilityAudit(for: auditTypes)
343
+ }
344
+ ```
345
+
346
+ #### Multi-Screen Regression Test
347
+
348
+ Use a UI test like this to audit several important screens in one run.
349
+ The test launches the app, navigates through key flows, and runs `performAccessibilityAudit()` after each navigation step.
350
+ This helps catch common regressions such as missing labels, low contrast, clipped text, small hit regions, and incorrect traits.
351
+
352
+ ```swift
353
+ class AccessibilityRegressionTests: XCTestCase {
354
+ func testFullAccessibilityAudit() throws {
355
+ let app = XCUIApplication()
356
+ app.launch()
357
+
358
+ // Audit the launch screen.
359
+ try app.performAccessibilityAudit()
360
+
361
+ // Navigate to Settings and audit that screen.
362
+ app.tabBars.buttons["Settings"].tap()
363
+ try app.performAccessibilityAudit()
364
+
365
+ // Navigate to Profile and audit that screen.
366
+ app.tabBars.buttons["Profile"].tap()
367
+ try app.performAccessibilityAudit()
368
+ }
369
+ }
370
+ ```
371
+
372
+ This does not replace manual testing with VoiceOver, Voice Control, Switch Control, or real-device checks.
373
+ It only audits the screens the test actually visits, so extend the navigation flow to cover the important user paths in your app.
374
+
375
+ ---
376
+
377
+ ## Manual Testing Checklist
378
+
379
+ ### VoiceOver Testing (Requires Real Device)
380
+
381
+ Enable: Settings → Accessibility → VoiceOver
382
+
383
+ | Test | Pass Criteria |
384
+ |---|---|
385
+ | Swipe right through all elements | Every interactive element is reachable |
386
+ | Tap any element | Label, value, and traits are announced |
387
+ | Double-tap interactive element | Correct action performed |
388
+ | Swipe up/down on adjustable element | Value changes (sliders, steppers) |
389
+ | Two-finger Z gesture on modal | Modal dismisses |
390
+ | Rotor navigation | Headings, links, actions all navigable |
391
+ | "Read All" (two-finger swipe up) | Reads entire screen in logical order |
392
+ | Focus after navigation push | Focus moves to first element in new screen |
393
+ | Focus after modal dismiss | Focus returns to trigger element |
394
+
395
+ **Critical flows to test:**
396
+ 1. Complete main user task start-to-finish with VoiceOver
397
+ 2. Login / account creation
398
+ 3. Key purchase or data-entry flow
399
+ 4. Settings changes
400
+
401
+ ### Voice Control Testing (Requires Real Device)
402
+
403
+ Enable: Settings → Accessibility → Voice Control
404
+
405
+ | Test | Pass Criteria |
406
+ |---|---|
407
+ | "Show numbers" | Every interactive element has a number |
408
+ | "Tap [number]" | Activates correct element |
409
+ | "Show names" | Every element shows a visible text label |
410
+ | "Tap [label]" | Activates element by voice |
411
+ | "Type [text]" | Inserts text in active field |
412
+ | "Select [word]" | Selects matching text |
413
+ | "Delete that" | Deletes selected text |
414
+ | "Scroll down/up" | Scrolls the content |
415
+
416
+ ### Switch Control Testing (Requires Real Device or Setting)
417
+
418
+ Enable: Settings → Accessibility → Switch Control
419
+
420
+ | Test | Pass Criteria |
421
+ |---|---|
422
+ | Item scanning | Every element is highlighted in turn |
423
+ | Group scanning | Related groups highlighted as units |
424
+ | Select highlighted element | Correct action triggered |
425
+ | Custom actions available | Actions appear in scanning menu |
426
+ | No timed interactions | No UI times out or auto-advances |
427
+
428
+ ### Full Keyboard Access (iPad/Mac)
429
+
430
+ Enable: Settings → Accessibility → Keyboards → Full Keyboard Access
431
+
432
+ | Test | Pass Criteria |
433
+ |---|---|
434
+ | Tab key | Focus moves forward through all interactive elements |
435
+ | Shift+Tab | Focus moves backward |
436
+ | Space/Return | Activates focused element |
437
+ | Escape | Dismisses modal / cancels |
438
+ | Arrow keys | Navigates within pickers, sliders |
439
+ | No focus gaps | Focus never gets stuck in a dead zone |
440
+
441
+ ### Dynamic Type
442
+
443
+ Enable: Settings → Accessibility → Display & Text Size → Larger Text → Enable Larger Accessibility Sizes
444
+
445
+ | Size | Test |
446
+ |---|---|
447
+ | Small | Text readable, no clipping |
448
+ | Large (default) | Normal experience |
449
+ | Accessibility Large | Layout adapts, no overlap |
450
+ | Accessibility 5 (max) | All content accessible, nothing truncated without affordance |
451
+
452
+ ### Grayscale (Differentiate Without Color)
453
+
454
+ Enable: Settings → Accessibility → Display & Text Size → Color Filters → Grayscale
455
+
456
+ | Test | Pass Criteria |
457
+ |---|---|
458
+ | Status indicators | Still meaningful in grayscale |
459
+ | Charts and graphs | Data distinguishable by shape/position |
460
+ | Error states | Clearly distinguishable from success |
461
+ | All UI | No information lost in grayscale |
462
+
463
+ ### Reduce Motion
464
+
465
+ Enable: Settings → Accessibility → Motion → Reduce Motion
466
+
467
+ | Test | Pass Criteria |
468
+ |---|---|
469
+ | Navigation transitions | No sliding; dissolve/fade instead |
470
+ | Animations on state change | Either removed or replaced with fade |
471
+ | Auto-playing content | Stopped or manual control provided |
472
+ | Loading animations | Replaced or removed |
473
+
474
+ ### Dark Mode + Increase Contrast
475
+
476
+ Enable: Settings → Appearance → Dark, AND Settings → Accessibility → Display & Text Size → Increase Contrast
477
+
478
+ | Test | Pass Criteria |
479
+ |---|---|
480
+ | All text | Readable against dark background |
481
+ | Borders and separators | Visible |
482
+ | Status indicators | High contrast |
483
+ | Images on dark background | No white halo effect |
484
+
485
+ ---
486
+
487
+ ## Common Audit Findings
488
+
489
+ | Finding | Severity | Detection | Fix |
490
+ |---|---|---|---|
491
+ | Missing label on icon button | Blocks Assistive Tech | Accessibility Inspector → Missing label warning | `.accessibilityLabel("Share")` |
492
+ | Decorative image announced | Degrades Experience | VO reads image name or "image" | `.accessibilityHidden(true)` |
493
+ | Touch target < 44pt | Degrades Experience | Inspector → Accessibility Frame < 44×44 | `.frame(minWidth: 44, minHeight: 44)` or `.contentShape` |
494
+ | State embedded in label | Degrades Experience | Inspector → label changes on toggle | Use `.accessibilityAddTraits(.isSelected)` |
495
+ | Wrong reading order | Degrades Experience | VO navigation mismatches visual | `.accessibilitySortPriority` or `accessibilityElements` |
496
+ | Color-only status indicator | Incomplete Support | Grayscale filter test | Add shape/icon/text redundancy |
497
+ | Text contrast fails dark mode | Incomplete Support | Inspector contrast checker | Use semantic colors, test both modes |
498
+ | Animation with Reduce Motion | Incomplete Support | Enable Reduce Motion, check for motion | Gate `withAnimation` or provide `.opacity` transition |
499
+ | No custom rotor for long lists | Incomplete Support | VoiceOver navigation test | Add `accessibilityRotor` |
500
+ | Modal doesn't trap VoiceOver | Blocks Assistive Tech | VO can reach background content | `accessibilityViewIsModal = true` |
501
+ | No focus movement after push | Degrades Experience | VO stays on previous screen | Post `.screenChanged` after navigation |
502
+ | Custom text truncates at any size | Incomplete Support | Dynamic Type max size test | `fixedSize()` → scroll, or adaptive layout |
503
+ | Missing `accessibilityPerformEscape` | Blocks Assistive Tech | VO two-finger Z doesn't dismiss | Implement `accessibilityPerformEscape()` |
504
+ | Voice Control element missing | Blocks Assistive Tech | "Show numbers" test | Use `Button` or add `.accessibilityTraits(.button)` |
505
+ | Hint describes action not result | Degrades Experience | Listen to VO hint announcement | Rewrite: "Saves your changes" not "Tap to save" |
506
+
507
+ > **Automation tip:** `performAccessibilityAudit()` (iOS 17+) automatically detects missing labels, low contrast, small hit regions, clipped text, missing traits, and Dynamic Type failures. Run it in CI to catch most of these findings before manual testing.