Part 5b: Iteration — Test Every Element of a Kind
Permalink to Part 5b: Iteration — Test Every Element of a KindSome accessibility checks are audit-shaped, not flow-shaped: "every image has
alt text," "every link inside the breadcrumb has an accessible name," "after
pressing Ctrl+A every option in the listbox is selected." The scope.for_each
field promotes a single use case into an iteration over a collection of
elements; the self token refers to the current iteration element.
id: every-image-has-alt
title: 'Every image on the page has an accessible name'
type: positive
start_location: 'https://example.com'
expected_result: 'No image lacks alt text'
scope:
for_each: 'role "img"' # iterate every element with role="img"
steps:
- locate: self
- verify: self attribute "alt" present
for_each accepts a relaxed target form. The accessible-name modifier is
optional (you usually want to iterate all elements of a role, not one):
scope:
for_each: 'role "img"' # custom-role form, no name
# equivalent:
# for_each: image # curated-token shorthand
# for_each: 'image "Logo"' # narrow to images named "Logo"
Scoping iteration to a parent region
Permalink to Scoping iteration to a parent regionWithout scoping, "every link in the breadcrumb" iterates every link on the page
— wrong scope, but a passing test still masks the mistake. Use within (or its
synonym inside) to scope the iteration:
scope:
for_each: 'link within navigation "Breadcrumb"'
# equivalent:
# for_each: 'link inside navigation "Breadcrumb"'
# for_each: 'role "option" within role "listbox" name "Tags"'
Terminal aggregate assertions
Permalink to Terminal aggregate assertionsAfter all iterations complete, the runner builds an iteration_summary with
total, passed, failed, and inapplicable counts. Assert against those
aggregates with a terminal verify: iteration_summary.<field> is N step — these
are pulled out of the iteration body and evaluated after iteration
completes:
scope:
for_each: 'option within listbox "Tags"'
steps:
- locate: self
- keyboard: 'Control+a'
- verify: self attribute "aria-selected" is "true"
- verify: iteration_summary.failed is 0 # terminal — runs once after iteration
If for_each resolves to zero elements, the case is reported as
inapplicable (not as a failure) — iteration_summary.inapplicable = 1.