From 1bc8e24accddfd022d65e765b0807afa9f485869 Mon Sep 17 00:00:00 2001 From: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@sprout-oss.stage.blox.sqprod.co> Date: Thu, 2 Jul 2026 20:59:57 -0400 Subject: [PATCH] test(desktop): pin island thread-head visibility in the actual panel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wren's #1486 review: the island-reply summary test exercised main-timeline aggregation, not buildThreadPanelData. Pin the exact panel shape — a marked island head with a marked descendant renders head + reply in the thread panel while producing zero main-timeline entries. Co-authored-by: Tyler Longwell Signed-off-by: Tyler Longwell --- .../messages/lib/threadPanel.test.mjs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/desktop/src/features/messages/lib/threadPanel.test.mjs b/desktop/src/features/messages/lib/threadPanel.test.mjs index ae237c4ef..132b6bb54 100644 --- a/desktop/src/features/messages/lib/threadPanel.test.mjs +++ b/desktop/src/features/messages/lib/threadPanel.test.mjs @@ -105,6 +105,42 @@ test("buildMainTimelineEntries hides non-contiguous islands until paging heals t ); }); +test("buildThreadPanelData renders a marked island head and its marked replies while the main timeline hides both", () => { + // Thread-open on a head that is itself an island (spliced by + // useThreadReplies/useLoadMissingAncestors before contiguous paging reached + // it): the panel derives from the full message list and must show the head + // and its descendants, while buildMainTimelineEntries hides the duplicate + // main-timeline rows until paging heals them. + const islandHead = message({ + id: "island-head", + createdAt: 1, + nonContiguous: true, + }); + const islandReply = message({ + id: "island-reply", + createdAt: 2, + parentId: "island-head", + rootId: "island-head", + depth: 1, + tags: [["e", "island-head", "", "reply"]], + nonContiguous: true, + }); + + const panelData = buildThreadPanelData( + [islandHead, islandReply], + "island-head", + null, + new Set(), + ); + assert.equal(panelData.threadHead?.id, "island-head"); + assert.deepEqual( + panelData.visibleReplies.map((entry) => entry.message.id), + ["island-reply"], + ); + + assert.deepEqual(buildMainTimelineEntries([islandHead, islandReply]), []); +}); + test("buildMainTimelineEntries keeps island replies in the visible parent's summary", () => { // The reply subtree fetched on thread-open is an island in the timeline, // but the summary on its (contiguous, visible) root must still count it.