user-management.page.ts 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. import { Page, Locator, expect } from '@playwright/test';
  2. export class UserManagementPage {
  3. readonly page: Page;
  4. readonly pageTitle: Locator;
  5. readonly createUserButton: Locator;
  6. readonly searchInput: Locator;
  7. readonly searchButton: Locator;
  8. readonly userTable: Locator;
  9. readonly editButtons: Locator;
  10. readonly deleteButtons: Locator;
  11. readonly pagination: Locator;
  12. constructor(page: Page) {
  13. this.page = page;
  14. this.pageTitle = page.getByRole('heading', { name: '用户管理' });
  15. this.createUserButton = page.getByRole('button', { name: '创建用户' });
  16. this.searchInput = page.getByPlaceholder('搜索用户名、昵称或邮箱...');
  17. this.searchButton = page.getByRole('button', { name: '搜索' });
  18. this.userTable = page.locator('table');
  19. this.editButtons = page.locator('button').filter({ hasText: '编辑' });
  20. this.deleteButtons = page.locator('button').filter({ hasText: '删除' });
  21. this.pagination = page.locator('[data-testid="pagination"]');
  22. }
  23. async goto() {
  24. // 直接导航到用户管理页面
  25. await this.page.goto('/admin/users');
  26. await this.page.waitForLoadState('networkidle');
  27. // 等待页面完全加载
  28. await this.page.waitForTimeout(5000);
  29. await this.expectToBeVisible();
  30. }
  31. async expectToBeVisible() {
  32. // 等待页面完全加载,使用更精确的选择器
  33. await this.page.waitForSelector('h1:has-text("用户管理")', { state: 'visible', timeout: 15000 });
  34. await expect(this.pageTitle).toBeVisible();
  35. await expect(this.createUserButton).toBeVisible();
  36. await expect(this.userTable).toBeVisible();
  37. }
  38. async searchUsers(keyword: string) {
  39. await this.searchInput.fill(keyword);
  40. await this.searchButton.click();
  41. await this.page.waitForLoadState('networkidle');
  42. }
  43. async createUser(userData: {
  44. username: string;
  45. password: string;
  46. nickname?: string;
  47. email?: string;
  48. phone?: string;
  49. name?: string;
  50. }) {
  51. await this.createUserButton.click();
  52. // 填写用户表单
  53. await this.page.getByLabel('用户名').fill(userData.username);
  54. await this.page.getByLabel('密码').fill(userData.password);
  55. if (userData.nickname) {
  56. await this.page.getByLabel('昵称').fill(userData.nickname);
  57. }
  58. if (userData.email) {
  59. await this.page.getByLabel('邮箱').fill(userData.email);
  60. }
  61. if (userData.phone) {
  62. await this.page.getByLabel('手机号').fill(userData.phone);
  63. }
  64. if (userData.name) {
  65. await this.page.getByLabel('真实姓名').fill(userData.name);
  66. }
  67. // 提交表单 - 使用模态框中的创建按钮
  68. await this.page.locator('[role="dialog"]').getByRole('button', { name: '创建用户' }).click();
  69. await this.page.waitForLoadState('networkidle');
  70. // 等待用户创建成功提示
  71. await this.page.waitForSelector('text=创建成功', { timeout: 10000 });
  72. // 等待页面自动刷新或手动刷新
  73. await this.page.waitForTimeout(1000);
  74. await this.page.reload();
  75. await this.page.waitForLoadState('networkidle');
  76. await this.expectToBeVisible();
  77. }
  78. async getUserCount(): Promise<number> {
  79. const rows = await this.userTable.locator('tbody tr').count();
  80. return rows;
  81. }
  82. async getUserByUsername(username: string): Promise<Locator | null> {
  83. const userRow = this.userTable.locator('tbody tr').filter({ hasText: username }).first();
  84. return (await userRow.count()) > 0 ? userRow : null;
  85. }
  86. async userExists(username: string): Promise<boolean> {
  87. const userRow = this.userTable.locator('tbody tr').filter({ hasText: username }).first();
  88. return (await userRow.count()) > 0;
  89. }
  90. async editUser(username: string, updates: {
  91. nickname?: string;
  92. email?: string;
  93. phone?: string;
  94. name?: string;
  95. }) {
  96. const userRow = await this.getUserByUsername(username);
  97. if (!userRow) throw new Error(`User ${username} not found`);
  98. // 编辑按钮是图标按钮,使用按钮定位(第一个按钮是编辑,第二个是删除)
  99. const editButton = userRow.locator('button').first();
  100. await editButton.waitFor({ state: 'visible', timeout: 10000 });
  101. await editButton.click();
  102. // 等待编辑模态框出现
  103. await this.page.waitForSelector('[role="dialog"]', { state: 'visible', timeout: 10000 });
  104. // 更新字段
  105. if (updates.nickname) {
  106. await this.page.getByLabel('昵称').fill(updates.nickname);
  107. }
  108. if (updates.email) {
  109. await this.page.getByLabel('邮箱').fill(updates.email);
  110. }
  111. if (updates.phone) {
  112. await this.page.getByLabel('手机号').fill(updates.phone);
  113. }
  114. if (updates.name) {
  115. await this.page.getByLabel('真实姓名').fill(updates.name);
  116. }
  117. // 提交更新
  118. await this.page.locator('[role="dialog"]').getByRole('button', { name: '更新用户' }).click();
  119. await this.page.waitForLoadState('networkidle');
  120. // 等待操作完成
  121. await this.page.waitForTimeout(1000);
  122. }
  123. async deleteUser(username: string) {
  124. const userRow = await this.getUserByUsername(username);
  125. if (!userRow) throw new Error(`User ${username} not found`);
  126. // 删除按钮是图标按钮,使用按钮定位(第二个按钮是删除)
  127. const deleteButton = userRow.locator('button').nth(1);
  128. await deleteButton.waitFor({ state: 'visible', timeout: 10000 });
  129. await deleteButton.click();
  130. // 确认删除对话框
  131. await this.page.getByRole('button', { name: '删除' }).click();
  132. // 等待删除操作完成
  133. await this.page.waitForTimeout(2000);
  134. // 检查是否有错误提示
  135. const errorVisible = await this.page.locator('text=删除失败').isVisible().catch(() => false);
  136. if (errorVisible) {
  137. throw new Error('删除操作失败:前端显示删除失败提示');
  138. }
  139. // 刷新页面确认用户是否被删除
  140. await this.page.reload();
  141. await this.page.waitForLoadState('networkidle');
  142. await this.expectToBeVisible();
  143. }
  144. async expectUserExists(username: string) {
  145. const exists = await this.userExists(username);
  146. expect(exists).toBe(true);
  147. }
  148. async expectUserNotExists(username: string) {
  149. const exists = await this.userExists(username);
  150. expect(exists).toBe(false);
  151. }
  152. }