macos-web/tests/cases/36-reminders.test.ts
2026-07-23 13:54:37 +08:00

41 lines
4.4 KiB
TypeScript

/**
* 36-reminders: Reminders Vue 组件化 — 深层测试
*/
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
import { h, render, nextTick } from 'vue'
import RemindersComponent from '../../src/apps/reminders/Reminders.vue'
import { store } from '../../src/composables/useStore'
import { setupDOM } from '../helpers'
function mk() { const e = document.createElement('div'); e.className = 'window'; document.getElementById('window-layer')?.appendChild(e); const b = document.createElement('div'); b.className = 'win-body'; e.appendChild(b); return { el: e, body: b, timers: [] as any[], data: {} } }
describe('36-reminders', () => {
let w: any
beforeEach(() => { localStorage.clear(); store.set('reminders', null); setupDOM(); w = mk() })
afterEach(() => { render(null, w.body); w.el.remove() })
function m() { render(h(RemindersComponent, { win: w }), w.body) }
it('3个默认列表', () => { m(); expect(w.body.querySelectorAll('.fb-side-item').length).toBe(3) })
it('颜色标识', () => { m(); expect(w.body.querySelector('.rem-color')).toBeTruthy() })
it('列表名称', () => { m(); expect(w.body.querySelector('.rem-lname')?.textContent).toBeTruthy() })
it('未完成计数', () => { m(); expect(w.body.querySelector('.rem-count')?.textContent).toBeTruthy() })
it('默认选中首列表', () => { m(); expect(w.body.querySelector('.fb-side-item.sel')).toBeTruthy() })
it('切换列表sel转移', async () => { m(); const items = w.body.querySelectorAll('.fb-side-item'); click(items[1]); await nextTick(); expect(items[1].classList.contains('sel')).toBe(true) })
it('checkbox存在', () => { m(); expect(w.body.querySelector('.rem-check')).toBeTruthy() })
it('标题输入存在', () => { m(); expect(w.body.querySelector('.rem-title')).toBeTruthy() })
it('日期输入存在', () => { m(); expect(w.body.querySelector('.rem-due')).toBeTruthy() })
it('默认数据含3个列表', () => { m(); expect(w.body.querySelectorAll('.fb-side-item').length).toBe(3) })
it('勾选未完成变done', async () => { m(); const cb = w.body.querySelector('.rem-check:not(.done)') as HTMLElement; click(cb); await nextTick(); await nextTick(); expect(w.body.querySelectorAll('.rem-check.done').length).toBeGreaterThanOrEqual(1) })
it('勾选后store持久化', async () => { m(); const cb = w.body.querySelector('.rem-check:not(.done)') as HTMLElement; click(cb); await nextTick(); await nextTick(); expect(store.get('reminders', {}).items.some((i: any) => i.done)).toBe(true) })
it('Enter新建清空输入', async () => { m(); const inp = w.body.querySelector('.rem-new') as HTMLInputElement; inp.value = '新提醒'; inp.dispatchEvent(new Event('input', { bubbles: true })); inp.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true })); await nextTick(); expect((w.body.querySelector('.rem-new') as HTMLInputElement).value).toBe('') })
it('空输入不新建', async () => { m(); const before = w.body.querySelectorAll('.rem-row').length; (w.body.querySelector('.rem-new') as HTMLInputElement).dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true })); await nextTick(); expect(w.body.querySelectorAll('.rem-row').length).toBe(before) })
it('标题change更新', async () => { m(); const ti = w.body.querySelector('.rem-title') as HTMLInputElement; ti.value = '改了'; ti.dispatchEvent(new Event('change', { bubbles: true })); await nextTick(); expect(store.get('reminders', {}).items.some((i: any) => i.title === '改了')).toBe(true) })
it('日期change更新', async () => { m(); const di = w.body.querySelector('.rem-due') as HTMLInputElement; di.value = '2026-12-25'; di.dispatchEvent(new Event('change', { bubbles: true })); await nextTick(); expect(store.get('reminders', {}).items.some((i: any) => i.due === '2026-12-25')).toBe(true) })
it('空列表提示', () => { store.set('reminders', { lists: [{ id:'e1', name:'空', color:'#ff9f0a' }], items: [] }); m(); expect(w.body.querySelector('.empty-state')?.textContent).toContain('此列表为空') })
it('store加载预设', () => { store.set('reminders', { lists: [{ id:'x1', name:'自定义', color:'#ff453a' }], items: [] }); m(); expect(w.body.querySelector('.rem-lname')?.textContent).toBe('自定义') })
it('卸载', () => { m(); render(null, w.body); expect(w.body.children.length).toBe(0) })
})
function click(el: Element | null) { el?.dispatchEvent(new MouseEvent('click', { bubbles: true })) }