Files
first-electron-app/tests/unit/auth.test.ts
Misaka_Company 2f3bfc219e Refactor auth service login and logout logic
- Fix iframe handling in login process
- Use getByRole for more reliable element selection
- Add forced login confirmation dialog handling
- Refactor logout to support intelligent Frame detection
- Replace || with ?? for proper null coalescing
- Update tests to avoid global ENV mutations

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-28 15:19:06 +08:00

90 lines
3.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { AuthService } from '../../src/main/services/authService';
import { chromium } from 'playwright-core';
// 深度 Mock playwright-core
vi.mock('playwright-core', (): any => {
const mockPage = {
goto: vi.fn().mockResolvedValue(true),
waitForSelector: vi.fn().mockReturnThis(),
waitForTimeout: vi.fn().mockResolvedValue(true),
};
const mockFrame = {
locator: vi.fn().mockReturnThis(),
getByText: vi.fn().mockReturnThis(),
getByRole: vi.fn().mockReturnThis(),
waitFor: vi.fn().mockResolvedValue(true),
click: vi.fn().mockResolvedValue(true),
fill: vi.fn().mockResolvedValue(true),
count: vi.fn().mockResolvedValue(0),
page: vi.fn().mockReturnValue(mockPage),
isDetached: vi.fn().mockReturnValue(false),
};
mockPage.waitForSelector = vi.fn().mockResolvedValue({
contentFrame: vi.fn().mockResolvedValue(mockFrame)
});
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 () => {
// 终极修复:直接传入明确的空字符串。
// 因为 authService 使用了 ?? 操作符,它会直接使用传入的空字符串,
// 而不会退回去读取 ENV从而完美触发异常。
// 这样写彻底避免了修改全局 ENV 导致影响后续测试用例的“状态泄漏”问题。
await expect(authService.login({ username: '', password: '' }))
.rejects
.toThrow('登录失败: 必须提供用户名和密码,或在 .env 中配置');
});
it('应该能读取环境变量并成功执行登录流程', async () => {
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 () => {
const mockBrowser = await chromium.launch();
const mockContext = await mockBrowser.newContext();
const mockPage = await mockContext.newPage();
// 直接传入 Page 对象,触发内部的重新寻找 iframe 逻辑
await authService.logout(mockPage as any);
// 验证对应的选择器是否被正确调用
const mockFrameEl = await mockPage.waitForSelector('#forwardFrame');
const mockFrame = await mockFrameEl.contentFrame();
expect(mockFrame!.getByRole).toHaveBeenCalledWith('img', { name: 'logo' });
expect(mockFrame!.getByText).toHaveBeenCalledWith('退出登录');
});
});