import assert from 'node:assert/strict'; import test from 'node:test'; import { createPortalPublishedPageDelivery, } from './portal-published-page-delivery.mjs'; function createResponse() { return { statusCode: 200, body: undefined, headers: {}, status(code) { this.statusCode = code; return this; }, type(value) { this.headers['Content-Type'] = value; return this; }, set(name, value) { this.headers[name] = value; return this; }, send(body) { this.body = body; return this; }, removeHeader(name) { delete this.headers[name]; }, }; } function createRequest(overrides = {}) { return { originalUrl: '/u/alice/pages/demo?source=test', url: '/u/alice/pages/demo', query: {}, headers: { host: 'portal.example', }, protocol: 'https', get(name) { return name === 'user-agent' ? 'desktop browser' : ''; }, ...overrides, }; } function createResult(overrides = {}) { return { html: 'Demo Page
Demo
', publication: { accessMode: 'public', }, pageSource: null, ...overrides, }; } test('injects rybbit tracker for publication HTML delivery', async () => { const sendPublishedPage = createPortalPublishedPageDelivery({ async registerLongImageArtifact() {}, rybbitConfig: { enabled: true, siteId: '2', idSecret: 'secret', scriptPath: '/rybbit/script.js', hostPath: '/rybbit', }, }); const response = createResponse(); await sendPublishedPage( createRequest(), response, { ...createResult(), ownerId: 'user-123', pageSource: { pageId: 'page-1' }, publication: { id: 'pub-1', accessMode: 'login_required' }, }, { raw: true }, ); assert.match(response.body, /src="\/rybbit\/script\.js"/); assert.match(response.body, /data-site-id="2"/); assert.doesNotMatch(response.body, /user-123/); }); test('wraps a normal full HTML publication in the share shell', async () => { const sendPublishedPage = createPortalPublishedPageDelivery({ async registerLongImageArtifact() {}, }); const response = createResponse(); await sendPublishedPage( createRequest(), response, createResult(), ); assert.equal(response.statusCode, 200); assert.match( response.body, /class="publication-frame"/, ); assert.match( response.body, /view=raw/, ); assert.equal( response.headers['Cache-Control'], 'public, max-age=60', ); }); test('raw and password publications bypass the share shell', async () => { const sendPublishedPage = createPortalPublishedPageDelivery({ async registerLongImageArtifact() {}, }); const rawResponse = createResponse(); await sendPublishedPage( createRequest(), rawResponse, createResult(), { raw: true }, ); assert.doesNotMatch( rawResponse.body, /publication-frame/, ); assert.match(rawResponse.body, /Demo/); const passwordResponse = createResponse(); await sendPublishedPage( createRequest(), passwordResponse, createResult({ publication: { accessMode: 'password', }, }), ); assert.doesNotMatch( passwordResponse.body, /publication-frame/, ); assert.equal( passwordResponse.headers['Cache-Control'], 'private, no-store', ); }); test('embed mode delivers embedded HTML and frame headers', async () => { const sendPublishedPage = createPortalPublishedPageDelivery({ async registerLongImageArtifact() {}, }); const response = createResponse(); await sendPublishedPage( createRequest(), response, createResult(), { embed: true }, ); assert.doesNotMatch( response.body, /publication-frame/, ); assert.equal( response.headers['X-Frame-Options'], undefined, ); }); test('long-image download renders, registers, and returns PNG', async () => { const calls = []; const image = Buffer.from('png-image'); const sendPublishedPage = createPortalPublishedPageDelivery({ async renderLongImage(options) { calls.push(['render', options]); return image; }, async registerLongImageArtifact( options, ) { calls.push(['register', options]); }, }); const response = createResponse(); await sendPublishedPage( createRequest({ query: { download: 'long-image', }, }), response, createResult(), ); assert.equal(response.body, image); assert.equal( response.headers['Content-Type'], 'image/png', ); assert.equal( response.headers['Cache-Control'], 'no-store', ); assert.match( calls[0][1].url, /view=raw/, ); assert.match( calls[1][1].canonicalUrl, /download=long-image/, ); }); test('long-image failures preserve the public error response', async () => { const sendPublishedPage = createPortalPublishedPageDelivery({ async renderLongImage() { throw new Error('renderer failed'); }, async registerLongImageArtifact() {}, }); const response = createResponse(); await sendPublishedPage( createRequest({ query: { download: 'long-image', }, }), response, createResult(), ); assert.equal(response.statusCode, 500); assert.match( response.body, /renderer failed/, ); });