Files
banban/banban-mini/tests/firmware-progress.test.cjs
T
stu2not 7bcace0410 fix(mini): address UI feedback and device status display
Correct battery colors, participant artwork, navigation icons, title layout, and map spacing.

Animate the binding countdown using the existing expiry, recover polling after transient failures, and show online and battery data on success. Keep current firmware messaging consistent with version availability.

Validation: WeChat mini-program build, 16 UI tests, and isolated developer-tool scenarios passed. Five pre-existing TypeScript errors remain; physical-device validation is pending.
2026-09-16 14:14:56 +08:00

144 lines
6.4 KiB
JavaScript

const assert = require('node:assert/strict')
const fs = require('node:fs')
const path = require('node:path')
const { test } = require('node:test')
const ts = require('typescript')
function loadTypeScript(file, mocks = {}) {
const source = fs.readFileSync(path.join(__dirname, '../src', file), 'utf8')
const { outputText } = ts.transpileModule(source, {
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2017, esModuleInterop: true },
})
const module = { exports: {} }
new Function('require', 'module', 'exports', outputText)(
(id) => mocks[id] || (id.startsWith('.')
? loadTypeScript(path.join(path.dirname(file), `${id}.ts`), mocks)
: require(id)), module, module.exports,
)
return module.exports
}
const { firmwareProgressView } = loadTypeScript('components/firmware-progress/view-model.ts')
const status = (state, progress) => ({ device_id: 'test-device', update_status: state, progress, latest_version: '1.8.2' })
test('accepted update without reported progress stays indeterminate', () => {
const view = firmwareProgressView(status('accepted', 0))
assert.equal(view.hasProgress, false)
assert.match(view.message, /等待进度上报/)
})
test('received progress is used directly, including fractional values', () => {
const view = firmwareProgressView(status('updating', 65.4))
assert.equal(view.progress, 65.4)
assert.equal(view.percent, 65)
assert.equal(view.complete, false)
})
test('nearly complete progress never rounds up to 100', () => {
assert.equal(firmwareProgressView(status('updating', 99.9)).percent, 99)
})
test('100 percent still waits for the device success result', () => {
const view = firmwareProgressView(status('updating', 100))
assert.equal(view.complete, false)
assert.match(view.message, /等待设备确认/)
})
test('both backend completion statuses show a completed update', () => {
for (const state of ['success', 'completed']) {
const view = firmwareProgressView(status(state, 0))
assert.equal(view.complete, true)
assert.equal(view.percent, 100)
}
})
test('failed update keeps the last real progress and offers recovery copy', () => {
const view = firmwareProgressView(status('failed', 42))
assert.equal(view.failed, true)
assert.equal(view.progress, 42)
assert.match(view.message, /重试/)
})
test('temporary query failure is not reported as an OTA failure', () => {
const view = firmwareProgressView(status('updating', 42), true)
assert.equal(view.failed, false)
assert.equal(view.progress, 42)
assert.match(view.message, /暂时无法刷新/)
})
test('invalid progress cannot overflow or break the display', () => {
for (const value of [undefined, NaN, Infinity, -10]) {
assert.equal(firmwareProgressView(status('updating', value)).hasProgress, false)
}
assert.equal(firmwareProgressView(status('updating', 120)).progress, 100)
})
test('backend placeholder version is not displayed as a release number', () => {
const view = firmwareProgressView({ ...status('updating', 12), target_version: 'updating' })
assert.equal(view.version, '1.8.2')
})
test('custom pages clear the capsule while native pages only add content spacing', () => {
const { getPageStyle } = loadTypeScript('utils/page-style.ts', {
'@tarojs/taro': {
getSystemInfoSync: () => ({ statusBarHeight: 44 }),
getMenuButtonBoundingClientRect: () => ({ bottom: 90 }),
},
})
assert.equal(getPageStyle()['--bb-navigation-top'], '102px')
assert.equal(getPageStyle(false)['--bb-navigation-top'], '12px')
})
const { firmwareSummaryView } = loadTypeScript('utils/firmware-status.ts')
const currentFirmware = { device_id: 'test-device', current_version: '1.8.2', latest_version: '1.8.2', update_available: false, can_update: false, update_status: 'failed', progress: 40 }
test('latest version takes precedence over a historical failed update in the summary', () => {
assert.deepEqual(firmwareSummaryView(currentFirmware), { action: '已最新', subtitle: '当前已是最新版本' })
const view = firmwareProgressView(currentFirmware)
assert.equal(view.current, true)
assert.equal(view.failed, false)
assert.equal(view.complete, false) // Current firmware does not rewrite the historical OTA outcome.
assert.equal(view.title, '当前已是最新版本')
assert.equal(view.version, '1.8.2')
})
test('a failed update with a newer version still offers a retry', () => {
const pending = { ...currentFirmware, current_version: '1.8.1', update_available: true, can_update: true }
assert.deepEqual(firmwareSummaryView(pending), { action: '更新', subtitle: '更新失败,可重试' })
assert.equal(firmwareProgressView(pending).failed, true)
})
test('missing or placeholder versions never claim the device is up to date', () => {
const cases = [null, ...['', 'unknown', '0.0.0', '--', 'updating'].flatMap(value => [
{ ...currentFirmware, current_version: value }, { ...currentFirmware, latest_version: value },
])]
for (const value of cases) {
assert.notEqual(firmwareSummaryView(value).action, '已最新')
assert.equal(firmwareProgressView(value).current, false)
}
})
test('an active update continues showing progress even after the version has changed', () => {
for (const update_status of ['sent', 'accepted', 'updating']) {
const updating = { ...currentFirmware, update_status }
assert.equal(firmwareSummaryView(updating).action, '查看进度')
assert.equal(firmwareProgressView(updating).current, false)
}
})
test('title rows align to the capsule and reserve its width on both sides', () => {
const { getPageStyle } = loadTypeScript('utils/page-style.ts', {
'@tarojs/taro': {
getSystemInfoSync: () => ({ statusBarHeight: 44, windowWidth: 375 }),
getMenuButtonBoundingClientRect: () => ({ top: 50, bottom: 82, height: 32, left: 278 }),
},
})
const style = getPageStyle()
assert.equal(style['--bb-navigation-bar-top'], '50px')
assert.equal(style['--bb-navigation-bar-height'], '32px')
assert.equal(style['--bb-navigation-side'], '105px')
})
test('navigation keeps usable dimensions when the capsule is unavailable', () => {
const { getPageStyle } = loadTypeScript('utils/page-style.ts', {
'@tarojs/taro': {
getSystemInfoSync: () => ({ statusBarHeight: 24 }),
getMenuButtonBoundingClientRect: () => { throw new Error('unavailable') },
},
})
const style = getPageStyle()
assert.equal(style['--bb-navigation-bar-top'], '30px')
assert.equal(style['--bb-navigation-bar-height'], '32px')
})