BangSo/apps/mobile/lib/thread-scroll.test.ts

64 lines
2.4 KiB
TypeScript
Raw Permalink Normal View History

2026-09-01 16:51:19 +00:00
import { describe, expect, it } from "vitest";
import { ThreadScrollBehavior } from "./thread-scroll.js";
describe("mobile thread initial scroll", () => {
it("waits for layout when messages arrive first, then opens at the latest message", () => {
const behavior = new ThreadScrollBehavior();
behavior.openThread("thread-1");
expect(behavior.onContentChanged(false, "m1")).toBe(null);
expect(behavior.onLayout()).toBe("jump");
});
it("opens at the latest message when layout arrives before content", () => {
const behavior = new ThreadScrollBehavior();
behavior.openThread("thread-1");
expect(behavior.onLayout()).toBe(null);
expect(behavior.onContentChanged(false, "m1")).toBe("jump");
});
it("does not move for expanded labels but smoothly follows a new message", () => {
const behavior = new ThreadScrollBehavior();
behavior.openThread("thread-1");
behavior.onLayout();
expect(behavior.onContentChanged(false, "m1")).toBe("jump");
expect(behavior.onContentChanged(false, "m1")).toBe(null);
expect(behavior.onContentChanged(false, "m2")).toBe("smooth");
});
it("keeps the latest message visible when the viewport resizes", () => {
const behavior = new ThreadScrollBehavior();
behavior.openThread("thread-1");
behavior.onContentChanged(false, "m1");
expect(behavior.onLayout()).toBe("jump");
expect(behavior.onLayout()).toBe("jump");
});
it("keeps the initial jump pending while another scroll target blocks it", () => {
const behavior = new ThreadScrollBehavior();
behavior.openThread("thread-1");
expect(behavior.onContentChanged(true, "m1")).toBe(null);
expect(behavior.onLayout()).toBe(null);
expect(behavior.onContentChanged(false, "m1")).toBe("jump");
expect(behavior.onContentChanged(false, "m1")).toBe(null);
});
it("leaves a detached reader in place and records unread messages", () => {
const behavior = new ThreadScrollBehavior();
behavior.openThread("thread-1");
behavior.onLayout();
behavior.onContentChanged(false, "m1");
expect(behavior.onUserScroll(120)).toEqual({ detached: true, unread: false });
expect(behavior.onLayout()).toBe(null);
expect(behavior.onContentChanged(false, "m2")).toBe(null);
expect(behavior.state()).toEqual({ detached: true, unread: true });
expect(behavior.jumpToLatest()).toBe("smooth");
expect(behavior.state()).toEqual({ detached: false, unread: false });
});
});