8.9 KiB
id, title, status, assignee, created_date, updated_date, labels, dependencies, references, documentation, modified_files, priority, ordinal
| id | title | status | assignee | created_date | updated_date | labels | dependencies | references | documentation | modified_files | priority | ordinal | |||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ML-182 | Analyze and plan elimination of LiveViewTest usage in favor of PhoenixTest | To Do | 2026-05-14 21:40 | 2026-05-14 21:41 |
|
|
|
|
medium | 10000 |
Description
Audit all LiveView and component tests that use LiveViewTest (either exclusively or mixed with PhoenixTest) and determine which can be converted to use only PhoenixTest. The project's ConnCase auto-imports both PhoenixTest (full) and Phoenix.LiveViewTest (subset via only:), creating a dual-framework testing situation. The goal is to reduce complexity by eliminating LiveViewTest usage where possible.
An initial analysis of 17 files has been completed. The task is to refine this analysis and produce a concrete migration plan with cost estimates.
Acceptance Criteria
- #1 All 17 files are classified as fully eliminable, partially eliminable, or blocked with clear rationale for each
- #2 Three blocking patterns (send_update/3, send(view.pid), live_isolated) are documented with suggested workarounds
- #3 A concrete migration order is proposed, prioritizing low-risk fully-eliminable files first
- #4 Cost estimates (effort level: low/medium/high) are assigned to each file or group of files
Implementation Notes
Initial Analysis (completed 2026-05-14)
Context
ConnCase auto-imports both frameworks:
PhoenixTest(full) — providesvisit/2,click/2,fill_in/2,assert_has/3,refute_has/3,assert_path/2,trigger_hook/3,upload/2,unwrap/2, etc.Phoenix.LiveViewTest(subset viaonly:) — providesrender_async/1,render_change/2,render_click/3,render_hook/3,element/2,form/3
Files that need live/2 (not auto-imported) add import Phoenix.LiveViewTest explicitly.
Per-file classification
🟢 Fully eliminable (11 files)
Pattern: live/2 → visit/2, render_click/3 → click/2, render_submit/1 → click_button/2, render_change/2 → fill_in/2, render/1 → assert_has/3, has_element?/2 → assert_has/3/refute_has/3, assert_patch/2 → assert_path/2, page_title/1 → assert_has("title", text: "...")
live/artist_live/show_test.exs—live/2for image edit modal;file_input/3+render_upload/3→ PhoenixTestupload/2live/maintenance_live/index_test.exs— All 11 tests uselive/2+render_click/3. External redirect test needsassert_redirect/2.live/online_store_template_live/index_test.exs— Mixedvisit/2andlive/2.assert_patch/2→assert_path/2.live/record_set_live/index_test.exs— Mixedvisit/2andlive/2.live/record_set_live/show_test.exs— Mixed.render_hook/3has PhoenixTesttrigger_hook/3equivalent.assert_redirect/2→assert_path/2.live/scrobble_live/index_test.exs— Usesunwrap/2bridge pattern, nolive/2. Dropunwrap, use direct PhoenixTest.live/scrobble_live/release_group_show_test.exs— Onelive/2forpage_title/1. Replace withassert_has("title", ...).live/scrobble_live/release_show_test.exs— Same page_title pattern.live/scrobble_rules_live/index_test.exs— Alllive/2. Standard conversion.live/scrobbled_tracks_live/index_test.exs—unwrap/2bridge, nolive/2. Dropunwrap.live/scrobbled_tracks_live/rule_picker_test.exs— Alllive/2. Standard conversion.live/stats_live/top_albums_test.exs— Mixed.live/2for cover URL/badge tests.
🟡 Mostly eliminable (4 files)
Blocked by send(view.pid, message) pattern for testing internal handle_info/2 callbacks.
live/collection_live/index_test.exs— 2 PubSub tests usesend(view.pid, :records_index_changed). 3 cart format tests uselive/2forrender_change/2with nested params.live/wishlist_live/index_test.exs— Same PubSub pattern. Single-item import useslive/2.live_helpers/record_actions_test.exs— One test usessend(view.pid, {Chat, :chats_changed}). Rest are standardlive/2+render_click/3.components/release_test.exs—render_change/2with nested LiveComponent form data.ShowPrintTestsub-module useslive_isolated/3.
🔴 Hard to eliminate (1 file)
components/chat_test.exs—Phoenix.LiveView.send_update(view.pid, Chat, [chunk: ..., done: ..., error: ...])drives the Chat component's internalupdate/2callback directly. This is unit-level LiveComponent testing with no PhoenixTest equivalent. 3 tests in "update/2 streaming state transitions" describe block.
Three blocking patterns
Pattern 1: Phoenix.LiveView.send_update/3 (chat_test.exs)
- Used to test component's
update/2callback with internal state tuples (chunk:,done:,error:) - No PhoenixTest equivalent — PhoenixTest has no concept of LiveComponent PIDs
- Workaround: Rewrite as integration tests through the actual SSE streaming pipeline
- Effort: High (rewrite 3 tests with streaming stub setup)
Pattern 2: send(view.pid, message) (collection_live, wishlist_live, record_actions)
- Used to test
handle_info/2callbacks for PubSub-driven updates - PhoenixTest sessions don't expose LiveView PIDs
- Workaround: Trigger the actual side effects (create records, broadcast via PubSub, interact with Chat component) and use
assert_has/3with timeout - Effort: Medium per affected test (need to verify PhoenixTest sessions pick up out-of-band PubSub updates)
Pattern 3: live_isolated/3 (components/release_test.exs ShowPrintTest)
- Mounts a LiveComponent in isolation to test a specific assign
- PhoenixTest requires full page navigation
- Workaround: Test through parent LiveView (
/collection/:id) withvisit/2 - Effort: Low (2 tests, simple assertion)
Proposed migration order
- Wave 1 (low risk): Drop
unwrap/2bridges —scrobble_live/index_test.exs,scrobbled_tracks_live/index_test.exs - Wave 2 (low risk): Convert
page_title/1tests —scrobble_live/release_group_show_test.exs,scrobble_live/release_show_test.exs - Wave 3 (medium risk): Convert
live/2→visit/2for standard CRUD LiveViews —scrobble_rules_live,online_store_template_live,record_set_live/index,record_set_live/show,scrobbled_tracks_live/rule_picker,maintenance_live - Wave 4 (medium risk): Convert mixed-usage files —
artist_live/show,stats_live/top_albums - Wave 5 (higher risk): Files with
send(view.pid)blockers —collection_live/index,wishlist_live/index,record_actions,components/release - Wave 6 (hardest): Component streaming tests —
components/chat
Cost estimates
| Wave | Effort | Files |
|---|---|---|
| 1 | Low (30 min) | 2 files — mechanical removal of unwrap/2 |
| 2 | Low (15 min) | 2 files — replace page_title/1 |
| 3 | Medium (2-3h) | 6 files — live/2→visit/2, selector adjustments |
| 4 | Medium (1-2h) | 2 files — file_input/3+render_upload/3→upload/2, live/2→visit/2 |
| 5 | Medium-High (3-4h) | 4 files — PubSub workarounds, live_isolated→parent page |
| 6 | High (4-6h) | 1 file — rewrite streaming tests as integration tests |