import { expect, tap } from '@git.zone/tstest/tapbundle'; import * as deesCatalog from '../ts_web/index.js'; import type { Column, ISortDescriptor, } from '../ts_web/elements/00group-dataview/dees-table/index.js'; interface ITestRow { id: string; score: number; label: string; } const testColumns: Column[] = [ { key: 'id', header: 'ID' }, { key: 'score', header: 'Score' }, { key: 'label', header: 'Label' }, ]; const scoreSort: ISortDescriptor[] = [{ key: 'score', dir: 'desc' }]; const waitForNextFrame = async () => { await new Promise((resolve) => { requestAnimationFrame(() => resolve()); }); }; const waitForMacrotask = async () => { await new Promise((resolve) => { window.setTimeout(() => resolve(), 0); }); }; const settleTable = async (table: deesCatalog.DeesTable) => { await table.updateComplete; await waitForNextFrame(); await waitForMacrotask(); await table.updateComplete; }; const createRows = (iteration: number): ITestRow[] => { const cycle = iteration % 3; if (cycle === 0) { return [ { id: 'alpha', score: 60, label: `Alpha ${iteration}` }, { id: 'beta', score: 20, label: `Beta ${iteration}` }, { id: 'gamma', score: 40, label: `Gamma ${iteration}` }, ]; } if (cycle === 1) { return [ { id: 'alpha', score: 30, label: `Alpha ${iteration}` }, { id: 'beta', score: 70, label: `Beta ${iteration}` }, { id: 'gamma', score: 50, label: `Gamma ${iteration}` }, ]; } return [ { id: 'alpha', score: 55, label: `Alpha ${iteration}` }, { id: 'beta', score: 35, label: `Beta ${iteration}` }, { id: 'gamma', score: 75, label: `Gamma ${iteration}` }, ]; }; const createTable = ( rows: ITestRow[], highlightUpdates: 'none' | 'flash' ): deesCatalog.DeesTable => { const table = new deesCatalog.DeesTable(); table.searchable = false; table.columns = testColumns; table.rowKey = 'id'; table.sortBy = scoreSort; table.highlightUpdates = highlightUpdates; table.data = rows; document.body.appendChild(table); return table; }; const countComments = (root: Node): number => { const walker = document.createTreeWalker(root, NodeFilter.SHOW_COMMENT); let count = 0; while (walker.nextNode()) count++; return count; }; const getBodyRows = (table: deesCatalog.DeesTable): HTMLTableRowElement[] => Array.from( table.shadowRoot?.querySelectorAll('tbody tr[data-row-idx]') ?? [] ) as HTMLTableRowElement[]; const getRenderedRowIds = (table: deesCatalog.DeesTable): string[] => getBodyRows(table).map((row) => row.cells[0]?.textContent?.trim() ?? ''); const getRenderedRowMap = ( table: deesCatalog.DeesTable ): Map => { const rowMap = new Map(); for (const row of getBodyRows(table)) { const rowId = row.cells[0]?.textContent?.trim() ?? ''; if (rowId) rowMap.set(rowId, row); } return rowMap; }; tap.test('dees-table avoids repeated width measurement and comment growth on live updates', async () => { const table = new deesCatalog.DeesTable(); let widthMeasureCalls = 0; const originalDetermineColumnWidths = table.determineColumnWidths.bind(table); table.determineColumnWidths = (async () => { widthMeasureCalls++; await originalDetermineColumnWidths(); }) as typeof table.determineColumnWidths; table.searchable = false; table.columns = testColumns; table.rowKey = 'id'; table.sortBy = scoreSort; table.highlightUpdates = 'none'; table.data = createRows(0); document.body.appendChild(table); try { await settleTable(table); const initialWidthMeasureCalls = widthMeasureCalls; const initialCommentCount = countComments(table.shadowRoot!); expect(initialWidthMeasureCalls).toBeGreaterThan(0); for (let iteration = 1; iteration <= 10; iteration++) { table.data = createRows(iteration); await settleTable(table); } expect(widthMeasureCalls).toEqual(initialWidthMeasureCalls); expect(countComments(table.shadowRoot!)).toEqual(initialCommentCount); } finally { table.remove(); } }); tap.test('dees-table reuses row DOM while flashing live-sorted updates', async () => { const table = createTable(createRows(0), 'flash'); try { await settleTable(table); const initialRowMap = getRenderedRowMap(table); table.data = createRows(1); await settleTable(table); const updatedRowMap = getRenderedRowMap(table); expect(getRenderedRowIds(table)).toEqual(['beta', 'gamma', 'alpha']); expect(updatedRowMap.get('alpha')).toEqual(initialRowMap.get('alpha')); expect(updatedRowMap.get('beta')).toEqual(initialRowMap.get('beta')); expect(updatedRowMap.get('gamma')).toEqual(initialRowMap.get('gamma')); } finally { table.remove(); } }); export default tap.start();