Files
blog/blog-admin/tools/mailtest.ts
T

80 lines
3.4 KiB
TypeScript
Raw Normal View History

/* 邮件模板自检:验证渲染不炸、转义生效、关键字段都在。
* 跑法(见 package.json selftest 同款套路,tools/ 不在 src 的 tsc 范围里):
* npx tsc tools/mailtest.ts --outDir .selftest-build --module commonjs \
* --target es2022 --moduleResolution node --skipLibCheck --esModuleInterop
* node .selftest-build/tools/mailtest.js
*/
import { replyMailHtml, replyMailSubject, adminMailHtml, adminMailSubject } from '../src/lib/mail';
import type { CommentRow } from '../src/types';
let pass = 0,
fail = 0;
const ok = (name: string, cond: boolean) => {
if (cond) {
pass++;
console.log(' ✓', name);
} else {
fail++;
console.log(' ✗', name);
}
};
// CommentRow 只要模板用到的字段;其余给空值占位
const row = (id: number, content: string, createdAt: string): CommentRow =>
({
id,
content,
created_at: createdAt,
page_key: '/20240811.html',
site_name: '优世界',
}) as unknown as CommentRow;
console.log('== 回复提醒模板(reply.html 气泡风) ==');
const rInput = {
siteName: '优世界',
siteUrl: 'https://usj.cc',
pageTitle: '迁移博客至hugo',
pageUrl: 'https://usj.cc/20240811.html',
parentComment: row(15580, '原始评论 <b>加粗</b>', '2026-10-01 10:00:00'),
parentNick: '小赵',
parentEmail: 'imql@qq.com',
comment: row(15590, '试试 <script>alert(1)</script> 和 <img src=x onerror=alert(1)>', '2026-10-02 10:00:00'),
commenterNick: '路人甲',
commenterEmail: 'walker@example.com',
toNick: '小赵',
};
const r = replyMailHtml(rInput);
ok('渲染出 HTML', r.startsWith('<!DOCTYPE html>'));
ok('包含站点名', r.includes('优世界'));
ok('包含页面标题', r.includes('迁移博客至hugo'));
ok('跳转链接带 atk_comment 锚参数', r.includes('atk_comment=15590'));
ok('script 标签被转义', !r.includes('<script>alert(1)</script>'));
ok('没有可执行的 onerror(img 白名单外的 img 一律转义成文本)', !/<img[^>]*onerror/i.test(r));
ok('被回复者昵称出现', r.includes('小赵'));
ok('回复者昵称出现', r.includes('路人甲'));
ok('两个头像 MD5 都渲染', (r.match(/weavatar\.com\/avatar\//g) || []).length >= 2);
ok('site_url 出现在落款', r.includes('https://usj.cc'));
ok('主题格式正确', replyMailSubject(rInput) === '[优世界] 您收到了来自 @路人甲 的回信');
console.log('== 管理员通知模板(notice.html 气泡风) ==');
const aInput = {
siteName: '优世界',
siteUrl: 'https://usj.cc',
pageTitle: '留言',
pageUrl: 'https://usj.cc/comment.html',
comment: row(999, '你好,<img src="https://usj.cc/emotion/douyin/19.png" atk-emoticon="19"> 哈哈', '2026-10-02 11:00:00'),
commenterNick: '路人',
commenterEmail: 'x@example.com',
adminNick: '博主',
};
const a = adminMailHtml(aInput);
ok('渲染出 HTML', a.startsWith('<!DOCTYPE html>'));
ok('标题是新评论', a.includes('有了新的评论'));
ok('含作者昵称', a.includes('路人'));
ok('表情包 img 被保留并内联宽度', /<img[^>]*width:100px[^>]*atk-emoticon/.test(a));
ok('跳转链接带锚参数', a.includes('atk_comment=999'));
ok('site_url 出现在落款', a.includes('https://usj.cc'));
ok('主题格式正确', adminMailSubject(aInput) === '[优世界] 其中 "留言" 页面有一条新的评论!');
console.log('\n通过 ' + pass + ' / 失败 ' + fail);
if (fail > 0) (globalThis as { __fail?: boolean }).__fail = true;