210 lines
5.8 KiB
TypeScript
210 lines
5.8 KiB
TypeScript
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
|
import { ref, nextTick } from 'vue'
|
|
import { useTaskRowContextMenu } from '@/components/TaskList/composables/taskRow/useTaskRowContextMenu'
|
|
import { createTask, createTimerTask } from '../../../fixtures/tasks'
|
|
import { sleep } from '../helpers/mount'
|
|
|
|
describe('useTaskRowContextMenu', () => {
|
|
let task: any
|
|
let emit: any
|
|
|
|
beforeEach(() => {
|
|
task = ref(createTask())
|
|
emit = vi.fn()
|
|
vi.useFakeTimers()
|
|
})
|
|
|
|
afterEach(() => {
|
|
vi.restoreAllMocks()
|
|
})
|
|
|
|
describe('右键菜单', () => {
|
|
it('应该初始隐藏右键菜单', () => {
|
|
const { contextMenuVisible } = useTaskRowContextMenu(task, emit)
|
|
|
|
expect(contextMenuVisible.value).toBe(false)
|
|
})
|
|
|
|
it('handleContextMenu 应显示右键菜单', () => {
|
|
// 明确指定为普通任务(非里程碑任务)
|
|
task.value = createTask({ type: 'task' })
|
|
|
|
const { handleContextMenu, contextMenuVisible, contextMenuPosition } =
|
|
useTaskRowContextMenu(task, emit)
|
|
|
|
const event = new MouseEvent('contextmenu', {
|
|
clientX: 100,
|
|
clientY: 200,
|
|
})
|
|
const preventDefault = vi.spyOn(event, 'preventDefault')
|
|
|
|
handleContextMenu(event)
|
|
|
|
expect(preventDefault).toHaveBeenCalled()
|
|
expect(contextMenuVisible.value).toBe(true)
|
|
expect(contextMenuPosition.value).toEqual({ x: 100, y: 200 })
|
|
})
|
|
|
|
it('closeContextMenu 应隐藏右键菜单', () => {
|
|
// 明确指定为普通任务
|
|
task.value = createTask({ type: 'task' })
|
|
|
|
const { handleContextMenu, closeContextMenu, contextMenuVisible } =
|
|
useTaskRowContextMenu(task, emit)
|
|
|
|
// 先显示
|
|
const event = new MouseEvent('contextmenu')
|
|
handleContextMenu(event)
|
|
expect(contextMenuVisible.value).toBe(true)
|
|
|
|
// 再隐藏
|
|
closeContextMenu()
|
|
expect(contextMenuVisible.value).toBe(false)
|
|
})
|
|
|
|
it('删除任务应触发 delete 事件', () => {
|
|
// 明确指定为普通任务
|
|
task.value = createTask({ type: 'task' })
|
|
|
|
const { handleTaskDelete } = useTaskRowContextMenu(task, emit)
|
|
|
|
handleTaskDelete(task.value)
|
|
|
|
expect(emit).toHaveBeenCalledWith('delete', task.value, undefined)
|
|
})
|
|
|
|
it('contextMenuTask 应返回当前任务', () => {
|
|
const { contextMenuTask } = useTaskRowContextMenu(task, emit)
|
|
|
|
expect(contextMenuTask.value).toBe(task.value)
|
|
})
|
|
})
|
|
|
|
describe('计时器格式化', () => {
|
|
it('应该将毫秒格式化为 HH:MM:SS', async () => {
|
|
task.value = createTimerTask({
|
|
isTimerRunning: false,
|
|
timerElapsedTime: 3661000, // 1小时1分1秒
|
|
})
|
|
|
|
const { formattedTimer } = useTaskRowContextMenu(task, emit)
|
|
await nextTick()
|
|
|
|
expect(formattedTimer.value).toBe('01:01:01')
|
|
})
|
|
|
|
it('应该正确格式化零时间', async () => {
|
|
task.value = createTask({
|
|
isTimerRunning: false,
|
|
timerElapsedTime: 0,
|
|
})
|
|
|
|
const { formattedTimer } = useTaskRowContextMenu(task, emit)
|
|
await nextTick()
|
|
|
|
expect(formattedTimer.value).toBe('00:00:00')
|
|
})
|
|
|
|
it('应该正确格式化超过24小时的时间', async () => {
|
|
task.value = createTask({
|
|
isTimerRunning: false,
|
|
timerElapsedTime: 90000000, // 25小时
|
|
})
|
|
|
|
const { formattedTimer } = useTaskRowContextMenu(task, emit)
|
|
await nextTick()
|
|
|
|
expect(formattedTimer.value).toBe('25:00:00')
|
|
})
|
|
})
|
|
|
|
describe('计时器更新', () => {
|
|
it('任务不在运行时应显示累计时间', async () => {
|
|
task.value = createTask({
|
|
isTimerRunning: false,
|
|
timerElapsedTime: 5000, // 5秒
|
|
})
|
|
|
|
const { timerElapsed } = useTaskRowContextMenu(task, emit)
|
|
await nextTick()
|
|
|
|
expect(timerElapsed.value).toBe(5000)
|
|
})
|
|
|
|
it('任务运行中应实时更新时间', async () => {
|
|
const now = Date.now()
|
|
task.value = createTimerTask({
|
|
isTimerRunning: true,
|
|
timerStartTime: now - 3000, // 3秒前启动
|
|
timerElapsedTime: 5000, // 之前累计5秒
|
|
})
|
|
|
|
const { timerElapsed } = useTaskRowContextMenu(task, emit)
|
|
await nextTick()
|
|
|
|
// 应该是 5000 (之前) + 3000 (现在) = 8000ms
|
|
expect(timerElapsed.value).toBeGreaterThanOrEqual(8000)
|
|
expect(timerElapsed.value).toBeLessThan(9000)
|
|
})
|
|
|
|
it('计时器启动时应每秒更新', async () => {
|
|
const now = Date.now()
|
|
task.value = createTimerTask({
|
|
isTimerRunning: true,
|
|
timerStartTime: now,
|
|
timerElapsedTime: 0,
|
|
})
|
|
|
|
const { timerElapsed } = useTaskRowContextMenu(task, emit)
|
|
await nextTick()
|
|
|
|
const initialValue = timerElapsed.value
|
|
|
|
// 推进1秒
|
|
vi.advanceTimersByTime(1000)
|
|
await nextTick()
|
|
|
|
// 时间应该增加约1秒
|
|
expect(timerElapsed.value).toBeGreaterThan(initialValue)
|
|
})
|
|
|
|
it('计时器停止时应停止更新', async () => {
|
|
const now = Date.now()
|
|
task.value = createTimerTask({
|
|
isTimerRunning: true,
|
|
timerStartTime: now,
|
|
timerElapsedTime: 0,
|
|
})
|
|
|
|
const { timerElapsed } = useTaskRowContextMenu(task, emit)
|
|
await nextTick()
|
|
|
|
// 停止计时器
|
|
task.value.isTimerRunning = false
|
|
await nextTick()
|
|
|
|
const stoppedValue = timerElapsed.value
|
|
|
|
// 推进时间
|
|
vi.advanceTimersByTime(5000)
|
|
await nextTick()
|
|
|
|
// 值不应该变化
|
|
expect(timerElapsed.value).toBe(stoppedValue)
|
|
})
|
|
})
|
|
|
|
describe('清理工作', () => {
|
|
it('组件卸载时应清除计时器', () => {
|
|
task.value = createTimerTask()
|
|
|
|
const result = useTaskRowContextMenu(task, emit)
|
|
|
|
// onUnmounted 会在组件卸载时自动清理
|
|
// 这里只验证返回值包含必要的函数
|
|
expect(result.timerElapsed).toBeDefined()
|
|
expect(result.formattedTimer).toBeDefined()
|
|
})
|
|
})
|
|
})
|