import { describe, it, expect, vi, beforeEach } from 'vitest' import { mount, flushPromises } from '@vue/test-utils' import { createRouter, createMemoryHistory } from 'vue-router' import ElementPlus from 'element-plus' import NewChatButton from '../src/components/NewChatButton.vue' import LoginView from '../src/views/LoginView.vue' import axios from 'axios' vi.mock('axios', () => ({ default: { post: vi.fn(), }, })) const mockedAxios = axios const makeRouter = () => createRouter({ history: createMemoryHistory(), routes: [ { path: '/', name: 'login', component: LoginView }, { path: '/welcome', name: 'welcome', component: LoginView }, ], }) describe('NewChatButton', () => { beforeEach(() => { localStorage.clear() vi.clearAllMocks() }) it('redirects to login when no token', async () => { const router = makeRouter() router.push('/welcome') await router.isReady() const wrapper = mount(NewChatButton, { global: { plugins: [router, ElementPlus], }, }) await wrapper.find('[data-testid="new-chat-trigger"]').trigger('click') await flushPromises() await wrapper.find('[data-testid="create-session"]').trigger('click') await flushPromises() expect(router.currentRoute.value.name).toBe('login') }) it('creates session with Authorization header', async () => { localStorage.setItem('ars-token', 'jwt-token') mockedAxios.post.mockResolvedValue({ data: { session_id: 'session-123', session_name: 'Demo' }, }) const router = makeRouter() router.push('/welcome') await router.isReady() const wrapper = mount(NewChatButton, { global: { plugins: [router, ElementPlus], }, }) // 直接调用方法以绕过弹层结构细节 wrapper.vm.sessionName = 'Demo Session' await wrapper.vm.createSession() await flushPromises() expect(mockedAxios.post).toHaveBeenCalledWith( 'http://localhost:8000/api/sessions', expect.objectContaining({ session_name: 'Demo Session' }), expect.objectContaining({ headers: expect.objectContaining({ Authorization: 'Bearer jwt-token', }), }) ) expect(localStorage.getItem('ars-last-session')).toBe('session-123') }) })