task-145: 前端可下载判定契约(fileReady/downloadUrl/终态 SUCCESS+FAILED 可下载,PENDING/RUNNING/无 resultId 不可下载)+ 8 条测试

This commit is contained in:
2026-09-02 05:49:01 +08:00
parent 6c674f0f1d
commit 0945882458
2 changed files with 69 additions and 2 deletions
@@ -17,13 +17,20 @@ export const FILE_PROGRESS_KEYS = [
export interface DownloadableItem { export interface DownloadableItem {
resultId?: number | null resultId?: number | null
fileReady?: boolean | null fileReady?: boolean | null
fileStatus?: string | null
downloadUrl?: string | null downloadUrl?: string | null
} }
/** 可下载判定:有结果记录且文件已就绪(fileReady 或 downloadUrl 非空)。 */ /**
* 可下载判定(Task 145):有结果记录,且满足其一——
* fileReady=true、downloadUrl 非空、fileStatus 为终态(SUCCESS 可下载结果文件,
* FAILED 可下载错误文件或用于展示错误)。
*/
export function canDownloadItem(item: DownloadableItem | null | undefined): boolean { export function canDownloadItem(item: DownloadableItem | null | undefined): boolean {
if (!item) return false if (!item) return false
return Boolean(item.resultId && (item.fileReady || item.downloadUrl)) const ready = item.fileReady || Boolean(item.downloadUrl)
const terminalStatus = item.fileStatus === 'SUCCESS' || item.fileStatus === 'FAILED'
return Boolean(item.resultId && (ready || terminalStatus))
} }
/** 有效进度值:仅 fileProgressPercent 需要严格 >0,其余字段非空即可(0 是合法计数)。 */ /** 有效进度值:仅 fileProgressPercent 需要严格 >0,其余字段非空即可(0 是合法计数)。 */
@@ -0,0 +1,60 @@
import { test } from 'node:test'
import assert from 'node:assert/strict'
import { canDownloadItem } from '../src/shared/merge-live-progress.ts'
interface Item {
taskId?: number
resultId?: number
fileReady?: boolean
fileStatus?: string
downloadUrl?: string
}
test('downloadable when fileReady is true', () => {
assert.equal(canDownloadItem({ resultId: 1, fileReady: true }), true)
})
test('downloadable when fileStatus is SUCCESS', () => {
assert.equal(canDownloadItem({ resultId: 1, fileStatus: 'SUCCESS' }), true)
})
test('downloadable when fileStatus is FAILED (error file or display)', () => {
assert.equal(canDownloadItem({ resultId: 1, fileStatus: 'FAILED' }), true)
})
test('not downloadable when not ready', () => {
assert.equal(canDownloadItem({ resultId: 1, fileReady: false, fileStatus: 'RUNNING' }), false)
assert.equal(canDownloadItem({ resultId: 1 }), false)
})
test('downloadable when downloadUrl present', () => {
assert.equal(canDownloadItem({ resultId: 1, downloadUrl: 'https://dl.example/a.xlsx' }), true)
})
test('not downloadable without resultId', () => {
assert.equal(canDownloadItem({ fileReady: true }), false)
assert.equal(canDownloadItem({ fileStatus: 'SUCCESS' }), false)
})
test('not downloadable while pending or running', () => {
assert.equal(canDownloadItem({ resultId: 1, fileStatus: 'PENDING' }), false)
assert.equal(canDownloadItem({ resultId: 1, fileStatus: 'RUNNING' }), false)
assert.equal(canDownloadItem({ resultId: 1, fileStatus: null }), false)
})
test('downloadability contract frozen', () => {
assert.equal(canDownloadItem(undefined), false)
assert.equal(canDownloadItem(null), false)
assert.equal(canDownloadItem({}), false)
// 终态与就绪任一满足即可下载;RUNNING/PENDING/空态均不可
const terminalCases = ['SUCCESS', 'FAILED']
const runningCases = ['PENDING', 'RUNNING', undefined, null]
for (const status of terminalCases) {
assert.equal(canDownloadItem({ resultId: 1, fileStatus: status as string }), true, `终态 ${status} 可下载`)
}
for (const status of runningCases) {
assert.equal(canDownloadItem({ resultId: 1, fileStatus: status as string | undefined }), false,
`非终态 ${String(status)} 不可下载`)
}
})