Files
ql-scripts/qqmusic/test_render.js
zhuhjay d081ac66da feat(qqmusic): 日志与通知按体系分组,每条都标清是什么签到
原来 63 处 step 和 60+ 处 log 全平铺,看日志分不清哪条属于哪套体系:
[签到] / [金币] / [福利站] 混在一起,通知里也是「✓ 签到 +15」这种没有上下文的行。

日志前缀统一成「体系·子项」两段:
  [任务中心·签到] [任务中心·挂件] [任务中心·装扮] [任务中心·听书] [任务中心·节目]
  [任务中心·领奖]  (原 [任务])
  [福利站·签到] [福利站·礼券] [福利站·激励] [福利站·月里程碑] [福利站·月礼]
  [福利站·抽奖] [福利站·周里程碑]
  [金币·签到] [金币·抽奖签到]

run() 里加四段分隔标题,日志一眼能看出走到哪套:
  ───── ① 任务中心(成长值)─────
  ───── ② 会员福利站(成长值 + 权益)─────
  ───── ③ 金币中心(金币,不计入成长值)─────
  ───── ④ VIP 体验券(分享卡)─────

末尾补一行说明:金币中心为独立体系,不产成长值(明细见上方 ③ 段)。
之前只有「本次新增成长值合计: 45」,看不出金币那部分跑没跑。

step 名同样统一成「体系·子项」(63 处),renderAccount 按体系分组渲染:
  🟢 1006764347:成长值 +45
     📈 任务中心(成长值)
        ✓ 签到 +15
        ✓ 挂件 已佩戴
        · 无需处理 1 项:装扮
     🎁 会员福利站(成长值 + 权益)
        ✓ 签到 15成长值(本月 8 天)
        ✓ 礼券 +10 心愿值
     💰 金币中心(金币,不计成长值)
        ✓ 签到 已签 + 30 金币
        · 无需处理 1 项:抽奖签到

分组规则:
- 组内每条都是「子项名 + detail」,不再出现只有 detail 的行
- 整组全 skip 时收成一行「💰 金币中心(金币,不计成长值):签到、抽奖签到 今日无需处理」
- 未知前缀落到「📌 其他」组,名字原样保留
- 分享卡链接改成「🔗 领卡链接 <url>」单独一行

coinCenter / 金币抽奖签到开头各加一行开始日志,带 ActID 值 —— 换季排查时
直接能看到脚本用的是哪个 ActID。

新增 test_render.js:24 条断言冻结分组契约
  ① 三套体系各自成组 + 组标题 emoji + 金币标注不计成长值
  ② 组内每条都带子项名(断言没有「只有 detail」的行)
  ③ 整组 skip 收成一行
  ④ ActID 过期 → warn 单独列且 detail 含 ActID
  ⑤ 分享卡链接单独一行
  ⑥ 空 steps 不崩
  ⑦ 未知前缀 → 其他组

test_coin.js 里 3 处 step 名断言同步改成新名(金币·签到 / 金币·抽奖签到)。
2026-11-07 18:58:15 +08:00

