// @vitest-environment jsdom import { beforeEach, describe, expect, it, vi } from 'vitest' import { defineComponent, h } from 'vue' import { mount, flushPromises } from '@vue/test-utils' import ArcoVue from '@arco-design/web-vue' const routeState = vi.hoisted(() => ({ query: { board: 'project-a' } as Record, })) const routerReplace = vi.hoisted(() => vi.fn()) const storeState = vi.hoisted(() => ({ tasks: [] as Array<{ id: string; title: string; status: string; created_at: number; assignee?: string | null }>, stats: { by_status: { todo: 1, done: 0 }, by_assignee: {}, total: 1 } as Record, assignees: [] as Array<{ name: string; counts: Record | null }>, activeBoards: [] as Array<{ slug: string; name: string; icon?: string; total?: number }>, loading: false, boardsLoading: false, selectedBoard: 'default', boardWarning: null as string | null, capabilities: null as Record | null, filterStatus: null as string | null, filterAssignee: null as string | null, })) const mockFetchBoards = vi.hoisted(() => vi.fn()) const mockFetchCapabilities = vi.hoisted(() => vi.fn()) const mockRefreshAll = vi.hoisted(() => vi.fn()) const mockFetchTasks = vi.hoisted(() => vi.fn()) const mockFetchStats = vi.hoisted(() => vi.fn()) const mockSetFilter = vi.hoisted(() => vi.fn()) const mockRecoverSelectedBoard = vi.hoisted(() => vi.fn()) const mockCreateBoard = vi.hoisted(() => vi.fn()) const mockArchiveSelectedBoard = vi.hoisted(() => vi.fn()) const mockDispatch = vi.hoisted(() => vi.fn()) const mockStartEventStream = vi.hoisted(() => vi.fn()) const mockStopEventStream = vi.hoisted(() => vi.fn()) const mockFetchProfiles = vi.hoisted(() => vi.fn()) const profilesState = vi.hoisted(() => ({ profiles: [] as Array<{ name: string; avatar?: Record | null }>, })) vi.mock('vue-router', () => ({ useRoute: () => routeState, useRouter: () => ({ replace: routerReplace }), })) vi.mock('vue-i18n', () => ({ useI18n: () => ({ t: (key: string) => key, }), })) // Arco's imperative Message API needs a live DOM, so mock the adapter composable. vi.mock('@/composables/useMessage', () => ({ useMessage: () => ({ warning: vi.fn(), error: vi.fn(), success: vi.fn(), info: vi.fn() }), })) vi.mock('@/stores/hermes/kanban', () => ({ DEFAULT_KANBAN_BOARD: 'default', useKanbanStore: () => ({ ...storeState, fetchBoards: mockFetchBoards, fetchCapabilities: mockFetchCapabilities, refreshAll: mockRefreshAll, fetchTasks: mockFetchTasks, fetchStats: mockFetchStats, setFilter: mockSetFilter, recoverSelectedBoard: mockRecoverSelectedBoard, createBoard: mockCreateBoard, archiveSelectedBoard: mockArchiveSelectedBoard, dispatch: mockDispatch, startEventStream: mockStartEventStream, stopEventStream: mockStopEventStream, }), })) vi.mock('@/stores/hermes/profiles', () => ({ useProfilesStore: () => ({ profiles: profilesState.profiles, fetchProfiles: mockFetchProfiles, }), })) vi.mock('@/components/hermes/kanban/KanbanTaskCard.vue', () => ({ default: defineComponent({ name: 'KanbanTaskCard', props: { task: { type: Object, required: true }, assigneeAvatar: { type: Object, required: false } }, template: '
{{ task.title }}
', }), })) vi.mock('@/components/hermes/kanban/KanbanTaskDrawer.vue', () => ({ default: defineComponent({ name: 'KanbanTaskDrawer', emits: ['updated', 'close'], template: '', }), })) vi.mock('@/components/hermes/kanban/KanbanCreateForm.vue', () => ({ default: defineComponent({ name: 'KanbanCreateForm', emits: ['created', 'close'], template: '', }), })) /** * Arco's a-select renders a custom dropdown (no native