Skip to content

Commit 5aad506

Browse files
authored
test(miner-ui): add unit coverage for chat-scroll stick-to-bottom logic (#7847)
apps/loopover-miner-ui/src/lib/chat-scroll.ts (isChatViewportNearBottom, scrollChatViewportToBottom, CHAT_NEAR_BOTTOM_PX) had no direct test despite already needing a dedicated bug-fix once (#7229/#7298), and message-list.test.tsx only covers DOM structure, not the scroll math. Add a co-located unit test following the one-test-per-pure-module convention (demo-data.test.ts): cover isChatViewportNearBottom's <= 80px boundary on both sides, short-content and custom-threshold cases, and scrollChatViewportToBottom's Math.max(0, ...) clamp.
1 parent 1402323 commit 5aad506

1 file changed

Lines changed: 64 additions & 0 deletions

File tree

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { describe, expect, it } from "vitest";
2+
import { CHAT_NEAR_BOTTOM_PX, isChatViewportNearBottom, scrollChatViewportToBottom } from "./chat-scroll";
3+
4+
// Pure-logic coverage for the stick-to-bottom auto-scroll math (#7793), following the one-test-per-pure-module
5+
// convention demo-data.test.ts establishes in this directory. jsdom doesn't meaningfully simulate a real
6+
// viewport's scrollTop/scrollHeight, so these drive the exported functions directly with plain metric objects.
7+
8+
/** A minimal viewport stand-in carrying just the three metrics isChatViewportNearBottom reads. */
9+
function viewport(scrollTop: number, scrollHeight: number, clientHeight: number) {
10+
return { scrollTop, scrollHeight, clientHeight };
11+
}
12+
13+
describe("isChatViewportNearBottom (#7793)", () => {
14+
it("is true when the viewport is scrolled to the very bottom (distance 0)", () => {
15+
// scrollHeight - scrollTop - clientHeight === 0 <= 80
16+
expect(isChatViewportNearBottom(viewport(900, 1000, 100))).toBe(true);
17+
});
18+
19+
it("is true exactly at the CHAT_NEAR_BOTTOM_PX boundary (distance === threshold)", () => {
20+
// distance = 1000 - 820 - 100 = 80, which is <= 80 -> still "pinned".
21+
expect(isChatViewportNearBottom(viewport(820, 1000, 100))).toBe(true);
22+
});
23+
24+
it("is false one pixel past the boundary (distance === threshold + 1)", () => {
25+
// distance = 1000 - 819 - 100 = 81, which is > 80 -> no longer pinned.
26+
expect(isChatViewportNearBottom(viewport(819, 1000, 100))).toBe(false);
27+
});
28+
29+
it("is false when scrolled well up from the bottom", () => {
30+
// distance = 1000 - 0 - 100 = 900 > 80
31+
expect(isChatViewportNearBottom(viewport(0, 1000, 100))).toBe(false);
32+
});
33+
34+
it("treats short content (viewport taller than content) as near the bottom", () => {
35+
// distance = 100 - 0 - 500 = -400 <= 80 -> a non-scrollable short chat is always "pinned".
36+
expect(isChatViewportNearBottom(viewport(0, 100, 500))).toBe(true);
37+
});
38+
39+
it("honors a custom threshold over the default CHAT_NEAR_BOTTOM_PX", () => {
40+
// distance = 1000 - 950 - 100 = -50; with a tiny threshold of 0 that's still <= 0 -> true...
41+
expect(isChatViewportNearBottom(viewport(950, 1000, 100), 0)).toBe(true);
42+
// ...and a distance of 10 exceeds a threshold of 5 -> false, proving the arg is actually used.
43+
expect(isChatViewportNearBottom(viewport(890, 1000, 100), 5)).toBe(false);
44+
});
45+
46+
it("exports the documented 80px default threshold", () => {
47+
expect(CHAT_NEAR_BOTTOM_PX).toBe(80);
48+
});
49+
});
50+
51+
describe("scrollChatViewportToBottom (#7793)", () => {
52+
it("sets scrollTop to scrollHeight - clientHeight for scrollable content", () => {
53+
const el = { scrollTop: 0, scrollHeight: 1000, clientHeight: 100 } as HTMLElement;
54+
scrollChatViewportToBottom(el);
55+
expect(el.scrollTop).toBe(900);
56+
});
57+
58+
it("clamps to 0 when the content is shorter than the viewport (never negative)", () => {
59+
// scrollHeight - clientHeight = 100 - 500 = -400 -> Math.max(0, ...) pins it at 0.
60+
const el = { scrollTop: 42, scrollHeight: 100, clientHeight: 500 } as HTMLElement;
61+
scrollChatViewportToBottom(el);
62+
expect(el.scrollTop).toBe(0);
63+
});
64+
});

0 commit comments

Comments
 (0)