229805a070
Add WeChat service account routing with sync acks, connectivity tests, and context isolation; document deploy runbooks; and bundle related MindSpace, voice, Plaza, and server gateway changes for production rollout. Co-authored-by: Cursor <cursoragent@cursor.com>
71 lines
3.6 KiB
JavaScript
71 lines
3.6 KiB
JavaScript
import { test } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { injectOgTags } from './mindspace-og-tags.mjs';
|
|
|
|
const ctx = {
|
|
origin: 'https://g2.tkmind.cn',
|
|
pageUrl: 'https://g2.tkmind.cn/MindSpace/john/public/space.html',
|
|
pageDirUrl: 'https://g2.tkmind.cn/MindSpace/john/public/',
|
|
};
|
|
|
|
test('injects og/twitter tags with absolute image from a relative cover', () => {
|
|
const html = `<html><head><title>🚀 太空小勇士 - 闯关大冒险</title>` +
|
|
`<meta name="description" content="一起闯关大冒险">` +
|
|
`<meta name="mindspace-cover" content='{"tag":"游戏","cover":"assets/hero.jpg"}'></head><body></body></html>`;
|
|
const out = injectOgTags(html, ctx);
|
|
assert.match(out, /<meta property="og:title" content="🚀 太空小勇士 - 闯关大冒险">/);
|
|
assert.match(out, /<meta property="og:description" content="一起闯关大冒险">/);
|
|
assert.match(out, /<meta property="og:image" content="https:\/\/g2\.tkmind\.cn\/MindSpace\/john\/public\/assets\/hero\.jpg">/);
|
|
assert.match(out, /<meta name="twitter:card" content="summary_large_image">/);
|
|
// injected before </head>
|
|
assert.ok(out.indexOf('og:image') < out.indexOf('</head>'));
|
|
});
|
|
|
|
test('falls back to the thumbnail png when the page has no cover of its own', () => {
|
|
const html = `<head><title>纯文字页面</title></head>`;
|
|
const out = injectOgTags(html, {
|
|
...ctx,
|
|
fallbackImageUrl: 'https://g2.tkmind.cn/MindSpace/john/public/space.thumbnail.png',
|
|
});
|
|
assert.match(out, /<meta property="og:image" content="https:\/\/g2\.tkmind\.cn\/MindSpace\/john\/public\/space\.thumbnail\.png">/);
|
|
assert.match(out, /<meta name="twitter:card" content="summary_large_image">/);
|
|
});
|
|
|
|
test('prefers the page cover over the thumbnail fallback', () => {
|
|
const html = `<head><title>X</title><meta name="mindspace-cover" content='{"cover":"assets/hero.jpg"}'></head>`;
|
|
const out = injectOgTags(html, { ...ctx, fallbackImageUrl: 'https://g2.tkmind.cn/x.thumbnail.png' });
|
|
assert.match(out, /og:image" content="https:\/\/g2\.tkmind\.cn\/MindSpace\/john\/public\/assets\/hero\.jpg"/);
|
|
assert.doesNotMatch(out, /thumbnail\.png/);
|
|
});
|
|
|
|
test('keeps an author-provided og:image and does not duplicate', () => {
|
|
const html = `<head><title>T</title><meta property="og:image" content="https://x/y.png"></head>`;
|
|
const out = injectOgTags(html, ctx);
|
|
assert.equal((out.match(/og:image/g) ?? []).length, 1);
|
|
});
|
|
|
|
test('skips og:image for svg-only cover, falls back to summary card', () => {
|
|
const html = `<head><title>仅SVG</title><meta name="mindspace-cover" content='{"cover":"foo.svg"}'></head>`;
|
|
const out = injectOgTags(html, ctx);
|
|
assert.doesNotMatch(out, /og:image/);
|
|
assert.match(out, /<meta name="twitter:card" content="summary">/);
|
|
});
|
|
|
|
test('passes through a full https cover url unchanged', () => {
|
|
const html = `<head><title>X</title><meta name="mindspace-cover" content='{"cover":"https://cdn.example.com/a.png"}'></head>`;
|
|
const out = injectOgTags(html, ctx);
|
|
assert.match(out, /<meta property="og:image" content="https:\/\/cdn\.example\.com\/a\.png">/);
|
|
});
|
|
|
|
test('resolves a root-absolute cover against the origin', () => {
|
|
const html = `<head><title>X</title><meta name="mindspace-cover" content='{"cover":"/shared/cover.jpg"}'></head>`;
|
|
const out = injectOgTags(html, ctx);
|
|
assert.match(out, /<meta property="og:image" content="https:\/\/g2\.tkmind\.cn\/shared\/cover\.jpg">/);
|
|
});
|
|
|
|
test('escapes quotes and ampersands in title to keep the meta tag well-formed', () => {
|
|
const html = `<head><title>say "hi" & bye</title></head>`;
|
|
const out = injectOgTags(html, ctx);
|
|
assert.match(out, /<meta property="og:title" content="say "hi" & bye">/);
|
|
});
|