114 lines
5.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env node
/**
* test_render.js —— 通知正文渲染的分组与「哪个签到完成了」可见性
*
* 2026-11-07 需求:执行日志/通知里必须一眼看出「是什么签到完成了」。
* 这个测试冻结 renderAccount 的分组契约:
* 1. 三套体系各自成组,组标题带 emoji
* 2. 组内每条都带「子项名 + detail」,不能只剩 detail
* 3. 整组全 skip → 收成一行
* 4. 金币组明确标注「不计成长值」,不与成长值混算
* 5. 分享卡链接单独一行
*
* 用法: node qqmusic/test_render.js
*/
'use strict'
const { renderAccount } = require('./scrip_qqmusic_checkin.js')
let pass = 0, fail = 0
const ok = (n, c, e = '') => {
if (c) { pass++; console.log(` ✓ ${n}`) }
else { fail++; console.log(` ✗ ${n}${e ? ' — ' + e : ''}`) }
}
const has = (out, s, label) => ok(label || `含「${s}」`, out.includes(s), out)
const not = (out, s, label) => ok(label || `不含「${s}」`, !out.includes(s), out)
/* ── 1. 三套体系都有收获 ── */
console.log('\n── 1. 三套体系都有收获 ──')
const r1 = renderAccount('1006764347', {
total: 45, verdict: 'done', cardUrl: '',
steps: [
{ name: '任务中心·签到', status: 'done', detail: '+15' },
{ name: '任务中心·挂件', status: 'done', detail: '已佩戴' },
{ name: '任务中心·装扮', status: 'skip', detail: '' },
{ name: '福利站·签到', status: 'done', detail: '15成长值(本月 8 天)' },
{ name: '福利站·礼券', status: 'done', detail: '+10 心愿值' },
{ name: '福利站·月礼', status: 'skip', detail: '' },
{ name: '金币·签到', status: 'done', detail: '已签 + 30 金币' },
{ name: '金币·抽奖签到', status: 'done', detail: '已签 + 已领' },
],
})
console.log(r1.split('\n').map(l => ' │ ' + l).join('\n'))
has(r1, '📈 任务中心', '有任务中心组标题')
has(r1, '🎁 会员福利站', '有福利站组标题')
has(r1, '💰 金币中心', '有金币中心组标题')
has(r1, '不计成长值', '金币组标注「不计成长值」')
has(r1, '✓ 签到 +15', '任务中心签到带子项名 + detail')
has(r1, '✓ 礼券 +10 心愿值', '福利站礼券带子项名 + detail')
has(r1, '✓ 签到 已签 + 30 金币', '金币签到带子项名 + detail')
has(r1, '✓ 抽奖签到', '金币抽奖签到也在')
has(r1, '无需处理 1 项:装扮', '任务中心 skip 收成一行')
has(r1, '无需处理 1 项:月礼', '福利站 skip 收成一行')
// 关键:不能出现「只有 detail 没有名字」的行
const detailOnly = r1.split('\n').filter(l => /^\s+[✓△✗·] (已签|\+|已领|已佩戴)/.test(l))
ok('没有「只有 detail 没有子项名」的行', detailOnly.length === 0, JSON.stringify(detailOnly))
/* ── 2. 整组全 skip → 收成一行 ── */
console.log('\n── 2. 金币全已签(整组 skip)──')
const r2 = renderAccount('1006764347', {
total: 30, verdict: 'done', cardUrl: '',
steps: [
{ name: '任务中心·签到', status: 'done', detail: '+15' },
{ name: '金币·签到', status: 'skip', detail: '今日已签(连续第 7 天)' },
{ name: '金币·抽奖签到', status: 'skip', detail: '今日已签' },
],
})
console.log(r2.split('\n').map(l => ' │ ' + l).join('\n'))
has(r2, '💰 金币中心', '金币组还在')
has(r2, '今日无需处理', '整组 skip 收成一行')
has(r2, '签到、抽奖签到', '两个子项都列出来了')
not(r2, '✓ 签到 今日已签', '没有多余的成功行')
/* ── 3. 金币 ActID 过期 → warn 单独列 ── */
console.log('\n── 3. 金币 ActID 过期 ──')
const r3 = renderAccount('1006764347', {
total: 30, verdict: 'warn', cardUrl: '',
steps: [
{ name: '任务中心·签到', status: 'done', detail: '+15' },
{ name: '金币·签到', status: 'warn', detail: '查询失败 code -1/-1(可能 ActID 过期)' },
],
})
console.log(r3.split('\n').map(l => ' │ ' + l).join('\n'))
has(r3, '🟡', 'verdict=warn 用黄脸')
has(r3, '△ 签到 查询失败', 'warn 带子项名 + detail')
has(r3, 'ActID', 'detail 里能看出是 ActID 问题')
/* ── 4. 分享卡链接 ── */
console.log('\n── 4. 分享卡链接 ──')
const r4 = renderAccount('1006764347', {
total: 30, verdict: 'done', cardUrl: 'https://y.qq.com/m/vip/experience_card/dist/index.html?cardid=ABC',
steps: [{ name: '分享卡', status: 'done', detail: '新建 1 张,还能被领 3 次' }],
})
console.log(r4.split('\n').map(l => ' │ ' + l).join('\n'))
has(r4, '🔗 领卡链接 https://y.qq.com', '链接单独一行且有前缀')
has(r4, '🎫 VIP 体验券', '有分享卡组标题')
/* ── 5. 空 steps 不崩 ── */
console.log('\n── 5. 空 steps ──')
const r5 = renderAccount('1006764347', { total: 0, verdict: 'done', cardUrl: '', steps: [] })
ok('不抛错', typeof r5 === 'string')
has(r5, '成长值 +0', '首行仍有成长值')
/* ── 6. 未知前缀落到「其他」组 ── */
console.log('\n── 6. 未知前缀 → 其他组 ──')
const r6 = renderAccount('1006764347', {
total: 0, verdict: 'done', cardUrl: '',
steps: [{ name: '某个新功能', status: 'done', detail: 'ok' }],
})
has(r6, '📌 其他', '落到「其他」组')
has(r6, '某个新功能', '名字保留完整(没有 · 可切)')
console.log(`\nRESULT: ${fail === 0 ? 'PASS' : `FAIL(${fail})`} (${pass} passed, ${fail} failed)`)
process.exit(fail === 0 ? 0 : 1)