Files
oh-my-pi/packages/tui/test/scroll-view.test.ts
T
2026-06-06 12:18:03 +08:00

80 lines
2.5 KiB
TypeScript

import { describe, expect, it } from "bun:test";
import { ScrollView } from "../src/components/scroll-view";
import { visibleWidth } from "../src/utils";
const theme = {
track: () => "T",
thumb: () => "B",
};
describe("ScrollView", () => {
it("renders a fixed-height viewport and omits auto scrollbar when content fits", () => {
const view = new ScrollView(["one", "two"], { height: 3, theme });
expect(view.render(10)).toEqual(["one", "two", ""]);
});
it("renders a right-edge scrollbar when content overflows", () => {
const view = new ScrollView(["alpha", "beta", "gamma", "delta", "omega"], { height: 3, theme });
expect(view.render(6)).toEqual(["alphaB", "beta T", "gammaT"]);
});
it("scrolls and clamps offsets", () => {
const view = new ScrollView(["one", "two", "three", "four", "five"], { height: 3, theme });
view.scroll(10);
expect(view.getScrollOffset()).toBe(2);
expect(view.render(6)).toEqual(["threeT", "four T", "five B"]);
view.scroll(-10);
expect(view.getScrollOffset()).toBe(0);
});
it("reserves a scrollbar column in always mode", () => {
const view = new ScrollView(["one"], { height: 2, scrollbar: "always", theme });
expect(view.render(5)).toEqual(["one B", " B"]);
});
it("does not reserve a scrollbar column in never mode", () => {
const view = new ScrollView(["alpha", "beta", "gamma"], { height: 2, scrollbar: "never", theme });
expect(view.render(6)).toEqual(["alpha", "beta"]);
});
it("renders scrollbar geometry for pre-windowed lines", () => {
const view = new ScrollView(["gamma", "delta"], { height: 2, totalRows: 4, theme });
view.setScrollOffset(2);
expect(view.render(6)).toEqual(["gammaT", "deltaB"]);
});
it("does not render a scrollbar when width is zero", () => {
const view = new ScrollView(["one", "two"], { height: 1, theme });
expect(view.render(0)).toEqual([""]);
});
it("clamps scroll offset when content shrinks", () => {
const view = new ScrollView(["one", "two", "three", "four"], { height: 2, theme });
view.scrollToBottom();
view.setLines(["one"]);
expect(view.getScrollOffset()).toBe(0);
expect(view.render(10)).toEqual(["one", ""]);
});
it("keeps rendered rows within requested width with ANSI input", () => {
const view = new ScrollView(["\x1b[31malphabet\x1b[0m", "plain", "tail"], { height: 2, theme });
const rendered = view.render(5);
expect(rendered).toHaveLength(2);
expect(rendered.every(line => visibleWidth(line) <= 5)).toBe(true);
expect(rendered[0]).toContain("B");
});
});