parent
859f873eb2
commit
5ebe68d640
@ -0,0 +1,123 @@
|
||||
// @vitest-environment jsdom
|
||||
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { createActiveDom } from '$adom';
|
||||
import { state } from '$libs/reactive';
|
||||
import type { Morfo } from '$uix/morfo';
|
||||
import { Soma } from '$soma/core/soma.svelte';
|
||||
import { createSomaRuntime, type SomaRuntimeSources } from '$soma/runtime.svelte';
|
||||
|
||||
import { VirtualGridProvider } from './virtual-grid-provider.svelte';
|
||||
|
||||
function withEffectRoot<T>(fn: () => T): { result: T; cleanup: () => void } {
|
||||
let result!: T;
|
||||
const cleanup = $effect.root(() => {
|
||||
result = fn();
|
||||
});
|
||||
return { result, cleanup };
|
||||
}
|
||||
|
||||
function installSomaHarness() {
|
||||
const dom = createActiveDom();
|
||||
const soma = {
|
||||
dom,
|
||||
runtime: (morfo: Morfo, sources: Omit<SomaRuntimeSources, 'dom' | 'eventEngine'>) =>
|
||||
createSomaRuntime(morfo, {
|
||||
dom,
|
||||
translate: (key) => key,
|
||||
...sources
|
||||
})
|
||||
} as unknown as Soma;
|
||||
|
||||
vi.spyOn(Soma, 'require').mockReturnValue(soma);
|
||||
vi.spyOn(VirtualGridProvider.ctx, 'set').mockImplementation((value) => value);
|
||||
|
||||
return { dom };
|
||||
}
|
||||
|
||||
function createVirtualGridOpts() {
|
||||
return {
|
||||
id: state('virtual-grid-root'),
|
||||
ref: state<HTMLElement | null>(null),
|
||||
rowCount: state(10),
|
||||
columnCount: state(5),
|
||||
rowSize: state(20),
|
||||
columnSize: state(50),
|
||||
rowOverscan: state(1),
|
||||
columnOverscan: state(1),
|
||||
getRowKey: state<(index: number) => string | number>((index) => `r${index}`),
|
||||
getColumnKey: state<(index: number) => string | number>((index) => `c${index}`)
|
||||
};
|
||||
}
|
||||
|
||||
describe('VirtualGridProvider', () => {
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
document.body.innerHTML = '';
|
||||
});
|
||||
|
||||
it('computes 2D virtual cells from viewport and overscan', () => {
|
||||
const { dom } = installSomaHarness();
|
||||
const opts = createVirtualGridOpts();
|
||||
|
||||
const { result: provider, cleanup } = withEffectRoot(() => VirtualGridProvider.create(opts));
|
||||
provider.viewportHeight = 60;
|
||||
provider.viewportWidth = 100;
|
||||
provider.scrollTop = 30;
|
||||
provider.scrollLeft = 55;
|
||||
|
||||
expect(provider.totalHeight).toBe(200);
|
||||
expect(provider.totalWidth).toBe(250);
|
||||
expect(provider.virtualCells).toHaveLength(30);
|
||||
expect(provider.virtualCells[0]).toEqual({
|
||||
rowIndex: 0,
|
||||
columnIndex: 0,
|
||||
rowStart: 0,
|
||||
columnStart: 0,
|
||||
rowSize: 20,
|
||||
columnSize: 50,
|
||||
key: 'r0|c0'
|
||||
});
|
||||
expect(provider.virtualCells.at(-1)).toEqual({
|
||||
rowIndex: 5,
|
||||
columnIndex: 4,
|
||||
rowStart: 100,
|
||||
columnStart: 200,
|
||||
rowSize: 20,
|
||||
columnSize: 50,
|
||||
key: 'r5|c4'
|
||||
});
|
||||
|
||||
cleanup();
|
||||
dom.dispose();
|
||||
});
|
||||
|
||||
it('routes scrollToCell through ActiveDom', () => {
|
||||
const { dom } = installSomaHarness();
|
||||
const opts = createVirtualGridOpts();
|
||||
const viewport = document.createElement('div');
|
||||
const scrollTo = vi.spyOn(dom, 'scrollTo');
|
||||
|
||||
const { result: provider, cleanup } = withEffectRoot(() => VirtualGridProvider.create(opts));
|
||||
provider.viewportRef = viewport;
|
||||
provider.viewportHeight = 100;
|
||||
provider.viewportWidth = 100;
|
||||
provider.scrollTop = 20;
|
||||
provider.scrollLeft = 30;
|
||||
|
||||
provider.scrollToCell(6, 3, {
|
||||
rowAlign: 'center',
|
||||
columnAlign: 'center'
|
||||
});
|
||||
|
||||
expect(scrollTo).toHaveBeenCalledWith(viewport, {
|
||||
top: 80,
|
||||
left: 125,
|
||||
behavior: 'auto'
|
||||
});
|
||||
|
||||
cleanup();
|
||||
dom.dispose();
|
||||
});
|
||||
});
|
||||
Loading…
Reference in new issue