| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418 |
- import { test, expect } from '../../utils/test-setup';
- import { AdminLoginPage } from '../../pages/admin/login.page';
- import { UserManagementPage } from '../../pages/admin/user-management.page';
- import { UserType } from '@d8d/shared-types';
- /**
- * 企业小程序登录 E2E 测试
- *
- * 测试企业用户通过小程序登录的功能,验证:
- * - 登录失败场景
- * - 表单验证
- * - 登录成功场景(使用独立 context 创建测试用户)
- * - Token 持久性
- * - 退出登录
- *
- * @see {@link ../pages/mini/enterprise-mini.page.ts} EnterpriseMiniPage
- */
- /**
- * 创建测试用户的辅助函数
- *
- * 在独立的 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;
- phone?: string;
- email?: string;
- userType?: UserType;
- companyName?: string;
- }): Promise<{ username: string; password: string }> {
- // 创建独立的 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();
- // 创建测试用户(使用 EMPLOYER 类型,企业用户)
- const result = await userManagementPage.createUser({
- username: userData.username,
- password: userData.password,
- nickname: userData.nickname || '测试企业用户',
- phone: userData.phone,
- email: userData.email,
- userType: userData.userType || UserType.EMPLOYER,
- }, userData.companyName || '测试公司_E2E');
- // 验证创建成功
- expect(result.success).toBe(true);
- return { username: userData.username, password: userData.password };
- } finally {
- // 清理:关闭独立 context
- await adminContext.close();
- }
- }
- test.describe('企业小程序登录功能', () => {
- test.describe('表单验证测试 (AC3)', () => {
- test('手机号为空时应该显示错误提示', async ({ enterpriseMiniPage }) => {
- // 导航到登录页面
- await enterpriseMiniPage.goto();
- // 不填写任何信息,直接点击登录按钮
- await enterpriseMiniPage.clickLoginButton();
- // 验证仍然在登录页面(未跳转)
- const currentUrl = enterpriseMiniPage.page.url();
- expect(currentUrl).toContain('/mini');
- // 验证登录页面容器仍然可见
- await expect(enterpriseMiniPage.loginPage).toBeVisible();
- });
- test('密码为空时应该显示错误提示', async ({ enterpriseMiniPage }) => {
- // 导航到登录页面
- await enterpriseMiniPage.goto();
- // 只填写手机号,不填写密码
- await enterpriseMiniPage.fillPhone('13800138000');
- // 尝试点击登录按钮
- await enterpriseMiniPage.clickLoginButton();
- // 验证仍然在登录页面(未跳转)
- const currentUrl = enterpriseMiniPage.page.url();
- expect(currentUrl).toContain('/mini');
- // 验证登录页面容器仍然可见
- await expect(enterpriseMiniPage.loginPage).toBeVisible();
- });
- test('表单验证错误提示应该清晰可见', async ({ enterpriseMiniPage }) => {
- // 导航到登录页面
- await enterpriseMiniPage.goto();
- // 不填写任何信息,直接点击登录
- await enterpriseMiniPage.clickLoginButton();
- // 验证仍在登录页面
- expect(enterpriseMiniPage.page.url()).toContain('/mini');
- // 验证登录页面容器仍然可见
- await expect(enterpriseMiniPage.loginPage).toBeVisible();
- });
- });
- test.describe('登录失败测试 (AC2)', () => {
- test('使用不存在的用户名登录失败', async ({ enterpriseMiniPage }) => {
- // 导航到登录页面
- await enterpriseMiniPage.goto();
- // 使用不存在的用户名尝试登录(使用有效的手机号格式)
- const fakeUsername = `199${Date.now().toString().slice(-8)}`; // 11位数字,符合手机号格式
- await enterpriseMiniPage.login(fakeUsername, 'password123');
- // 验证显示错误提示
- await enterpriseMiniPage.expectLoginError('用户名或密码错误');
- // 验证未存储 token
- const token = await enterpriseMiniPage.getToken();
- expect(token).toBeNull();
- });
- test('使用错误的密码登录失败', async ({ enterpriseMiniPage }) => {
- // 导航到登录页面
- await enterpriseMiniPage.goto();
- // 使用不存在的用户尝试登录(使用有效的手机号格式)
- await enterpriseMiniPage.login('19912345678', 'wrongpassword');
- // 验证显示错误提示
- await enterpriseMiniPage.expectLoginError('用户名或密码错误');
- // 验证未存储 token
- const token = await enterpriseMiniPage.getToken();
- expect(token).toBeNull();
- });
- test('错误提示内容应该正确', async ({ enterpriseMiniPage }) => {
- // 导航到登录页面
- await enterpriseMiniPage.goto();
- // 使用错误的凭据尝试登录(使用有效的手机号格式)
- await enterpriseMiniPage.login('19987654321', 'wrongpassword');
- // 验证错误提示包含"用户名或密码错误"或类似内容
- await enterpriseMiniPage.expectLoginError();
- });
- });
- test.describe.serial('基本登录成功测试 (AC1)', () => {
- test('应该成功登录企业小程序', async ({ enterpriseMiniPage, browser }) => {
- // 1. 创建测试用户(使用独立 context)
- const testUsername = `mini_test_${Date.now()}`;
- const testPassword = 'Test123!@#';
- const testPhone = `138${Date.now().toString().slice(-8)}`;
- await createTestUser(browser, {
- username: testUsername,
- password: testPassword,
- phone: testPhone,
- nickname: '小程序测试用户',
- userType: UserType.EMPLOYER,
- });
- // 2. 使用该用户登录小程序
- await enterpriseMiniPage.goto();
- await enterpriseMiniPage.login(testPhone, testPassword);
- // 3. 验证登录成功(URL 跳转到 dashboard 或显示用户信息)
- await enterpriseMiniPage.expectLoginSuccess();
- });
- test('登录成功后应该显示用户信息', async ({ enterpriseMiniPage, browser }) => {
- // 1. 创建测试用户
- const testUsername = `mini_info_${Date.now()}`;
- const testPassword = 'Test123!@#';
- const testPhone = `139${Date.now().toString().slice(-8)}`;
- await createTestUser(browser, {
- username: testUsername,
- password: testPassword,
- phone: testPhone,
- nickname: '小程序信息测试',
- userType: UserType.EMPLOYER,
- });
- // 2. 登录小程序
- await enterpriseMiniPage.goto();
- await enterpriseMiniPage.login(testPhone, testPassword);
- // 3. 验证登录成功
- await enterpriseMiniPage.expectLoginSuccess();
- // 4. 验证用户信息显示(检查 userInfo 元素或 dashboard 可见)
- const currentUrl = enterpriseMiniPage.page.url();
- expect(currentUrl).toMatch(/dashboard|pages/);
- });
- test('登录成功后 token 应该正确存储', async ({ enterpriseMiniPage, browser }) => {
- // 1. 创建测试用户
- const testUsername = `mini_token_${Date.now()}`;
- const testPassword = 'Test123!@#';
- const testPhone = `137${Date.now().toString().slice(-8)}`;
- await createTestUser(browser, {
- username: testUsername,
- password: testPassword,
- phone: testPhone,
- nickname: '小程序 Token 测试',
- userType: UserType.EMPLOYER,
- });
- // 2. 登录小程序
- await enterpriseMiniPage.goto();
- await enterpriseMiniPage.login(testPhone, testPassword);
- // 3. 验证登录成功
- await enterpriseMiniPage.expectLoginSuccess();
- // 4. 验证 token 被正确存储
- const token = await enterpriseMiniPage.getToken();
- expect(token).not.toBeNull();
- expect(token?.length).toBeGreaterThan(0);
- });
- });
- test.describe.serial('Token 持久性测试 (AC4)', () => {
- test('页面刷新后 token 仍然有效', async ({ enterpriseMiniPage, browser }) => {
- // 1. 创建测试用户
- const testUsername = `mini_refresh_${Date.now()}`;
- const testPassword = 'Test123!@#';
- const testPhone = `136${Date.now().toString().slice(-8)}`;
- await createTestUser(browser, {
- username: testUsername,
- password: testPassword,
- phone: testPhone,
- nickname: '小程序刷新测试',
- userType: UserType.EMPLOYER,
- });
- // 2. 登录小程序
- await enterpriseMiniPage.goto();
- await enterpriseMiniPage.login(testPhone, testPassword);
- await enterpriseMiniPage.expectLoginSuccess();
- // 3. 获取登录后的 token
- const tokenBeforeRefresh = await enterpriseMiniPage.getToken();
- expect(tokenBeforeRefresh).not.toBeNull();
- // 4. 刷新页面
- await enterpriseMiniPage.page.reload();
- // 5. 等待页面加载完成
- await enterpriseMiniPage.page.waitForLoadState('domcontentloaded');
- // 6. 验证 token 仍然存在
- const tokenAfterRefresh = await enterpriseMiniPage.getToken();
- expect(tokenAfterRefresh).toBe(tokenBeforeRefresh);
- });
- test('使用已存储 token 可以继续访问', async ({ enterpriseMiniPage, browser }) => {
- // 1. 创建测试用户
- const testUsername = `mini_persist_${Date.now()}`;
- const testPassword = 'Test123!@#';
- const testPhone = `135${Date.now().toString().slice(-8)}`;
- await createTestUser(browser, {
- username: testUsername,
- password: testPassword,
- phone: testPhone,
- nickname: '小程序持久化测试',
- userType: UserType.EMPLOYER,
- });
- // 2. 登录小程序
- await enterpriseMiniPage.goto();
- await enterpriseMiniPage.login(testPhone, testPassword);
- await enterpriseMiniPage.expectLoginSuccess();
- // 3. 获取 token
- const token = await enterpriseMiniPage.getToken();
- expect(token).not.toBeNull();
- // 4. 重新导航到登录页面(模拟关闭后重新打开)
- await enterpriseMiniPage.goto();
- // 5. 验证由于 token 存在,页面自动跳转到 dashboard
- await enterpriseMiniPage.page.waitForURL(
- url => url.pathname.includes('/dashboard') || url.pathname.includes('/pages'),
- { timeout: 10000 }
- ).catch(() => {
- // 如果没有自动跳转,检查当前 URL
- const currentUrl = enterpriseMiniPage.page.url();
- expect(currentUrl).toMatch(/dashboard|pages/);
- });
- });
- });
- test.describe.serial('退出登录测试 (AC5)', () => {
- test('应该成功退出登录', async ({ enterpriseMiniPage, browser }) => {
- // 1. 创建测试用户
- const testUsername = `mini_logout_${Date.now()}`;
- const testPassword = 'Test123!@#';
- const testPhone = `134${Date.now().toString().slice(-8)}`;
- await createTestUser(browser, {
- username: testUsername,
- password: testPassword,
- phone: testPhone,
- nickname: '小程序退出测试',
- userType: UserType.EMPLOYER,
- });
- // 2. 登录小程序
- await enterpriseMiniPage.goto();
- await enterpriseMiniPage.login(testPhone, testPassword);
- await enterpriseMiniPage.expectLoginSuccess();
- // 3. 退出登录
- await enterpriseMiniPage.logout();
- // 4. 验证返回到登录页面
- await enterpriseMiniPage.expectLoggedOut();
- // 5. 验证 URL 返回到登录页面
- const currentUrl = enterpriseMiniPage.page.url();
- expect(currentUrl).toContain('/mini');
- });
- test('退出后 token 应该被清除', async ({ enterpriseMiniPage, browser }) => {
- // 1. 创建测试用户
- const testUsername = `mini_token_clear_${Date.now()}`;
- const testPassword = 'Test123!@#';
- const testPhone = `133${Date.now().toString().slice(-8)}`;
- await createTestUser(browser, {
- username: testUsername,
- password: testPassword,
- phone: testPhone,
- nickname: '小程序 Token 清除测试',
- userType: UserType.EMPLOYER,
- });
- // 2. 登录小程序
- await enterpriseMiniPage.goto();
- await enterpriseMiniPage.login(testPhone, testPassword);
- await enterpriseMiniPage.expectLoginSuccess();
- // 3. 验证 token 存在
- const tokenBeforeLogout = await enterpriseMiniPage.getToken();
- expect(tokenBeforeLogout).not.toBeNull();
- // 4. 退出登录
- await enterpriseMiniPage.logout();
- await enterpriseMiniPage.expectLoggedOut();
- // 5. 验证 token 已被清除
- const tokenAfterLogout = await enterpriseMiniPage.getToken();
- expect(tokenAfterLogout).toBeNull();
- });
- test('退出后无法访问需要认证的页面', async ({ enterpriseMiniPage, browser }) => {
- // 1. 创建测试用户
- const testUsername = `mini_auth_${Date.now()}`;
- const testPassword = 'Test123!@#';
- const testPhone = `132${Date.now().toString().slice(-8)}`;
- await createTestUser(browser, {
- username: testUsername,
- password: testPassword,
- phone: testPhone,
- nickname: '小程序认证测试',
- userType: UserType.EMPLOYER,
- });
- // 2. 登录小程序
- await enterpriseMiniPage.goto();
- await enterpriseMiniPage.login(testPhone, testPassword);
- await enterpriseMiniPage.expectLoginSuccess();
- // 3. 退出登录
- await enterpriseMiniPage.logout();
- await enterpriseMiniPage.expectLoggedOut();
- // 4. 尝试直接访问需要认证的页面(dashboard)
- await enterpriseMiniPage.page.goto('/mini/dashboard');
- // 5. 验证被重定向回登录页面
- await enterpriseMiniPage.page.waitForLoadState('domcontentloaded');
- const currentUrl = enterpriseMiniPage.page.url();
- expect(currentUrl).toContain('/mini');
- // 6. 验证登录页面可见
- await expect(enterpriseMiniPage.loginPage).toBeVisible();
- });
- });
- });
|