import { TIMEOUTS } from '../../utils/timeouts'; import { test, expect } from '../../utils/test-setup'; import { UserType } from '@d8d/shared-types'; /** * 企业用户创建 E2E 测试 * * 测试后台创建企业用户功能的正确性 * 验证创建基本企业用户、完整信息企业用户、公司关联验证、表单验证等功能 * * @see {@link ../pages/admin/user-management.page.ts} UserManagementPage */ test.describe('企业用户创建功能', () => { // 测试创建的公司名称,用于清理 let testCompanyName: string; test.beforeEach(async ({ adminLoginPage, companyManagementPage, userManagementPage }) => { // 以管理员身份登录后台 await adminLoginPage.goto(); await adminLoginPage.login('admin', 'admin123'); await adminLoginPage.expectLoginSuccess(); // 创建测试公司(企业用户必须关联公司) const timestamp = Date.now(); testCompanyName = `测试公司_${timestamp}`; await companyManagementPage.goto(); await companyManagementPage.createCompany({ companyName: testCompanyName, }); // 验证公司创建成功 const companyExists = await companyManagementPage.companyExists(testCompanyName); expect(companyExists).toBe(true); // 导航到用户管理页面 await userManagementPage.goto(); }); test.afterEach(async ({ companyManagementPage }) => { // 清理测试数据(公司) await companyManagementPage.goto(); await companyManagementPage.deleteCompany(testCompanyName); }); test.describe('基本创建流程测试', () => { test('应该成功创建基本企业用户', async ({ userManagementPage }) => { // 生成唯一用户名 const timestamp = Date.now(); const username = `test_employer_${timestamp}`; // 创建企业用户(填写必填字段 + 选择公司) const result = await userManagementPage.createUser({ username, password: 'password123', nickname: '测试企业用户', userType: UserType.EMPLOYER, companyId: 1, // 使用 beforeEach 中创建的公司 }, testCompanyName); // 验证 API 响应成功 expect(result.responses).toBeDefined(); expect(result.responses?.length).toBeGreaterThan(0); const createResponse = result.responses?.find(r => r.url.includes('/api/v1/users')); expect(createResponse?.ok).toBe(true); // 验证创建成功提示(可选,Toast 检测可能不稳定) // 如果能检测到 Toast,验证消息内容 if (result.hasSuccess && result.successMessage) { expect(result.successMessage).toContain('成功'); } // 最终验证:用户出现在列表中(这才是真正的成功证明) // 验证用户出现在列表中 await expect(async () => { const exists = await userManagementPage.userExists(username); expect(exists).toBe(true); }).toPass({ timeout: TIMEOUTS.DIALOG }); // 验证用户类型徽章显示为企业用户 // 使用 nth(1) 定位到用户类型列(第6列),避免与昵称列中的"企业用户"文本冲突 const userRow = userManagementPage.getUserByUsername(username); const userTypeBadge = userRow.locator('td').nth(5).getByText('企业用户'); await expect(userTypeBadge).toBeVisible(); // 清理测试数据(用户) const deleteResult = await userManagementPage.deleteUser(username); expect(deleteResult).toBe(true); // 验证用户已被删除 const existsAfterDelete = await userManagementPage.userExists(username); expect(existsAfterDelete).toBe(false); }); test('创建后企业用户应该出现在列表中', async ({ userManagementPage }) => { const timestamp = Date.now(); const username = `employer_list_${timestamp}`; // 创建企业用户 await userManagementPage.createUser({ username, password: 'password123', nickname: '列表测试用户', userType: UserType.EMPLOYER, }, testCompanyName); // 验证用户出现在列表中 const exists = await userManagementPage.userExists(username); expect(exists).toBe(true); // 清理 await userManagementPage.deleteUser(username); }); }); test.describe('完整表单字段测试', () => { test('应该成功创建完整信息企业用户', async ({ userManagementPage }) => { const timestamp = Date.now(); const username = `employer_full_${timestamp}`; // 创建企业用户(填写所有字段) const result = await userManagementPage.createUser({ username, password: 'password123', nickname: '完整信息用户', email: `full_${timestamp}@example.com`, phone: '13800138000', name: '张三', userType: UserType.EMPLOYER, companyId: 1, }, testCompanyName); // 验证 API 响应成功 const createResponse = result.responses?.find(r => r.url.includes('/api/v1/users')); expect(createResponse?.ok).toBe(true); // 验证用户出现在列表中 await expect(async () => { const exists = await userManagementPage.userExists(username); expect(exists).toBe(true); }).toPass({ timeout: TIMEOUTS.DIALOG }); // 清理 await userManagementPage.deleteUser(username); }); test('应该保存所有填写的字段数据', async ({ userManagementPage }) => { const timestamp = Date.now(); const username = `employer_fields_${timestamp}`; // 创建企业用户(填写所有字段) const result = await userManagementPage.createUser({ username, password: 'password123', nickname: `字段测试_${timestamp}`, email: `fields_${timestamp}@test.com`, phone: '13900139000', name: '李四', userType: UserType.EMPLOYER, companyId: 1, }, testCompanyName); // 验证创建成功(优先检查 API 响应) const createResponse = result.responses?.find(r => r.url.includes('/api/v1/users')); expect(createResponse?.ok).toBe(true); // 验证创建成功提示(可选,Toast 检测可能不稳定) if (result.hasSuccess && result.successMessage) { expect(result.successMessage).toContain('成功'); } // 验证用户出现在列表中 const exists = await userManagementPage.userExists(username); expect(exists).toBe(true); // 清理 await userManagementPage.deleteUser(username); }); }); test.describe('公司关联验证测试', () => { // TODO: 后端当前未强制要求企业用户必须关联公司 // 当前行为:后端允许创建没有 companyId 的 EMPLOYER 用户 // 期望行为:后端应返回 400 错误,要求企业用户必须关联公司 test.skip('企业用户必须关联公司 [后端验证未实现]', async ({ userManagementPage }) => { const timestamp = Date.now(); const username = `employer_no_company_${timestamp}`; // 打开创建对话框 await userManagementPage.openCreateDialog(); // 填写用户名和密码 await userManagementPage.usernameInput.fill(username); await userManagementPage.passwordInput.fill('password123'); // 选择用户类型为企业用户(但不选择公司) await userManagementPage.page.waitForSelector('[data-testid="用户类型-trigger"]', { state: 'visible', timeout: TIMEOUTS.DIALOG }); await userManagementPage.userTypeSelector.click(); await userManagementPage.page.waitForSelector('[role="option"]', { state: 'visible', timeout: TIMEOUTS.DIALOG }); await userManagementPage.page.getByRole('option', { name: '企业用户' }).click(); // 尝试提交表单 const submitResult = await userManagementPage.submitForm(); // 验证 API 响应包含错误(后端验证) const createResponse = submitResult.responses?.find(r => r.url.includes('/api/v1/users')); // 后端应该返回 400 错误或 Toast 错误消息 expect(createResponse?.ok || submitResult.hasError).toBe(false); // 验证用户没有被创建(列表中不存在) const exists = await userManagementPage.userExists(username); expect(exists).toBe(false); }); test.skip('不选择公司时应该显示错误提示 [后端验证未实现]', async ({ userManagementPage }) => { const timestamp = Date.now(); const username = `employer_error_${timestamp}`; // 打开创建对话框 await userManagementPage.openCreateDialog(); // 填写必填字段 await userManagementPage.usernameInput.fill(username); await userManagementPage.passwordInput.fill('password123'); await userManagementPage.nicknameInput.fill('错误测试用户'); // 选择用户类型为企业用户(但不选择公司) await userManagementPage.page.waitForSelector('[data-testid="用户类型-trigger"]', { state: 'visible', timeout: TIMEOUTS.DIALOG }); await userManagementPage.userTypeSelector.click(); await userManagementPage.page.waitForSelector('[role="option"]', { state: 'visible', timeout: TIMEOUTS.DIALOG }); await userManagementPage.page.getByRole('option', { name: '企业用户' }).click(); // 尝试提交表单 const submitResult = await userManagementPage.submitForm(); // 验证后端返回错误(公司必填验证) const createResponse = submitResult.responses?.find(r => r.url.includes('/api/v1/users')); expect(createResponse?.ok || submitResult.hasError).toBe(false); // 验证用户没有被创建 const exists = await userManagementPage.userExists(username); expect(exists).toBe(false); }); }); test.describe('表单验证测试', () => { test('用户名为空时应显示验证错误', async ({ userManagementPage }) => { // 打开创建对话框 await userManagementPage.openCreateDialog(); // 不填写用户名,直接填写密码 await userManagementPage.passwordInput.fill('password123'); // 尝试提交表单 await userManagementPage.submitForm(); // 验证对话框仍然打开(表单验证阻止了提交) const dialog = userManagementPage.page.locator('[role="dialog"]'); await expect(dialog).toBeVisible(); // 关闭对话框 await userManagementPage.cancelDialog(); }); test('密码为空时应显示验证错误', async ({ userManagementPage }) => { // 打开创建对话框 await userManagementPage.openCreateDialog(); // 填写用户名,但不填写密码 const timestamp = Date.now(); await userManagementPage.usernameInput.fill(`user_no_pwd_${timestamp}`); // 尝试提交表单 await userManagementPage.submitForm(); // 验证对话框仍然打开(表单验证阻止了提交) const dialog = userManagementPage.page.locator('[role="dialog"]'); await expect(dialog).toBeVisible(); // 关闭对话框 await userManagementPage.cancelDialog(); }); // 注意:昵称是可选字段(没有红色星号),所以表单会允许不填昵称提交 // 此测试已移除,因为它测试的是不存在的验证 test('邮箱格式不正确时应显示验证错误', async ({ userManagementPage }) => { const timestamp = Date.now(); const username = `user_bad_email_${timestamp}`; // 打开创建对话框 await userManagementPage.openCreateDialog(); // 填写用户名、密码和无效格式的邮箱 await userManagementPage.usernameInput.fill(username); await userManagementPage.passwordInput.fill('password123'); await userManagementPage.nicknameInput.fill('邮箱测试用户'); await userManagementPage.emailInput.fill('invalid-email-format'); // 尝试提交表单 await userManagementPage.submitForm(); // 验证对话框仍然打开(表单验证阻止了提交) const dialog = userManagementPage.page.locator('[role="dialog"]'); await expect(dialog).toBeVisible(); // 关闭对话框 await userManagementPage.cancelDialog(); }); }); test.describe('数据唯一性测试', () => { test('不同测试应该使用不同的用户名', async ({ userManagementPage }) => { // 生成两个不同的用户名 const timestamp = Date.now(); const username1 = `unique_employer_A_${timestamp}`; const username2 = `unique_employer_B_${timestamp}`; // 创建第一个企业用户 await userManagementPage.createUser({ username: username1, password: 'password123', nickname: '唯一性测试A', userType: UserType.EMPLOYER, }, testCompanyName); expect(await userManagementPage.userExists(username1)).toBe(true); // 创建第二个企业用户 await userManagementPage.createUser({ username: username2, password: 'password123', nickname: '唯一性测试B', userType: UserType.EMPLOYER, }, testCompanyName); expect(await userManagementPage.userExists(username2)).toBe(true); // 清理两个用户 await userManagementPage.deleteUser(username1); await userManagementPage.deleteUser(username2); // 验证清理成功 expect(await userManagementPage.userExists(username1)).toBe(false); expect(await userManagementPage.userExists(username2)).toBe(false); }); test('使用时间戳确保用户名唯一', async ({ userManagementPage }) => { // 使用时间戳生成唯一用户名 const timestamp = Date.now(); const username = `timestamp_user_${timestamp}`; // 创建企业用户 await userManagementPage.createUser({ username, password: 'password123', nickname: '时间戳测试用户', userType: UserType.EMPLOYER, }, testCompanyName); // 验证用户创建成功 expect(await userManagementPage.userExists(username)).toBe(true); // 清理 await userManagementPage.deleteUser(username); }); }); test.describe('测试后清理验证', () => { test('应该能成功删除测试创建的企业用户', async ({ userManagementPage }) => { const timestamp = Date.now(); const username = `cleanup_employer_${timestamp}`; // 创建企业用户 const result = await userManagementPage.createUser({ username, password: 'password123', nickname: '清理测试用户', email: `cleanup_${timestamp}@test.com`, phone: '13800003333', userType: UserType.EMPLOYER, }, testCompanyName); // 验证用户存在 const createResponse = result.responses?.find(r => r.url.includes('/api/v1/users')); expect(createResponse?.ok).toBe(true); expect(await userManagementPage.userExists(username)).toBe(true); // 删除用户 const deleteResult = await userManagementPage.deleteUser(username); expect(deleteResult).toBe(true); // 验证用户已被删除 await expect(async () => { const exists = await userManagementPage.userExists(username); expect(exists).toBe(false); }).toPass({ timeout: TIMEOUTS.DIALOG }); }); }); test.describe('对话框元素验证', () => { test('应该显示创建用户对话框的所有字段', async ({ userManagementPage }) => { // 打开创建对话框 await userManagementPage.openCreateDialog(); // 验证对话框存在 const dialog = userManagementPage.page.locator('[role="dialog"]'); await expect(dialog).toBeVisible(); // 验证用户类型选择器存在 await expect(userManagementPage.userTypeSelector).toBeVisible(); // 验证必填字段输入框存在 await expect(userManagementPage.usernameInput).toBeVisible(); await expect(userManagementPage.passwordInput).toBeVisible(); await expect(userManagementPage.nicknameInput).toBeVisible(); // 验证可选字段输入框存在 await expect(userManagementPage.emailInput).toBeVisible(); await expect(userManagementPage.phoneInput).toBeVisible(); await expect(userManagementPage.nameInput).toBeVisible(); // 企业选择器是条件渲染的,只有选择了 EMPLOYER 类型才会显示 // 先选择企业用户类型 await userManagementPage.userTypeSelector.click(); await userManagementPage.page.waitForSelector('[role="option"]', { state: 'visible', timeout: TIMEOUTS.DIALOG }); await userManagementPage.page.getByRole('option', { name: '企业用户' }).click(); // 现在验证企业选择器存在 await expect(userManagementPage.companySelector).toBeVisible(); // 验证按钮存在 await expect(userManagementPage.createSubmitButton).toBeVisible(); await expect(userManagementPage.cancelButton).toBeVisible(); // 关闭对话框 await userManagementPage.cancelDialog(); }); }); test.describe('取消和关闭操作测试', () => { test('应该能取消创建企业用户操作', async ({ userManagementPage }) => { const timestamp = Date.now(); const username = `cancel_employer_${timestamp}`; // 打开创建对话框并填写表单 await userManagementPage.openCreateDialog(); await userManagementPage.usernameInput.fill(username); await userManagementPage.passwordInput.fill('password123'); // 点击取消按钮 await userManagementPage.cancelDialog(); // 验证对话框关闭 const dialog = userManagementPage.page.locator('[role="dialog"]'); await expect(dialog).not.toBeVisible(); // 验证用户没有被创建 const exists = await userManagementPage.userExists(username); expect(exists).toBe(false); }); test('应该能通过关闭对话框取消创建', async ({ userManagementPage }) => { const timestamp = Date.now(); const username = `close_employer_${timestamp}`; // 打开创建对话框并填写表单 await userManagementPage.openCreateDialog(); await userManagementPage.usernameInput.fill(username); await userManagementPage.passwordInput.fill('password123'); // 按 ESC 键关闭对话框 await userManagementPage.page.keyboard.press('Escape'); // 等待对话框关闭 await userManagementPage.waitForDialogClosed(); // 验证用户没有被创建 const exists = await userManagementPage.userExists(username); expect(exists).toBe(false); }); }); });