This strategy uses a textual representation of the view hierarchy, focusing on just the information that is relevant for VoiceOver. (Related work: AccessibilitySnapshot is a visual snapshot-test tool for a similar use case.)
import SnapshotTesting import AccessibilityTextSnapshot assertSnapshot( // SnapshotTesting gives you this... matching: someView, as: .recursiveA11yDescription) // ... but AccessibilityTextSnapshot gives you this
This generates a recursive (textual) description of all voiceover-relevant information, suitable for snapshot testing.
The string shows
- all UIView subclasses with isAccessibilityElement true, together with their ancestor UIViews (if any) to show hierarchy
- their voiceover-relevant properties (accessibilityValue, accessibilityLabel, etc)
- any a11y-relevant subviews they might have, prefixed by
|to emphasise that they are not involved in VoiceOver
It does not show UIImageViews, which we maybe should reconsider at some point.
* UIView // non-a11y view but has a11y-relevant descendant * UIScrollView // (same) * UIView // (same) * UIStackView // ... * MDViewLayer.ElementView * UIStackView * MDViewModels.Label // | hanging from this view means it has a11y-relevant stuff | -label: Relaxation exercises // a11y property | -traits: .staticText // a11y property * UIStackView * MDViewLayer.MultilineButton | -label: Yes | -hint: Unselected option | -traits: .button * MDViewLayer.MultilineButton | -label: No | -hint: Unselected option | -traits: .button * MDViewLayer.ConversationListItemView // hanging | means a11y-relevant view | -label: Only you. No messages yet // a11y property | -hint: Open conversation // a11y property | * UIStackView // subviews that would be a11y-relevant | * UIStackView // BUT are not read by VoiceOver because | * UIStackView // the parent view overrides, note leading | | * MDViewModels.Label | | -label: Only you | * UIStackView | * MDViewModels.Label | | -label: No messages yet. | * MDViewLayer.Button | * UIView | * MDViewModels.Label | | -label: Ongoing video call o MDViewLayer.StepValidationView // o means isHidden=true (on self or a parent) o -label: Please correct the errors above. Actions available o -action: Go to first error // We still show it because we want to o * MDViewLayer.MultilineButton // be reminded that there *could* be something! o | -label: Please correct the errors above
Installing with CocoaPods
target 'MyAppTests' do pod 'AccessibilityTextSnapshot' end