macos-web/tests/cases/07-notify.test.ts
2026-07-23 15:16:57 +08:00

139 lines
4.4 KiB
TypeScript

/**
* 07-notify — 通知系统
*
* 使用 vitest 原汁原味的 vi.fn() + mock 依赖注入模式。
* 不依赖真实 DOM 渲染,仅测试 Notify 核心逻辑。
*/
import { describe, it, expect, beforeEach, beforeAll, vi } from 'vitest'
import { Notify, setSysForNotify } from '../../src/composables/useNotify'
// ---- Mock Sys 依赖 ----
function createMockSys(overrides: Record<string, any> = {}) {
return {
settings: {
notificationsEnabled: true,
notifAllow: {} as Record<string, boolean>,
focus: false,
...overrides,
},
renderDock: vi.fn(),
}
}
let mockSys = createMockSys()
setSysForNotify(mockSys)
describe('07-notify — 通知系统', () => {
beforeAll(() => {
document.body.innerHTML = `
<div id="notification-center" class="hidden"></div>
<div id="banner-container"></div>
<nav id="dock"></nav>
`
})
beforeEach(() => {
Notify.list = []
mockSys = createMockSys()
setSysForNotify(mockSys)
})
// ==================== 基本发送 ====================
describe('发送通知', () => {
it('初始列表为空', () => {
expect(Notify.list).toHaveLength(0)
})
it('send 添加通知到列表', () => {
const n = Notify.send({ appId: 'finder', title: '测试', body: '内容', silent: true })
expect(n).not.toBeNull()
expect(Notify.list).toHaveLength(1)
expect(n!.appId).toBe('finder')
expect(n!.title).toBe('测试')
})
it('返回的通知包含 id 和 ts', () => {
const n = Notify.send({ appId: 'f', title: 'T', body: 'B', silent: true })
expect(n!.id).toBeTruthy()
expect(n!.ts).toBeGreaterThan(0)
})
})
// ==================== 开关控制 ====================
describe('开关控制', () => {
it('总开关关闭时 send 返回 null', () => {
mockSys.settings.notificationsEnabled = false
expect(Notify.send({ appId: 'f', title: 'T', body: 'B', silent: true })).toBeNull()
})
it('per-app 关闭时 send 返回 null', () => {
mockSys.settings.notifAllow['finder'] = false
expect(Notify.send({ appId: 'finder', title: 'T', body: 'B', silent: true })).toBeNull()
})
it('allowed() 正确判断', () => {
expect(Notify.allowed('clock')).toBe(true)
mockSys.settings.notifAllow['clock'] = false
expect(Notify.allowed('clock')).toBe(false)
mockSys.settings.notifAllow['clock'] = true
mockSys.settings.notificationsEnabled = false
expect(Notify.allowed('clock')).toBe(false)
})
})
// ==================== 已读/未读 ====================
describe('已读/未读', () => {
it('新通知默认未读', () => {
const n = Notify.send({ appId: 'f', title: 'T', body: 'B', silent: true })
expect(n!.read).toBe(false)
})
it('markRead 标记已读', () => {
const n = Notify.send({ appId: 'f', title: 'T', body: 'B', silent: true })
Notify.markRead(n!.id)
expect(n!.read).toBe(true)
})
it('badgeCount 统计未读数', () => {
Notify.send({ appId: 'clock', title: 'A', body: '1', silent: true })
Notify.send({ appId: 'clock', title: 'B', body: '2', silent: true })
expect(Notify.badgeCount('clock')).toBe(2)
})
it('markRead 减少未读计数', () => {
const n = Notify.send({ appId: 'clock', title: 'T', body: 'B', silent: true })
expect(Notify.badgeCount('clock')).toBe(1)
Notify.markRead(n!.id)
expect(Notify.badgeCount('clock')).toBe(0)
})
})
// ==================== 专注模式 ====================
describe('专注模式', () => {
it('突破型通知在专注模式下仍发送', () => {
mockSys.settings.focus = true
const n = Notify.send({ appId: 'clock', title: '计时器', body: '时间到!', breakthrough: true, silent: true })
expect(n).not.toBeNull()
})
it('非突破型通知在专注模式下仍记录但不弹横幅', () => {
mockSys.settings.focus = true
const n = Notify.send({ appId: 'clock', title: '普通', body: '', silent: true })
expect(n).not.toBeNull()
expect(Notify.list).toHaveLength(1)
})
})
// ==================== 清理 ====================
describe('清理', () => {
it('clearAll 清空所有通知', () => {
Notify.send({ appId: 'f', title: 'T', body: 'B', silent: true })
expect(Notify.list).toHaveLength(1)
Notify.clearAll()
expect(Notify.list).toHaveLength(0)
})
})
})