---
phase: 10-ux-interaction
plan: 05
type: execute
wave: 0
depends_on: []
files_modified:
- frontend/src/components/storage/__tests__/StorageBrowser.skeleton.test.js
- frontend/src/components/layout/__tests__/AppSidebar.empty.test.js
- frontend/src/views/admin/__tests__/AdminAuditView.skeleton.test.js
- frontend/src/views/admin/__tests__/AdminUsersView.skeleton.test.js
- frontend/src/__tests__/keyboard.test.js
- frontend/src/components/layout/__tests__/OsDragOverlay.test.js
- frontend/src/components/storage/__tests__/StorageBrowser.dragmove.test.js
- frontend/src/components/ui/__tests__/dropdown.test.js
autonomous: true
requirements: [UX-02, UX-03, UX-04, UX-05, UX-06, UX-07, UX-08, UX-09, UX-11, UX-13, UX-14]
must_haves:
truths:
- "Wave 0 xfail test stubs exist for every requirement that is implemented in Waves 1-4"
- "Each stub is marked .skip or .todo so the test runner reports unrun tests instead of false greens"
- "Each requirement ID is referenced by at least one stub"
artifacts:
- path: "frontend/src/__tests__/keyboard.test.js"
provides: "Wave 0 xfail stubs for UX-05..08 keyboard shortcuts"
- path: "frontend/src/components/storage/__tests__/StorageBrowser.skeleton.test.js"
provides: "Wave 0 xfail stubs for UX-02 skeleton + UX-13 dropdown teleport"
key_links:
- from: "Each stub describe() block"
to: "Requirement ID in test title or comment"
via: "describe('UX-XX: ...')"
pattern: "describe.*UX-"
---
Create Wave 0 test stubs (Nyquist pattern — RED tests before implementation) for the requirements that are wired in Waves 1-4. This ensures:
1. The test runner reports unrun tests for every requirement (no false greens)
2. Wave 1-4 implementations have a place to "promote" stubs to real assertions
3. Coverage of all 15 phase requirements is provable up-front
This plan covers the 11 requirements NOT covered by Wave 0 foundation plans (10-01..10-04 already include their tests):
- Foundation already covered by their own plans: UX-01 (EmptyState — 10-02), UX-10 (Toast — 10-04), UX-12 (BreadcrumbBar — 10-03), CODE-05 (AppIcon — 10-01)
- This plan covers: UX-02, UX-03, UX-04, UX-05, UX-06, UX-07, UX-08, UX-09, UX-11, UX-13, UX-14
Output: 8 stub test files, each with `it.skip` or `it.todo` placeholders annotating the requirement IDs and expected behavior. Wave 1-4 implementing plans will replace `.skip`/`.todo` with real tests.
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
@CLAUDE.md
@.planning/phases/10-ux-interaction/10-CONTEXT.md
@.planning/phases/10-ux-interaction/10-RESEARCH.md
@.planning/phases/10-ux-interaction/10-VALIDATION.md
@frontend/src/components/folders/__tests__/FolderBreadcrumb.test.js
Vitest stubs use `it.todo('description')` or `it.skip('description', ...)`. Each stub file should `describe('UX-XX: requirement summary', ...)` with one or more `it.todo` placeholders for the behaviors that Wave 1-4 will implement.
Test file locations (mirror the source structure):
- `frontend/src/components/storage/__tests__/StorageBrowser.skeleton.test.js` — UX-02 (skeleton rows) + UX-13 (folder picker dropdown)
- `frontend/src/components/storage/__tests__/StorageBrowser.dragmove.test.js` — UX-11 (drag-to-move toast trigger + ring highlight)
- `frontend/src/components/layout/__tests__/AppSidebar.empty.test.js` — UX-03 (sidebar skeleton + empty micro states) + UX-14 (sidebar New button removed)
- `frontend/src/views/admin/__tests__/AdminAuditView.skeleton.test.js` — UX-04 (audit log skeleton rows)
- `frontend/src/views/admin/__tests__/AdminUsersView.skeleton.test.js` — UX-04 (users table skeleton rows)
- `frontend/src/__tests__/keyboard.test.js` — UX-05..08 (global keyboard shortcuts)
- `frontend/src/components/layout/__tests__/OsDragOverlay.test.js` — UX-09 (OS file drag overlay depth-counter)
- `frontend/src/components/ui/__tests__/dropdown.test.js` — UX-13 (Teleport+getBoundingClientRect dropdown positioning)
Task 1: Create skeleton + dropdown stubs (UX-02, UX-03, UX-04, UX-13, UX-14)
frontend/src/components/storage/__tests__/StorageBrowser.skeleton.test.js,
frontend/src/components/layout/__tests__/AppSidebar.empty.test.js,
frontend/src/views/admin/__tests__/AdminAuditView.skeleton.test.js,
frontend/src/views/admin/__tests__/AdminUsersView.skeleton.test.js,
frontend/src/components/ui/__tests__/dropdown.test.js
- frontend/src/components/folders/__tests__/FolderBreadcrumb.test.js (style reference)
- .planning/phases/10-ux-interaction/10-VALIDATION.md (test map)
- .planning/phases/10-ux-interaction/10-RESEARCH.md §"Pitfall 7: Skeleton Row Height" and §"Component Inventory §2: Dropdown Clipping Audit"
Create 5 stub test files. Each file is a single `describe('UX-XX: requirement', ...)` block with `it.todo(...)` entries. Use `import { describe, it } from 'vitest'` at the top.
**File A — `frontend/src/components/storage/__tests__/StorageBrowser.skeleton.test.js`:**
```
import { describe, it } from 'vitest'
describe('UX-02: StorageBrowser shows skeleton rows during loading', () => {
it.todo('renders 5+ skeleton rows when loading=true (replaces Loading… text)')
it.todo('skeleton rows use grid-cols-[2rem_1fr_6rem_8rem_6rem] matching real row grid')
it.todo('skeleton rows use animate-pulse')
it.todo('Loading… text is absent when loading=true (skeleton replaces it)')
})
describe('UX-13: StorageBrowser folder picker uses Teleport + getBoundingClientRect', () => {
it.todo('folder picker dropdown is teleported to body (escapes overflow container)')
it.todo('dropdown position reflects getBoundingClientRect of the trigger button')
it.todo('window scroll while open recalculates position')
})
```
**File B — `frontend/src/components/layout/__tests__/AppSidebar.empty.test.js`:**
```
import { describe, it } from 'vitest'
describe('UX-03: AppSidebar shows skeleton placeholders while loading', () => {
it.todo('renders skeleton rows in folder section when loadingRoots=true')
it.todo('renders skeleton rows in topics section when topicsStore.loading=true')
it.todo('renders skeleton rows in cloud section when loadingCloudConnections=true')
it.todo('Loading… text is removed from all three sections')
})
describe('UX-01 (sidebar micro): EmptyState size=sm appears when each section is empty', () => {
it.todo('folders empty: EmptyState size=sm with icon=folder')
it.todo('topics empty: EmptyState size=sm with icon=tag')
it.todo('cloud empty: EmptyState size=sm with icon=cloud and a Settings link in #cta')
})
describe('UX-14: AppSidebar no longer renders an inline "New" folder button', () => {
it.todo('no