Files
jordium-gantt-vue3/tests/unit/composables/taskRow/useTaskRowContextMenu.spec.ts
2025-12-17 18:09:55 +08:00

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()
})
})
})