···11+# MM-150 Human Test Plan
22+33+**Ticket:** MM-150 — Wallet Home Screen: Identity Overview + Session Status
44+**Implementation plan:** `docs/implementation-plans/2026-03-27-MM-150/`
55+**Generated:** 2026-03-27
66+77+---
88+99+## Prerequisites
1010+1111+- macOS with Xcode installed
1212+- iOS Simulator platform installed (Xcode → Settings → Platforms → iOS)
1313+- Nix dev shell active from the workspace root: `nix develop --impure --accept-flake-config`
1414+- Frontend dependencies installed: `cd apps/identity-wallet && pnpm install`
1515+- Xcode project generated: `cargo tauri ios init`
1616+- A relay instance running and accessible from the simulator (local at `localhost:8080` for debug builds)
1717+- `cargo test -p identity-wallet` passing (all Phase 1 automated tests green)
1818+1919+---
2020+2121+## Phase 2: DIDAvatar Component
2222+2323+| Step | Action | Expected |
2424+|------|--------|----------|
2525+| 2.1 (AC1.5) | Launch the app from a fresh simulator. Complete the full onboarding flow. After the `complete` step, observe the avatar circle in the identity card on the home screen. | A solid-color circle is displayed (not white, not black, not transparent). The color is derived from the DID. |
2626+| 2.2 (AC1.5) | Note the exact color of the avatar circle. Force-quit the app completely. Relaunch the app. | The avatar circle color is identical to what was observed before the force-quit. The hue is deterministic and stable. |
2727+| 2.3 (AC1.6) | On the home screen, read the letter displayed inside the avatar circle. Compare it to the handle shown in the identity card. | The avatar letter is the first character of the handle, uppercased. For example, if the handle is `testuser.test`, the avatar displays `T`. |
2828+| 2.4 (AC1.7) | Create an account where the relay returns `handle.invalid` as the handle (requires mocking or a test account without a registered handle). Navigate to the home screen. | The avatar displays `?` instead of a letter. |
2929+3030+---
3131+3232+## Phase 3: HomeScreen Component
3333+3434+| Step | Action | Expected |
3535+|------|--------|----------|
3636+| 3.1 (AC1.1) | Complete onboarding with a known handle (e.g., `testuser.test`). On the home screen, read the handle in the identity card. | The identity card shows `@testuser.test` (the handle prefixed with `@`). |
3737+| 3.2 (AC1.2) | On the home screen, read the DID string in the identity card. | The DID is displayed as `did:plc:XXXXXXXX…XXXXXX` — the full `did:plc:` prefix is visible, followed by 8 characters, an ellipsis, and 6 characters. |
3838+| 3.3 (AC1.3) | On the home screen, tap the "Copy" button next to the DID. | The button text changes to "Copied!" for approximately 2 seconds, then reverts to "Copy". |
3939+| 3.4 (AC1.3) | After tapping "Copy", switch to the Notes app and paste. | The pasted text is the full, untruncated DID (e.g., `did:plc:abcdefghijklmnopqrstuvwx`), not the truncated display string. |
4040+| 3.5 (AC1.4) | On the home screen, read the email address in the identity card. | The displayed email matches the email used during registration. |
4141+| 3.6 (AC1.8) | Force-quit and relaunch the app (or tap the refresh button). | A loading spinner with "Loading…" text appears briefly before the identity card data renders. |
4242+| 3.7 (AC3.2) | On the home screen, tap "Log Out". | The app navigates to the welcome screen. No identity data is visible on the welcome screen. |
4343+| 3.8 (AC3.8) | After completing standard onboarding (which publishes a DID document), observe the home screen. | The "View DID Document" button is visible. |
4444+| 3.9 (AC3.8) | If `didDoc` is null in the `getSession` response (no published DID document), observe the home screen. | The "View DID Document" button is hidden (not rendered). |
4545+4646+---
4747+4848+## Phase 4: State Machine Wiring
4949+5050+| Step | Action | Expected |
5151+|------|--------|----------|
5252+| 4.1 (AC3.4) | On the home screen, tap "View DID Document" (requires `didDoc` to be non-null). | The app transitions to the DID Document screen. The header reads "DID Document". |
5353+| 4.2 (AC3.9) | On the DID Document screen, tap the "Back" button. | The app returns to the home screen. All identity card data is intact and unchanged. |
5454+| 4.3 (AC3.10) | On the home screen, tap "Recovery Info". | The app transitions to the Recovery Info screen. The header reads "Recovery Info". |
5555+| 4.4 (AC3.14) | On the Recovery Info screen, tap the "Back" button. | The app returns to the home screen. All identity card data is intact and unchanged. |
5656+| 4.5 (AC5.1) | Complete onboarding so OAuth tokens are stored in Keychain. Force-quit the app completely. Relaunch the app. | The app opens directly to the home screen (not the welcome screen). |
5757+| 4.6 (AC5.2 — entry via onboarding) | Complete onboarding. After the `complete` step, the app navigates to home. | The identity card is fully populated (handle, DID, email, avatar, status indicators all present). |
5858+| 4.7 (AC5.2 — entry via relaunch) | Force-quit and relaunch the app after onboarding is complete. | The identity card is fully populated on the home screen (loaded on mount regardless of entry path). |
5959+6060+---
6161+6262+## Phase 5: DIDDocumentScreen Component
6363+6464+| Step | Action | Expected |
6565+|------|--------|----------|
6666+| 5.1 (AC3.5) | Navigate to the DID Document screen (tap "View DID Document" from home). | The screen displays sections: "Identifier" (full DID), "Also Known As" (`at://handle` entries if present), "Verification Keys" (type + truncated `publicKeyMultibase`), "Services" (type + endpoint URL). |
6767+| 5.2 (AC3.6) | On the DID Document screen, tap "Show Raw JSON". | A monospace code block appears showing the full DID document JSON with proper indentation. |
6868+| 5.3 (AC3.6) | Tap "Hide Raw JSON". | The monospace JSON block disappears. The structured view remains. |
6969+| 5.4 (AC3.7) | On the DID Document screen, tap the "Copy" button next to a verification key's `publicKeyMultibase` value. | The button text changes to "Copied!" for approximately 2 seconds. |
7070+| 5.5 (AC3.7) | Switch to Notes or another text-input app and paste. | The pasted text is the full `publicKeyMultibase` string (e.g., `zDnae…`), not the truncated display value. |
7171+7272+---
7373+7474+## Phase 6: RecoveryInfoScreen Component
7575+7676+| Step | Action | Expected |
7777+|------|--------|----------|
7878+| 6.1 (AC3.11) | Complete onboarding (which stores `recovery-share-1` in Keychain). Navigate to Recovery Info from the home screen. | Share 1 row shows a green checkmark icon and text "Saved to iCloud Keychain". |
7979+| 6.2 (AC3.12) | Manually delete `recovery-share-1` from the Keychain (using Xcode Keychain debugging or a test helper). Return to the home screen, refresh, then navigate to Recovery Info. | Share 1 row shows a red X icon and text "Not found in Keychain". |
8080+| 6.3 (AC3.13) | Navigate to Recovery Info. | Share 2 row always shows a green checkmark icon and text "Held by the relay". |
8181+8282+---
8383+8484+## End-to-End Scenarios
8585+8686+### E2E-1: Full Onboarding to Home Screen
8787+8888+**Purpose:** Full user journey from first launch through account creation to the home screen.
8989+9090+| Step | Action | Expected |
9191+|------|--------|----------|
9292+| 1 | Reset the iOS Simulator (Device → Erase All Content and Settings). Launch the app with `cargo tauri ios dev`. | The welcome screen appears. |
9393+| 2 | Complete the full onboarding flow (claim code, email, handle, password, DID ceremony, Shamir backup). | Each step transitions correctly. |
9494+| 3 | After the `complete` step, observe the transition. | The app navigates to the home screen automatically. |
9595+| 4 | Verify the identity card. | Handle (`@handle`), truncated DID (`did:plc:XXXXXXXX…XXXXXX`), email, and colored avatar with handle initial are all displayed. |
9696+| 5 | Verify the status indicators. | Relay shows "Connected" (green dot). Session shows "Active" (green dot). |
9797+| 6 | Verify the action buttons. | "View DID Document", "Recovery Info", and "Log Out" are all visible. |
9898+9999+### E2E-2: Home Screen to DID Document and Back
100100+101101+**Purpose:** DID Document navigation round-trip.
102102+103103+| Step | Action | Expected |
104104+|------|--------|----------|
105105+| 1 | From the home screen, tap "View DID Document". | DID Document screen appears with "DID Document" header. |
106106+| 2 | Verify structured content. | Identifier, verification keys, and services sections are populated. |
107107+| 3 | Tap "Show Raw JSON". | Monospace JSON block appears. |
108108+| 4 | Tap "Hide Raw JSON". | JSON block disappears. |
109109+| 5 | Tap the "Copy" button on a verification key. | Button text changes to "Copied!". |
110110+| 6 | Tap "Back". | Returns to the home screen with all data intact. |
111111+112112+### E2E-3: Home Screen to Recovery Info and Back
113113+114114+**Purpose:** Recovery Info navigation round-trip.
115115+116116+| Step | Action | Expected |
117117+|------|--------|----------|
118118+| 1 | From the home screen, tap "Recovery Info". | Recovery Info screen appears with "Recovery Info" header. |
119119+| 2 | Verify Share 1. | Green checkmark, "Saved to iCloud Keychain". |
120120+| 3 | Verify Share 2. | Green checkmark, "Held by the relay". |
121121+| 4 | Verify Share 3. | Clipboard icon, "Your manual backup". |
122122+| 5 | Tap "Back". | Returns to the home screen with all data intact. |
123123+124124+### E2E-4: Logout and Re-authentication
125125+126126+**Purpose:** Logout clears tokens and returns app to clean state.
127127+128128+| Step | Action | Expected |
129129+|------|--------|----------|
130130+| 1 | From the home screen, tap "Log Out". | App navigates to the welcome screen. |
131131+| 2 | Force-quit and relaunch the app. | Welcome screen appears (not home), confirming tokens were cleared. |
132132+| 3 | Complete the OAuth login flow again. | App navigates to the home screen with fresh session data. |
133133+134134+### E2E-5: App Relaunch with Existing Session
135135+136136+**Purpose:** App launches to home when already onboarded (AC5.1).
137137+138138+| Step | Action | Expected |
139139+|------|--------|----------|
140140+| 1 | Start from a state where onboarding is complete and the home screen is showing. | Home screen displayed. |
141141+| 2 | Force-quit the app. | App terminated. |
142142+| 3 | Relaunch the app. | App opens directly to the home screen (not the welcome screen). |
143143+| 4 | Verify identity card is populated. | Handle, DID, email, and avatar all displayed. |
144144+145145+### E2E-6: Refresh Button
146146+147147+**Purpose:** Refresh button re-fetches data without navigating away.
148148+149149+| Step | Action | Expected |
150150+|------|--------|----------|
151151+| 1 | On the home screen, note the current identity card data. | Data is displayed. |
152152+| 2 | Tap the refresh button (top-right corner). | Loading spinner appears briefly, then data re-renders. |
153153+| 3 | Verify data is unchanged. | Same handle, DID, email, and status indicators as before. |
154154+155155+---
156156+157157+## Traceability Matrix
158158+159159+| Acceptance Criterion | Automated Test | Manual Step |
160160+|----------------------|----------------|-------------|
161161+| MM-150.AC1.1 | — | 3.1 |
162162+| MM-150.AC1.2 | — | 3.2 |
163163+| MM-150.AC1.3 | — | 3.3, 3.4 |
164164+| MM-150.AC1.4 | — | 3.5 |
165165+| MM-150.AC1.5 | — | 2.1, 2.2 |
166166+| MM-150.AC1.6 | — | 2.3 |
167167+| MM-150.AC1.7 | — | 2.4 |
168168+| MM-150.AC1.8 | — | 3.6 |
169169+| MM-150.AC2.1 | `load_home_data_relay_healthy_true_when_health_returns_200` | — |
170170+| MM-150.AC2.2 | `load_home_data_relay_healthy_false_when_health_fails` | — |
171171+| MM-150.AC2.3 | `load_home_data_session_populated_when_get_session_succeeds` | — |
172172+| MM-150.AC2.4 | `load_home_data_session_null_when_get_session_fails` | — |
173173+| MM-150.AC2.5 | `relay_healthy_false_when_health_fails` + `session_null_when_get_session_fails` | — |
174174+| MM-150.AC3.1 | `log_out_deletes_oauth_and_did_from_keychain` | — |
175175+| MM-150.AC3.2 | — | 3.7 |
176176+| MM-150.AC3.3 | `log_out_preserves_device_and_dpop_keys` | — |
177177+| MM-150.AC3.4 | — | 4.1 |
178178+| MM-150.AC3.5 | — | 5.1 |
179179+| MM-150.AC3.6 | — | 5.2, 5.3 |
180180+| MM-150.AC3.7 | — | 5.4, 5.5 |
181181+| MM-150.AC3.8 | — | 3.8, 3.9 |
182182+| MM-150.AC3.9 | — | 4.2 |
183183+| MM-150.AC3.10 | — | 4.3 |
184184+| MM-150.AC3.11 | — | 6.1 |
185185+| MM-150.AC3.12 | — | 6.2 |
186186+| MM-150.AC3.13 | — | 6.3 |
187187+| MM-150.AC3.14 | — | 4.4 |
188188+| MM-150.AC4.1 | `load_home_data_relay_healthy_true_when_health_returns_200` | — |
189189+| MM-150.AC4.2 | `load_home_data_session_populated_when_get_session_succeeds` | — |
190190+| MM-150.AC4.3 | `load_home_data_relay_healthy_false_when_health_fails` | — |
191191+| MM-150.AC4.4 | `load_home_data_session_null_when_get_session_fails` | — |
192192+| MM-150.AC4.5 | `load_home_data_no_session_returns_not_authenticated` | — |
193193+| MM-150.AC4.6 | `log_out_deletes_oauth_and_did_from_keychain` | — |
194194+| MM-150.AC4.7 | `log_out_succeeds_when_keychain_items_absent` | — |
195195+| MM-150.AC5.1 | — | 4.5 |
196196+| MM-150.AC5.2 | — | 4.6, 4.7 |