···11+# Testing Strategy
22+33+Audit of the presentation layer and evaluation of visual testing tooling to
44+improve test coverage, reduce code duplication, and establish a golden testing
55+baseline.
66+77+## Presentation Layer Audit
88+99+A full audit of `lib/features/*/presentation/` identified significant
1010+duplication across 40+ files. The findings group into ten categories.
1111+1212+### 1. Duplicated Utility Functions
1313+1414+| Function | Pattern | Occurrences |
1515+| ----------------------- | ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- |
1616+| `_initials(String)` | Generates initials from display name | 10 files (post_card, grid_post_card, post_embed_view, notification items, suggested_follows, labeler_detail, moderation_settings, search, hashtag) |
1717+| `_formatCount(int)` | Formats numbers with K/M suffixes | 5 files (post_action_bar, post_card_footer, starter_pack_card, starter_pack_detail, profile_screen) |
1818+| `_formatTime(DateTime)` | Relative time strings ("2h ago") | 4 files (notification items, search, hashtag) — overlaps with `formatPostTime()` in post_card_footer |
1919+2020+**Target**: Extract to `lib/shared/utils/format_utils.dart`.
2121+2222+### 2. Duplicated Widgets
2323+2424+**Avatar display** — 14 files repeat `CircleAvatar` / `ModeratedAvatar` with
2525+identical styling. Extract to a configurable `ProfileAvatar` widget.
2626+2727+**Author name + handle** — Repeated two-line text widget (displayName / @handle)
2828+in post_card, grid_post_card, post_embed_view, convo_list_item. Extract to
2929+`ActorNameWidget`.
3030+3131+**Greyscale color filter** — Identical 4x5 color matrix defined in
3232+grid_post_card and profile_screen. Extract to `lib/core/theme/color_filters.dart`.
3333+3434+**Notification reason icon** — Large switch statement mapping notification
3535+reasons to icons/colors duplicated identically in notification_list_item and
3636+grouped_notification_list_item. Extract to `NotificationIconMapper`.
3737+3838+### 3. Bottom Sheets & Dialogs
3939+4040+**Modal bottom sheets** — 9 files repeat `showModalBottomSheet` with ListTile
4141+option lists. Create `OptionsSheet` builder.
4242+4343+**Confirmation dialogs** — 26 occurrences of AlertDialog with
4444+title/content/cancel/confirm. Create `ConfirmationDialog(title, content,
4545+confirmLabel, onConfirm)`.
4646+4747+### 4. State Handling Patterns
4848+4949+**Loading** — `Center(child: CircularProgressIndicator())` in 8+ screens.
5050+**Error with retry** — Center + error message + retry button in 8+ screens.
5151+**Empty state** — Center + message + optional action in multiple screens.
5252+5353+Create `LoadingState`, `ErrorState(message, onRetry)`, `EmptyState(message,
5454+icon, action)` widgets in `lib/shared/presentation/widgets/`.
5555+5656+### 5. SnackBar Display
5757+5858+`ScaffoldMessenger.of(context).showSnackBar(SnackBar(..., behavior:
5959+floating))` appears in 14 files. Create `showAppSnackBar(context, message,
6060+{isError})` helper.
6161+6262+### 6. Theme Access Boilerplate
6363+6464+`Theme.of(context).colorScheme.*` appears 142 times across 27 files.
6565+`Border.all(color: colorScheme.outlineVariant)` is the most common repeated
6666+decoration. Consider a `BuildContext` extension:
6767+6868+```dart
6969+extension ThemeX on BuildContext {
7070+ ColorScheme get colorScheme => Theme.of(this).colorScheme;
7171+}
7272+```
7373+7474+### 7. Spacing Constants
7575+7676+`EdgeInsets.symmetric(horizontal: 16)` appears 34+ times. `SizedBox(height: 8)`
7777+and variants repeat throughout. Define constants in
7878+`lib/core/theme/spacing.dart`.
7979+8080+### 8. Navigation Helpers
8181+8282+Profile navigation (`GoRouter.maybeOf(context)?.push('/profile/view?actor=...')`)
8383+repeated across post cards and notification items. Extract to route helper
8484+functions.
8585+8686+### 9. Haptic Feedback
8787+8888+17 occurrences of `HapticFeedback.mediumImpact()` across 6 files. Minor, but a
8989+`HapticHelper` would centralize.
9090+9191+### 10. List Item Tiles
9292+9393+23 occurrences of ListTile with avatar/title/subtitle across features. A
9494+`BaseListItemTile` could reduce this, though diversity of layouts may limit
9595+reuse.
9696+9797+## Visual Testing Evaluation
9898+9999+### Current State
100100+101101+- 122 test files across 16 feature modules
102102+- Stack: `flutter_test`, `bloc_test`, `mocktail`
103103+- Test types: unit (cubits, repos, services) + widget (screens, widgets)
104104+- **No golden tests, no integration tests, no visual regression testing**
105105+106106+### Widgetbook
107107+108108+Component catalog + visual testing platform for Flutter (v3.22.0 stable,
109109+v4.0.0-beta.3).
110110+111111+| Capability | Detail |
112112+| ----------------- | --------------------------------------------------------- |
113113+| Component catalog | Render widgets in isolation with configurable knobs |
114114+| Visual regression | `widgetbook_golden_test` generates goldens from use cases |
115115+| Widgetbook Cloud | CI visual diffs, platform-independent rendering (paid) |
116116+| Addons | Multi-theme, locale, text scale, device frame testing |
117117+118118+**Verdict: Not recommended for Lazurite at this time.**
119119+120120+Reasons:
121121+122122+- Requires building/maintaining a separate Widgetbook app with use-case
123123+ definitions for every widget — high overhead for a small team
124124+- The project's gap is golden tests and integration tests, not a design catalog
125125+- No dedicated designer reviewing components, so collaborative review value is
126126+ unrealized
127127+- Converting 122 existing widget tests into Widgetbook use cases is low ROI
128128+129129+**When to reconsider**: If a shared design system emerges, a designer joins, or
130130+PR visual review becomes a bottleneck.
131131+132132+### Recommended Approach
133133+134134+**Golden Toolkit** (`golden_toolkit` package) — add visual regression to
135135+existing widget tests with minimal overhead:
136136+137137+- One or two lines per existing test to capture golden snapshots
138138+- No separate app to maintain
139139+- Works with existing `pumpWidget` patterns
140140+- `multiScreenGolden` for multi-device-size snapshots
141141+142142+**Patrol** — consider later if native feature testing (permissions, deep links)
143143+becomes important.
144144+145145+**Built-in integration tests** — add end-to-end flow tests using
146146+`integration_test` package for critical paths (compose, auth, navigation).
147147+148148+### Platform Rendering Note
149149+150150+Golden tests produce platform-dependent pixel output (macOS dev vs Linux CI).
151151+Mitigations:
152152+153153+- Tolerance thresholds in comparisons
154154+- CI-only golden generation with committed baselines
155155+- Or Widgetbook Cloud (if budget allows) for platform-independent rendering