Переглянути джерело

test: encapsulate login and initialization flow in custom Cypress command

- Add cy.loginAndInitialize() command to simplify test setup
- Create TypeScript type definitions for custom commands
- Refactor logout.cy.ts to use new command (17 lines  1 line)
- Encapsulate all necessary mocks (i18n, quota, patient types, body parts)
- Add automatic waiting for initialization completion
dengdx 1 тиждень тому
батько
коміт
b1d56ab8e4

+ 3 - 21
cypress/e2e/security/logout.cy.ts

@@ -1,7 +1,4 @@
-import { mockLoginSuccess, mockLogoutSuccess } from '../../support/mock/handlers/user';
-import { mockI18nSuccess, mockAllRequiredAPIs } from '../../support/mock/handlers/i18n';
-import { mockGetQuotaSuccess } from '../../support/mock/handlers/quota';
-import { mockGetPatientTypeHuman, mockGetBodyPartHuman } from '../../support/mock/handlers/protocol';
+import { mockLogoutSuccess } from '../../support/mock/handlers/user';
 import LoginPage from '../../support/pageObjects/LoginPage';
 import MainPage from '../../support/pageObjects/MainPage';
 import ExitModalPage from '../../support/pageObjects/ExitModalPage';
@@ -12,23 +9,8 @@ describe('User Logout', () => {
   const exitModalPage = new ExitModalPage();
 
   beforeEach(() => {
-    // 清除存储
-    cy.clearAllSessionStorage();
-    cy.clearAllLocalStorage();
-    
-    // Mock 所有必要的 API
-    mockAllRequiredAPIs();      // 软件信息、日志
-    mockI18nSuccess('zh');      // 多语言资源
-    mockGetQuotaSuccess();      // 配额检查
-    mockGetPatientTypeHuman();  // 患者类型
-    mockGetBodyPartHuman();     // 身体部位
-    mockLoginSuccess();         // 登录
-    
-    // 访问并登录
-    loginPage.visit();
-    loginPage.login('admin', '123456');
-    cy.wait('@loginSuccess');
-    cy.contains('登录成功').should('be.visible');
+    // 使用封装的登录并初始化命令
+    cy.loginAndInitialize();
   });
 
   it('should successfully logout and return to login page', () => {

+ 33 - 0
cypress/support/commands.d.ts

@@ -0,0 +1,33 @@
+/// <reference types="cypress" />
+
+declare namespace Cypress {
+  interface Chainable<Subject = any> {
+    /**
+     * 自定义命令:登录并完成初始化进入主页
+     * 
+     * 这个命令封装了完整的登录流程:
+     * 1. 清除存储
+     * 2. Mock 所有必要的 API(i18n、quota、patient types、body parts)
+     * 3. 执行登录
+     * 4. 等待初始化完成
+     * 
+     * @param username - 用户名,默认 'admin'
+     * @param password - 密码,默认 '123456'
+     * 
+     * @example
+     * cy.loginAndInitialize();
+     * cy.loginAndInitialize('testuser', 'testpass');
+     */
+    loginAndInitialize(username?: string, password?: string): Chainable<Subject>;
+
+    /**
+     * 记录带时间戳的日志
+     * 
+     * @param message - 日志消息
+     * @param args - 额外参数
+     */
+    logWithDate(message: string, ...args: any[]): Chainable<Subject>;
+  }
+}
+
+export {};

+ 52 - 1
cypress/support/commands.js

@@ -39,6 +39,57 @@ Cypress.Commands.add('logWithDate', (message, ...args) => {
   return null; // Cypress 命令需要返回 null 或 Promise
 });
 
+/**
+ * 自定义命令:登录并完成初始化进入主页
+ * 
+ * 这个命令封装了完整的登录流程:
+ * 1. 清除存储
+ * 2. Mock 所有必要的 API(i18n、quota、patient types、body parts)
+ * 3. 执行登录
+ * 4. 等待初始化完成
+ * 
+ * @param {string} username - 用户名,默认 'admin'
+ * @param {string} password - 密码,默认 '123456'
+ * 
+ * @example
+ * cy.loginAndInitialize();
+ * cy.loginAndInitialize('testuser', 'testpass');
+ */
+Cypress.Commands.add('loginAndInitialize', (username = 'admin', password = '123456') => {
+  // 导入所需的 mock handlers
+  const { mockAllRequiredAPIs, mockI18nSuccess } = require('./mock/handlers/i18n');
+  const { mockGetQuotaSuccess } = require('./mock/handlers/quota');
+  const { mockGetPatientTypeHuman, mockGetBodyPartHuman } = require('./mock/handlers/protocol');
+  const { mockLoginSuccess } = require('./mock/handlers/user');
+  const LoginPage = require('./pageObjects/LoginPage').default;
+
+  // 清除存储
+  cy.clearAllSessionStorage();
+  cy.clearAllLocalStorage();
+  
+  // Mock 所有必要的 API
+  mockAllRequiredAPIs();      // 软件信息、日志
+  mockI18nSuccess('zh');      // 多语言资源
+  mockGetQuotaSuccess();      // 配额检查
+  mockGetPatientTypeHuman();  // 患者类型 - 必需!
+  mockGetBodyPartHuman();     // 身体部位 - 必需!
+  mockLoginSuccess();         // 登录
+  
+  // 使用 LoginPage Page Object 进行登录
+  const loginPage = new LoginPage();
+  loginPage.visit();
+  loginPage.login(username, password);
+  
+  // 等待登录成功消息
+  cy.wait('@loginSuccess');
+  cy.contains('登录成功', { timeout: 5000 }).should('be.visible');
+  
+  // 等待初始化完成 - 退出按钮可见表示已成功进入主页
+  cy.get('[data-testid="exit-button"]', { timeout: 10000 }).should('be.visible');
+  
+  cy.log('✅ 登录并初始化完成');
+});
+
 // Cypress.on('window:before:load', (win) => {
 //   // 每打开/刷新一页都会触发
 //   cy.then(() => {
@@ -46,4 +97,4 @@ Cypress.Commands.add('logWithDate', (message, ...args) => {
 //     const [, stamp] = win.location.href.match(/[?&]stamp=([^&]*)/) || [];
 //     if (stamp) console.log('[全局] 当前 stamp:', stamp);
 //   });
-// });
+// });