import { describe, it, expect, vi, beforeEach } from 'vitest'; import { AuthService } from '../../src/main/services/authService'; import { chromium } from 'playwright-core'; import { ENV } from '../../src/main/config/env'; // <-- 引入 ENV 对象 // 深度 Mock playwright-core,显式声明返回 any 绕过 TS 严格模式检查 vi.mock('playwright-core', (): any => { const mockFrame = { locator: vi.fn().mockReturnThis(), getByText: vi.fn().mockReturnThis(), waitFor: vi.fn().mockResolvedValue(true), click: vi.fn().mockResolvedValue(true), }; const mockFrameElement = { contentFrame: vi.fn().mockResolvedValue(mockFrame), }; const mockPage = { goto: vi.fn().mockResolvedValue(true), locator: vi.fn().mockReturnThis(), first: vi.fn().mockReturnThis(), nth: vi.fn().mockReturnThis(), fill: vi.fn().mockResolvedValue(true), click: vi.fn().mockResolvedValue(true), waitForSelector: vi.fn().mockResolvedValue(mockFrameElement), waitFor: vi.fn().mockResolvedValue(true), waitForURL: vi.fn().mockResolvedValue(true), }; const mockContext = { newPage: vi.fn().mockResolvedValue(mockPage), }; const mockBrowser = { newContext: vi.fn().mockResolvedValue(mockContext), close: vi.fn().mockResolvedValue(true), }; return { chromium: { launch: vi.fn().mockResolvedValue(mockBrowser), }, }; }); describe('AuthService', () => { let authService: AuthService; beforeEach(() => { authService = new AuthService(); vi.clearAllMocks(); // 强制设置测试环境变量 process.env.NODE_ENV = 'production'; }); it('应该抛出错误,如果未提供且环境变量中也没有用户名或密码', async () => { // 临时清空 ENV 对象中缓存的配置 const originalUsername = ENV.ERP_USERNAME; const originalPassword = ENV.ERP_PASSWORD; ENV.ERP_USERNAME = ''; ENV.ERP_PASSWORD = ''; // 此时 ENV 为空,options 也为空,必定会触发报错 await expect(authService.login({ username: '', password: '' })) .rejects .toThrow('登录失败: 必须提供用户名和密码,或在 .env 中配置'); // 恢复全局配置,以免影响后面的测试用例 ENV.ERP_USERNAME = originalUsername; ENV.ERP_PASSWORD = originalPassword; }); it('应该能读取环境变量并成功执行登录流程', async () => { // 这里的 login 不传参数,将自动从 ENV 对象(也就是你的 .env 文件)中读取账号密码 const result = await authService.login({ headless: true, // 强制测试静默模式 }); expect(chromium.launch).toHaveBeenCalled(); expect(result).toHaveProperty('browser'); expect(result).toHaveProperty('page'); expect(result).toHaveProperty('mainFrame'); }); it('登出操作应该按顺序点击头像和退出按钮', async () => { // 拿到 Mock 的 frame 对象 const mockBrowser = await chromium.launch(); const mockContext = await mockBrowser.newContext(); const mockPage = await mockContext.newPage(); const mockFrameEl = await mockPage.waitForSelector('#forwardFrame'); const mockFrame = await mockFrameEl.contentFrame(); await authService.logout(mockFrame!, mockPage); // 验证对应的选择器是否被正确调用 expect(mockFrame!.locator).toHaveBeenCalledWith('.diwork-avatar-default'); expect(mockFrame!.getByText).toHaveBeenCalledWith('退出登录'); }); });