coming together
This commit is contained in:
79
static/js/__tests__/highlight.test.js
Normal file
79
static/js/__tests__/highlight.test.js
Normal file
@@ -0,0 +1,79 @@
|
||||
/** @jest-environment jsdom */
|
||||
|
||||
// Load dependencies used by highlight utils
|
||||
require('../sanitizer.js');
|
||||
require('../highlight.js');
|
||||
|
||||
describe('highlightUtils', () => {
|
||||
const { buildTokens, highlight, escape: esc, formatSnippet } = window.highlightUtils;
|
||||
|
||||
test('buildTokens normalizes punctuation, trims non-alphanumerics, and dedupes', () => {
|
||||
const tokens = buildTokens(' John, Smith; "Smith" (J.) ');
|
||||
// Expect order preserved except deduping
|
||||
expect(tokens).toEqual(['John', 'Smith', 'J']);
|
||||
const empty = buildTokens(' , ; : ');
|
||||
expect(empty).toEqual([]);
|
||||
});
|
||||
|
||||
test('escape encodes special characters safely', () => {
|
||||
const out = esc('<div> & "quotes" and \'apostrophes\'');
|
||||
expect(out).toContain('<div>');
|
||||
expect(out).toContain('&');
|
||||
expect(out).toContain('"');
|
||||
expect(out).toContain(''');
|
||||
expect(esc('Tom & Jerry')).toBe('Tom & Jerry');
|
||||
});
|
||||
|
||||
test('highlight wraps tokens in <strong> and does not break HTML by escaping first', () => {
|
||||
const tokens = buildTokens('john smith');
|
||||
const result = highlight('Hello <b>John</b> Smith & Sons', tokens);
|
||||
// Should escape original tags and then apply strong
|
||||
expect(result).toContain('<b>');
|
||||
expect(result).toMatch(/<strong>John<\/strong>/i);
|
||||
expect(result).toMatch(/<strong>Smith<\/strong>/i);
|
||||
// Ampersand must be escaped
|
||||
expect(result).toContain('& Sons');
|
||||
});
|
||||
|
||||
test('highlight handles overlapping tokens by sequential replacement', () => {
|
||||
const tokens = buildTokens('ann anna');
|
||||
const out = highlight('Anna and Ann went', tokens);
|
||||
// Both tokens should appear highlighted; order of replacement should not remove prior highlights
|
||||
const strongCount = (out.match(/<strong>/g) || []).length;
|
||||
expect(strongCount).toBeGreaterThanOrEqual(2);
|
||||
expect(out).toMatch(/<strong>Anna<\/strong> and <strong>Ann<\/strong> went/i);
|
||||
});
|
||||
|
||||
test('formatSnippet uses server-provided strong tags if present', () => {
|
||||
const tokens = buildTokens('alpha');
|
||||
const serverSnippet = 'Value: <strong>Alpha</strong> beta';
|
||||
const html = formatSnippet(serverSnippet, tokens);
|
||||
// Should preserve strong from server
|
||||
expect(html).toContain('<strong>Alpha</strong>');
|
||||
// Should be sanitized and not double-escaped
|
||||
expect(html).toContain('Value: ');
|
||||
});
|
||||
|
||||
test('formatSnippet applies client-side bold when server snippet is plain text', () => {
|
||||
const tokens = buildTokens('delta');
|
||||
const plain = 'Gamma delta epsilon';
|
||||
const html = formatSnippet(plain, tokens);
|
||||
expect(html).toMatch(/Gamma <strong>delta<\/strong> epsilon/i);
|
||||
});
|
||||
|
||||
test('highlight is case-insensitive and preserves original text casing', () => {
|
||||
const tokens = buildTokens('joHN smiTH');
|
||||
const out = highlight('John Smith', tokens);
|
||||
// Must wrap both tokens and preserve the original casing from the source text
|
||||
expect(out).toBe('<strong>John</strong> <strong>Smith</strong>');
|
||||
});
|
||||
|
||||
test('formatSnippet highlights with mixed-case query tokens but keeps snippet casing', () => {
|
||||
const tokens = buildTokens('doE');
|
||||
const html = formatSnippet('Hello Doe', tokens);
|
||||
// Exact casing from snippet should be preserved inside <strong>
|
||||
expect(html).toContain('Hello <strong>Doe</strong>');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user