| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461 |
- import { test, expect } from '../../utils/test-setup';
- /**
- * 人才小程序登录 E2E 测试
- *
- * 测试人才用户通过小程序登录的功能,验证:
- * - 表单验证
- * - 登录失败场景
- * - 登录成功场景
- * - Token 持久性
- * - 退出登录
- *
- * @see {@link ../pages/mini/talent-mini.page.ts} TalentMiniPage
- * 测试用户信息(Story 12.3 创建):
- * - 账号: 13800128219
- * - 密码: admin123
- */
- /**
- * 创建测试用户的辅助函数
- *
- * 在独立的 browser context 中通过管理后台创建测试用户,
- * 避免与小程序登录测试共享 page 实例导致的冲突。
- *
- * @param browser Playwright browser 实例
- * @param userData 用户数据
- * @returns 创建的用户名和密码
- */
- async function createTestUser(browser: typeof test['fixtures']['browser'], userData: {
- username: string;
- password: string;
- nickname?: string;
- disabilityPersonId?: number;
- }): Promise<{ username: string; password: string }> {
- // 动态导入 AdminLoginPage 和 UserManagementPage,避免与小程序测试共享 context
- const { AdminLoginPage } = await import('../../pages/admin/login.page');
- const { UserManagementPage } = await import('../../pages/admin/user-management.page');
- // 创建独立的 browser context
- const adminContext = await browser.newContext();
- try {
- // 在独立 context 中创建 page
- const adminPage = await adminContext.newPage();
- // 创建管理后台 Page Objects
- const adminLoginPage = new AdminLoginPage(adminPage);
- const userManagementPage = new UserManagementPage(adminPage);
- // 登录管理后台
- await adminLoginPage.goto();
- await adminLoginPage.login('admin', 'admin123');
- // 导航到用户管理页面
- await userManagementPage.goto();
- // 创建测试用户(使用 TALENT 类型,人才用户)
- const result = await userManagementPage.createUser({
- username: userData.username,
- password: userData.password,
- nickname: userData.nickname || '测试人才用户',
- disabilityPersonId: userData.disabilityPersonId || 1,
- });
- // 验证创建成功
- expect(result.success).toBe(true);
- return { username: userData.username, password: userData.password };
- } finally {
- // 清理:关闭独立 context
- await adminContext.close();
- }
- }
- test.describe('人才小程序登录功能', () => {
- test.describe('表单验证测试 (AC3)', () => {
- test('不输入任何信息应该无法登录', async ({ talentMiniPage }) => {
- // 导航到登录页面
- await talentMiniPage.goto();
- // 不填写任何信息,直接点击登录按钮
- await talentMiniPage.clickLoginButton();
- // 等待表单验证完成
- await talentMiniPage.page.waitForTimeout(500);
- // 验证仍然在登录页面(未跳转)
- // Toast 消息在 headless 模式下可能不稳定,但页面不应该跳转
- const currentUrl = talentMiniPage.page.url();
- expect(currentUrl).toContain('/talent-mini');
- expect(currentUrl).toContain('/pages/login/index');
- // 验证未存储 token
- const token = await talentMiniPage.getToken();
- expect(token).toBeNull();
- });
- test('只输入账号不输入密码应该无法登录', async ({ talentMiniPage }) => {
- // 导航到登录页面
- await talentMiniPage.goto();
- // 只填写账号,不填写密码
- await talentMiniPage.fillIdentifier('13800128219');
- // 尝试点击登录按钮
- await talentMiniPage.clickLoginButton();
- // 等待表单验证完成
- await talentMiniPage.page.waitForTimeout(500);
- // 验证仍然在登录页面(未跳转)
- const currentUrl = talentMiniPage.page.url();
- expect(currentUrl).toContain('/talent-mini');
- expect(currentUrl).toContain('/pages/login/index');
- // 验证未存储 token
- const token = await talentMiniPage.getToken();
- expect(token).toBeNull();
- });
- test('只输入密码不输入账号应该无法登录', async ({ talentMiniPage }) => {
- // 导航到登录页面
- await talentMiniPage.goto();
- // 只填写密码,不填写账号
- await talentMiniPage.fillPassword('admin123');
- // 尝试点击登录按钮
- await talentMiniPage.clickLoginButton();
- // 等待表单验证完成
- await talentMiniPage.page.waitForTimeout(500);
- // 验证仍然在登录页面(未跳转)
- const currentUrl = talentMiniPage.page.url();
- expect(currentUrl).toContain('/talent-mini');
- expect(currentUrl).toContain('/pages/login/index');
- // 验证未存储 token
- const token = await talentMiniPage.getToken();
- expect(token).toBeNull();
- });
- });
- test.describe('登录失败测试 (AC2)', () => {
- test('使用不存在的用户名登录失败', async ({ talentMiniPage }) => {
- // 导航到登录页面
- await talentMiniPage.goto();
- // 使用不存在的用户名尝试登录
- const fakeUsername = '12345678901';
- await talentMiniPage.login(fakeUsername, 'password123');
- // 等待 API 响应
- await talentMiniPage.page.waitForTimeout(2000);
- // 验证仍然在登录页面(未跳转)
- const currentUrl = talentMiniPage.page.url();
- expect(currentUrl).toContain('/talent-mini');
- // 验证未存储 token
- const token = await talentMiniPage.getToken();
- expect(token).toBeNull();
- });
- test('使用错误的密码登录失败', async ({ talentMiniPage }) => {
- // 导航到登录页面
- await talentMiniPage.goto();
- // 使用存在的用户但错误的密码尝试登录
- await talentMiniPage.login('13800128219', 'wrongpassword');
- // 等待 API 响应
- await talentMiniPage.page.waitForTimeout(2000);
- // 验证仍然在登录页面(未跳转)
- const currentUrl = talentMiniPage.page.url();
- expect(currentUrl).toContain('/talent-mini');
- // 验证未存储 token
- const token = await talentMiniPage.getToken();
- expect(token).toBeNull();
- });
- test('登录失败后登录按钮可以重新点击', async ({ talentMiniPage }) => {
- // 导航到登录页面
- await talentMiniPage.goto();
- // 使用错误的凭据尝试登录
- await talentMiniPage.login('12345678901', 'wrongpassword');
- // 等待 API 响应
- await talentMiniPage.page.waitForTimeout(2000);
- // 验证登录按钮仍然可见且可点击
- const loginButton = talentMiniPage.page.getByText('登录').nth(1);
- await expect(loginButton).toBeVisible();
- await expect(loginButton).toBeEnabled();
- });
- });
- test.describe.serial('基本登录成功测试 (AC1)', () => {
- // 使用 Story 12.3 创建的固定测试用户
- const TEST_USER = {
- account: '13800128219',
- password: 'admin123',
- username: 'talent_test_e2e',
- };
- test.afterEach(async ({ talentMiniPage }) => {
- // 清理认证状态
- await talentMiniPage.clearAuth();
- });
- test('应该成功登录人才小程序', async ({ talentMiniPage }) => {
- // 1. 导航到登录页面
- await talentMiniPage.goto();
- // 2. 使用测试用户登录
- await talentMiniPage.login(TEST_USER.account, TEST_USER.password);
- // 3. 验证登录成功(URL 跳转到主页)
- await talentMiniPage.expectLoginSuccess();
- });
- test('登录成功后应该显示主页或用户信息', async ({ talentMiniPage }) => {
- // 1. 导航到登录页面
- await talentMiniPage.goto();
- // 2. 使用测试用户登录
- await talentMiniPage.login(TEST_USER.account, TEST_USER.password);
- // 3. 验证登录成功
- await talentMiniPage.expectLoginSuccess();
- // 4. 验证 URL 跳转到主页
- const currentUrl = talentMiniPage.page.url();
- expect(currentUrl).toMatch(/pages\/index\/index/);
- });
- test('登录成功后 token 应该正确存储到 localStorage (AC1)', async ({ talentMiniPage }) => {
- // 1. 导航到登录页面
- await talentMiniPage.goto();
- // 2. 使用测试用户登录
- await talentMiniPage.login(TEST_USER.account, TEST_USER.password);
- // 3. 验证登录成功
- await talentMiniPage.expectLoginSuccess();
- // 4. 验证 token 被正确存储到 localStorage(key: talent_token)
- const token = await talentMiniPage.getToken();
- expect(token).not.toBeNull();
- expect(token?.length).toBeGreaterThan(0);
- });
- });
- test.describe.serial('Token 持久性测试 (AC4)', () => {
- const TEST_USER = {
- account: '13800128219',
- password: 'admin123',
- username: 'talent_test_e2e',
- };
- test.afterEach(async ({ talentMiniPage }) => {
- // 清理认证状态
- await talentMiniPage.clearAuth();
- });
- test('页面刷新后 token 仍然有效', async ({ talentMiniPage }) => {
- // 1. 导航到登录页面
- await talentMiniPage.goto();
- // 2. 使用测试用户登录
- await talentMiniPage.login(TEST_USER.account, TEST_USER.password);
- // 3. 验证登录成功
- await talentMiniPage.expectLoginSuccess();
- // 4. 获取登录后的 token
- const tokenBeforeRefresh = await talentMiniPage.getToken();
- expect(tokenBeforeRefresh).not.toBeNull();
- // 5. 刷新页面
- await talentMiniPage.page.reload();
- // 6. 等待页面加载完成
- await talentMiniPage.page.waitForLoadState('domcontentloaded');
- // 7. 验证 token 仍然存在
- const tokenAfterRefresh = await talentMiniPage.getToken();
- expect(tokenAfterRefresh).toBe(tokenBeforeRefresh);
- });
- test('使用已存储 token 可以继续访问', async ({ talentMiniPage }) => {
- // 1. 导航到登录页面
- await talentMiniPage.goto();
- // 2. 使用测试用户登录
- await talentMiniPage.login(TEST_USER.account, TEST_USER.password);
- // 3. 验证登录成功
- await talentMiniPage.expectLoginSuccess();
- // 4. 获取 token
- const token = await talentMiniPage.getToken();
- expect(token).not.toBeNull();
- // 5. 重新导航到小程序(模拟关闭后重新打开)
- await talentMiniPage.goto();
- // 6. 验证由于 token 存在,用户保持登录状态
- await talentMiniPage.page.waitForURL(
- url => url.pathname.includes('/pages/index/index') || url.hash.includes('/pages/index/index'),
- { timeout: 10000 }
- ).catch(() => {
- // 如果没有自动跳转,检查当前 URL
- const currentUrl = talentMiniPage.page.url();
- expect(currentUrl).toMatch(/pages\/index\/index/);
- });
- });
- });
- test.describe.serial('退出登录测试 (AC5)', () => {
- const TEST_USER = {
- account: '13800128219',
- password: 'admin123',
- username: 'talent_test_e2e',
- };
- test.afterEach(async ({ talentMiniPage }) => {
- // 清理认证状态
- await talentMiniPage.clearAuth();
- });
- test('应该成功退出登录', async ({ talentMiniPage }) => {
- // 1. 导航到登录页面
- await talentMiniPage.goto();
- // 2. 使用测试用户登录
- await talentMiniPage.login(TEST_USER.account, TEST_USER.password);
- // 3. 验证登录成功
- await talentMiniPage.expectLoginSuccess();
- // 4. 退出登录
- await talentMiniPage.gotoMorePage();
- await talentMiniPage.clickLogout();
- // 5. 验证返回到登录页面
- await talentMiniPage.expectToBeOnLoginPage();
- // 6. 验证 URL 返回到登录页面
- const currentUrl = talentMiniPage.page.url();
- expect(currentUrl).toContain('/talent-mini');
- expect(currentUrl).toContain('/pages/login/index');
- });
- test('退出后 token 应该被清除', async ({ talentMiniPage }) => {
- // 1. 导航到登录页面
- await talentMiniPage.goto();
- // 2. 使用测试用户登录
- await talentMiniPage.login(TEST_USER.account, TEST_USER.password);
- // 3. 验证登录成功
- await talentMiniPage.expectLoginSuccess();
- // 4. 验证 token 存在
- const tokenBeforeLogout = await talentMiniPage.getToken();
- expect(tokenBeforeLogout).not.toBeNull();
- // 5. 退出登录
- await talentMiniPage.gotoMorePage();
- await talentMiniPage.clickLogout();
- // 6. 等待退出完成
- await talentMiniPage.page.waitForTimeout(1000);
- // 7. 验证 token 已被清除
- const tokenAfterLogout = await talentMiniPage.getToken();
- expect(tokenAfterLogout).toBeNull();
- });
- test('退出后无法访问需要认证的页面', async ({ talentMiniPage }) => {
- // 1. 导航到登录页面
- await talentMiniPage.goto();
- // 2. 使用测试用户登录
- await talentMiniPage.login(TEST_USER.account, TEST_USER.password);
- // 3. 验证登录成功
- await talentMiniPage.expectLoginSuccess();
- // 4. 退出登录
- await talentMiniPage.gotoMorePage();
- await talentMiniPage.clickLogout();
- await talentMiniPage.expectToBeOnLoginPage();
- // 5. 尝试直接访问需要认证的页面(主页)
- await talentMiniPage.page.goto('/talent-mini/#/talent-mini/pages/index/index');
- // 6. 验证被重定向回登录页面
- await talentMiniPage.page.waitForLoadState('domcontentloaded');
- const currentUrl = talentMiniPage.page.url();
- expect(currentUrl).toContain('/pages/login/index');
- // 7. 验证登录页面可见
- // 验证仍然在登录页面(未跳转)
- });
- });
- test.describe.serial('测试隔离和清理 (AC6)', () => {
- test('每个测试使用独立的测试用户', async ({ talentMiniPage, browser }) => {
- // 1. 创建唯一的测试用户
- const uniqueId = Date.now();
- const testUsername = `talent_isolated_${uniqueId}`;
- const testPassword = 'Test123!@#';
- await createTestUser(browser, {
- username: testUsername,
- password: testPassword,
- nickname: `隔离测试用户_${uniqueId}`,
- disabilityPersonId: 1,
- });
- // 2. 使用该用户登录小程序
- await talentMiniPage.goto();
- await talentMiniPage.login(testUsername, testPassword);
- // 3. 验证登录成功
- await talentMiniPage.expectLoginSuccess();
- // 4. 验证 token 存储
- const token = await talentMiniPage.getToken();
- expect(token).not.toBeNull();
- });
- test('测试后清理认证状态', async ({ talentMiniPage }) => {
- // 1. 导航到登录页面
- await talentMiniPage.goto();
- // 2. 使用测试用户登录
- await talentMiniPage.login('13800128219', 'admin123');
- // 3. 验证登录成功
- await talentMiniPage.expectLoginSuccess();
- // 4. 验证 token 存在
- const tokenBeforeClear = await talentMiniPage.getToken();
- expect(tokenBeforeClear).not.toBeNull();
- // 5. 清理认证状态
- await talentMiniPage.clearAuth();
- // 6. 验证 token 已被清除
- const tokenAfterClear = await talentMiniPage.getToken();
- expect(tokenAfterClear).toBeNull();
- });
- });
- });
|