c7718c683b
Memind CI / Test, build, and release guards (push) Successful in 1m36s
Publication routes and share shells were missing the Rybbit tracker, and bootstrap now reuses the stored MindSpace analytics secret when Rybbit env secret is absent. Co-authored-by: Cursor <cursoragent@cursor.com>
247 lines
5.4 KiB
JavaScript
247 lines
5.4 KiB
JavaScript
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: '<!doctype html><html><head><title>Demo Page</title></head><body><main>Demo</main></body></html>',
|
|
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/,
|
|
);
|
|
});
|