# Years Decoding Bug Fix + Full UI Test Suite ## Part 1: Fix Years Decoding Bug ### Problem Navigating to Cloud → Browse → Years shows "Failed to decode response: The data couldn't be read because it isn't in the correct format." ### Root cause investigation needed The `ChadCategory` model expects `item: String` and `count: Int?`. The `/api/cat/year` endpoint likely returns `item` as a number (e.g., `2012` instead of `"2012"`), causing `JSONDecoder` to fail on the `String` type. ### Fix approach 1. Check what the API actually returns — add temporary logging or use the flexible decoding approach 2. Make `ChadCategory.item` decode flexibly — accept both String and numeric values via custom `init(from decoder:)` 3. Verify all category endpoints work after the fix (artist, genre, year, publisher, country, type, status) ### Acceptance criteria - [ ] Browse → Years loads and displays year items without error - [ ] All other category types still work (artist, genre, publisher, country, type, status) - [ ] Year items display as clean integers (e.g., "2012" not "2012.0") - [ ] Tapping a year navigates to filtered album list (from the previous fix) ### Files to change - `Sources/Models/ChadMusic.swift` — `ChadCategory`: add custom `Decodable` init to handle numeric `item` values --- ## Part 2: UI Test Suite (All Phases) ### Prerequisites Add `accessibilityIdentifier`s to key views: - `CloudBrowserView` — browse section items, stat badges, search field - `CategoryDetailView` — category item rows, error text, loading indicator - `FilteredAlbumListView` — album rows, empty state - `AlbumDetailView` — track rows, play button, album header - `QueueView` — now playing section, user queue items, up next items, clear button - `NowPlayingView` — play/pause, next, previous, progress bar - `MiniPlayerView` — track title, play/pause ### Phase 1: Cloud Browser Smoke Tests (P1 — highest value) 4 test methods: 1. `testCloudHomeLoads` — Cloud tab shows stats + Browse section with all category types 2. `testAllCategoriesLoad` — Each category type loads without error text 3. `testAlbumDetailOpens` — Browse → Albums → tap first album → tracks appear 4. `testCategoryDrillDown` — Browse → Artists → tap first artist → filtered albums appear ### Phase 2: Playback & Queue Tests 4 test methods: 5. `testPlayCloudTrack` — Albums → tap album → tap track → mini player appears with track title 6. `testAddToQueue` — Long-press track → "Add to Queue" → queue view shows entry 7. `testQueuePlayNext` — Long-press track → "Play Next" → queue view shows it at top 8. `testQueueClear` — Add tracks to queue → tap Clear → queue is empty ### Phase 3: CI-Reliable Offline Tests 3 test methods using URLProtocol stubs: 9. `testCloudBrowserWithMockData` — Stub stats + categories → verify UI renders 10. `testDecodingErrorShowsMessage` — Stub malformed JSON → verify error text appears 11. `testAlbumTracksWithMockData` — Stub album tracks → verify track list renders ### Technical approach - **Phase 1-2**: Test against real Chad Music server. Tests require server to be running. Mark with `@MainActor` and use `XCUIApplication` with launch arguments. - **Phase 3**: Use `URLProtocol` subclass registered via `-UITesting` launch argument. App code checks for this flag and registers the stub protocol. - Add `-UITesting` flag handling in app startup to enable test-specific behaviors. ### Files to create/modify - `UITests/MixBoardUITests.swift` — add new test methods - `UITests/CloudBrowserUITests.swift` — new file for cloud browser tests (Phase 1) - `UITests/PlaybackUITests.swift` — new file for playback tests (Phase 2) - `UITests/MockURLProtocol.swift` — new file for URL stubs (Phase 3) - Multiple view files — add accessibilityIdentifier calls ### Appetite - Phase 1: ~4 files changed, ~150 lines new code (tests + accessibility IDs) - Phase 2: ~3 files changed, ~120 lines - Phase 3: ~3 files changed, ~200 lines - Total: reasonable for one builder session ### Constraints - Don't modify existing 20 UI tests - Keep test file organization clean (separate files per test area) - accessibilityIdentifier values must use dot-notation: "cloud.browse.artists", "queue.clearButton", etc. - Tests must compile and pass `xcodebuild test` on iPhone 17 Pro simulator ### Dependencies - Part 1 (Years fix) must be done first — Phase 1 tests will verify it - Chad Music server must be running for Phase 1-2 tests