Repository navigation
feat(installment): 增加分期计划金额与期数编辑及自动重算功能 #140
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: E2E Tests | |
| on: | |
| push: | |
| branches: [main, release] | |
| pull_request: | |
| branches: [main, release] | |
| workflow_dispatch: | |
| env: | |
| NODE_VERSION: '20.x' | |
| PNPM_VERSION: '10' | |
| jobs: | |
| e2e: | |
| runs-on: ubuntu-latest | |
| services: | |
| postgres: | |
| image: postgres:16-alpine | |
| env: | |
| POSTGRES_USER: qmx | |
| POSTGRES_PASSWORD: qmx_password | |
| POSTGRES_DB: qmx_test | |
| ports: | |
| - 5432:5432 | |
| options: >- | |
| --health-cmd="pg_isready -U qmx -d qmx_test" | |
| --health-interval=10s | |
| --health-timeout=5s | |
| --health-retries=5 | |
| env: | |
| DATABASE_URL: postgresql://qmx:qmx_password@localhost:5432/qmx_test | |
| REDIS_ENABLED: 'false' | |
| strategy: | |
| matrix: | |
| # CI环境只运行chromium,本地可配置多浏览器 | |
| browser: [chromium] | |
| timeout-minutes: 25 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js ${{ env.NODE_VERSION }} | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| timeout-minutes: 10 | |
| - name: Setup pnpm ${{ env.PNPM_VERSION }} | |
| uses: pnpm/action-setup@v2 | |
| with: | |
| version: ${{ env.PNPM_VERSION }} | |
| - name: Get pnpm store directory | |
| shell: bash | |
| run: | | |
| echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV | |
| # 多层缓存 | |
| - name: Setup pnpm cache | |
| uses: actions/cache@v4 | |
| with: | |
| path: ${{ env.STORE_PATH }} | |
| key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pnpm-store- | |
| - name: Setup Playwright browser cache | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cache/ms-playwright | |
| ~/.cache/ms-edge | |
| key: ${{ runner.os }}-playwright-${{ hashFiles('**/pnpm-lock.yaml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-playwright- | |
| - name: Setup Vite cache | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| node_modules/.vite | |
| node_modules/.vitest | |
| key: ${{ runner.os }}-vite-vitest-${{ hashFiles('**/pnpm-lock.yaml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-vite-vitest- | |
| # 依赖安装(带重试) | |
| - name: Install dependencies | |
| shell: bash | |
| run: | | |
| set -e | |
| MAX_RETRIES=3 | |
| RETRY_COUNT=0 | |
| while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do | |
| if pnpm install --frozen-lockfile; then | |
| echo "✓ Dependencies installed successfully" | |
| exit 0 | |
| fi | |
| RETRY_COUNT=$((RETRY_COUNT + 1)) | |
| if [ $RETRY_COUNT -lt $MAX_RETRIES ]; then | |
| echo "⚠️ Install failed, retrying ($RETRY_COUNT/$MAX_RETRIES)..." | |
| sleep 5 | |
| fi | |
| done | |
| echo "❌ Install failed after $MAX_RETRIES attempts" | |
| exit 1 | |
| env: | |
| CYPRESS_INSTALL_BINARY: 0 | |
| - name: Sync backend schema | |
| run: pnpm run --filter qmx-backend db:push | |
| timeout-minutes: 5 | |
| # 安装Playwright浏览器及系统依赖 | |
| - name: Install Playwright browsers and dependencies | |
| shell: bash | |
| run: | | |
| pnpx playwright install --with-deps chromium | |
| timeout-minutes: 10 | |
| # 设置测试环境 | |
| - name: Setup test environment | |
| shell: bash | |
| run: | | |
| cp .env.test .env | |
| echo "NODE_ENV=test" >> $GITHUB_ENV | |
| echo "CI=true" >> $GITHUB_ENV | |
| echo "TZ=UTC" >> $GITHUB_ENV | |
| echo "BASE_URL=http://localhost:1420" >> $GITHUB_ENV | |
| echo "VITE_API_BASE_URL=http://localhost:3001/api/v1" >> $GITHUB_ENV | |
| echo "DATABASE_URL=postgresql://qmx:qmx_password@localhost:5432/qmx_test" >> $GITHUB_ENV | |
| echo "REDIS_ENABLED=false" >> $GITHUB_ENV | |
| # 启动服务(后端和前端) | |
| - name: Start backend and frontend services | |
| shell: bash | |
| run: | | |
| echo "Starting services..." | |
| pnpm run dev:full > services.log 2>&1 & | |
| SERVICES_PID=$! | |
| echo "SERVICES_PID=$SERVICES_PID" >> $GITHUB_ENV | |
| echo "Waiting for services to be ready..." | |
| # 后端就绪检测(指数退避重试) | |
| RETRY_COUNT=0 | |
| MAX_RETRIES=60 | |
| WAIT_TIME=1 | |
| while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do | |
| if curl -sf http://localhost:3001/api/v1/health 2>/dev/null || \ | |
| curl -sf http://localhost:3001/api/v1/ 2>/dev/null; then | |
| echo "✓ Backend service is ready" | |
| break | |
| fi | |
| RETRY_COUNT=$((RETRY_COUNT + 1)) | |
| if [ $RETRY_COUNT -eq $MAX_RETRIES ]; then | |
| echo "❌ Backend service failed to start" | |
| tail -50 services.log | |
| exit 1 | |
| fi | |
| echo "Waiting for backend... ($RETRY_COUNT/$MAX_RETRIES, wait ${WAIT_TIME}s)" | |
| sleep $WAIT_TIME | |
| # 指数退避,最多等待2秒 | |
| WAIT_TIME=$((WAIT_TIME < 2 ? WAIT_TIME * 2 : 2)) | |
| done | |
| # 前端就绪检测 | |
| RETRY_COUNT=0 | |
| MAX_RETRIES=60 | |
| WAIT_TIME=1 | |
| while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do | |
| if curl -sf http://localhost:1420 2>/dev/null; then | |
| echo "✓ Frontend service is ready" | |
| break | |
| fi | |
| RETRY_COUNT=$((RETRY_COUNT + 1)) | |
| if [ $RETRY_COUNT -eq $MAX_RETRIES ]; then | |
| echo "❌ Frontend service failed to start" | |
| tail -50 services.log | |
| exit 1 | |
| fi | |
| echo "Waiting for frontend... ($RETRY_COUNT/$MAX_RETRIES, wait ${WAIT_TIME}s)" | |
| sleep $WAIT_TIME | |
| WAIT_TIME=$((WAIT_TIME < 2 ? WAIT_TIME * 2 : 2)) | |
| done | |
| env: | |
| CI: true | |
| NODE_ENV: test | |
| TZ: UTC | |
| DATABASE_URL: postgresql://qmx:qmx_password@localhost:5432/qmx_test | |
| REDIS_ENABLED: 'false' | |
| # 测试数据初始化 | |
| - name: Initialize test data | |
| shell: bash | |
| run: | | |
| echo "Initializing test data..." | |
| RETRY_COUNT=0 | |
| MAX_RETRIES=3 | |
| while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do | |
| if curl -X POST http://localhost:3001/api/v1/test/seed 2>/dev/null; then | |
| echo "✓ Test data initialized" | |
| exit 0 | |
| fi | |
| RETRY_COUNT=$((RETRY_COUNT + 1)) | |
| if [ $RETRY_COUNT -lt $MAX_RETRIES ]; then | |
| echo "⚠️ Test data init failed, retrying ($RETRY_COUNT/$MAX_RETRIES)..." | |
| sleep 2 | |
| fi | |
| done | |
| echo "⚠️ Test data init failed after $MAX_RETRIES attempts, continuing anyway" | |
| # 运行E2E测试(带重试) | |
| - name: Run E2E tests | |
| shell: bash | |
| run: | | |
| pnpm run e2e \ | |
| --project=${{ matrix.browser }} \ | |
| --reporter=html,json | |
| timeout-minutes: 12 | |
| env: | |
| CI: true | |
| NODE_ENV: test | |
| TZ: UTC | |
| BASE_URL: http://localhost:1420 | |
| VITE_API_BASE_URL: http://localhost:3001/api/v1 | |
| continue-on-error: true | |
| # 失败诊断:检查服务日志 | |
| - name: Check services logs on failure | |
| if: failure() | |
| shell: bash | |
| run: | | |
| echo "=== Last 100 lines of services.log ===" | |
| tail -100 services.log || echo "No services.log found" | |
| echo "" | |
| echo "=== Process information ===" | |
| ps aux | grep -E "node|vite|playwright|mongo" | grep -v grep || echo "No processes found" | |
| echo "" | |
| echo "=== Network connections ===" | |
| netstat -tlnp 2>/dev/null | grep -E "3001|1420|27017" || ss -tlnp 2>/dev/null | grep -E "3001|1420|27017" || echo "No network info available" | |
| echo "" | |
| echo "=== MongoDB logs ===" | |
| docker logs mongodb-test 2>/dev/null | tail -20 || echo "MongoDB logs not available" | |
| # 上传测试结果 | |
| - name: Upload test results | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: e2e-test-results-${{ matrix.browser }} | |
| path: test-results/ | |
| retention-days: 7 | |
| # 上传Playwright报告 | |
| - name: Upload Playwright report | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: e2e-playwright-report-${{ matrix.browser }} | |
| path: playwright-report/ | |
| retention-days: 7 | |
| # 上传服务日志 | |
| - name: Upload services log | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: e2e-services-log-${{ matrix.browser }} | |
| path: services.log | |
| retention-days: 7 | |
| # 清理资源 | |
| - name: Cleanup | |
| if: always() | |
| shell: bash | |
| run: | | |
| echo "Cleaning up..." | |
| pkill -f "pnpm run dev:full" 2>/dev/null || true | |
| pkill -f "vite" 2>/dev/null || true | |
| echo "Cleanup completed" |