/
Starolat
/
DeepDive
Обзор
Документация
Войти
/
Starolat
/
DeepDive
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
tests/data-grid.test.js
252 строки
10 KB
Starolat Sergei
merge: рефакторинг DataGrid + DataGridToolbar + DataSource (v1.4.2)
06 июл 2026, 22:49
06 июл 2026, 22:49
3864163
Код
Авторство
О чём код?
// @ts-check /** * @fileoverview Unit tests for DataGrid core component * @jest-environment jsdom */ import { jest } from '@jest/globals'; import '../js/components/DataGrid.js'; describe('DataGrid — core table behavior', () => { let grid; beforeEach(() => { grid = document.createElement('data-grid'); document.body.appendChild(grid); Object.defineProperty(navigator, 'clipboard', { value: { writeText: jest.fn(() => Promise.resolve()) }, configurable: true, }); }); afterEach(() => { grid.remove(); }); const flatColumns = [ { id: 'name', header: 'Name', field: 'name', type: 'text', width: 200, visible: true, sortable: true, filterable: true }, { id: 'value', header: 'Value', field: 'value', type: 'number', width: 100, visible: true, sortable: true, filterable: false }, ]; const flatRows = [ { id: 'r1', type: 'row', level: 0, hasChildren: false, expanded: false, displayName: 'Alpha', data: { name: 'Alpha', value: 10 } }, { id: 'r2', type: 'row', level: 0, hasChildren: false, expanded: false, displayName: 'Beta', data: { name: 'Beta', value: 5 } }, { id: 'r3', type: 'row', level: 0, hasChildren: false, expanded: false, displayName: 'Gamma', data: { name: 'Gamma', value: 20 } }, ]; // ===================================================================== // Lifecycle / attributes // ===================================================================== describe('UT-DG-001: initialization', () => { it('should define custom element', () => { expect(customElements.get('data-grid')).toBeTruthy(); }); it('should have shadow root', () => { expect(grid.shadowRoot).toBeTruthy(); }); it('should default row-height to 20', () => { expect(grid.getAttribute('row-height') || '20').toBe('20'); }); it('should accept row-height attribute', () => { grid.setAttribute('row-height', '24'); expect(grid.getAttribute('row-height')).toBe('24'); }); }); // ===================================================================== // Columns & rows // ===================================================================== describe('UT-DG-002: columns and rows', () => { it('should set columns', () => { grid.setColumns(flatColumns); expect(grid.columns).toHaveLength(2); expect(grid.columns[0].id).toBe('name'); }); it('should set rows', () => { grid.setColumns(flatColumns); grid.setRows(flatRows); expect(grid.allRows).toHaveLength(3); }); it('should render header cells for visible columns', () => { grid.setColumns(flatColumns); grid.setRows(flatRows); const headers = grid.shadowRoot.querySelectorAll('.header-cell'); expect(headers.length).toBeGreaterThanOrEqual(2); }); it('should hide invisible columns', () => { const cols = flatColumns.map(c => ({ ...c, visible: c.id === 'name' })); grid.setColumns(cols); grid.setRows(flatRows); const visibleHeaders = grid.shadowRoot.querySelectorAll('.header-cell:not(.hidden)'); expect(visibleHeaders.length).toBe(1); }); }); // ===================================================================== // Sorting // ===================================================================== describe('UT-DG-003: sorting', () => { it('should sort rows ascending by number column', () => { grid.setColumns(flatColumns); grid.setRows(flatRows); grid.sortBy('value', 'asc'); const values = grid.visibleRows.map(r => r.data.value); expect(values).toEqual([5, 10, 20]); }); it('should sort rows descending by number column', () => { grid.setColumns(flatColumns); grid.setRows(flatRows); grid.sortBy('value', 'desc'); const values = grid.visibleRows.map(r => r.data.value); expect(values).toEqual([20, 10, 5]); }); it('should emit grid-sort-change event', () => { grid.setColumns(flatColumns); grid.setRows(flatRows); const handler = jest.fn(); grid.addEventListener('grid-sort-change', handler); const header = grid.shadowRoot.querySelector('.header-cell[data-column-id="value"]'); if (header) header.click(); expect(handler).toHaveBeenCalledTimes(1); }); }); // ===================================================================== // Selection // ===================================================================== describe('UT-DG-004: row selection', () => { it('should select a single row via property', () => { grid.setColumns(flatColumns); grid.setRows(flatRows); grid.selectedRowIds.add('r1'); grid._updateSelectionVisuals(); expect(grid.selectedRowIds.has('r1')).toBe(true); }); it('should emit grid-selection-change on row click', () => { grid.setColumns(flatColumns); grid.setRows(flatRows); const handler = jest.fn(); grid.addEventListener('grid-selection-change', handler); const row = grid.shadowRoot.querySelector('[data-row-id="r1"]'); if (row) row.click(); expect(handler).toHaveBeenCalled(); }); it('should clear selection', () => { grid.setColumns(flatColumns); grid.setRows(flatRows); grid.selectedRowIds.add('r1'); grid.selectedRowIds.clear(); grid._updateSelectionVisuals(); expect(grid.selectedRowIds.size).toBe(0); }); }); // ===================================================================== // Tree expand/collapse // ===================================================================== describe('UT-DG-005: tree rows', () => { const treeRows = [ { id: 'p1', type: 'wbs', level: 0, hasChildren: true, expanded: false, displayName: 'Parent', data: {} }, { id: 'c1', type: 'activity', level: 1, hasChildren: false, expanded: false, displayName: 'Child 1', data: {}, parentId: 'p1' }, { id: 'c2', type: 'activity', level: 1, hasChildren: false, expanded: false, displayName: 'Child 2', data: {}, parentId: 'p1' }, ]; it('should collapse children by default', () => { grid.setColumns(flatColumns); grid.setRows(treeRows); expect(grid.visibleRows.length).toBe(1); }); it('should expand row and show children', () => { grid.setColumns(flatColumns); grid.setRows(treeRows); grid.expandRow('p1'); expect(grid.visibleRows.length).toBe(3); }); it('should collapse expanded row', () => { grid.setColumns(flatColumns); grid.setRows(treeRows); grid.expandRow('p1'); grid.collapseRow('p1'); expect(grid.visibleRows.length).toBe(1); }); it('should expand all rows with children', () => { grid.setColumns(flatColumns); grid.setRows(treeRows); grid.expandAll(); expect(grid.visibleRows.length).toBe(3); }); it('should collapse all rows', () => { grid.setColumns(flatColumns); grid.setRows(treeRows); grid.expandAll(); grid.collapseAll(); expect(grid.visibleRows.length).toBe(1); }); }); // ===================================================================== // Filtering // ===================================================================== describe('UT-DG-006: auto filters', () => { it('should filter rows by text', () => { grid.setColumns(flatColumns); grid.setRows(flatRows); grid.applyFilters([{ columnId: 'name', field: 'name', operator: 'contains', value: 'et', isActive: true }]); expect(grid.visibleRows.length).toBe(1); expect(grid.visibleRows[0].data.name).toBe('Beta'); }); it('should clear filters', () => { grid.setColumns(flatColumns); grid.setRows(flatRows); grid.applyFilters([{ columnId: 'name', field: 'name', operator: 'contains', value: 'et', isActive: true }]); grid.clearFilters(); expect(grid.visibleRows.length).toBe(3); }); it('should emit grid-filter-change event', () => { grid.setColumns(flatColumns); grid.setRows(flatRows); const handler = jest.fn(); grid.addEventListener('grid-filter-change', handler); grid.applyFilters([{ columnId: 'name', field: 'name', operator: 'contains', value: 'et', isActive: true }]); expect(handler).toHaveBeenCalled(); }); }); // ===================================================================== // Copy / export // ===================================================================== describe('UT-DG-007: clipboard helpers', () => { it('should call clipboard writeText on copy', async () => { grid.setColumns(flatColumns); grid.setRows(flatRows); await grid.copyToClipboard({ format: 'csv', delimiter: ';' }); expect(navigator.clipboard.writeText).toHaveBeenCalled(); const text = navigator.clipboard.writeText.mock.calls[0][0]; expect(text).toContain('Name'); expect(text).toContain('Alpha'); }); }); });