Expand i18n locales and improve reviews UI
Add many new language packs with RTL support, refresh brand assets, and harden review rendering with tests. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* The review body renderer, against hostile relay content.
|
||||
*
|
||||
* `lib/review-body.ts` is deliberately import-free so this file can load it under
|
||||
* plain node with type stripping: `pnpm test` (node --experimental-strip-types).
|
||||
* If these fail, an event someone can sign today can break or script the card.
|
||||
*/
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { escapeHtml, reviewBodyHtml } from '../src/lib/review-body.ts';
|
||||
import { HOSTILE_REVIEW_CONTENT, LONG_URL, PASTED_NPUB } from './hostile-review.mjs';
|
||||
|
||||
/** The output with this module's own <a> elements removed: nothing else may be markup. */
|
||||
function withoutOwnLinks(html) {
|
||||
return html.replace(/<a class="rev-link" [^>]*>.*?<\/a>/gs, '');
|
||||
}
|
||||
|
||||
test('the hostile fixture renders with no live markup', () => {
|
||||
const html = reviewBodyHtml(HOSTILE_REVIEW_CONTENT);
|
||||
const rest = withoutOwnLinks(html);
|
||||
assert.ok(!rest.includes('<'), `unescaped markup survived: ${rest.slice(0, 200)}`);
|
||||
assert.ok(html.includes('<script>'), 'script tag must render as text');
|
||||
assert.ok(!/<img|<b>|<script/.test(html), 'no element from the body ever becomes real');
|
||||
});
|
||||
|
||||
test('40 newlines collapse to a single blank line', () => {
|
||||
const html = reviewBodyHtml(HOSTILE_REVIEW_CONTENT);
|
||||
assert.ok(!/\n{3,}/.test(html), '3+ consecutive newlines must not survive');
|
||||
});
|
||||
|
||||
test('the 500-char URL links out but shows at most 40 characters', () => {
|
||||
const html = reviewBodyHtml(HOSTILE_REVIEW_CONTENT);
|
||||
const match = /<a class="rev-link" href="([^"]+)" target="_blank" rel="nofollow ugc noopener">([^<]+)<\/a>/.exec(html);
|
||||
assert.ok(match, 'the URL must become a link');
|
||||
assert.equal(match[1], LONG_URL, 'the full URL goes in the href');
|
||||
assert.ok(match[2].length <= 40, `shown text is ${match[2].length} chars, wanted <= 40`);
|
||||
assert.ok(match[2].includes('…'), 'truncation is middle-out, marked with an ellipsis');
|
||||
assert.ok(match[2].startsWith('https://very.long.exampl'), 'the head survives');
|
||||
});
|
||||
|
||||
test('a pasted npub stays inert text', () => {
|
||||
const html = reviewBodyHtml(HOSTILE_REVIEW_CONTENT);
|
||||
assert.ok(html.includes(PASTED_NPUB), 'the npub passes through as text');
|
||||
assert.ok(!html.includes(`href="${PASTED_NPUB}`), 'and is never a link');
|
||||
});
|
||||
|
||||
test('emoji pass through untouched', () => {
|
||||
const html = reviewBodyHtml(HOSTILE_REVIEW_CONTENT);
|
||||
assert.ok(html.includes('\u{1F9C0}✅'));
|
||||
});
|
||||
|
||||
test('nostr: URIs render as short plain text, never links', () => {
|
||||
const html = reviewBodyHtml(`see nostr:${PASTED_NPUB} for who I am`);
|
||||
assert.ok(!html.includes('<a'), 'a nostr URI must not become a link');
|
||||
assert.ok(!html.includes('nostr:'), 'the scheme is dropped');
|
||||
assert.ok(html.includes('npub180cvv07…yjh6w6'), 'the payload is shortened middle-out');
|
||||
});
|
||||
|
||||
test('control characters and bidi overrides are stripped', () => {
|
||||
const html = reviewBodyHtml('a\u0000bc \u202Eevil\u202C d\u200Be');
|
||||
assert.equal(html, 'abc evil de', 'controls, overrides and zero-widths gone');
|
||||
});
|
||||
|
||||
test('trailing sentence punctuation stays out of the href', () => {
|
||||
const html = reviewBodyHtml('read this (https://example.com/page).');
|
||||
assert.ok(html.includes('href="https://example.com/page"'), 'the parenthesis and dot are prose');
|
||||
assert.ok(html.includes('</a>).'), 'and stay visible after the link');
|
||||
});
|
||||
|
||||
test('short URLs are shown whole', () => {
|
||||
const html = reviewBodyHtml('https://mint.example.com');
|
||||
assert.ok(html.includes('>https://mint.example.com</a>'));
|
||||
});
|
||||
|
||||
test('escapeHtml escapes all five characters', () => {
|
||||
assert.equal(escapeHtml(`<a b="c" & 'd'>`), '<a b="c" & 'd'>');
|
||||
});
|
||||
Reference in New Issue
Block a user