import { test } from 'node:test' import assert from 'node:assert/strict' import { CLIENT_CHANGELOG, newestChangelogVersion, selectChangelogEntries, type ClientChangelogEntry, } from '../src/shared/client-changelog.ts' const FIXTURE: ClientChangelogEntry[] = [ { version: '4.1.0', date: '2026-09-20', items: ['新功能甲'] }, { version: '4.0.11', date: '2026-09-13', items: ['修复乙'] }, { version: '4.0.9', date: '2026-09-13', items: ['修复丙'] }, { version: '4.0.4', date: '2026-09-13', items: ['修复丁'] }, ] test('更新日志:数据文件新版本在前且版本号唯一', () => { const versions = CLIENT_CHANGELOG.map((entry) => entry.version) assert.ok(versions.length > 0, '更新日志不应为空') assert.deepEqual( versions, [...new Set(versions)], '版本号不得重复(重复会让面板出现两条同名记录)', ) const sorted = [...versions].sort((a, b) => { const pa = a.split('.').map(Number) const pb = b.split('.').map(Number) for (let i = 0; i < Math.max(pa.length, pb.length); i++) { const diff = (pa[i] ?? 0) - (pb[i] ?? 0) if (diff !== 0) return diff } return 0 }) assert.deepEqual(versions, sorted.reverse(), '更新日志应按版本号从新到旧排列') }) test('更新日志:每条都有日期与面向用户的说明', () => { for (const entry of CLIENT_CHANGELOG) { assert.match(entry.version, /^\d+(\.\d+)+$/, `版本号格式异常:${entry.version}`) assert.match(entry.date, /^\d{4}-\d{2}-\d{2}$/, `日期格式异常:${entry.version}`) assert.ok(entry.items.length > 0, `缺少更新说明:${entry.version}`) for (const item of entry.items) { assert.ok(item.trim().length > 0, `更新说明为空:${entry.version}`) assert.ok(item.length <= 40, `更新说明过长(面板放不下,需精简):${entry.version} -> ${item}`) } } }) test('更新日志:最新版本号取数据文件第一条', () => { assert.equal(newestChangelogVersion(FIXTURE), '4.1.0') assert.equal(newestChangelogVersion([]), '') }) test('更新日志:只给本机版本之后的条目,新版本在前', () => { const entries = selectChangelogEntries({ entries: FIXTURE, currentVersion: '4.0.11', latestVersion: '4.1.0' }) assert.deepEqual(entries.map((entry) => entry.version), ['4.1.0']) }) test('更新日志:落后多个版本时逐版本列出(含中间版本)', () => { const entries = selectChangelogEntries({ entries: FIXTURE, currentVersion: '4.0.4', latestVersion: '4.1.0' }) assert.deepEqual(entries.map((entry) => entry.version), ['4.1.0', '4.0.11', '4.0.9']) }) test('更新日志:已是最新版本时没有条目(面板隐藏该区块)', () => { assert.deepEqual( selectChangelogEntries({ entries: FIXTURE, currentVersion: '4.0.11', latestVersion: '4.0.11' }), [], ) }) test('更新日志:本机版本高于线上(灰度/回滚)不列条目', () => { assert.deepEqual( selectChangelogEntries({ entries: FIXTURE, currentVersion: '4.1.0', latestVersion: '4.0.11' }), [], ) }) test('更新日志:线上已发布但日志未收录的新版本不误报旧条目', () => { const entries = selectChangelogEntries({ entries: FIXTURE, currentVersion: '4.1.0', latestVersion: '4.2.0' }) assert.deepEqual(entries, [], '没有对应版本条目不倒推历史,避免把已装过的改动当成新内容') }) test('更新日志:拿不到本机版本(旧客户端)时只给最新一条', () => { const entries = selectChangelogEntries({ entries: FIXTURE, currentVersion: '', latestVersion: '4.1.0' }) assert.deepEqual(entries.map((entry) => entry.version), ['4.1.0']) }) test('更新日志:检测未完成(线上版本为空)时按数据文件最新版本兜底', () => { const entries = selectChangelogEntries({ entries: FIXTURE, currentVersion: '4.0.4', latestVersion: '' }) assert.deepEqual(entries.map((entry) => entry.version), ['4.1.0', '4.0.11', '4.0.9']) }) test('更新日志:两边版本都拿不到时给数据文件最新一条', () => { const entries = selectChangelogEntries({ entries: FIXTURE }) assert.deepEqual(entries.map((entry) => entry.version), ['4.1.0']) }) test('更新日志:空数据不报错', () => { assert.deepEqual(selectChangelogEntries({ entries: [], currentVersion: '4.0.4' }), []) }) test('更新日志:版本号前缀 v 不影响筛选', () => { const entries = selectChangelogEntries({ entries: FIXTURE, currentVersion: 'v4.0.4', latestVersion: 'v4.0.11' }) assert.deepEqual(entries.map((entry) => entry.version), ['4.0.11', '4.0.9']) })