feat(desktop): pure scroll-decision logic for new message list

This commit is contained in:
byGalax
2026-06-02 20:25:06 +02:00
parent f73abbd860
commit 43a99a8d6d
2 changed files with 100 additions and 0 deletions
@@ -0,0 +1,57 @@
import { describe, expect, it } from 'vitest';
import { isNearBottom, isNearTop, resolveInitialAnchor } from './scrollController';
const m = (scrollTop: number, scrollHeight: number, clientHeight: number) => ({
scrollTop,
scrollHeight,
clientHeight,
});
describe('isNearBottom', () => {
it('true exactly at the bottom', () => {
expect(isNearBottom(m(900, 1000, 100), 64)).toBe(true);
});
it('true within threshold', () => {
expect(isNearBottom(m(860, 1000, 100), 64)).toBe(true);
});
it('false beyond threshold', () => {
expect(isNearBottom(m(800, 1000, 100), 64)).toBe(false);
});
});
describe('isNearTop', () => {
it('true at top', () => {
expect(isNearTop(m(0, 1000, 100), 64)).toBe(true);
});
it('false past threshold', () => {
expect(isNearTop(m(200, 1000, 100), 64)).toBe(false);
});
});
describe('resolveInitialAnchor', () => {
it('anchors to last row at end by default (no saved position)', () => {
expect(resolveInitialAnchor(null, 50)).toEqual({ index: 49, align: 'end' });
});
it('anchors to bottom when saved position stuck to bottom', () => {
expect(resolveInitialAnchor({ topmostIndex: 10, stickToBottom: true }, 50)).toEqual({
index: 49,
align: 'end',
});
});
it('restores the saved row at the top when scrolled up', () => {
expect(resolveInitialAnchor({ topmostIndex: 12, stickToBottom: false }, 50)).toEqual({
index: 12,
align: 'start',
});
});
it('clamps a stale saved index to the current row count', () => {
expect(resolveInitialAnchor({ topmostIndex: 999, stickToBottom: false }, 50)).toEqual({
index: 49,
align: 'start',
});
});
it('handles an empty list', () => {
expect(resolveInitialAnchor(null, 0)).toEqual({ index: 0, align: 'end' });
});
});