瀏覽代碼

refactor(e2e): restructure test code using Page Object Model (POM) pattern

ddx 1 月之前
父節點
當前提交
4fb797489e

+ 0 - 45
__e2e_test__/login.spec.ts

@@ -1,45 +0,0 @@
-describe('Login Page', () => {
-  it('should successfully log in with correct credentials', () => {
-    // Visit the base URL
-    cy.visit('/');
-
-    // Wait for the page to load and ensure the elements are present
-    cy.get('[data-testid="login-username-input"]').should('be.visible');
-    cy.get('[data-testid="login-password-input"]').should('be.visible');
-    cy.get('[data-testid="login-submit-button"]').should('be.visible');
-
-    // Enter the username
-    cy.get('[data-testid="login-username-input"]').type('admin');
-
-    // Enter the password
-    cy.get('[data-testid="login-password-input"]').type('123456');
-
-    // Click the login button
-    cy.get('[data-testid="login-submit-button"]').click();
-
-    // Wait for the login process to complete
-    cy.contains('登录成功').should('be.visible', { timeout: 10000 });
-  });
-
-  it('should show an error message for incorrect credentials', () => {
-    // Visit the base URL
-    cy.visit('/');
-
-    // Wait for the page to load and ensure the elements are present
-    cy.get('[data-testid="login-username-input"]').should('be.visible');
-    cy.get('[data-testid="login-password-input"]').should('be.visible');
-    cy.get('[data-testid="login-submit-button"]').should('be.visible');
-
-    // Enter the incorrect username
-    cy.get('[data-testid="login-username-input"]').type('wronguser');
-
-    // Enter the incorrect password
-    cy.get('[data-testid="login-password-input"]').type('wrongpassword');
-
-    // Click the login button
-    cy.get('[data-testid="login-submit-button"]').click();
-
-    // Wait for the error message to be visible
-    cy.contains('登录失败').should('be.visible', { timeout: 10000 });
-  });
-});

+ 1 - 1
cypress.config.ts

