Files
你的用户名 237c7802e5
Some checks failed
Deploy / deploy (push) Has been cancelled
Initial commit: Telegram Management System
Full-stack web application for Telegram management
- Frontend: Vue 3 + Vben Admin
- Backend: NestJS
- Features: User management, group broadcast, statistics

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-04 15:37:50 +08:00

358 lines
11 KiB
TypeScript

/**
* 登录和认证流程端到端测试
* 使用 Playwright 进行自动化测试
*/
import { test, expect, Page } from '@playwright/test';
// 测试配置
const TEST_CONFIG = {
baseURL: 'http://localhost:5173',
timeout: 30000,
// 测试账号信息
testUser: {
username: 'admin',
password: '111111',
},
// 超级管理员账号
superAdmin: {
username: 'super_admin',
password: 'super123456',
},
// 普通用户账号
normalUser: {
username: 'test_user',
password: 'test123456',
},
};
test.describe('登录和认证流程测试', () => {
test.beforeEach(async ({ page }) => {
// 设置较长的超时时间
test.setTimeout(TEST_CONFIG.timeout);
// 访问登录页面
await page.goto(TEST_CONFIG.baseURL);
// 等待页面加载完成
await page.waitForLoadState('networkidle');
});
test('应该正确显示登录页面', async ({ page }) => {
// 检查页面标题
await expect(page).toHaveTitle(/Telegram Management System|登录/);
// 检查登录表单元素是否存在
await expect(page.locator('[data-testid="username-input"]')).toBeVisible();
await expect(page.locator('[data-testid="password-input"]')).toBeVisible();
await expect(page.locator('[data-testid="login-button"]')).toBeVisible();
// 检查记住密码复选框
await expect(page.locator('[data-testid="remember-me"]')).toBeVisible();
// 检查语言切换按钮
await expect(
page.locator('[data-testid="language-switcher"]'),
).toBeVisible();
});
test('空用户名密码应该显示验证错误', async ({ page }) => {
// 直接点击登录按钮
await page.click('[data-testid="login-button"]');
// 等待验证错误消息出现
await expect(page.locator('.ant-form-item-explain-error')).toContainText(
'请输入用户名',
);
});
test('错误的用户名密码应该显示错误信息', async ({ page }) => {
// 输入错误的用户名和密码
await page.fill('[data-testid="username-input"]', 'wrong_user');
await page.fill('[data-testid="password-input"]', 'wrong_password');
// 点击登录按钮
await page.click('[data-testid="login-button"]');
// 等待错误消息出现
await expect(page.locator('.ant-message-error')).toBeVisible();
await expect(page.locator('.ant-message-error')).toContainText(
/用户名或密码错误|登录失败/,
);
});
test('正确的用户名密码应该成功登录', async ({ page }) => {
await loginWithCredentials(page, TEST_CONFIG.testUser);
// 验证登录成功后跳转到首页
await expect(page).toHaveURL(/\/dashboard/);
// 检查用户信息是否正确显示
await expect(page.locator('[data-testid="user-avatar"]')).toBeVisible();
await expect(
page.locator('[data-testid="username-display"]'),
).toContainText(TEST_CONFIG.testUser.username);
});
test('记住密码功能应该正常工作', async ({ page }) => {
// 输入用户名密码
await page.fill(
'[data-testid="username-input"]',
TEST_CONFIG.testUser.username,
);
await page.fill(
'[data-testid="password-input"]',
TEST_CONFIG.testUser.password,
);
// 勾选记住密码
await page.check('[data-testid="remember-me"]');
// 登录
await page.click('[data-testid="login-button"]');
// 等待登录完成
await page.waitForURL(/\/dashboard/);
// 退出登录
await page.click('[data-testid="user-dropdown"]');
await page.click('[data-testid="logout-button"]');
// 回到登录页面,检查是否记住了用户名
await page.waitForURL(/\/login/);
await expect(page.locator('[data-testid="username-input"]')).toHaveValue(
TEST_CONFIG.testUser.username,
);
});
test('语言切换功能应该正常工作', async ({ page }) => {
// 点击语言切换按钮
await page.click('[data-testid="language-switcher"]');
// 选择英文
await page.click('[data-testid="lang-en"]');
// 检查页面是否切换到英文
await expect(page.locator('[data-testid="login-title"]')).toContainText(
/Login|Sign In/,
);
// 切换回中文
await page.click('[data-testid="language-switcher"]');
await page.click('[data-testid="lang-zh"]');
// 检查页面是否切换回中文
await expect(page.locator('[data-testid="login-title"]')).toContainText(
/登录|用户登录/,
);
});
test('Token过期应该自动跳转到登录页', async ({ page }) => {
// 先正常登录
await loginWithCredentials(page, TEST_CONFIG.testUser);
await expect(page).toHaveURL(/\/dashboard/);
// 模拟Token过期 - 清除localStorage中的token
await page.evaluate(() => {
localStorage.removeItem('access_token');
localStorage.removeItem('refresh_token');
});
// 尝试访问需要认证的页面
await page.goto(`${TEST_CONFIG.baseURL}/account/list`);
// 应该自动跳转到登录页
await expect(page).toHaveURL(/\/login/);
// 应该显示登录过期提示
await expect(page.locator('.ant-message-warning')).toContainText(
/登录过期|请重新登录/,
);
});
test('退出登录应该清除认证状态', async ({ page }) => {
// 先登录
await loginWithCredentials(page, TEST_CONFIG.testUser);
await expect(page).toHaveURL(/\/dashboard/);
// 退出登录
await page.click('[data-testid="user-dropdown"]');
await page.click('[data-testid="logout-button"]');
// 应该跳转到登录页
await expect(page).toHaveURL(/\/login/);
// 验证Token已被清除
const accessToken = await page.evaluate(() =>
localStorage.getItem('access_token'),
);
expect(accessToken).toBeNull();
// 尝试直接访问受保护页面应该被重定向
await page.goto(`${TEST_CONFIG.baseURL}/account/list`);
await expect(page).toHaveURL(/\/login/);
});
test('刷新页面应该保持登录状态', async ({ page }) => {
// 登录
await loginWithCredentials(page, TEST_CONFIG.testUser);
await expect(page).toHaveURL(/\/dashboard/);
// 刷新页面
await page.reload();
// 应该仍然保持登录状态
await expect(page).toHaveURL(/\/dashboard/);
await expect(page.locator('[data-testid="user-avatar"]')).toBeVisible();
});
test('多标签页登录状态应该同步', async ({ context }) => {
const page1 = await context.newPage();
const page2 = await context.newPage();
// 在第一个标签页登录
await page1.goto(TEST_CONFIG.baseURL);
await loginWithCredentials(page1, TEST_CONFIG.testUser);
await expect(page1).toHaveURL(/\/dashboard/);
// 在第二个标签页访问应用
await page2.goto(TEST_CONFIG.baseURL);
// 第二个标签页应该也是登录状态
await expect(page2).toHaveURL(/\/dashboard/);
await expect(page2.locator('[data-testid="user-avatar"]')).toBeVisible();
// 在第一个标签页退出登录
await page1.click('[data-testid="user-dropdown"]');
await page1.click('[data-testid="logout-button"]');
// 刷新第二个标签页,应该也被退出登录
await page2.reload();
await expect(page2).toHaveURL(/\/login/);
});
});
test.describe('权限和角色测试', () => {
test('超级管理员应该能访问所有页面', async ({ page }) => {
await page.goto(TEST_CONFIG.baseURL);
await loginWithCredentials(page, TEST_CONFIG.superAdmin);
// 检查菜单项是否完整显示
const menuItems = [
'[data-testid="menu-dashboard"]',
'[data-testid="menu-account"]',
'[data-testid="menu-system"]',
'[data-testid="menu-logs"]',
'[data-testid="menu-marketing"]',
];
for (const menuItem of menuItems) {
await expect(page.locator(menuItem)).toBeVisible();
}
// 测试访问系统管理页面
await page.click('[data-testid="menu-system"]');
await page.click('[data-testid="menu-permission-management"]');
await expect(page).toHaveURL(/\/system\/permission/);
});
test('普通用户应该只能访问授权页面', async ({ page }) => {
await page.goto(TEST_CONFIG.baseURL);
await loginWithCredentials(page, TEST_CONFIG.normalUser);
// 检查某些管理功能不可见
await expect(page.locator('[data-testid="menu-system"]')).not.toBeVisible();
// 尝试直接访问受限页面应该被拒绝
await page.goto(`${TEST_CONFIG.baseURL}/system/permission`);
await expect(page.locator('.ant-result-403')).toBeVisible();
await expect(page.locator('.ant-result-title')).toContainText('403');
});
test('按钮级权限控制应该正常工作', async ({ page }) => {
await page.goto(TEST_CONFIG.baseURL);
await loginWithCredentials(page, TEST_CONFIG.normalUser);
// 访问账号列表页面
await page.goto(`${TEST_CONFIG.baseURL}/account/list`);
// 检查删除按钮是否被隐藏(假设普通用户没有删除权限)
await expect(
page.locator('[data-testid="delete-button"]'),
).not.toBeVisible();
// 但查看按钮应该可见
await expect(page.locator('[data-testid="view-button"]')).toBeVisible();
});
});
test.describe('国际化功能测试', () => {
test('语言切换应该影响整个应用', async ({ page }) => {
await page.goto(TEST_CONFIG.baseURL);
await loginWithCredentials(page, TEST_CONFIG.testUser);
// 切换到英文
await page.click('[data-testid="language-switcher"]');
await page.click('[data-testid="lang-en"]');
// 检查导航菜单是否切换到英文
await expect(page.locator('[data-testid="menu-dashboard"]')).toContainText(
/Dashboard/,
);
await expect(page.locator('[data-testid="menu-account"]')).toContainText(
/Account/,
);
// 切换回中文
await page.click('[data-testid="language-switcher"]');
await page.click('[data-testid="lang-zh"]');
// 检查是否切换回中文
await expect(page.locator('[data-testid="menu-dashboard"]')).toContainText(
/仪表盘|首页/,
);
await expect(page.locator('[data-testid="menu-account"]')).toContainText(
/账号管理/,
);
});
test('语言偏好应该被持久化', async ({ page }) => {
await page.goto(TEST_CONFIG.baseURL);
// 在登录页切换到英文
await page.click('[data-testid="language-switcher"]');
await page.click('[data-testid="lang-en"]');
// 登录
await loginWithCredentials(page, TEST_CONFIG.testUser);
// 刷新页面,语言设置应该保持
await page.reload();
await expect(page.locator('[data-testid="menu-dashboard"]')).toContainText(
/Dashboard/,
);
// 退出重新登录,语言设置也应该保持
await page.click('[data-testid="user-dropdown"]');
await page.click('[data-testid="logout-button"]');
await page.waitForURL(/\/login/);
await expect(page.locator('[data-testid="login-title"]')).toContainText(
/Login|Sign In/,
);
});
});
// 辅助函数:使用指定凭据登录
async function loginWithCredentials(
page: Page,
credentials: { username: string; password: string },
) {
await page.fill('[data-testid="username-input"]', credentials.username);
await page.fill('[data-testid="password-input"]', credentials.password);
await page.click('[data-testid="login-button"]');
// 等待登录完成(等待跳转到仪表盘页面)
await page.waitForURL(/\/dashboard/, { timeout: 10000 });
}