high priority high complexity testing pending testing specialist Tier 5

Acceptance Criteria

ChapterAffiliationsPanel: test verifies correct number of chapter badges rendered for a member with multiple affiliations
ChapterAffiliationsPanel: each badge's semantic label includes both chapter name and affiliation status
ChapterAffiliationsPanel: SemanticsChecker.check() passes with no warnings after pumpAndSettle
DuplicateActivityWarningDialog: test pumps a widget tree that triggers the dialog and asserts it is present via find.byType(DuplicateActivityWarningDialog)
DuplicateActivityWarningDialog: tapping Confirm button invokes the registered callback and dismisses the dialog
DuplicateActivityWarningDialog: tapping Cancel button dismisses without invoking the confirm callback
DuplicateActivityWarningDialog: audit log invocation callback is called exactly once on confirm
DuplicateActivityWarningDialog: focus is trapped inside the dialog — tabbing does not move focus to elements behind the modal
ChapterAssignmentEditor: entering text in search field filters chapter list to matching items only
ChapterAssignmentEditor: tapping End Affiliation opens the confirmation bottom sheet
ChapterAssignmentEditor: adding a 6th chapter displays the max-chapter banner
All three component tests include a SemanticsChecker.check() assertion after pumpAndSettle
All tests use tester.pumpAndSettle() after interactions and confirm no pending timers remain

Technical Requirements

frameworks
Flutter
flutter_test
BLoC
mockito
data models
ChapterAffiliation
DuplicateActivityWarning
ChapterAssignmentState
AuditLogEntry
performance requirements
No widget test should run longer than 5 seconds including pumpAndSettle
Avoid real async gaps — use FakeAsync or override durations to zero in tests
security requirements
No real Supabase connections in widget tests — all data injected via provider overrides or constructor parameters
ui components
ChapterAffiliationsPanel
DuplicateActivityWarningDialog
ChapterAssignmentEditor
Chapter badge widget
Confirmation bottom sheet

Execution Context

Execution Tier
Tier 5

Tier 5 - 253 tasks

Can start after Tier 4 completes

Implementation Notes

Wrap each test widget in MaterialApp + BlocProvider (or ProviderScope) to satisfy context dependencies. For the DuplicateActivityWarningDialog focus-trap test, note that Flutter's default dialog implementation wraps content in a FocusScope — assert FocusScope.of(context).hasFocus or use FocusManager.instance.primaryFocus to check the active node. For the bottom sheet test, call pumpAndSettle after the tap and use find.byType(ModalBottomSheet) or find.byKey to locate the sheet. Be aware that SemanticsChecker.check() is strict — if the preceding task (task-010) has not been completed and merged, placeholder Semantics may cause failures; ensure the test dependency is honoured in CI ordering.

For search filter tests, wrap the widget with a controlled TextEditingController rather than relying on internal state to make filter assertions deterministic.

Testing Requirements

Write three separate test groups (group() blocks) in a single file or split per component. Each group must call tester.ensureSemantics() at setUp and SemanticsChecker.check(tester) after every pumpAndSettle. For focus-trapping tests in DuplicateActivityWarningDialog, use tester.sendKeyEvent(LogicalKeyboardKey.tab) repeatedly and assert that the focused widget finder always finds a widget inside the dialog subtree. For the search filter test, set the text field value via tester.enterText and assert find.text for non-matching chapters returns findsNothing.

Provide all component dependencies through BlocProvider.value or ProviderScope overrides — never instantiate real services. Target ≥ 85% line coverage across the three widget files.

Component
Chapter Affiliations Panel
ui medium
Epic Risks (3)
high impact medium prob technical

The Duplicate Activity Warning Dialog must announce itself to VoiceOver and TalkBack immediately on appearance. Flutter's default modal semantics do not guarantee focus shift to the dialog on all platform versions, risking silent appearance for screen reader users — a WCAG 2.2 failure.

Mitigation & Contingency

Mitigation: Wrap the dialog content in a Semantics node with liveRegion: true and explicitly request focus via FocusScope.of(context).requestFocus() on the dialog's primary action button in the post-frame callback. Test on physical iOS (VoiceOver) and Android (TalkBack) devices, not only simulators.

Contingency: If automatic focus fails on a specific platform version, add a platform-specific fallback using SemanticsService.announce() to force a live region announcement of the dialog's headline text.

medium impact medium prob technical

The Chapter Membership Cubit tracks pending changes before commit to support the two-step add/confirm flow. If the user navigates away mid-edit or the app is backgrounded, uncommitted pending state could be replayed incorrectly on return, causing phantom affiliation additions or removals.

Mitigation & Contingency

Mitigation: Design the Cubit to hold pending changes only in transient in-memory state with no persistence. On any navigation-away event, emit a reset state that discards pending changes. Prevent accidental navigation during an active edit by showing a discard-changes confirmation dialog.

Contingency: If state desync is reported in production, add an explicit state reconciliation step in the Cubit's onResume handler that re-fetches the authoritative affiliation list from the repository and resets all pending state before re-rendering.

medium impact high prob technical

The Chapter Assignment Editor's searchable chapter list must load quickly. If the organisation has hundreds of chapters (NHF has 1,400 local chapters) and the full list is fetched on dialog open, the editor will be slow to display and the search will be sluggish.

Mitigation & Contingency

Mitigation: Scope the chapter list to only chapters within the coordinator's administrative scope (not all 1,400), leveraging the existing hierarchy access scope service. Implement server-side search with a minimum 2-character threshold and debounce to avoid excessive Supabase queries.

Contingency: If the scoped list is still too large, add local caching of the chapter list with a 15-minute TTL and an explicit refresh button, ensuring the editor is always responsive even on poor network conditions.