64 lines
3.6 KiB
TypeScript
64 lines
3.6 KiB
TypeScript
import { createElement } from 'react';
|
||
import { renderToStaticMarkup } from 'react-dom/server';
|
||
import { readFileSync } from 'node:fs';
|
||
import { describe, expect, it } from 'vitest';
|
||
import { PathText, isWholePath } from '../../src/components/PathText/PathText';
|
||
import { RichTextValue } from '../../src/components/RichTextValue/RichTextValue';
|
||
|
||
const render = (value: string, label?: string, search?: string) => renderToStaticMarkup(createElement(PathText, { value, label, search }));
|
||
|
||
describe('shared path presentation', () => {
|
||
it.each(['C:\\Program Files\\Synthetic\\report.xml', '\\\\synthetic.invalid\\Reports\\scan.xml', 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Synthetic', 'SOFTWARE\\Policies\\Synthetic', '/var/log/synthetic.log', '../Synthetic/report.xml'])('boxes a complete path without changing it: %s', value => {
|
||
expect(render(value)).toBe(`<code class="technical-path">${value}</code>`);
|
||
});
|
||
|
||
it('isolates path lines from labels, metadata and audit guidance', () => {
|
||
const html = render('Source 1\nSource path: {synthetic}/DomainSysvol/GPO/Machine/windows nt/report.inf#lines=9\nScope: computer\nKey: SOFTWARE\\Synthetic\nData: 0\nComputer policy: system audit subcategory · synthetic');
|
||
expect(html.match(/class="technical-path"/g)).toHaveLength(2);
|
||
expect(html).toContain('</code>\nScope: computer');
|
||
expect(html).toContain('</code>\nData: 0');
|
||
expect(html).toContain('Computer policy: system audit subcategory · synthetic');
|
||
});
|
||
|
||
it('preserves spaces, full long paths and search highlighting', () => {
|
||
const path = 'Root folder/' + 'segment/'.repeat(100) + 'Synthetic.xml';
|
||
expect(render(path, 'Source path', 'synthetic')).toContain('Root folder/');
|
||
expect(render(path, 'Source path', 'synthetic')).toContain('<mark class="search-highlight">Synthetic</mark>.xml');
|
||
expect(render(path, 'Source path')).toContain(path);
|
||
});
|
||
|
||
it('escapes path content and never introduces links or active markup', () => {
|
||
const html = render('<img src="https://synthetic.invalid">', 'Source path');
|
||
expect(html).toContain('<img');
|
||
expect(html).not.toContain('<img');
|
||
expect(html).not.toContain('href=');
|
||
expect(renderToStaticMarkup(createElement(RichTextValue, { label: 'Source path', value: '<b>synthetic</b>' }))).toContain('<b>');
|
||
});
|
||
|
||
it('leaves empty values, placeholders, identifiers and URLs alone', () => {
|
||
for (const value of ['', 'Not configured', '–', 'backup-synthetic', 'Scope: computer', 'https://example.invalid/page']) {
|
||
expect(isWholePath(value)).toBe(false);
|
||
expect(render(value)).not.toContain('technical-path');
|
||
}
|
||
expect(render('Not configured', 'Registry path')).toBe('Not configured');
|
||
});
|
||
|
||
it('uses path styling in ordinary report text as well', () => {
|
||
for (const value of ['Source path: Synthetic/report.xml\nScope: computer', 'Source path: Synthetic/report.xml']) {
|
||
const html = renderToStaticMarkup(createElement(RichTextValue, { value }));
|
||
expect(html).toContain('Source path: <code class="technical-path">Synthetic/report.xml</code>');
|
||
}
|
||
});
|
||
|
||
it('uses shared theme colors and a path-only font exception without clipping', () => {
|
||
const css = readFileSync(new URL('../../src/styles/components.css', import.meta.url), 'utf8');
|
||
const rule = css.slice(css.indexOf('.technical-path,')).split('}')[0];
|
||
expect(rule).toContain('font-family: var(--font-path)');
|
||
expect(rule).toContain('font-size: inherit');
|
||
expect(rule).toContain('background: var(--surface-inset)');
|
||
expect(rule).toContain('overflow-wrap: anywhere');
|
||
expect(rule).toContain('white-space: pre-wrap');
|
||
expect(rule).not.toMatch(/hidden|ellipsis|nowrap/);
|
||
});
|
||
});
|