import at_record_web/model.{type ReleaseInfo, Entry, Model, ReleaseInfo, Source} import at_record_web/msg.{ ArmRemove, DisarmRemove, EntryAction, GotTimeline, OnRouteChange, TimelineData, } import at_record_web/pages/record import at_record_web/update.{update} import gleam/dict import gleam/option.{None, Some} import gleam/string import lustre/element import support.{an_entry, logged_in} pub fn record_view_shows_the_sleeve_grade_card_when_present_test() { let html = record.view(logged_in(), an_entry()) |> element.to_string assert string.contains(html, "SLEEVE") assert string.contains(html, "VG+") } pub fn record_view_omits_the_sleeve_grade_card_when_absent_test() { let html = record.view(logged_in(), Entry(..an_entry(), sleeve_grade: None)) |> element.to_string assert !string.contains(html, "SLEEVE") } pub fn record_view_shows_paid_and_from_rows_when_present_test() { let html = record.view(logged_in(), an_entry()) |> element.to_string assert string.contains(html, "PAID") assert string.contains(html, "EUR 40.00") assert string.contains(html, "FROM") assert string.contains(html, "Record shop") } pub fn record_view_omits_paid_and_from_rows_when_absent_test() { let html = record.view( logged_in(), Entry(..an_entry(), price: None, counterparty: None), ) |> element.to_string assert !string.contains(html, "PAID") assert !string.contains(html, "FROM") } pub fn record_view_shows_the_provenance_line_when_source_is_present_test() { let source = Source(origin: Some("scan"), provider: Some("discogs")) let html = record.view(logged_in(), Entry(..an_entry(), source: Some(source))) |> element.to_string assert string.contains(html, "class=\"layer-provenance\"") assert string.contains(html, "scanned ยท via Discogs") } pub fn record_view_shows_added_by_hand_for_manual_source_test() { let source = Source(origin: Some("manual"), provider: None) let html = record.view(logged_in(), Entry(..an_entry(), source: Some(source))) |> element.to_string assert string.contains(html, "added by hand") } pub fn record_view_omits_the_provenance_line_when_source_is_absent_test() { let html = record.view(logged_in(), Entry(..an_entry(), source: None)) |> element.to_string assert !string.contains(html, "class=\"layer-provenance\"") } pub fn arm_remove_then_entry_action_disarms_and_sets_busy_test() { let #(armed, _) = update(logged_in(), ArmRemove) assert armed.confirm_remove == True let #(after, _) = update(armed, EntryAction("e1", "dropped")) assert after.confirm_remove == False assert after.busy == True } // DisarmRemove is what both the outside-click watcher and the auto-disarm // timeout dispatch; neither should touch `busy`. pub fn arm_remove_then_disarm_remove_clears_confirm_without_busy_test() { let #(armed, _) = update(logged_in(), ArmRemove) assert armed.confirm_remove == True let #(after, _) = update(armed, DisarmRemove) assert after.confirm_remove == False assert after.busy == False } // Re-arming (e.g. a tap on REMOVE while already armed) stays armed and still // confirms normally on the next EntryAction; the watcher/timer replacement // that guards against a stale disarm lives in effects.arm_confirm, not here. pub fn rearming_remove_stays_armed_and_still_confirms_test() { let #(armed_once, _) = update(logged_in(), ArmRemove) let #(rearmed, _) = update(armed_once, ArmRemove) assert rearmed.confirm_remove == True let #(after, _) = update(rearmed, EntryAction("e1", "dropped")) assert after.confirm_remove == False assert after.busy == True } fn a_release_info() -> ReleaseInfo { ReleaseInfo( artist_display: Some("Slint"), genres: ["Rock"], styles: ["Math Rock"], country: Some("US"), released: Some("1991"), ) } pub fn got_timeline_with_release_stores_release_info_test() { let #(model, _) = update( logged_in(), GotTimeline(Ok(TimelineData(events: [], release: Some(a_release_info())))), ) assert model.release_info == Some(a_release_info()) } pub fn got_timeline_without_release_leaves_release_info_none_test() { let #(model, _) = update( logged_in(), GotTimeline(Ok(TimelineData(events: [], release: None))), ) assert model.release_info == None } pub fn route_change_clears_release_info_test() { let seeded = model.Model(..logged_in(), release_info: Some(a_release_info())) let #(model, _) = update(seeded, OnRouteChange(model.Crate)) assert model.release_info == None } pub fn record_view_shows_a_copy_share_link_button_with_the_public_path_test() { let html = record.view(logged_in(), an_entry()) |> element.to_string assert string.contains(html, "COPY SHARE LINK") assert string.contains(html, "/u/alice.test/record/e1") } // The fold-out is gone: AMEND/SUGGEST A FIX is now a plain nav link to the // routed amend screen, not a button dispatching a toggle message. pub fn record_view_renders_the_amend_action_as_a_link_to_its_own_route_test() { let html = record.view(logged_in(), an_entry()) |> element.to_string assert string.contains( html, "AMEND", ) } pub fn record_view_labels_the_amend_link_as_suggest_a_fix_for_an_adopted_entry_test() { let via_handles = dict.from_list([#("e1", "bob.test")]) let html = record.view(Model(..logged_in(), via_handles:), an_entry()) |> element.to_string assert string.contains( html, "SUGGEST A FIX", ) }