Files
huangzd1997 94a0c287e0 feat(客户端更新): 登录页/首页更新面板显示更新包下载进度条
- 新增 shared/utils/update-progress.ts:进度事件解析/百分比钳制/文案格式化(纯函数)
- 新增 shared/components/UpdateProgressBar.vue:两页共用,失败态琥珀色并停在断点
  百分比、总大小未知走不确定态
- useVersionUpdate:先挂监听再发桥调用(避免丢首帧),监听 pywebview-update-progress
  (Python 侧 evaluate_js 推送,同 pywebview-download-progress 约定);失败保留上次进度
- 测试:tests/update-progress.test.ts(8 用例)

兼容:老客户端没有该事件源,进度条不出现,其余行为不变(优雅降级)。
注:本仓库 modules-withdraw / modules-image-video 有 3 个既存失败用例(隔离复现),
与本次改动无关;全仓库仅新增测试引用本次新增模块。
2026-09-11 01:59:42 +08:00

121 lines
4.4 KiB
TypeScript
Raw Permalink 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.
import { test } from 'node:test'
import assert from 'node:assert/strict'
import {
formatBytes,
formatUpdateProgressText,
normalizeUpdateProgress,
updateProgressPercent,
type UpdateProgress,
} from '../src/shared/utils/update-progress.ts'
function progressOf(partial: Partial<UpdateProgress>): UpdateProgress {
return {
status: 'downloading',
message: '',
downloaded: 0,
total: 0,
percent: -1,
...partial,
}
}
test('更新进度:正常进度帧解析出字节数与百分比', () => {
const progress = normalizeUpdateProgress({
status: 'downloading',
message: '正在下载更新包...',
downloaded: 62914560,
total: 104857600,
percent: 60,
error: '',
})
assert.ok(progress, '合法事件必须解析成功')
assert.equal(progress.status, 'downloading')
assert.equal(progress.downloaded, 62914560)
assert.equal(progress.total, 104857600)
assert.equal(progress.percent, 60)
assert.equal(updateProgressPercent(progress), 60)
})
test('更新进度:状态缺失或非法的事件必须丢弃(不得把进度打回初始态)', () => {
assert.equal(normalizeUpdateProgress(null), null)
assert.equal(normalizeUpdateProgress(undefined), null)
assert.equal(normalizeUpdateProgress({}), null)
assert.equal(normalizeUpdateProgress({ downloaded: 100 }), null)
assert.equal(normalizeUpdateProgress({ status: 'unknown-stage' }), null)
assert.equal(normalizeUpdateProgress('downloading'), null)
})
test('更新进度:缺字段的脏事件按 0 字节/未知总大小兜底,不产生 NaN', () => {
const progress = normalizeUpdateProgress({ status: 'failed', message: '下载失败' })
assert.ok(progress)
assert.equal(progress.downloaded, 0)
assert.equal(progress.total, 0)
assert.equal(progress.percent, -1, '缺百分比按未知处理')
assert.equal(updateProgressPercent(progress), -1, '未知总大小走不确定态')
assert.equal(Number.isNaN(progress.downloaded), false)
})
test('更新进度:百分比越界钳制到 0-100,负值视为不确定态', () => {
assert.equal(updateProgressPercent(progressOf({ percent: 120 })), 100)
assert.equal(updateProgressPercent(progressOf({ percent: -5 })), -1)
assert.equal(updateProgressPercent(progressOf({ percent: 99.6 })), 100, '四舍五入取整')
assert.equal(updateProgressPercent(null), -1)
})
test('更新进度文案:下载中显示百分比与已下载/总大小', () => {
const text = formatUpdateProgressText(progressOf({
downloaded: 62914560,
total: 104857600,
percent: 60,
}))
assert.equal(text, '正在下载更新包 60%60.0 MB/100.0 MB')
})
test('更新进度文案:总大小未知时显示已下载量,刚开始时退回阶段文案', () => {
assert.equal(
formatUpdateProgressText(progressOf({ downloaded: 3145728, percent: -1 })),
'正在下载更新包(已下载 3.0 MB)',
)
assert.equal(
formatUpdateProgressText(progressOf({ message: '正在准备下载更新包...' })),
'正在准备下载更新包...',
)
})
test('更新进度文案:校验中/已就绪/失败直接用 Python 侧说明(失败停在断点处)', () => {
assert.equal(
formatUpdateProgressText(progressOf({
status: 'verifying',
message: '安装包下载完成,正在校验完整性...',
})),
'安装包下载完成,正在校验完整性...',
)
assert.equal(
formatUpdateProgressText(progressOf({
status: 'ready',
message: '安装包已就绪,正在启动更新程序,程序即将退出...',
percent: 100,
})),
'安装包已就绪,正在启动更新程序,程序即将退出...',
)
const failed = progressOf({
status: 'failed',
message: '下载中断(65536/307510 字节),断点已保留,请重试续传',
downloaded: 65536,
total: 307510,
percent: 21.3,
})
assert.equal(formatUpdateProgressText(failed), '下载中断(65536/307510 字节),断点已保留,请重试续传')
assert.equal(updateProgressPercent(failed), 21, '失败时进度条停在断点百分比')
assert.equal(formatUpdateProgressText(null), '')
})
test('更新进度文案:字节数格式化覆盖 KB/MB 与异常输入', () => {
assert.equal(formatBytes(0), '0 MB')
assert.equal(formatBytes(-1), '0 MB')
assert.equal(formatBytes(Number.NaN), '0 MB')
assert.equal(formatBytes(512 * 1024), '512 KB')
assert.equal(formatBytes(3 * 1024 * 1024), '3.0 MB')
})