← Files CastReaderARCHIVED FILE
tests/read-answer.test.mjs
1.79 KB · Sep 30, 2026 · 23:16 UTC
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { get } from 'node:http';
import { answerPayload, readerURL, openAnswerBridge } from '../scripts/read-answer.mjs';
test('complete Markdown survives transport without a developer API key', () => {
const markdown = '# Answer\n\n**Bold** and [link](https://castreader.com).\n\n```js\nconst x = 1;\n```\n';
const payload = answerPayload(markdown);
const url = new URL(readerURL(payload));
assert.equal(url.origin, 'https://castreader.com');
assert.equal(url.search, '');
const decoded = JSON.parse(Buffer.from(new URLSearchParams(url.hash.slice(1)).get('answer'), 'base64url'));
assert.equal(decoded.markdown, markdown);
assert.equal(decoded.sha256, payload.sha256);
assert.throws(() => answerPayload('a'.repeat(120001)));
assert.throws(() => answerPayload('你好', { language: 'zh' }));
});
test('bridge exposes only an unguessable loopback path; no workspace or credentials', async t => {
const bridge = await openAnswerBridge(answerPayload('Hello **world**'));
t.after(() => bridge.server.close());
const response = await fetch(bridge.url);
const html = await response.text();
assert.equal(response.status, 200);
assert.match(response.headers.get('content-security-policy'), /frame-ancestors 'none'/);
assert.match(html, /location.replace/);
assert.doesNotMatch(html, /API_KEY|state\.json|receipt\.json/);
assert.equal((await fetch(new URL('/.env', bridge.url))).status, 404);
assert.equal((await fetch(bridge.url, { method: 'POST' })).status, 404);
const wrongHostStatus = await new Promise((resolve, reject) => {
get(bridge.url, { headers: { Host: 'evil.example' } }, response => { response.resume(); resolve(response.statusCode); }).on('error', reject);
});
assert.equal(wrongHostStatus, 404);
});
SHA-256: 361c695c7df28f17e6423b7101d4941f9809940d6f1758a9a86b5dfbb17ed1fb