136 lines
4.9 KiB
TypeScript
136 lines
4.9 KiB
TypeScript
/**
|
||
* 28-launchpad: Launchpad Vue 组件化测试
|
||
* 覆盖: show/hide、搜索过滤、网格排序、Escape/背景关闭、storeApp 过滤
|
||
*/
|
||
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
|
||
import { nextTick } from 'vue'
|
||
import { setupDOM, bootSystem } from '../helpers'
|
||
import { Launchpad } from '../../src/apps/launchpad/index'
|
||
import { Apps } from '../../src/composables/useApps'
|
||
|
||
describe('28-launchpad — Vue 组件化', () => {
|
||
beforeEach(async () => {
|
||
localStorage.clear()
|
||
await bootSystem()
|
||
})
|
||
afterEach(() => { Launchpad.hide() })
|
||
|
||
// ==================== show/hide ====================
|
||
describe('show/hide', () => {
|
||
it('show() 创建 overlay', () => {
|
||
Launchpad.show()
|
||
expect(document.querySelector('.launchpad')).toBeTruthy()
|
||
})
|
||
|
||
it('第二次 show() 先 hide 再 show(不重复)', () => {
|
||
Launchpad.show()
|
||
Launchpad.show()
|
||
expect(document.querySelectorAll('.launchpad').length).toBe(1)
|
||
})
|
||
|
||
it('hide() 移除 overlay(250ms 后)', async () => {
|
||
Launchpad.show()
|
||
Launchpad.hide()
|
||
await new Promise(r => setTimeout(r, 300))
|
||
expect(document.querySelector('.launchpad')).toBeNull()
|
||
})
|
||
})
|
||
|
||
// ==================== 结构 ====================
|
||
describe('结构', () => {
|
||
it('有搜索框', () => {
|
||
Launchpad.show()
|
||
expect(document.querySelector('.lp-search')).toBeTruthy()
|
||
})
|
||
|
||
it('有应用网格', () => {
|
||
Launchpad.show()
|
||
expect(document.querySelector('.lp-grid')).toBeTruthy()
|
||
expect(document.querySelectorAll('.lp-cell').length).toBeGreaterThan(0)
|
||
})
|
||
|
||
it('应用按名称排序', () => {
|
||
Launchpad.show()
|
||
const names = [...document.querySelectorAll('.lp-name')].map(e => e.textContent || '')
|
||
const sorted = [...names].sort((a, b) => a.localeCompare(b, 'zh-Hans-CN'))
|
||
expect(names).toEqual(sorted)
|
||
})
|
||
|
||
it('不包含自身(launchpad)', () => {
|
||
Launchpad.show()
|
||
const names = [...document.querySelectorAll('.lp-name')].map(e => e.textContent)
|
||
expect(names).not.toContain('启动台')
|
||
})
|
||
})
|
||
|
||
// ==================== 搜索 ====================
|
||
describe('搜索', () => {
|
||
it('输入关键字过滤应用', async () => {
|
||
Launchpad.show()
|
||
const input = document.querySelector('.lp-search') as HTMLInputElement
|
||
input.value = '终端'
|
||
input.dispatchEvent(new Event('input', { bubbles: true }))
|
||
await nextTick()
|
||
const names = [...document.querySelectorAll('.lp-name')].map(e => e.textContent)
|
||
expect(names.length).toBeGreaterThanOrEqual(1)
|
||
expect(names.every(n => n!.includes('终端'))).toBe(true)
|
||
})
|
||
|
||
it('无匹配显示"没有匹配的 App"', async () => {
|
||
Launchpad.show()
|
||
const input = document.querySelector('.lp-search') as HTMLInputElement
|
||
input.value = 'zzzzz_no_match'
|
||
input.dispatchEvent(new Event('input', { bubbles: true }))
|
||
await nextTick()
|
||
expect(document.querySelector('.lp-empty')?.textContent).toContain('没有匹配')
|
||
})
|
||
|
||
it('清除搜索恢复全量', async () => {
|
||
Launchpad.show()
|
||
const input = document.querySelector('.lp-search') as HTMLInputElement
|
||
input.value = '终端'; input.dispatchEvent(new Event('input', { bubbles: true }))
|
||
await nextTick()
|
||
const filtered = document.querySelectorAll('.lp-cell').length
|
||
input.value = ''; input.dispatchEvent(new Event('input', { bubbles: true }))
|
||
await nextTick()
|
||
expect(document.querySelectorAll('.lp-cell').length).toBeGreaterThan(filtered)
|
||
})
|
||
})
|
||
|
||
// ==================== 关闭 ====================
|
||
describe('关闭', () => {
|
||
it('Escape 键关闭', async () => {
|
||
Launchpad.show()
|
||
const lp = document.querySelector('.launchpad') as HTMLElement
|
||
lp.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }))
|
||
await new Promise(r => setTimeout(r, 300))
|
||
expect(document.querySelector('.launchpad')).toBeNull()
|
||
})
|
||
|
||
it('点击背景关闭', async () => {
|
||
Launchpad.show()
|
||
const lp = document.querySelector('.launchpad') as HTMLElement
|
||
lp.dispatchEvent(new MouseEvent('click', { bubbles: true }))
|
||
await new Promise(r => setTimeout(r, 300))
|
||
expect(document.querySelector('.launchpad')).toBeNull()
|
||
})
|
||
|
||
it('点击应用单元格关闭并打开应用', async () => {
|
||
Launchpad.show()
|
||
const cell = document.querySelector('.lp-cell') as HTMLElement
|
||
cell.dispatchEvent(new MouseEvent('click', { bubbles: true }))
|
||
await new Promise(r => setTimeout(r, 300))
|
||
expect(document.querySelector('.launchpad')).toBeNull()
|
||
})
|
||
})
|
||
|
||
// ==================== Apps.open 拦截 ====================
|
||
describe('Apps.open 拦截', () => {
|
||
it('open("launchpad") 调用 show', () => {
|
||
const result = Apps.open('launchpad')
|
||
expect(document.querySelector('.launchpad')).toBeTruthy()
|
||
expect(result).toBeNull()
|
||
})
|
||
})
|
||
})
|