Assessor_2.0/tests/app/table-row-marking.test.tsx

83 lines
4.6 KiB
TypeScript

// @vitest-environment jsdom
import { readFileSync } from 'node:fs';
import { resolve } from 'node:path';
import { afterEach, expect, it } from 'vitest';
import { installTableRowMarking } from '../../src/app/table-row-marking';
const styles = readFileSync(resolve('src/styles/components.css'), 'utf8');
const resultStyles = readFileSync(resolve('src/styles/datahub.css'), 'utf8');
const tokens = readFileSync(resolve('src/styles/ui-tokens.css'), 'utf8');
afterEach(() => { document.body.replaceChildren(); });
it('marks a clicked data row across the whole native table, including after horizontal scrolling', () => {
const scroll = document.createElement('div');
scroll.innerHTML = '<table><thead><tr><th>First</th><th>Last</th></tr></thead><tbody>'
+ '<tr><td>First A</td><td>Last A</td></tr><tr><td>First B</td><td>Last B</td></tr></tbody></table>';
document.body.append(scroll);
const stop = installTableRowMarking(document);
const rows = scroll.querySelectorAll('tbody tr');
scroll.scrollLeft = 400;
rows[0].lastElementChild!.dispatchEvent(new MouseEvent('click', { bubbles: true }));
expect(rows[0].getAttribute('data-row-marked')).toBe('true');
expect(rows[1].hasAttribute('data-row-marked')).toBe(false);
rows[1].lastElementChild!.dispatchEvent(new MouseEvent('click', { bubbles: true }));
expect(rows[0].hasAttribute('data-row-marked')).toBe(false);
expect(rows[1].getAttribute('data-row-marked')).toBe('true');
scroll.querySelector('thead th')!.dispatchEvent(new MouseEvent('click', { bubbles: true }));
expect(rows[1].getAttribute('data-row-marked')).toBe('true');
stop();
expect(styles).toMatch(/table tbody tr\[data-row-marked="true"\] > :is\(th, td\)/);
expect(styles).toContain('inset 0 0 0 9999px var(--table-row-marking-surface)');
expect(styles).toContain('inset 0 var(--bw-emphasis) 0 var(--table-row-marking)');
});
it('marks a Result DB row without preventing its existing expand action or affecting another table', () => {
const area = document.createElement('div');
area.innerHTML = '<div role="table"><div class="results-browser-row results-browser-head" role="row">Header</div>'
+ '<div class="results-browser-row" role="row"><button type="button"><span>Finding A</span></button></div>'
+ '<div class="results-browser-row" role="row"><button type="button"><span>Finding B</span></button></div></div>'
+ '<table><tbody><tr><td>Independent table</td></tr></tbody></table>';
document.body.append(area);
const stop = installTableRowMarking(document);
const rows = area.querySelectorAll('[role="table"] [role="row"]');
const button = rows[1].querySelector('button')!;
let expanded = false;
button.addEventListener('click', () => { expanded = true; });
button.querySelector('span')!.dispatchEvent(new MouseEvent('click', { bubbles: true }));
expect(expanded).toBe(true);
expect(rows[1].getAttribute('data-row-marked')).toBe('true');
rows[2].querySelector('button')!.click();
expect(rows[1].hasAttribute('data-row-marked')).toBe(false);
expect(rows[2].getAttribute('data-row-marked')).toBe('true');
area.querySelector('td')!.dispatchEvent(new MouseEvent('click', { bubbles: true }));
expect(rows[2].getAttribute('data-row-marked')).toBe('true');
rows[0].dispatchEvent(new MouseEvent('click', { bubbles: true }));
expect(rows[0].hasAttribute('data-row-marked')).toBe(false);
stop();
expect(resultStyles).toContain('.results-browser-row[data-row-marked="true"]');
expect(resultStyles).toContain('background: var(--table-row-marking-surface)');
expect(resultStyles).toContain('inset 0 var(--bw-emphasis) 0 var(--table-row-marking)');
});
it('uses the blue table reading marker in both themes while keeping ordinary selection separate', () => {
expect(tokens.match(/--table-row-marking: #(?:4CC2FF|0A66C2);/g)).toHaveLength(2);
expect(tokens.match(/--table-row-marking-surface: color-mix\(in srgb, var\(--table-row-marking\) 14%, transparent\);/g)).toHaveLength(2);
expect(tokens).toContain('--selection-border: var(--marking-color)');
expect(tokens).toContain('--focus-ring: #4CC2FF');
expect(tokens).toContain('--focus-ring: #0A66C2');
});
it('ignores virtual spacer rows and releases the listener on unmount', () => {
const table = document.createElement('table');
table.innerHTML = '<tbody><tr aria-hidden="true"><td>Spacer</td></tr><tr><td>Value</td></tr></tbody>';
document.body.append(table);
const stop = installTableRowMarking(document);
const rows = table.querySelectorAll('tr');
rows[0].querySelector('td')!.click();
expect(rows[0].hasAttribute('data-row-marked')).toBe(false);
stop();
rows[1].querySelector('td')!.click();
expect(rows[1].hasAttribute('data-row-marked')).toBe(false);
});