import { describe, it, expect, vi, beforeEach } from 'vitest' import { mount } from '@vue/test-utils' import { createPinia, setActivePinia } from 'pinia' import Header from '@/components/Header.vue' import { useCategoryStore } from '@/stores/categoryStore' // 模拟路由 const mockRouter = { push: vi.fn(), replace: vi.fn(), go: vi.fn(), back: vi.fn(), forward: vi.fn(), currentRoute: { value: { path: '/', name: 'Home', params: {}, query: {}, hash: '', fullPath: '/', matched: [], meta: {}, } } } // 模拟Element Plus组件 vi.mock('element-plus', () => ({ ElMenu: { name: 'ElMenu', template: '
', props: ['mode', 'default-active', 'router'] }, ElMenuItem: { name: 'ElMenuItem', template: '
', props: ['index'] }, ElSubMenu: { name: 'ElSubMenu', template: '
', props: ['index'] }, ElButton: { name: 'ElButton', template: '', props: ['type', 'size', 'icon'] }, ElIcon: { name: 'ElIcon', template: '' }, ElDropdown: { name: 'ElDropdown', template: '
', props: ['trigger'] }, ElDropdownMenu: { name: 'ElDropdownMenu', template: '
' }, ElDropdownItem: { name: 'ElDropdownItem', template: '
' }, ElDrawer: { name: 'ElDrawer', template: '
', props: ['modelValue', 'title', 'direction', 'size'], emits: ['update:modelValue'] } })) // 模拟Element Plus图标 vi.mock('@element-plus/icons-vue', () => ({ Menu: { name: 'Menu', template: '' }, Close: { name: 'Close', template: '' }, User: { name: 'User', template: '' }, Setting: { name: 'Setting', template: '' }, Monitor: { name: 'Monitor', template: '' }, DataAnalysis: { name: 'DataAnalysis', template: '' } })) describe('Header.vue', () => { let wrapper let pinia let categoryStore beforeEach(() => { // 创建Pinia实例 pinia = createPinia() setActivePinia(pinia) // 获取store实例 categoryStore = useCategoryStore() // 模拟store数据 categoryStore.categories = [ { id: 1, name: '手机CPU', productCount: 50 }, { id: 2, name: '手机GPU', productCount: 40 }, { id: 3, name: '电脑CPU', productCount: 60 }, { id: 4, name: '电脑GPU', productCount: 45 } ] // 挂载组件 wrapper = mount(Header, { global: { plugins: [pinia], mocks: { $router: mockRouter }, stubs: { 'router-link': true, 'router-view': true, 'cache-status-indicator': true } } }) }) it('应该正确渲染Header组件', () => { expect(wrapper.exists()).toBe(true) expect(wrapper.find('.header').exists()).toBe(true) expect(wrapper.find('.header__logo').exists()).toBe(true) expect(wrapper.find('.header__nav').exists()).toBe(true) }) it('应该显示应用标题', () => { const title = wrapper.find('.header__title') expect(title.exists()).toBe(true) expect(title.text()).toBe('硬件性能排行榜') }) it('应该显示产品类别菜单', async () => { // 等待组件加载完成 await wrapper.vm.$nextTick() // 检查类别菜单是否存在 const categoryMenu = wrapper.find('.category-menu') expect(categoryMenu.exists()).toBe(true) // 检查类别数量 const menuItems = wrapper.findAll('.el-menu-item') expect(menuItems.length).toBeGreaterThan(0) }) it('应该显示产品对比按钮', () => { const compareButton = wrapper.find('[data-testid="compare-button"]') expect(compareButton.exists()).toBe(true) expect(compareButton.text()).toContain('产品对比') }) it('应该显示性能监控按钮', () => { const monitorButton = wrapper.find('[data-testid="monitor-button"]') expect(monitorButton.exists()).toBe(true) expect(monitorButton.text()).toContain('性能监控') }) it('应该响应式地在移动端显示菜单按钮', async () => { // 模拟移动端窗口大小 global.innerWidth = 500 window.dispatchEvent(new Event('resize')) await wrapper.vm.$nextTick() // 检查移动端菜单按钮是否存在 const menuButton = wrapper.find('.header__mobile-menu') expect(menuButton.exists()).toBe(true) }) it('应该正确处理菜单点击事件', async () => { // 获取第一个菜单项 const firstMenuItem = wrapper.find('.el-menu-item') expect(firstMenuItem.exists()).toBe(true) // 点击菜单项 await firstMenuItem.trigger('click') // 检查是否触发了路由导航 // 注意:由于使用了router-link stub,这里需要检查组件内部逻辑 // 在实际测试中,你可能需要模拟router-link的行为或检查组件内部状态 }) it('应该正确处理产品对比按钮点击', async () => { const compareButton = wrapper.find('[data-testid="compare-button"]') expect(compareButton.exists()).toBe(true) // 点击产品对比按钮 await compareButton.trigger('click') // 检查是否触发了路由导航 expect(mockRouter.push).toHaveBeenCalledWith('/compare') }) it('应该正确处理性能监控按钮点击', async () => { const monitorButton = wrapper.find('[data-testid="monitor-button"]') expect(monitorButton.exists()).toBe(true) // 点击性能监控按钮 await monitorButton.trigger('click') // 检查是否触发了路由导航 expect(mockRouter.push).toHaveBeenCalledWith('/monitor') }) it('应该在移动端正确处理菜单展开/收起', async () => { // 模拟移动端窗口大小 global.innerWidth = 500 window.dispatchEvent(new Event('resize')) await wrapper.vm.$nextTick() // 获取菜单按钮 const menuButton = wrapper.find('.header__mobile-menu') expect(menuButton.exists()).toBe(true) // 点击菜单按钮 await menuButton.trigger('click') // 检查菜单是否展开 expect(wrapper.vm.mobileMenuVisible).toBe(true) // 再次点击菜单按钮 await menuButton.trigger('click') // 检查菜单是否收起 expect(wrapper.vm.mobileMenuVisible).toBe(false) }) it('应该正确计算当前激活的菜单项', async () => { // 模拟当前路由为类别页面 mockRouter.currentRoute.value.path = '/category/1' await wrapper.vm.$nextTick() // 检查当前激活的菜单项 expect(wrapper.vm.activeMenuItem).toBe('category') }) it('应该在组件挂载时加载类别数据', async () => { // 模拟fetchCategories方法 const fetchCategoriesSpy = vi.spyOn(categoryStore, 'fetchCategories') // 重新挂载组件 wrapper = mount(Header, { global: { plugins: [pinia], mocks: { $router: mockRouter }, stubs: { 'router-link': true, 'router-view': true, 'cache-status-indicator': true } } }) // 等待组件加载完成 await wrapper.vm.$nextTick() // 检查是否调用了fetchCategories expect(fetchCategoriesSpy).toHaveBeenCalled() }) it('应该正确处理窗口大小变化', async () => { // 模拟桌面端窗口大小 global.innerWidth = 1200 window.dispatchEvent(new Event('resize')) await wrapper.vm.$nextTick() // 检查isMobile计算属性 expect(wrapper.vm.isMobile).toBe(false) // 模拟移动端窗口大小 global.innerWidth = 500 window.dispatchEvent(new Event('resize')) await wrapper.vm.$nextTick() // 检查isMobile计算属性 expect(wrapper.vm.isMobile).toBe(true) }) })