// @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 = '
| First | Last |
'
+ '| First A | Last A |
| First B | Last B |
';
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 = 'Header
'
+ '
'
+ '
'
+ '';
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 = '| Spacer |
| Value |
';
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);
});