diff --git a/test/wechatSubscribeFields.test.mjs b/test/wechatSubscribeFields.test.mjs index b676663..ac231e9 100644 --- a/test/wechatSubscribeFields.test.mjs +++ b/test/wechatSubscribeFields.test.mjs @@ -111,6 +111,59 @@ test('SONG_SELECTED 的内置字段映射:每个字段名后缀都要跟发出 for (const key of Object.keys(out)) assert.ok(out[key].length > 0, key + ' 不能为空') }) +test('SONG_REJECTED 的内置字段映射:长驳回原因必须裁进 thing 的 20 字内', () => { + /* + * 模板字段(站长在公众平台选好的): + * 审核内容 = thing6 → songTitle + * 驳回原因 = thing4 → reason + * 驳回原因是管理员手填的自由文本,经常远超 20 字;thing 超长是整条消息 47003 的头号原因, + * 所以这里专门盯住「长原因不会被原样发出去」。 + */ + const fields = { thing6: 'songTitle', thing4: 'reason' } + const vars = { + songTitle: '晴天 - 周杰伦', + reason: + '已有同名单曲,暂不重复收录;另外上传的音频码率过低,建议重新投稿 320kbps 版本后再试一次' + } + const out = {} + for (const key of Object.keys(fields)) out[key] = clampField(key, vars[fields[key]]) + + assert.equal(out.thing6, '晴天 - 周杰伦') + assert.ok(len(out.thing4) <= 20) + assert.ok(out.thing4.endsWith('…')) + for (const key of Object.keys(out)) assert.ok(out[key].length > 0, key + ' 不能为空') +}) + +test('内置模板与线上代码一致(直接读源码,防止映射被改坏没人发现)', async () => { + /* + * 为什么不 import:wechatSubscribeService.ts 顶部 import 了 `~~/server/...` 这类 Nuxt 别名, + * 纯 `node --test` 解析不了。这里只校验「模板 ID 和字段映射」这类静态事实,读文本足够, + * 而且不需要跑起来就能在 CI 里拦住「手滑改了模板 ID / 字段名」。 + */ + const { readFileSync } = await import('node:fs') + const { fileURLToPath } = await import('node:url') + const src = readFileSync( + fileURLToPath(new URL('../server/services/wechatSubscribeService.ts', import.meta.url)), + 'utf8' + ) + const block = (kind) => { + const m = src.match(new RegExp(kind + ':\\s*\\{([\\s\\S]*?)\\n \\}')) + assert.ok(m, '源码里找不到 ' + kind + ' 的内置模板') + return m[1] + } + + const rejected = block('SONG_REJECTED') + assert.match(rejected, /erAK99M38ZeD-F1mOIgN2M7iAPVTU0YXo-adlkSwg_c/) + assert.match(rejected, /thing6:\s*'songTitle'/) + assert.match(rejected, /thing4:\s*'reason'/) + + const selected = block('SONG_SELECTED') + assert.match(selected, /oLTAefO92xYYlGRYmcsm5AfUUlUI5IKFfXhIVNrItSk/) + for (const f of ['thing2', 'date4', 'time1', 'character_string3', 'phrase5']) { + assert.match(selected, new RegExp(f + ":\\s*'"), f + ' 的映射丢了') + } +}) + test('beijingNow 是合法的 time 型值,且与北京时间一致', () => { assert.match(beijingNow(), /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/) // beijingNow() 内部按 UTC+8 取值,用同一算法反推对比