high priority low complexity testing pending testing specialist Tier 2

Acceptance Criteria

Given a query typed and debounce duration not yet elapsed, when checking emitted events, then no event has been emitted to the output stream
Given a query typed and debounce duration elapsed, when checking emitted events, then exactly one event with the trimmed query string has been emitted
Given rapid successive inputs within the debounce window, when debounce fires, then only one event is emitted corresponding to the last input
Given an input shorter than the minimum query length (e.g., 1 character), when debounce fires, then no event is emitted to the output stream
Given an input of exactly the minimum query length, when debounce fires, then one event is emitted
Given a whitespace-only input (e.g., ' '), when debounce fires, then no event is emitted (whitespace is equivalent to empty after trim)
Given an empty string input, when debounce fires, then no event is emitted
Given the utility is disposed, when close() or dispose() is called, then the output stream closes and no further events are emitted
Given new input after disposal, when emitting to a closed utility, then no exception is thrown (graceful no-op)
All timing assertions must use fake_async — no real Timer.run() calls in tests

Technical Requirements

frameworks
Flutter
Dart
flutter_test
performance requirements
Tests must run without real async delays — use fake_async package to control Timer advancement
Each test case must complete in under 100ms wall-clock time

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Use the `fake_async` package (already a transitive dep via flutter_test) to control time: wrap test bodies in `fakeAsync((async) { ... async.elapse(Duration(milliseconds: 350)); ... })`. Create a StreamController as the input sink and pass it to SearchDebounceUtility, then listen to the utility's output stream to collect emissions.

Verify emission count using `expect(emissions.length, equals(1))` after advancing fake time. For disposal tests, call dispose() then attempt to add more input and verify the output stream emits no further events. Name test files following Flutter convention: `test/utils/search_debounce_utility_test.dart`. Group related tests using nested `group()` calls for readability.

Testing Requirements

Unit tests only using flutter_test and fake_async. Organize tests in a group('SearchDebounceUtility', ...) block with sub-groups for each behavior category: debounce timing, minimum length, whitespace handling, disposal. Use setUp() to create a fresh SearchDebounceUtility instance per test and tearDown() to dispose it. Use StreamQueue or collectAsync to capture stream emissions.

Minimum 12 test cases. Achieve 100% statement and branch coverage on SearchDebounceUtility. Run with: `flutter test test/utils/search_debounce_utility_test.dart`.

Component
Search Debounce Utility
infrastructure low
Epic Risks (2)
medium impact medium prob technical

Cancelling in-flight Supabase HTTP requests via RxDart switchMap may not actually abort the server-side query if the Supabase Dart client does not support request cancellation tokens, leading to wasted API calls and potential race conditions where a slow earlier response arrives after a faster later one.

Mitigation & Contingency

Mitigation: Audit the supabase-flutter client's cancellation support before implementation. Use RxDart switchMap to discard stale emissions even if HTTP cancellation is unavailable, ensuring only the latest result reaches the UI.

Contingency: If race conditions surface in testing, add a query sequence counter to tag each emission and discard any response whose sequence number is lower than the most recently emitted one.

medium impact low prob technical

Connectivity detection used to route between online and offline repositories may have latency or give false positives on flaky connections, causing the service to attempt Supabase queries that time out instead of falling back to the cache promptly.

Mitigation & Contingency

Mitigation: Use a try/catch with a short timeout on Supabase calls. On network error, immediately fall back to the offline repository and emit a cached result with an offline indicator rather than surfacing an error state.

Contingency: If the timeout-based fallback proves insufficient, implement a connection health check stream that pre-validates connectivity before each query batch.