const test = require('node:test'); const assert = require('node:assert/strict'); const fs = require('node:fs'); const path = require('node:path'); const vm = require('node:vm'); const { JSDOM } = require('jsdom'); const { marked } = require('marked'); const read = file => fs.readFileSync(path.join(__dirname, '..', file), 'utf8'); function ui(t) { const dom = new JSDOM('
inline code<\/code>/);
assert.equal(app.context.messages[0].content, md, 'raw user text is stored unchanged');
assert.equal(app.context.messages[0].role, 'user');
assert.deepEqual(JSON.parse(JSON.stringify(app.context.messages[0].sources)), [], 'user turns carry no source map');
assert.equal(bubble.querySelector('.assistant-cite'), null, 'user text cannot create citation links');
});
test('user tables render with the OWUI wrapper and keyboard-scroll accessibility attributes', t => {
const app = ui(t);
app.context.appendMessage('user', '| Item | Dose |\n| :--- | ---: |\n| Alpha | 2 |');
const scroll = userBubble(app).querySelector('.assistant-table-scroll');
assert.ok(scroll, 'user table gets the shared wrapper');
assert.equal(scroll.getAttribute('tabindex'), '0');
assert.equal(scroll.getAttribute('role'), 'region');
assert.equal(scroll.getAttribute('aria-label'), 'Scrollable table');
assert.equal(scroll.querySelectorAll('tbody tr').length, 1);
});
test('inline markdown images respect the safe allowlist: own assets and data URIs only', t => {
const app = ui(t);
const id = '12345678-1234-1234-1234-123456789abc';
app.context.appendMessage('user', ' and ');
const imgs = userBubble(app).querySelectorAll('img');
assert.equal(imgs.length, 2);
assert.ok(imgs[0].getAttribute('src').endsWith('/api/generated-images/' + id));
assert.ok(imgs[1].getAttribute('src').startsWith('data:image/png;base64,'));
app.context.appendMessage('user', ' and a normal [link](https://example.test/page)');
const bubbles = app.document.querySelectorAll('.assistant-msg.user .assistant-bubble');
assert.equal(bubbles[1].querySelectorAll('img').length, 0, 'external image URLs never render as images');
assert.match(bubbles[1].textContent, /evil/);
assert.equal(bubbles[1].querySelector('a[href="https://example.test/page"]') !== null, true, 'ordinary links stay links');
});
test('assistant markdown rendering and citation chips are unchanged by user-markdown mode', t => {
const app = ui(t);
const sources = [{ title: 'Synthetic A', page: 7 }];
app.context.appendMessage('user', 'What is the dose [1]?');
app.context.appendMessage('assistant', 'Dose [1].', sources);
const assistantBubble = app.document.querySelector('.assistant-msg.assistant .assistant-bubble');
assert.ok(assistantBubble.querySelector('.assistant-cite[data-source-number="1"]'));
assert.equal(userBubble(app).querySelector('.assistant-cite'), null);
assert.deepEqual(app.context.messages[1].sources, sources, 'per-turn source maps preserved');
});