dashboard.page.ts 4.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. import { TIMEOUTS } from '../../utils/timeouts';
  2. import { Page, Locator, expect } from '@playwright/test';
  3. export class DashboardPage {
  4. readonly page: Page;
  5. readonly pageTitle: Locator;
  6. readonly activeUsersCard: Locator;
  7. readonly systemMessagesCard: Locator;
  8. readonly onlineUsersCard: Locator;
  9. readonly userManagementCard: Locator;
  10. readonly systemSettingsCard: Locator;
  11. constructor(page: Page) {
  12. this.page = page;
  13. this.pageTitle = page.getByRole('heading', { name: '仪表盘' });
  14. this.activeUsersCard = page.getByText('活跃用户');
  15. this.systemMessagesCard = page.getByText('系统消息');
  16. this.onlineUsersCard = page.getByText('在线用户');
  17. this.userManagementCard = page.getByText('用户管理');
  18. this.systemSettingsCard = page.getByText('系统设置');
  19. }
  20. async expectToBeVisible(options?: { timeout?: number }) {
  21. await expect(this.pageTitle).toBeVisible(options);
  22. await expect(this.activeUsersCard).toBeVisible(options);
  23. await expect(this.systemMessagesCard).toBeVisible(options);
  24. await expect(this.onlineUsersCard).toBeVisible(options);
  25. }
  26. async navigateToUserManagement() {
  27. // 检查是否为移动端,需要先打开菜单
  28. const isMobile = (this.page.viewportSize()?.width || 0) < 768;
  29. if (isMobile) {
  30. // 移动端需要先点击菜单按钮 - 使用测试ID
  31. const menuButton = this.page.getByTestId('mobile-menu-button');
  32. await expect(menuButton).toBeVisible({ timeout: TIMEOUTS.TABLE_LOAD });
  33. await menuButton.click({ timeout: TIMEOUTS.PAGE_LOAD });
  34. await this.page.waitForTimeout(TIMEOUTS.LONG); // 等待菜单完全展开
  35. }
  36. // 移动端需要点击侧边栏菜单项,而不是快捷操作卡片
  37. const userManagementCard = isMobile
  38. ? this.page.getByRole('button', { name: '用户管理' }).first()
  39. : this.page.locator('text=用户管理').first();
  40. await expect(userManagementCard).toBeVisible({ timeout: TIMEOUTS.TABLE_LOAD });
  41. await userManagementCard.click({ timeout: TIMEOUTS.TABLE_LOAD });
  42. await this.page.waitForLoadState('networkidle');
  43. }
  44. async navigateToSystemSettings() {
  45. // 检查是否为移动端,需要先打开菜单
  46. const isMobile = (this.page.viewportSize()?.width || 0) < 768;
  47. if (isMobile) {
  48. // 移动端需要先点击菜单按钮 - 使用测试ID
  49. const menuButton = this.page.getByTestId('mobile-menu-button');
  50. await expect(menuButton).toBeVisible({ timeout: TIMEOUTS.TABLE_LOAD });
  51. await menuButton.click({ timeout: TIMEOUTS.PAGE_LOAD });
  52. await this.page.waitForTimeout(TIMEOUTS.LONG); // 等待菜单完全展开
  53. }
  54. // 使用更具体的定位器来避免重复元素问题
  55. const systemSettingsCard = this.page.locator('text=系统设置').first();
  56. await systemSettingsCard.click({ timeout: TIMEOUTS.TABLE_LOAD });
  57. await this.page.waitForLoadState('networkidle');
  58. }
  59. async getActiveUsersCount(): Promise<string> {
  60. // 使用更可靠的定位器来获取活跃用户统计数字
  61. const countElement = this.page.locator('text=活跃用户').locator('xpath=following::div[contains(@class, "text-2xl")][1]');
  62. await expect(countElement).toBeVisible({ timeout: TIMEOUTS.TABLE_LOAD });
  63. return await countElement.textContent() || '';
  64. }
  65. async getSystemMessagesCount(): Promise<string> {
  66. // 使用更可靠的定位器来获取系统消息统计数字
  67. const countElement = this.page.locator('text=系统消息').locator('xpath=following::div[contains(@class, "text-2xl")][1]');
  68. await expect(countElement).toBeVisible({ timeout: TIMEOUTS.TABLE_LOAD });
  69. return await countElement.textContent() || '';
  70. }
  71. async logout() {
  72. // 先点击用户头像/用户名打开下拉菜单
  73. const userMenuButton = this.page.getByRole('button', { name: 'admin' });
  74. await userMenuButton.click();
  75. // 然后查找并点击登出按钮
  76. const logoutButton = this.page.getByRole('menuitem', { name: /登出|退出|Logout|Sign out/i });
  77. await logoutButton.click();
  78. await this.page.waitForLoadState('networkidle');
  79. }
  80. clone(newPage: Page): DashboardPage {
  81. return new DashboardPage(newPage);
  82. }
  83. }