diff --git a/server/test/crate_overlap_test.gleam b/server/test/crate_overlap_test.gleam index 2e65ff1..11d1a64 100644 --- a/server/test/crate_overlap_test.gleam +++ b/server/test/crate_overlap_test.gleam @@ -63,15 +63,13 @@ pub fn common_count_is_shared_owned_releases_test() { entry("c", crate.Owned, Some("uri1"), "A"), entry("d", crate.Owned, Some("uri3"), "C"), ] - let result = crate_overlap.overlap(own, theirs) - assert result.common_count == 1 + assert crate_overlap.overlap(own, theirs).common_count == 1 } pub fn entries_without_a_release_never_match_test() { let own = [entry("a", crate.Owned, None, "Same Title")] let theirs = [entry("b", crate.Owned, None, "Same Title")] - let result = crate_overlap.overlap(own, theirs) - assert result.common_count == 0 + assert crate_overlap.overlap(own, theirs).common_count == 0 } pub fn both_wanted_title_picks_the_alphabetically_first_match_test() { @@ -83,15 +81,13 @@ pub fn both_wanted_title_picks_the_alphabetically_first_match_test() { entry("c", crate.Wanted, Some("u1"), "Zebra"), entry("d", crate.Wanted, Some("u2"), "Apple"), ] - let result = crate_overlap.overlap(own, theirs) - assert result.both_wanted_title == Some("Apple") + assert crate_overlap.overlap(own, theirs).both_wanted_title == Some("Apple") } pub fn both_wanted_title_is_absent_with_no_shared_wants_test() { let own = [entry("a", crate.Wanted, Some("u1"), "Zebra")] let theirs = [entry("b", crate.Wanted, Some("u2"), "Apple")] - let result = crate_overlap.overlap(own, theirs) - assert result.both_wanted_title == None + assert crate_overlap.overlap(own, theirs).both_wanted_title == None } pub fn want_match_count_is_their_owned_on_your_wantlist_test() { @@ -100,8 +96,7 @@ pub fn want_match_count_is_their_owned_on_your_wantlist_test() { entry("b", crate.Owned, Some("u1"), "X"), entry("c", crate.Owned, Some("u2"), "Y"), ] - let result = crate_overlap.overlap(own, theirs) - assert result.want_match_count == 1 + assert crate_overlap.overlap(own, theirs).want_match_count == 1 } pub fn want_match_count_dedupes_repeat_owned_copies_test() { @@ -110,8 +105,7 @@ pub fn want_match_count_dedupes_repeat_owned_copies_test() { entry("b", crate.Owned, Some("u1"), "X"), entry("c", crate.Owned, Some("u1"), "X"), ] - let result = crate_overlap.overlap(own, theirs) - assert result.want_match_count == 1 + assert crate_overlap.overlap(own, theirs).want_match_count == 1 } const own_did = "did:plc:x" diff --git a/server/test/feed_handler_test.gleam b/server/test/feed_handler_test.gleam index c5e0c22..4008128 100644 --- a/server/test/feed_handler_test.gleam +++ b/server/test/feed_handler_test.gleam @@ -41,23 +41,27 @@ fn a_session() -> sessions.OauthSession { ) } +/// Always an "acquired" row -- no test in this file varies the status. fn adoption( did did: String, rkey rkey: String, release_uri release_uri: String, - status status: String, created_at created_at: String, ) -> Adoption { Adoption( entry_uri: "at://" <> did <> "/dev.mokkenstorm.crate.shelf.entry/" <> rkey, did:, release_uri:, - status:, + status: "acquired", created_at:, source: None, ) } +fn release_uri(rkey: String) -> String { + "at://did:plc:pub/dev.mokkenstorm.crate.catalog.release/" <> rkey +} + /// The nth day since the epoch, RFC3339 -- a cheap way to generate rows /// spaced far enough apart (24h) that none of them ever collapse together. fn nth_day(n: Int) -> String { @@ -148,22 +152,19 @@ pub fn followed_rows_are_included_and_viewer_and_non_followed_are_excluded_test( store.adoptions.upsert(adoption( did: "did:plc:f1", rkey: "e1", - release_uri: "at://did:plc:pub/dev.mokkenstorm.crate.catalog.release/r1", - status: "acquired", + release_uri: release_uri("r1"), created_at: nth_day(3), )) store.adoptions.upsert(adoption( did: "did:plc:n1", rkey: "e2", - release_uri: "at://did:plc:pub/dev.mokkenstorm.crate.catalog.release/r2", - status: "acquired", + release_uri: release_uri("r2"), created_at: nth_day(2), )) store.adoptions.upsert(adoption( did: viewer_did, rkey: "e3", - release_uri: "at://did:plc:pub/dev.mokkenstorm.crate.catalog.release/r3", - status: "acquired", + release_uri: release_uri("r3"), created_at: nth_day(1), )) let client = @@ -183,15 +184,13 @@ pub fn empty_follow_graph_falls_back_to_network_wide_including_the_viewer_test() store.adoptions.upsert(adoption( did: viewer_did, rkey: "e1", - release_uri: "at://did:plc:pub/dev.mokkenstorm.crate.catalog.release/r1", - status: "acquired", + release_uri: release_uri("r1"), created_at: nth_day(2), )) store.adoptions.upsert(adoption( did: "did:plc:n1", rkey: "e2", - release_uri: "at://did:plc:pub/dev.mokkenstorm.crate.catalog.release/r2", - status: "acquired", + release_uri: release_uri("r2"), created_at: nth_day(1), )) let client = network_client(list_records_body([])) @@ -210,8 +209,7 @@ pub fn nonempty_follows_with_no_followed_adoptions_falls_back_on_the_first_page_ store.adoptions.upsert(adoption( did: "did:plc:n1", rkey: "e1", - release_uri: "at://did:plc:pub/dev.mokkenstorm.crate.catalog.release/r1", - status: "acquired", + release_uri: release_uri("r1"), created_at: nth_day(1), )) // Followed, but they have no adoptions of their own. @@ -232,22 +230,19 @@ pub fn cursor_stays_in_the_followed_namespace_across_pages_test() { store.adoptions.upsert(adoption( did: "did:plc:f1", rkey: "e1", - release_uri: "at://did:plc:pub/dev.mokkenstorm.crate.catalog.release/r1", - status: "acquired", + release_uri: release_uri("r1"), created_at: nth_day(3), )) store.adoptions.upsert(adoption( did: "did:plc:f2", rkey: "e2", - release_uri: "at://did:plc:pub/dev.mokkenstorm.crate.catalog.release/r2", - status: "acquired", + release_uri: release_uri("r2"), created_at: nth_day(2), )) store.adoptions.upsert(adoption( did: "did:plc:f3", rkey: "e3", - release_uri: "at://did:plc:pub/dev.mokkenstorm.crate.catalog.release/r3", - status: "acquired", + release_uri: release_uri("r3"), created_at: nth_day(1), )) let client = @@ -283,9 +278,7 @@ pub fn limit_is_capped_at_the_lexicon_default_test() { store.adoptions.upsert(adoption( did: "did:plc:f1", rkey: "e" <> int.to_string(n), - release_uri: "at://did:plc:pub/dev.mokkenstorm.crate.catalog.release/r" - <> int.to_string(n), - status: "acquired", + release_uri: release_uri("r" <> int.to_string(n)), created_at: nth_day(n), )) }) diff --git a/server/test/feed_skeleton_test.gleam b/server/test/feed_skeleton_test.gleam index b8bd2ea..58f86c5 100644 --- a/server/test/feed_skeleton_test.gleam +++ b/server/test/feed_skeleton_test.gleam @@ -9,6 +9,7 @@ import at_record/gen/feed/get_feed_skeleton.{ } import at_record_server/catalog_index.{type Adoption, Adoption} import at_record_server/feed_skeleton +import gleam/int import gleam/list import gleam/option.{None, Some} @@ -38,166 +39,104 @@ fn row( ) } -pub fn single_passthrough_test() { - let rows = [ - row( - did: "did:plc:a", - rkey: "e1", - release_uri: release_a, - status: "acquired", - created_at: "2026-01-01T00:00:00Z", - source: None, - ), - ] - let assert [FeedItem(entries:, reason: FeedItemReasonReasonSingle(inner))] = - feed_skeleton.collapse(rows) - assert entries - == [get_feed_skeleton.EntryRef(actor: "did:plc:a", entry_id: "e1")] - assert inner == ReasonSingle(action: "owned") -} - -pub fn single_passthrough_reports_wanted_action_test() { - let rows = [ - row( - did: "did:plc:a", - rkey: "e1", - release_uri: release_a, - status: "wanted", - created_at: "2026-01-01T00:00:00Z", - source: None, - ), - ] - let assert [FeedItem(reason: FeedItemReasonReasonSingle(inner), ..)] = - feed_skeleton.collapse(rows) - assert inner.action == "wanted" +/// An "acquired" row with no import source -- the shape of almost every row +/// in this file that isn't specifically exercising status or source. +fn acquired_row( + did did: String, + rkey rkey: String, + release_uri release_uri: String, + created_at created_at: String, +) -> Adoption { + row(did:, rkey:, release_uri:, status: "acquired", created_at:, source: None) } -pub fn actor_batch_at_the_window_boundary_is_included_test() { - let rows = [ - row( - did: "did:plc:a", - rkey: "e1", - release_uri: release_a, - status: "acquired", - created_at: "2026-01-01T00:00:00Z", - source: None, - ), - row( - did: "did:plc:a", - rkey: "e2", - release_uri: release_b, - status: "acquired", - created_at: "2026-01-01T06:00:00Z", - source: None, - ), - ] - let assert [FeedItem(entries:, reason: FeedItemReasonReasonActorBatch(inner))] = - feed_skeleton.collapse(rows) - assert list.length(entries) == 2 - assert inner - == ReasonActorBatch( - action: "owned", - window_end: "2026-01-01T06:00:00Z", - window_start: "2026-01-01T00:00:00Z", - ) +pub fn single_passthrough_reflects_the_row_status_test() { + [#("acquired", "owned"), #("wanted", "wanted")] + |> list.each(fn(c) { + let #(status, expected_action) = c + let rows = [ + row( + did: "did:plc:a", + rkey: "e1", + release_uri: release_a, + status:, + created_at: "2026-01-01T00:00:00Z", + source: None, + ), + ] + let assert [FeedItem(entries:, reason: FeedItemReasonReasonSingle(inner))] = + feed_skeleton.collapse(rows) + assert entries + == [get_feed_skeleton.EntryRef(actor: "did:plc:a", entry_id: "e1")] + assert inner == ReasonSingle(action: expected_action) + }) } -pub fn actor_batch_just_past_the_window_boundary_splits_into_singles_test() { - let rows = [ - row( - did: "did:plc:a", - rkey: "e1", - release_uri: release_a, - status: "acquired", - created_at: "2026-01-01T00:00:00Z", - source: None, - ), - row( - did: "did:plc:a", - rkey: "e2", - release_uri: release_b, - status: "acquired", - created_at: "2026-01-01T06:00:01Z", - source: None, - ), - ] - let items = feed_skeleton.collapse(rows) - assert list.length(items) == 2 - assert list.all(items, fn(item) { - case item.reason { - FeedItemReasonReasonSingle(_) -> True - _ -> False +pub fn actor_batch_window_boundary_test() { + [#("2026-01-01T06:00:00Z", True), #("2026-01-01T06:00:01Z", False)] + |> list.each(fn(c) { + let #(second_created_at, batches) = c + let rows = [ + acquired_row( + did: "did:plc:a", + rkey: "e1", + release_uri: release_a, + created_at: "2026-01-01T00:00:00Z", + ), + acquired_row( + did: "did:plc:a", + rkey: "e2", + release_uri: release_b, + created_at: second_created_at, + ), + ] + let items = feed_skeleton.collapse(rows) + case batches { + True -> { + let assert [ + FeedItem(entries:, reason: FeedItemReasonReasonActorBatch(inner)), + ] = items + assert list.length(entries) == 2 + assert inner + == ReasonActorBatch( + action: "owned", + window_end: second_created_at, + window_start: "2026-01-01T00:00:00Z", + ) + } + False -> { + assert list.length(items) == 2 + assert list.all(items, fn(item) { + case item.reason { + FeedItemReasonReasonSingle(_) -> True + _ -> False + } + }) + } } }) } pub fn import_via_count_collapses_five_same_did_rows_test() { - let rows = [ - row( - did: "did:plc:a", - rkey: "e1", - release_uri: release_a, - status: "acquired", - created_at: "2026-01-01T01:00:00Z", - source: None, - ), - row( - did: "did:plc:a", - rkey: "e2", - release_uri: release_a, - status: "acquired", - created_at: "2026-01-01T02:00:00Z", - source: None, - ), - row( - did: "did:plc:a", - rkey: "e3", - release_uri: release_a, - status: "acquired", - created_at: "2026-01-01T03:00:00Z", - source: None, - ), - row( - did: "did:plc:a", - rkey: "e4", - release_uri: release_a, - status: "acquired", - created_at: "2026-01-01T04:00:00Z", - source: None, - ), - row( - did: "did:plc:a", - rkey: "e5", - release_uri: release_a, - status: "acquired", - created_at: "2026-01-01T05:00:00Z", - source: None, - ), - ] + let rows = + list.repeat(0, 5) + |> list.index_map(fn(_, i) { i + 1 }) + |> list.map(fn(n) { + acquired_row( + did: "did:plc:a", + rkey: "e" <> int.to_string(n), + release_uri: release_a, + created_at: "2026-01-01T0" <> int.to_string(n) <> ":00:00Z", + ) + }) let assert [FeedItem(entries:, reason: FeedItemReasonReasonImport(inner))] = feed_skeleton.collapse(rows) assert list.length(entries) == 5 assert inner == ReasonImport(source: None) } -pub fn import_via_source_collapses_even_a_single_row_test() { - let rows = [ - row( - did: "did:plc:a", - rkey: "e1", - release_uri: release_a, - status: "acquired", - created_at: "2026-01-01T00:00:00Z", - source: Some("discogs"), - ), - ] - let assert [FeedItem(reason: FeedItemReasonReasonImport(inner), ..)] = - feed_skeleton.collapse(rows) - assert inner == ReasonImport(source: Some("discogs")) -} - -pub fn import_via_source_wins_over_actor_batch_for_a_small_cluster_test() { - let rows = [ +pub fn import_via_source_wins_regardless_of_cluster_size_test() { + let imported_row = row( did: "did:plc:a", rkey: "e1", @@ -205,30 +144,29 @@ pub fn import_via_source_wins_over_actor_batch_for_a_small_cluster_test() { status: "acquired", created_at: "2026-01-01T00:00:00Z", source: Some("discogs"), - ), - row( + ) + let same_did_neighbor = + acquired_row( did: "did:plc:a", rkey: "e2", release_uri: release_b, - status: "acquired", created_at: "2026-01-01T01:00:00Z", - source: None, - ), - ] - let assert [FeedItem(reason: FeedItemReasonReasonImport(inner), ..)] = - feed_skeleton.collapse(rows) - assert inner == ReasonImport(source: Some("discogs")) + ) + [[imported_row], [imported_row, same_did_neighbor]] + |> list.each(fn(rows) { + let assert [FeedItem(reason: FeedItemReasonReasonImport(inner), ..)] = + feed_skeleton.collapse(rows) + assert inner == ReasonImport(source: Some("discogs")) + }) } pub fn subject_converge_with_two_actors_test() { let rows = [ - row( + acquired_row( did: "did:plc:a", rkey: "e1", release_uri: release_a, - status: "acquired", created_at: "2026-01-01T00:00:00Z", - source: None, ), row( did: "did:plc:b", @@ -250,29 +188,23 @@ pub fn subject_converge_with_two_actors_test() { pub fn subject_converge_with_three_actors_test() { let rows = [ - row( + acquired_row( did: "did:plc:a", rkey: "e1", release_uri: release_a, - status: "acquired", created_at: "2026-01-01T00:00:00Z", - source: None, ), - row( + acquired_row( did: "did:plc:b", rkey: "e2", release_uri: release_a, - status: "acquired", created_at: "2026-01-01T01:00:00Z", - source: None, ), - row( + acquired_row( did: "did:plc:c", rkey: "e3", release_uri: release_a, - status: "acquired", created_at: "2026-01-01T02:00:00Z", - source: None, ), ] let assert [FeedItem(entries:, ..)] = feed_skeleton.collapse(rows) @@ -280,38 +212,28 @@ pub fn subject_converge_with_three_actors_test() { } pub fn converge_takes_precedence_over_the_same_did_also_batching_test() { - // did:plc:a adopts release_a, then did:plc:b adopts the same release soon - // after (converge), while did:plc:a also has a second, unrelated row close - // enough in time to have otherwise formed an actor batch with the first. + // a+b converge on release_a; a's second, unrelated row stays a lone single. let rows = [ - row( + acquired_row( did: "did:plc:a", rkey: "e1", release_uri: release_a, - status: "acquired", created_at: "2026-01-01T00:00:00Z", - source: None, ), - row( + acquired_row( did: "did:plc:b", rkey: "e2", release_uri: release_a, - status: "acquired", created_at: "2026-01-01T01:00:00Z", - source: None, ), - row( + acquired_row( did: "did:plc:a", rkey: "e3", release_uri: release_b, - status: "acquired", created_at: "2026-01-01T02:00:00Z", - source: None, ), ] let items = feed_skeleton.collapse(rows) - // e1+e2 converge into one item; e3 (did:plc:a's only remaining row) is a - // lone single, not merged with the consumed e1. assert list.length(items) == 2 let assert Ok(converge) = list.find(items, fn(item) { @@ -329,36 +251,28 @@ pub fn converge_takes_precedence_over_the_same_did_also_batching_test() { } }) assert single.entries - == [ - get_feed_skeleton.EntryRef(actor: "did:plc:a", entry_id: "e3"), - ] + == [get_feed_skeleton.EntryRef(actor: "did:plc:a", entry_id: "e3")] } pub fn ordering_by_recency_is_preserved_for_unrelated_singles_test() { let rows = [ - row( + acquired_row( did: "did:plc:c", rkey: "e3", release_uri: release_a, - status: "acquired", created_at: "2026-01-03T00:00:00Z", - source: None, ), - row( + acquired_row( did: "did:plc:b", rkey: "e2", release_uri: release_b, - status: "acquired", created_at: "2026-01-02T00:00:00Z", - source: None, ), - row( + acquired_row( did: "did:plc:a", rkey: "e1", release_uri: "at://did:plc:pub/dev.mokkenstorm.crate.catalog.release/rc", - status: "acquired", created_at: "2026-01-01T00:00:00Z", - source: None, ), ] let items = feed_skeleton.collapse(rows) diff --git a/server/test/graph_handler_test.gleam b/server/test/graph_handler_test.gleam index 63d0259..d9ea6d8 100644 --- a/server/test/graph_handler_test.gleam +++ b/server/test/graph_handler_test.gleam @@ -42,18 +42,18 @@ fn stored_follow(rkey: String, subject: String) -> StoredItem(GraphFollow) { ) } -pub fn find_returns_the_stored_follow_for_the_subject_test() { +pub fn find_locates_the_stored_follow_or_returns_none_test() { let stored = [ stored_follow("3aaa", "did:plc:other"), stored_follow("3bbb", target_did), ] let assert Some(found) = graph_follows.find(stored, target_did) assert found.rkey == "3bbb" -} - -pub fn find_returns_none_when_not_following_test() { - let stored = [stored_follow("3aaa", "did:plc:other")] - assert graph_follows.find(stored, target_did) == None + assert graph_follows.find( + [stored_follow("3aaa", "did:plc:other")], + target_did, + ) + == None } fn list_records_body(records: List(json.Json)) -> String { diff --git a/web/test/feed_test.gleam b/web/test/feed_test.gleam index 2403234..ba37953 100644 --- a/web/test/feed_test.gleam +++ b/web/test/feed_test.gleam @@ -175,29 +175,20 @@ pub fn subject_converge_hydrated_links_to_the_pressing_test() { assert string.contains(html, "href=\"/pressing/did:x/rk1\"") } -pub fn import_reason_hydrated_shows_via_provider_test() { +pub fn import_reason_via_line_reflects_the_source_test() { let refs = [ref("did:a", "e0")] - let html = - render( - with_feed([import_item(refs, Some("discogs"))], False, [ - #(#("did:a", "e0"), fe("alice.test", "2026-07-18T10:00:00Z")), - ]), - ) - assert string.contains(html, "@alice.test imported 1 record") - assert string.contains(html, "via Discogs") - assert string.contains(html, "class=\"feed-strip\"") -} + let hydrated = [#(#("did:a", "e0"), fe("alice.test", "2026-07-18T10:00:00Z"))] -pub fn import_reason_without_source_omits_via_test() { - let refs = [ref("did:a", "e0")] - let html = - render( - with_feed([import_item(refs, None)], False, [ - #(#("did:a", "e0"), fe("alice.test", "2026-07-18T10:00:00Z")), - ]), - ) - assert string.contains(html, "@alice.test imported 1 record") - assert !string.contains(html, " via ") + let with_source = + render(with_feed([import_item(refs, Some("discogs"))], False, hydrated)) + assert string.contains(with_source, "@alice.test imported 1 record") + assert string.contains(with_source, "via Discogs") + assert string.contains(with_source, "class=\"feed-strip\"") + + let without_source = + render(with_feed([import_item(refs, None)], False, hydrated)) + assert string.contains(without_source, "@alice.test imported 1 record") + assert !string.contains(without_source, " via ") } // --- reason rows: unhydrated (skeleton, no crash) ----------------------- @@ -218,52 +209,41 @@ pub fn every_reason_renders_a_skeleton_when_unhydrated_test() { // --- fallback label ------------------------------------------------------ -pub fn fallback_true_shows_the_wider_network_label_test() { - let html = - render( - with_feed([single("did:a", "e0", "added")], True, [ - #(#("did:a", "e0"), fe("alice.test", "2026-07-18T10:00:00Z")), - ]), - ) - assert string.contains(html, "FROM THE WIDER NETWORK") -} - -pub fn fallback_false_omits_the_wider_network_label_test() { - let html = - render( - with_feed([single("did:a", "e0", "added")], False, [ - #(#("did:a", "e0"), fe("alice.test", "2026-07-18T10:00:00Z")), - ]), - ) - assert !string.contains(html, "FROM THE WIDER NETWORK") +pub fn fallback_label_shows_only_when_true_test() { + let hydrated = [#(#("did:a", "e0"), fe("alice.test", "2026-07-18T10:00:00Z"))] + [True, False] + |> list.each(fn(fallback) { + let html = + render(with_feed([single("did:a", "e0", "added")], fallback, hydrated)) + assert string.contains(html, "FROM THE WIDER NETWORK") == fallback + }) } // --- day separators ------------------------------------------------------ -pub fn items_on_different_days_render_two_separators_test() { +pub fn day_separator_count_reflects_distinct_and_same_hydrated_days_test() { let items = [single("did:a", "e0", "added"), single("did:a", "e1", "added")] - let html = + let e0 = #(#("did:a", "e0"), fe("alice.test", "2026-07-18T10:00:00Z")) + + let different_days = render( with_feed(items, False, [ - #(#("did:a", "e0"), fe("alice.test", "2026-07-18T10:00:00Z")), + e0, #(#("did:a", "e1"), fe("alice.test", "2026-07-17T10:00:00Z")), ]), ) - assert occurrences(html, "class=\"feed-day\"") == 2 - assert string.contains(html, "2026-07-18") - assert string.contains(html, "2026-07-17") -} + assert occurrences(different_days, "class=\"feed-day\"") == 2 + assert string.contains(different_days, "2026-07-18") + assert string.contains(different_days, "2026-07-17") -pub fn items_on_the_same_day_render_one_separator_test() { - let items = [single("did:a", "e0", "added"), single("did:a", "e1", "added")] - let html = + let same_day = render( with_feed(items, False, [ - #(#("did:a", "e0"), fe("alice.test", "2026-07-18T10:00:00Z")), + e0, #(#("did:a", "e1"), fe("alice.test", "2026-07-18T09:00:00Z")), ]), ) - assert occurrences(html, "class=\"feed-day\"") == 1 + assert occurrences(same_day, "class=\"feed-day\"") == 1 } // --- update: routing + pagination --------------------------------------- diff --git a/web/test/nav_test.gleam b/web/test/nav_test.gleam index 6f31f15..50407f4 100644 --- a/web/test/nav_test.gleam +++ b/web/test/nav_test.gleam @@ -12,39 +12,36 @@ import at_record_web/msg.{Back, OnRouteChange} import at_record_web/route import at_record_web/update.{update} import at_record_web/view +import gleam/list import gleam/string import lustre/element import support.{an_entry, empty_effect, logged_in} -pub fn section_maps_every_crate_drilldown_to_crate_test() { - assert route.section(Crate) == Crate - assert route.section(Record("e1")) == Crate - assert route.section(RecordAmend("e1")) == Crate - assert route.section(Add) == Crate - assert route.section(Scan) == Crate - assert route.section(ScanReview) == Crate - assert route.section(ScanDone) == Crate -} - -pub fn section_maps_browse_drilldowns_to_browse_test() { - assert route.section(Browse) == Browse - assert route.section(PressingDetail("did:plc:abc", "3jz")) == Browse -} - -pub fn section_maps_feed_to_itself_test() { - assert route.section(Feed) == Feed -} - -pub fn section_maps_settings_drilldowns_to_settings_test() { - assert route.section(Settings) == Settings - assert route.section(EditInbox) == Settings - assert route.section(EditProposalDetail("uri-1")) == Settings -} - -pub fn section_leaves_public_routes_unmapped_test() { - assert route.section(PublicCrate("alice.test")) == PublicCrate("alice.test") - assert route.section(PublicRecord("alice.test", "e1")) - == PublicRecord("alice.test", "e1") +/// Every drill-down maps to its tab's own section (crate/browse/settings +/// each own several, feed maps only to itself); public routes are the one +/// family left unmapped (each maps to itself instead of a real section). +pub fn route_section_maps_every_drilldown_to_its_tab_test() { + [ + #(Crate, Crate), + #(Record("e1"), Crate), + #(RecordAmend("e1"), Crate), + #(Add, Crate), + #(Scan, Crate), + #(ScanReview, Crate), + #(ScanDone, Crate), + #(Browse, Browse), + #(PressingDetail("did:plc:abc", "3jz"), Browse), + #(Feed, Feed), + #(Settings, Settings), + #(EditInbox, Settings), + #(EditProposalDetail("uri-1"), Settings), + #(PublicCrate("alice.test"), PublicCrate("alice.test")), + #(PublicRecord("alice.test", "e1"), PublicRecord("alice.test", "e1")), + ] + |> list.each(fn(row) { + let #(route_, expected) = row + assert route.section(route_) == expected + }) } pub fn crate_tab_stays_active_when_drilled_into_a_record_test() { diff --git a/web/test/public_crate_test.gleam b/web/test/public_crate_test.gleam index 9e27b7b..85dc187 100644 --- a/web/test/public_crate_test.gleam +++ b/web/test/public_crate_test.gleam @@ -149,7 +149,7 @@ pub fn on_route_change_to_public_crate_resets_overlap_test() { } pub fn got_crate_overlap_ok_sets_overlap_test() { - let #(model, _) = + let #(counts, _) = update( base(), GotCrateOverlap( @@ -162,12 +162,10 @@ pub fn got_crate_overlap_ok_sets_overlap_test() { )), ), ) - assert model.overlap + assert counts.overlap == Some(CrateOverlap(2, Some("Spiderland"), 1, False, None)) -} -pub fn got_crate_overlap_ok_carries_the_viewer_follow_state_test() { - let #(model, _) = + let #(following, _) = update( base(), GotCrateOverlap( @@ -182,7 +180,7 @@ pub fn got_crate_overlap_ok_carries_the_viewer_follow_state_test() { )), ), ) - assert model.overlap + assert following.overlap == Some(CrateOverlap( 0, None, @@ -222,54 +220,39 @@ pub fn overlap_panel_shows_when_signed_in_viewing_someone_else_test() { assert string.contains(html, "they have 2 records from your wantlist") } -pub fn overlap_panel_hidden_when_viewing_own_crate_test() { - let html = +pub fn overlap_panel_stays_hidden_test() { + // own crate, logged out, and nothing worth showing all suppress the panel. + [ Model( ..public_crate_model("alice.test", "alice.test"), overlap: Some(CrateOverlap(3, None, 0, False, None)), - ) - |> view.view - |> element.to_string - assert !string.contains(html, "TASTE OVERLAP") -} - -pub fn overlap_panel_hidden_when_logged_out_test() { - let html = + ), Model( ..public_crate_model("me.test", "alice.test"), auth: LoggedOut, overlap: Some(CrateOverlap(3, None, 0, False, None)), - ) - |> view.view - |> element.to_string - assert !string.contains(html, "TASTE OVERLAP") -} - -pub fn overlap_panel_hidden_when_nothing_to_show_test() { - let html = + ), Model( ..public_crate_model("me.test", "alice.test"), overlap: Some(CrateOverlap(0, None, 0, False, None)), - ) - |> view.view - |> element.to_string - assert !string.contains(html, "TASTE OVERLAP") -} - -pub fn follow_button_hidden_when_logged_out_test() { - let html = - Model(..public_crate_model("me.test", "alice.test"), auth: LoggedOut) - |> view.view - |> element.to_string - assert !string.contains(html, "FOLLOW") + ), + ] + |> list.each(fn(model) { + let html = model |> view.view |> element.to_string + assert !string.contains(html, "TASTE OVERLAP") + }) } -pub fn follow_button_hidden_when_viewing_own_crate_test() { - let html = - public_crate_model("alice.test", "alice.test") - |> view.view - |> element.to_string - assert !string.contains(html, "FOLLOW") +pub fn follow_button_stays_hidden_test() { + // logged out, or viewing one's own crate, both suppress the button. + [ + Model(..public_crate_model("me.test", "alice.test"), auth: LoggedOut), + public_crate_model("alice.test", "alice.test"), + ] + |> list.each(fn(model) { + let html = model |> view.view |> element.to_string + assert !string.contains(html, "FOLLOW") + }) } pub fn follow_button_shows_follow_when_not_yet_following_test() { diff --git a/web/test/record_amend_test.gleam b/web/test/record_amend_test.gleam index 2479687..5e123a9 100644 --- a/web/test/record_amend_test.gleam +++ b/web/test/record_amend_test.gleam @@ -12,6 +12,7 @@ import at_record_web/route import at_record_web/update.{update} import at_record_web/view import gleam/dict +import gleam/list import gleam/option.{None, Some} import gleam/string import gleam/uri @@ -50,45 +51,30 @@ pub fn on_route_change_fetches_the_shelf_when_not_yet_loaded_test() { assert effect != empty_effect() } -pub fn got_shelf_reseeds_the_draft_when_still_on_the_amend_route_test() { - let seeded = - Model( - ..logged_in(), - route: RecordAmend("e1"), - shelf: ShelfLoading, - amend: blank_amend(), - ) - let #(after, _) = - update( - seeded, - GotShelf( - Ok(ShelfData( - handle: "alice.test", - items: [an_entry()], - via_handles: dict.new(), - cursor: None, - )), - ), - ) - assert after.amend.title == "Spiderland" - assert after.amend.released == "1991" -} - -pub fn got_shelf_leaves_the_draft_alone_off_the_amend_route_test() { - let seeded = Model(..logged_in(), route: Crate, amend: blank_amend()) - let #(after, _) = - update( - seeded, - GotShelf( - Ok(ShelfData( - handle: "alice.test", - items: [an_entry()], - via_handles: dict.new(), - cursor: None, - )), - ), - ) - assert after.amend.title == "" +pub fn got_shelf_reseeds_the_draft_only_while_still_on_the_amend_route_test() { + [#(RecordAmend("e1"), "Spiderland", Some("1991")), #(Crate, "", None)] + |> list.each(fn(row) { + let #(route, expected_title, expected_released) = row + let seeded = + Model(..logged_in(), route:, shelf: ShelfLoading, amend: blank_amend()) + let #(after, _) = + update( + seeded, + GotShelf( + Ok(ShelfData( + handle: "alice.test", + items: [an_entry()], + via_handles: dict.new(), + cursor: None, + )), + ), + ) + assert after.amend.title == expected_title + assert case expected_released { + Some(released) -> after.amend.released == released + None -> True + } + }) } pub fn got_amend_ok_clears_publishing_and_navigates_back_test() { @@ -104,27 +90,23 @@ pub fn cover_uploaded_ok_navigates_back_test() { assert effect != empty_effect() } -pub fn record_amend_page_titles_itself_amend_pressing_for_a_self_minted_entry_test() { - let seeded = - Model( - ..logged_in(), - route: RecordAmend("e1"), - shelf: ShelfLoaded([an_entry()]), - ) - let html = view.view(seeded) |> element.to_string - assert string.contains(html, "AMEND PRESSING") -} - -pub fn record_amend_page_titles_itself_suggest_a_fix_for_an_adopted_entry_test() { - let seeded = - Model( - ..logged_in(), - route: RecordAmend("e1"), - shelf: ShelfLoaded([an_entry()]), - via_handles: dict.from_list([#("e1", "bob.test")]), - ) - let html = view.view(seeded) |> element.to_string - assert string.contains(html, "SUGGEST A FIX") +pub fn record_amend_page_titles_itself_by_the_entrys_provenance_test() { + [ + #(dict.new(), "AMEND PRESSING"), + #(dict.from_list([#("e1", "bob.test")]), "SUGGEST A FIX"), + ] + |> list.each(fn(row) { + let #(via_handles, expected_title) = row + let seeded = + Model( + ..logged_in(), + route: RecordAmend("e1"), + shelf: ShelfLoaded([an_entry()]), + via_handles:, + ) + let html = view.view(seeded) |> element.to_string + assert string.contains(html, expected_title) + }) } pub fn record_amend_page_renders_the_seeded_draft_and_the_cover_input_test() {