Files
crawler-plugin/admin-frontend-vue/tests/task-13.test.ts
T
huangzd1997 c3f160afa5 task-13(壳层/路由): 实现全局请求错误提示容器
error-bus 提供框架无关的订阅式错误总线:notify/dismiss/clear、负载归一化、
3 条上限截断、订阅返回取消函数防泄漏;GlobalErrorContainer 订阅并渲染可关闭
错误条,挂在 AdminLayout 内容区顶部。
2026-09-05 14:43:54 +08:00

95 lines
3.7 KiB
TypeScript

import test from 'node:test'
import assert from 'node:assert/strict'
import { readSource } from './helpers.ts'
import {
clearGlobalErrors,
dismissGlobalError,
GLOBAL_ERROR_FALLBACK,
GLOBAL_ERROR_LIMIT,
normalizeErrorMessage,
notifyGlobalError,
snapshotGlobalErrors,
subscribeGlobalError,
} from '../src/layout/error-bus.ts'
test('test_task_013_global_error_notice_normal_primary_path', () => {
// 正常主路径:通知一条错误进入提示流。
clearGlobalErrors()
notifyGlobalError('登录已过期')
const list = snapshotGlobalErrors()
assert.equal(list.length, 1)
assert.equal(list[0].message, '登录已过期')
})
test('test_task_013_global_error_notice_normal_variant_input', () => {
// 正常变体:不同错误逐条追加、顺序保留。
clearGlobalErrors()
notifyGlobalError('错误A')
notifyGlobalError('错误B')
assert.deepEqual(snapshotGlobalErrors().map((i) => i.message), ['错误A', '错误B'])
})
test('test_task_013_global_error_notice_normal_repeated_operation_is_idempotent', () => {
// 正常重复:相同消息重复通知产生稳定独立的条目(id 单调递增)。
clearGlobalErrors()
notifyGlobalError('重试')
const first = snapshotGlobalErrors()[0]
notifyGlobalError('重试')
const second = snapshotGlobalErrors()[1]
assert.notEqual(first.id, second.id)
assert.equal(first.message, second.message)
})
test('test_task_013_global_error_notice_boundary_empty_input', () => {
// 边界空值:空/缺省消息回落到通用提示,不出现空白条目。
clearGlobalErrors()
assert.equal(normalizeErrorMessage(' '), GLOBAL_ERROR_FALLBACK)
notifyGlobalError('')
assert.equal(snapshotGlobalErrors()[0].message, GLOBAL_ERROR_FALLBACK)
})
test('test_task_013_global_error_notice_boundary_single_item', () => {
// 边界单元素:单条可按 id 关闭。
clearGlobalErrors()
notifyGlobalError('单条')
const [item] = snapshotGlobalErrors()
dismissGlobalError(item.id)
assert.deepEqual(snapshotGlobalErrors(), [])
})
test('test_task_013_global_error_notice_boundary_limit_or_missing_field', () => {
// 边界上限:超过上限只保留最近 N 条,不堆积。
clearGlobalErrors()
for (let i = 1; i <= GLOBAL_ERROR_LIMIT + 2; i += 1) notifyGlobalError(`err${i}`)
const list = snapshotGlobalErrors()
assert.equal(list.length, GLOBAL_ERROR_LIMIT)
assert.equal(list[list.length - 1].message, `err${GLOBAL_ERROR_LIMIT + 2}`)
})
test('test_task_013_global_error_notice_invalid_input_rejected', () => {
// 异常输入:Error/数字/对象负载均归一化到可展示文案。
clearGlobalErrors()
assert.equal(normalizeErrorMessage(new Error('连接被拒绝')), '连接被拒绝')
assert.equal(normalizeErrorMessage(500), GLOBAL_ERROR_FALLBACK)
assert.equal(normalizeErrorMessage({ code: 1 }), GLOBAL_ERROR_FALLBACK)
assert.equal(normalizeErrorMessage(new Error(' ')), GLOBAL_ERROR_FALLBACK)
})
test('test_task_013_global_error_notice_dependency_failure_returns_actionable_message', () => {
// 依赖失败:订阅提供取消函数,取消后不再回调(容器卸载无泄漏)。
clearGlobalErrors()
const seen: number[] = []
const unsubscribe = subscribeGlobalError((list) => seen.push(list.length))
notifyGlobalError('a')
unsubscribe()
notifyGlobalError('b')
assert.deepEqual(seen, [0, 1], '取消订阅后不应再收到更新')
clearGlobalErrors()
// 容器组件本身在卸载时执行清理并保留可关闭错误项。
const container = readSource('src/layout/GlobalErrorContainer.vue')
assert.match(container, /unsubscribe/)
assert.match(container, /dismissGlobalError/)
const layout = readSource('src/layout/AdminLayout.vue')
assert.match(layout, /GlobalErrorContainer/)
})