const test = require('node:test'); const assert = require('node:assert/strict'); const fs = require('node:fs'); const path = require('node:path'); const root = path.join(__dirname, '..'); const read = file => fs.readFileSync(path.join(root, file), 'utf8'); // Signed-out preview is an admin opt-in that widens who can reach the assistant, // so the boundaries matter more than the feature. test('preview is off unless an admin turns it on', () => { const route = read('src/routes/clinicalAssistant.js'); assert.match(route, /getSetting\('clinical_assistant\.preview_enabled', 'false'\)/, 'default is off'); assert.match(route, /=== 'true'/, 'and only the exact string enables it'); const admin = read('src/routes/adminConfig.js'); assert.match(admin, /clinical_assistant\.preview_enabled' && !\['true', 'false'\]/, 'the server refuses a non-boolean'); }); test('preview reaches an allow-list of paths, never a pattern', () => { const route = read('src/routes/clinicalAssistant.js'); const block = route.slice(route.indexOf('var PREVIEW_PATHS'), route.indexOf('var PREVIEW_USER')); // A pattern would silently include future routes; an exact list means a new // endpoint is private until someone adds it here deliberately. for (const allowed of ['/clinical-assistant/status', '/clinical-assistant/examples', '/clinical-assistant/chat', '/clinical-assistant/chat/stream']) { assert.ok(block.includes("'" + allowed + "'"), allowed + ' is previewable'); } for (const denied of ['/clinical-assistant/chats', '/clinical-assistant/image', '/clinical-assistant/patient-takehome', '/clinical-assistant/translate']) { assert.ok(!block.includes("'" + denied + "'"), denied + ' must stay private'); } assert.match(route, /PREVIEW_PATHS\.has\(req\.path\)/, 'matched exactly, not by prefix'); }); test('preview never downgrades a real session, and a lookup failure closes the door', () => { const route = read('src/routes/clinicalAssistant.js'); const mw = route.slice(route.indexOf('router.use(async function(req, res, next)'), route.indexOf('router.use(authMiddleware);')); assert.match(mw, /if \(req\.user\) return next\(\);/, 'an established identity is untouched'); assert.match(mw, /hasCredential[\s\S]*?return authMiddleware/, 'a caller presenting a token is authenticated normally, not previewed'); assert.match(mw, /catch \(_\) \{\s*\n\s*return authMiddleware/, 'if the setting cannot be read, authentication is required'); }); test('a preview visitor has no identity, so nothing can be owned or billed', () => { const route = read('src/routes/clinicalAssistant.js'); assert.match(route, /PREVIEW_USER = Object\.freeze\(\{ id: null, preview: true/, 'no user id at all'); // Image generation is owned, stored and paid for, so the tool is withheld // rather than left to fail on a null owner downstream. assert.match(route, /tools: req\.user\.preview \? undefined : imageTool\.tools/); // Each dispatch must be reachable only behind a preview check — either inline // on the same statement, or inside an enclosing `if (!req.user.preview) {`. const lines = route.split('\n'); lines.forEach((line, i) => { if (!line.includes('imageTool.dispatch(')) return; const guardedInline = line.includes('!req.user.preview'); const guardedByBlock = lines.slice(Math.max(0, i - 3), i) .some(l => l.includes('if (!req.user.preview) {')); assert.ok(guardedInline || guardedByBlock, 'unguarded imageTool.dispatch at line ' + (i + 1) + ': ' + line.trim().slice(0, 60)); }); assert.equal(lines.filter(l => l.includes('imageTool.dispatch(')).length, 2, 'both chat paths are covered'); assert.match(route, /if \(!req\.user\.preview\) logger\.audit/, 'audit rows are not written against a null user'); }); test('preview is entered by declining the login overlay, not by faking a session', () => { const auth = read('public/js/auth.js'); const fn = auth.slice(auth.indexOf('function showAuthScreen()'), auth.indexOf('// ── Check for SSO redirect')); assert.match(fn, /pathname === '\/assistant'/, 'only the assistant page previews'); assert.match(fn, /data\.success && data\.preview/, 'and only when the server says so'); assert.match(fn, /authScreen\.style\.display = 'flex';/, 'anything else raises the login screen'); // No token, no user object, no stored credential — the overlay is simply not // shown, so nothing downstream can mistake a visitor for a signed-in user. assert.doesNotMatch(fn, /CURRENT_USER =|SecureStorage\.set/, 'preview never mints an identity'); }); test('reaching for the workspace is where a preview visitor is asked to sign in', () => { const app = read('public/js/app.js'); const handler = app.slice(app.indexOf('// Assistant / Workspace switch'), app.indexOf('window.activateTab = activateTab;')); assert.match(handler, /assistant-preview'\) && !wantsAssistant/); assert.match(handler, /screen\.style\.display = 'flex'/, 'the login screen is raised'); // Actions that need an account are hidden rather than offered and refused. const css = read('public/css/styles.css'); for (const hidden of ['.assistant-plus', '.assistant-history .card', '.assistant-rail-actions']) { assert.ok(css.includes('body.assistant-preview ' + hidden), hidden + ' is hidden in preview'); } assert.match(read('public/components/assistant.html'), /assistant-preview-note/, 'and the state is stated plainly'); });