@@ -3,7 +3,7 @@ import { defineConfig } from 'cypress';
 export default defineConfig({
   e2e: {
     baseUrl: 'http://localhost:10086/#/pages/index/index', // Adjust this to match your application's base URL
-    specPattern: '__e2e_test__/**/*.spec.ts',
+    // specPattern: '__e2e_test__/**/*.spec.ts',
     setupNodeEvents(on, config) {
       return require('./cypress/plugins/index.js')(on, config);
     },

+ 25 - 0
cypress/e2e/login.cy.ts

@@ -0,0 +1,25 @@
+// import { describe, it } from 'node:test';
+import LoginPage from '../support/pageObjects/LoginPage';
+// import "cypress";
+
+describe('Login Page', () => {
+  const loginPage = new LoginPage();
+
+  it('should successfully log in with correct credentials', () => {
+    loginPage.visit();
+    loginPage.getUsernameInput().should('be.visible');
+    loginPage.getPasswordInput().should('be.visible');
+    loginPage.getSubmitButton().should('be.visible');
+    loginPage.login('admin', '123456');
+    cy.contains('登录成功').should('be.visible', { timeout: 10000 });
+  });
+
+  it('should show an error message for incorrect credentials', () => {
+    loginPage.visit();
+    loginPage.getUsernameInput().should('be.visible');
+    loginPage.getPasswordInput().should('be.visible');
+    loginPage.getSubmitButton().should('be.visible');
+    loginPage.login('wronguser', 'wrongpassword');
+    cy.contains('登录失败').should('be.visible', { timeout: 10000 });
+  });
+});

+ 6 - 10
cypress/plugins/index.js

@@ -1,14 +1,10 @@
 const webpackPreprocessor = require('@cypress/webpack-preprocessor');
+const webpackConfig = require('../webpack.config');
 
 module.exports = (on, config) => {
-  const options = {
-    webpackOptions: {
-      output: {
-        chunkFormat: 'commonjs',
-      },
-      target: 'node',
-    },
-  };
+  on('file:preprocessor', webpackPreprocessor({
+    webpackOptions: webpackConfig
+  }));
 
-  on('file:preprocessor', webpackPreprocessor(options));
-};
+  return config;
+};

+ 2 - 0
cypress/support/e2e.ts

@@ -2,6 +2,8 @@
 
 // Import commands.js using ES2015 syntax:
 import './commands';
+import './pageObjects/LoginPage';
 
 // Alternatively you can use CommonJS syntax:
 // require('./commands')
+// require('./pageObjects/LoginPage')

+ 27 - 0
cypress/support/pageObjects/LoginPage.ts

@@ -0,0 +1,27 @@
+// import 'cypress';
+
+class LoginPage {
+  visit() {
+    cy.visit('/');
+  }
+
+  getUsernameInput() {
+    return cy.get('[data-testid="login-username-input"]');
+  }
+
+  getPasswordInput() {
+    return cy.get('[data-testid="login-password-input"]');
+  }
+
+  getSubmitButton() {
+    return cy.get('[data-testid="login-submit-button"]');
+  }
+
+  login(username: string, password: string) {
+    this.getUsernameInput().type(username);
+    this.getPasswordInput().type(password);
+    this.getSubmitButton().click();
+  }
+}
+
+export default LoginPage;

+ 59 - 0
cypress/webpack.config.js

@@ -0,0 +1,59 @@
+const path = require('path');
+
+module.exports = {
+  mode: 'development',
+  target: 'web',
+  
+  output: {
+    chunkFormat: 'array-push',
+    chunkLoading: 'jsonp'
+  },
+  
+  resolve: {
+    extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
+    // 关键:配置模块回退,避免 Node.js 核心模块错误
+    fallback: {
+      "module": false,
+      "test": false,
+      "fs": false,
+      "path": false,
+      "os": false,
+      "crypto": false,
+      "stream": false,
+      "util": false,
+      "buffer": require.resolve('buffer/'),
+    //   "url": require.resolve('url/'),
+    //   "http": require.resolve('stream-http'),
+    //   "https": require.resolve('https-browserify'),
+    //   "zlib": require.resolve('browserify-zlib')
+    }
+  },
+  
+  module: {
+    rules: [
+      {
+        test: /\.(js|jsx|ts|tsx)$/,
+        exclude: /node_modules\/(?!cypress)/, // 排除 node_modules,但包含 cypress
+        use: {
+          loader: 'babel-loader',
+          options: {
+            presets: [
+              ['@babel/preset-env'],
+              ['@babel/preset-react'],
+              ['@babel/preset-typescript']
+            ]
+          }
+        }
+      }
+    ]
+  },
+  
+  // 忽略 Node.js 核心模块的警告
+  stats: {
+    warningsFilter: [
+      /Critical dependency:/,
+      /Can't resolve/,
+      /Module not found/
+    ]
+  }
+};

File diff suppressed because it is too large
+ 85 - 119
package-lock.json


+ 1 - 1
package.json

@@ -38,7 +38,7 @@
     "build:electron:win": "electron-builder --config electron-builder.json  --win",
     "build:electron:linux": "electron-builder --config electron-builder.json  --linux",
     "build:android": "node ./.build/build-android.js",
-    "e2e": "npx cypress run --spec '__e2e_test__/*.ts'  --headed"
+    "e2e": "npx cypress run --headed"
   },
   "browserslist": [
     "defaults and fully supports es6-module",

+ 7 - 1
tsconfig.json

@@ -23,6 +23,12 @@
       "@/*": ["./src/*"]
     }
   },
-  "include": ["./src", "./types", "./config", "public/mockServiceWorker.js"],
+  "include": [
+    "./src",
+    "./types",
+    "./config",
+    "public/mockServiceWorker.js",
+    "./cypress/**/*.ts"
+  ],
   "compileOnSave": false
 }

+ 44 - 0
webpack.config.cypress.js

@@ -0,0 +1,44 @@
+const path = require('path');
+
+module.exports = {
+  mode: 'development', // 设置为开发模式,便于调试
+  resolve: {
+    extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'], // 解析这些扩展名
+    alias: {
+      // 根据需要设置路径别名,确保与 Taro 项目一致
+      '@': path.resolve(__dirname, 'src'),
+    },
+  },
+  module: {
+    rules: [
+      {
+        test: /\.(js|jsx|ts|tsx)$/,
+        exclude: /node_modules/,
+        use: {
+          loader: 'babel-loader',
+          options: {
+            // 使用你的 Taro 项目中的 Babel 配置
+            // 或者一个适用于测试环境的基础配置
+            presets: [
+              ['@babel/preset-env'],
+              ['@babel/preset-react'],
+              ['@babel/preset-typescript']
+            ],
+            plugins: [
+              // 根据需要添加 Babel 插件
+            ]
+          }
+        }
+      },
+      {
+        test: /\.css$/,
+        use: ['style-loader', 'css-loader'] // 简单处理 CSS
+      },
+      {
+        test: /\.(png|jpg|gif|svg)$/,
+        type: 'asset/inline' // 将图片等资源内联处理
+      }
+    ]
+  },
+  // 其他必要的 Webpack 配置...
+};

Some files were not shown because too many files changed in this diff