fixes and refactor
This commit is contained in:
82
tests/test_highlight_parity.py
Normal file
82
tests/test_highlight_parity.py
Normal file
@@ -0,0 +1,82 @@
|
||||
import json
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from app.api.search_highlight import build_query_tokens, highlight_text
|
||||
|
||||
|
||||
def _run_node_highlight(value: str, query: str):
|
||||
"""Invoke Node to run client highlight.js and return tokens and html.
|
||||
|
||||
Skips DOM and sanitizer loading by providing a minimal window with an
|
||||
escape() function that mirrors server escaping behavior.
|
||||
"""
|
||||
node_path = shutil.which("node")
|
||||
if not node_path:
|
||||
return None
|
||||
|
||||
repo_root = Path(__file__).resolve().parents[1]
|
||||
highlight_js_path = repo_root / "static/js/highlight.js"
|
||||
if not highlight_js_path.exists():
|
||||
return None
|
||||
|
||||
payload = json.dumps({"value": value, "query": query})
|
||||
script = f"""
|
||||
const fs = require('fs');
|
||||
global.window = {{}};
|
||||
// Provide escape that matches server: replace &, <, >, ", '
|
||||
window.htmlSanitizer = {{
|
||||
escape: function(text) {{
|
||||
const str = String(text == null ? '' : text);
|
||||
return str
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
}}
|
||||
}};
|
||||
require('{highlight_js_path.as_posix()}');
|
||||
const input = JSON.parse(process.argv[2]);
|
||||
const tokens = window.highlightUtils.buildTokens(input.query);
|
||||
const html = window.highlightUtils.highlight(input.value, tokens);
|
||||
process.stdout.write(JSON.stringify({{ tokens, html }}));
|
||||
"""
|
||||
res = subprocess.run(
|
||||
[node_path, "-e", script, payload],
|
||||
cwd=str(repo_root),
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
if res.returncode != 0:
|
||||
return None
|
||||
return json.loads(res.stdout)
|
||||
|
||||
|
||||
def test_highlight_parity_with_client_when_node_available():
|
||||
"""Compare tokens and highlighted HTML between server and client implementations.
|
||||
|
||||
This test is skipped when Node is unavailable.
|
||||
"""
|
||||
samples = [
|
||||
("Hello John Smith", "john smith"),
|
||||
("<b>A&B</b> and C", "a b"),
|
||||
("Anna and Ann went", "ann anna"),
|
||||
("He said \"Hello\" & it's fine", "hello"),
|
||||
("Case 12345", "case 123"),
|
||||
]
|
||||
|
||||
for value, query in samples:
|
||||
client = _run_node_highlight(value, query)
|
||||
if client is None:
|
||||
# Skip gracefully if Node not present or script failed
|
||||
import pytest
|
||||
pytest.skip("Node or client highlight not available")
|
||||
server_tokens = build_query_tokens(query)
|
||||
server_html = highlight_text(value, server_tokens)
|
||||
assert client["tokens"] == server_tokens
|
||||
assert client["html"] == server_html
|
||||
|
||||
|
||||
Reference in New Issue
Block a user