user-create-employer.spec.ts 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. import { TIMEOUTS } from '../../utils/timeouts';
  2. import { test, expect } from '../../utils/test-setup';
  3. import { UserType } from '@d8d/shared-types';
  4. /**
  5. * 企业用户创建 E2E 测试
  6. *
  7. * 测试后台创建企业用户功能的正确性
  8. * 验证创建基本企业用户、完整信息企业用户、公司关联验证、表单验证等功能
  9. *
  10. * @see {@link ../pages/admin/user-management.page.ts} UserManagementPage
  11. */
  12. test.describe('企业用户创建功能', () => {
  13. // 测试创建的公司名称,用于清理
  14. let testCompanyName: string;
  15. test.beforeEach(async ({ adminLoginPage, companyManagementPage, userManagementPage }) => {
  16. // 以管理员身份登录后台
  17. await adminLoginPage.goto();
  18. await adminLoginPage.login('admin', 'admin123');
  19. await adminLoginPage.expectLoginSuccess();
  20. // 创建测试公司(企业用户必须关联公司)
  21. const timestamp = Date.now();
  22. testCompanyName = `测试公司_${timestamp}`;
  23. await companyManagementPage.goto();
  24. await companyManagementPage.createCompany({
  25. companyName: testCompanyName,
  26. });
  27. // 验证公司创建成功
  28. const companyExists = await companyManagementPage.companyExists(testCompanyName);
  29. expect(companyExists).toBe(true);
  30. // 导航到用户管理页面
  31. await userManagementPage.goto();
  32. });
  33. test.afterEach(async ({ companyManagementPage }) => {
  34. // 清理测试数据(公司)
  35. await companyManagementPage.goto();
  36. await companyManagementPage.deleteCompany(testCompanyName);
  37. });
  38. test.describe('基本创建流程测试', () => {
  39. test('应该成功创建基本企业用户', async ({ userManagementPage }) => {
  40. // 生成唯一用户名
  41. const timestamp = Date.now();
  42. const username = `test_employer_${timestamp}`;
  43. // 创建企业用户(填写必填字段 + 选择公司)
  44. const result = await userManagementPage.createUser({
  45. username,
  46. password: 'password123',
  47. nickname: '测试企业用户',
  48. userType: UserType.EMPLOYER,
  49. companyId: 1, // 使用 beforeEach 中创建的公司
  50. }, testCompanyName);
  51. // 验证 API 响应成功
  52. expect(result.responses).toBeDefined();
  53. expect(result.responses?.length).toBeGreaterThan(0);
  54. const createResponse = result.responses?.find(r => r.url.includes('/api/v1/users'));
  55. expect(createResponse?.ok).toBe(true);
  56. // 验证创建成功提示(可选,Toast 检测可能不稳定)
  57. // 如果能检测到 Toast,验证消息内容
  58. if (result.hasSuccess && result.successMessage) {
  59. expect(result.successMessage).toContain('成功');
  60. }
  61. // 最终验证:用户出现在列表中(这才是真正的成功证明)
  62. // 验证用户出现在列表中
  63. await expect(async () => {
  64. const exists = await userManagementPage.userExists(username);
  65. expect(exists).toBe(true);
  66. }).toPass({ timeout: TIMEOUTS.DIALOG });
  67. // 验证用户类型徽章显示为企业用户
  68. // 使用 nth(1) 定位到用户类型列(第6列),避免与昵称列中的"企业用户"文本冲突
  69. const userRow = userManagementPage.getUserByUsername(username);
  70. const userTypeBadge = userRow.locator('td').nth(5).getByText('企业用户');
  71. await expect(userTypeBadge).toBeVisible();
  72. // 清理测试数据(用户)
  73. const deleteResult = await userManagementPage.deleteUser(username);
  74. expect(deleteResult).toBe(true);
  75. // 验证用户已被删除
  76. const existsAfterDelete = await userManagementPage.userExists(username);
  77. expect(existsAfterDelete).toBe(false);
  78. });
  79. test('创建后企业用户应该出现在列表中', async ({ userManagementPage }) => {
  80. const timestamp = Date.now();
  81. const username = `employer_list_${timestamp}`;
  82. // 创建企业用户
  83. await userManagementPage.createUser({
  84. username,
  85. password: 'password123',
  86. nickname: '列表测试用户',
  87. userType: UserType.EMPLOYER,
  88. }, testCompanyName);
  89. // 验证用户出现在列表中
  90. const exists = await userManagementPage.userExists(username);
  91. expect(exists).toBe(true);
  92. // 清理
  93. await userManagementPage.deleteUser(username);
  94. });
  95. });
  96. test.describe('完整表单字段测试', () => {
  97. test('应该成功创建完整信息企业用户', async ({ userManagementPage }) => {
  98. const timestamp = Date.now();
  99. const username = `employer_full_${timestamp}`;
  100. // 创建企业用户(填写所有字段)
  101. const result = await userManagementPage.createUser({
  102. username,
  103. password: 'password123',
  104. nickname: '完整信息用户',
  105. email: `full_${timestamp}@example.com`,
  106. phone: '13800138000',
  107. name: '张三',
  108. userType: UserType.EMPLOYER,
  109. companyId: 1,
  110. }, testCompanyName);
  111. // 验证 API 响应成功
  112. const createResponse = result.responses?.find(r => r.url.includes('/api/v1/users'));
  113. expect(createResponse?.ok).toBe(true);
  114. // 验证用户出现在列表中
  115. await expect(async () => {
  116. const exists = await userManagementPage.userExists(username);
  117. expect(exists).toBe(true);
  118. }).toPass({ timeout: TIMEOUTS.DIALOG });
  119. // 清理
  120. await userManagementPage.deleteUser(username);
  121. });
  122. test('应该保存所有填写的字段数据', async ({ userManagementPage }) => {
  123. const timestamp = Date.now();
  124. const username = `employer_fields_${timestamp}`;
  125. // 创建企业用户(填写所有字段)
  126. const result = await userManagementPage.createUser({
  127. username,
  128. password: 'password123',
  129. nickname: `字段测试_${timestamp}`,
  130. email: `fields_${timestamp}@test.com`,
  131. phone: '13900139000',
  132. name: '李四',
  133. userType: UserType.EMPLOYER,
  134. companyId: 1,
  135. }, testCompanyName);
  136. // 验证创建成功(优先检查 API 响应)
  137. const createResponse = result.responses?.find(r => r.url.includes('/api/v1/users'));
  138. expect(createResponse?.ok).toBe(true);
  139. // 验证创建成功提示(可选,Toast 检测可能不稳定)
  140. if (result.hasSuccess && result.successMessage) {
  141. expect(result.successMessage).toContain('成功');
  142. }
  143. // 验证用户出现在列表中
  144. const exists = await userManagementPage.userExists(username);
  145. expect(exists).toBe(true);
  146. // 清理
  147. await userManagementPage.deleteUser(username);
  148. });
  149. });
  150. test.describe('公司关联验证测试', () => {
  151. // TODO: 后端当前未强制要求企业用户必须关联公司
  152. // 当前行为:后端允许创建没有 companyId 的 EMPLOYER 用户
  153. // 期望行为:后端应返回 400 错误,要求企业用户必须关联公司
  154. test.skip('企业用户必须关联公司 [后端验证未实现]', async ({ userManagementPage }) => {
  155. const timestamp = Date.now();
  156. const username = `employer_no_company_${timestamp}`;
  157. // 打开创建对话框
  158. await userManagementPage.openCreateDialog();
  159. // 填写用户名和密码
  160. await userManagementPage.usernameInput.fill(username);
  161. await userManagementPage.passwordInput.fill('password123');
  162. // 选择用户类型为企业用户(但不选择公司)
  163. await userManagementPage.page.waitForSelector('[data-testid="用户类型-trigger"]', { state: 'visible', timeout: TIMEOUTS.DIALOG });
  164. await userManagementPage.userTypeSelector.click();
  165. await userManagementPage.page.waitForSelector('[role="option"]', { state: 'visible', timeout: TIMEOUTS.DIALOG });
  166. await userManagementPage.page.getByRole('option', { name: '企业用户' }).click();
  167. // 尝试提交表单
  168. const submitResult = await userManagementPage.submitForm();
  169. // 验证 API 响应包含错误(后端验证)
  170. const createResponse = submitResult.responses?.find(r => r.url.includes('/api/v1/users'));
  171. // 后端应该返回 400 错误或 Toast 错误消息
  172. expect(createResponse?.ok || submitResult.hasError).toBe(false);
  173. // 验证用户没有被创建(列表中不存在)
  174. const exists = await userManagementPage.userExists(username);
  175. expect(exists).toBe(false);
  176. });
  177. test.skip('不选择公司时应该显示错误提示 [后端验证未实现]', async ({ userManagementPage }) => {
  178. const timestamp = Date.now();
  179. const username = `employer_error_${timestamp}`;
  180. // 打开创建对话框
  181. await userManagementPage.openCreateDialog();
  182. // 填写必填字段
  183. await userManagementPage.usernameInput.fill(username);
  184. await userManagementPage.passwordInput.fill('password123');
  185. await userManagementPage.nicknameInput.fill('错误测试用户');
  186. // 选择用户类型为企业用户(但不选择公司)
  187. await userManagementPage.page.waitForSelector('[data-testid="用户类型-trigger"]', { state: 'visible', timeout: TIMEOUTS.DIALOG });
  188. await userManagementPage.userTypeSelector.click();
  189. await userManagementPage.page.waitForSelector('[role="option"]', { state: 'visible', timeout: TIMEOUTS.DIALOG });
  190. await userManagementPage.page.getByRole('option', { name: '企业用户' }).click();
  191. // 尝试提交表单
  192. const submitResult = await userManagementPage.submitForm();
  193. // 验证后端返回错误(公司必填验证)
  194. const createResponse = submitResult.responses?.find(r => r.url.includes('/api/v1/users'));
  195. expect(createResponse?.ok || submitResult.hasError).toBe(false);
  196. // 验证用户没有被创建
  197. const exists = await userManagementPage.userExists(username);
  198. expect(exists).toBe(false);
  199. });
  200. });
  201. test.describe('表单验证测试', () => {
  202. test('用户名为空时应显示验证错误', async ({ userManagementPage }) => {
  203. // 打开创建对话框
  204. await userManagementPage.openCreateDialog();
  205. // 不填写用户名,直接填写密码
  206. await userManagementPage.passwordInput.fill('password123');
  207. // 尝试提交表单
  208. await userManagementPage.submitForm();
  209. // 验证对话框仍然打开(表单验证阻止了提交)
  210. const dialog = userManagementPage.page.locator('[role="dialog"]');
  211. await expect(dialog).toBeVisible();
  212. // 关闭对话框
  213. await userManagementPage.cancelDialog();
  214. });
  215. test('密码为空时应显示验证错误', async ({ userManagementPage }) => {
  216. // 打开创建对话框
  217. await userManagementPage.openCreateDialog();
  218. // 填写用户名,但不填写密码
  219. const timestamp = Date.now();
  220. await userManagementPage.usernameInput.fill(`user_no_pwd_${timestamp}`);
  221. // 尝试提交表单
  222. await userManagementPage.submitForm();
  223. // 验证对话框仍然打开(表单验证阻止了提交)
  224. const dialog = userManagementPage.page.locator('[role="dialog"]');
  225. await expect(dialog).toBeVisible();
  226. // 关闭对话框
  227. await userManagementPage.cancelDialog();
  228. });
  229. // 注意:昵称是可选字段(没有红色星号),所以表单会允许不填昵称提交
  230. // 此测试已移除,因为它测试的是不存在的验证
  231. test('邮箱格式不正确时应显示验证错误', async ({ userManagementPage }) => {
  232. const timestamp = Date.now();
  233. const username = `user_bad_email_${timestamp}`;
  234. // 打开创建对话框
  235. await userManagementPage.openCreateDialog();
  236. // 填写用户名、密码和无效格式的邮箱
  237. await userManagementPage.usernameInput.fill(username);
  238. await userManagementPage.passwordInput.fill('password123');
  239. await userManagementPage.nicknameInput.fill('邮箱测试用户');
  240. await userManagementPage.emailInput.fill('invalid-email-format');
  241. // 尝试提交表单
  242. await userManagementPage.submitForm();
  243. // 验证对话框仍然打开(表单验证阻止了提交)
  244. const dialog = userManagementPage.page.locator('[role="dialog"]');
  245. await expect(dialog).toBeVisible();
  246. // 关闭对话框
  247. await userManagementPage.cancelDialog();
  248. });
  249. });
  250. test.describe('数据唯一性测试', () => {
  251. test('不同测试应该使用不同的用户名', async ({ userManagementPage }) => {
  252. // 生成两个不同的用户名
  253. const timestamp = Date.now();
  254. const username1 = `unique_employer_A_${timestamp}`;
  255. const username2 = `unique_employer_B_${timestamp}`;
  256. // 创建第一个企业用户
  257. await userManagementPage.createUser({
  258. username: username1,
  259. password: 'password123',
  260. nickname: '唯一性测试A',
  261. userType: UserType.EMPLOYER,
  262. }, testCompanyName);
  263. expect(await userManagementPage.userExists(username1)).toBe(true);
  264. // 创建第二个企业用户
  265. await userManagementPage.createUser({
  266. username: username2,
  267. password: 'password123',
  268. nickname: '唯一性测试B',
  269. userType: UserType.EMPLOYER,
  270. }, testCompanyName);
  271. expect(await userManagementPage.userExists(username2)).toBe(true);
  272. // 清理两个用户
  273. await userManagementPage.deleteUser(username1);
  274. await userManagementPage.deleteUser(username2);
  275. // 验证清理成功
  276. expect(await userManagementPage.userExists(username1)).toBe(false);
  277. expect(await userManagementPage.userExists(username2)).toBe(false);
  278. });
  279. test('使用时间戳确保用户名唯一', async ({ userManagementPage }) => {
  280. // 使用时间戳生成唯一用户名
  281. const timestamp = Date.now();
  282. const username = `timestamp_user_${timestamp}`;
  283. // 创建企业用户
  284. await userManagementPage.createUser({
  285. username,
  286. password: 'password123',
  287. nickname: '时间戳测试用户',
  288. userType: UserType.EMPLOYER,
  289. }, testCompanyName);
  290. // 验证用户创建成功
  291. expect(await userManagementPage.userExists(username)).toBe(true);
  292. // 清理
  293. await userManagementPage.deleteUser(username);
  294. });
  295. });
  296. test.describe('测试后清理验证', () => {
  297. test('应该能成功删除测试创建的企业用户', async ({ userManagementPage }) => {
  298. const timestamp = Date.now();
  299. const username = `cleanup_employer_${timestamp}`;
  300. // 创建企业用户
  301. const result = await userManagementPage.createUser({
  302. username,
  303. password: 'password123',
  304. nickname: '清理测试用户',
  305. email: `cleanup_${timestamp}@test.com`,
  306. phone: '13800003333',
  307. userType: UserType.EMPLOYER,
  308. }, testCompanyName);
  309. // 验证用户存在
  310. const createResponse = result.responses?.find(r => r.url.includes('/api/v1/users'));
  311. expect(createResponse?.ok).toBe(true);
  312. expect(await userManagementPage.userExists(username)).toBe(true);
  313. // 删除用户
  314. const deleteResult = await userManagementPage.deleteUser(username);
  315. expect(deleteResult).toBe(true);
  316. // 验证用户已被删除
  317. await expect(async () => {
  318. const exists = await userManagementPage.userExists(username);
  319. expect(exists).toBe(false);
  320. }).toPass({ timeout: TIMEOUTS.DIALOG });
  321. });
  322. });
  323. test.describe('对话框元素验证', () => {
  324. test('应该显示创建用户对话框的所有字段', async ({ userManagementPage }) => {
  325. // 打开创建对话框
  326. await userManagementPage.openCreateDialog();
  327. // 验证对话框存在
  328. const dialog = userManagementPage.page.locator('[role="dialog"]');
  329. await expect(dialog).toBeVisible();
  330. // 验证用户类型选择器存在
  331. await expect(userManagementPage.userTypeSelector).toBeVisible();
  332. // 验证必填字段输入框存在
  333. await expect(userManagementPage.usernameInput).toBeVisible();
  334. await expect(userManagementPage.passwordInput).toBeVisible();
  335. await expect(userManagementPage.nicknameInput).toBeVisible();
  336. // 验证可选字段输入框存在
  337. await expect(userManagementPage.emailInput).toBeVisible();
  338. await expect(userManagementPage.phoneInput).toBeVisible();
  339. await expect(userManagementPage.nameInput).toBeVisible();
  340. // 企业选择器是条件渲染的,只有选择了 EMPLOYER 类型才会显示
  341. // 先选择企业用户类型
  342. await userManagementPage.userTypeSelector.click();
  343. await userManagementPage.page.waitForSelector('[role="option"]', { state: 'visible', timeout: TIMEOUTS.DIALOG });
  344. await userManagementPage.page.getByRole('option', { name: '企业用户' }).click();
  345. // 现在验证企业选择器存在
  346. await expect(userManagementPage.companySelector).toBeVisible();
  347. // 验证按钮存在
  348. await expect(userManagementPage.createSubmitButton).toBeVisible();
  349. await expect(userManagementPage.cancelButton).toBeVisible();
  350. // 关闭对话框
  351. await userManagementPage.cancelDialog();
  352. });
  353. });
  354. test.describe('取消和关闭操作测试', () => {
  355. test('应该能取消创建企业用户操作', async ({ userManagementPage }) => {
  356. const timestamp = Date.now();
  357. const username = `cancel_employer_${timestamp}`;
  358. // 打开创建对话框并填写表单
  359. await userManagementPage.openCreateDialog();
  360. await userManagementPage.usernameInput.fill(username);
  361. await userManagementPage.passwordInput.fill('password123');
  362. // 点击取消按钮
  363. await userManagementPage.cancelDialog();
  364. // 验证对话框关闭
  365. const dialog = userManagementPage.page.locator('[role="dialog"]');
  366. await expect(dialog).not.toBeVisible();
  367. // 验证用户没有被创建
  368. const exists = await userManagementPage.userExists(username);
  369. expect(exists).toBe(false);
  370. });
  371. test('应该能通过关闭对话框取消创建', async ({ userManagementPage }) => {
  372. const timestamp = Date.now();
  373. const username = `close_employer_${timestamp}`;
  374. // 打开创建对话框并填写表单
  375. await userManagementPage.openCreateDialog();
  376. await userManagementPage.usernameInput.fill(username);
  377. await userManagementPage.passwordInput.fill('password123');
  378. // 按 ESC 键关闭对话框
  379. await userManagementPage.page.keyboard.press('Escape');
  380. // 等待对话框关闭
  381. await userManagementPage.waitForDialogClosed();
  382. // 验证用户没有被创建
  383. const exists = await userManagementPage.userExists(username);
  384. expect(exists).toBe(false);
  385. });
  386. });
  387. });