name: Docker E2E Tests # 在 Docker 環境中運行完整 E2E 測試 # 包含所有轉換工具和翻譯服務 on: push: branches: ["main"] paths: - "src/**" - "tests/**" - "Dockerfile" - ".github/workflows/docker-e2e-tests.yml" pull_request: branches: ["main"] paths: - "src/**" - "tests/**" - "Dockerfile" workflow_dispatch: inputs: run_translation_tests: description: "Run translation tests (requires API keys)" required: false default: false type: boolean env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: # ============================================ # Job 1: Build test image # ============================================ build-test-image: name: Build Test Image runs-on: ubuntu-24.04 permissions: contents: read packages: write outputs: image: ${{ steps.image.outputs.image }} steps: - name: Checkout repository uses: actions/checkout@v4 - name: Free disk space run: | echo "🧹 Cleaning disk space..." sudo rm -rf /usr/share/dotnet || true sudo rm -rf /usr/local/lib/android || true sudo rm -rf /opt/ghc || true sudo rm -rf /opt/hostedtoolcache || true docker system prune -af --volumes || true echo "📊 Available space:" df -h / - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to GitHub Container Registry uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: downcase REPO run: echo "REPO=${GITHUB_REPOSITORY@L}" >> "${GITHUB_ENV}" - name: Build and push test image uses: docker/build-push-action@v6 with: context: . push: true tags: ${{ env.REGISTRY }}/${{ env.REPO }}:test-${{ github.sha }} cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.REPO }}:buildcache-linux-amd64 cache-to: type=inline - name: Set image output id: image run: echo "image=${{ env.REGISTRY }}/${{ env.REPO }}:test-${{ github.sha }}" >> $GITHUB_OUTPUT # ============================================ # Job 2: Run E2E tests in Docker # ============================================ e2e-tests: name: E2E Tests in Docker runs-on: ubuntu-24.04 needs: build-test-image timeout-minutes: 30 services: # Run the test image as a service convertx: image: ${{ needs.build-test-image.outputs.image }} credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} ports: - 3000:3000 options: >- --health-cmd "curl -f http://localhost:3000/healthcheck || exit 1" --health-interval 10s --health-timeout 5s --health-retries 10 --health-start-period 30s steps: - name: Checkout repository uses: actions/checkout@v4 - name: Wait for service to be healthy run: | echo "⏳ Waiting for ConvertX service..." for i in {1..30}; do if curl -f http://localhost:3000/healthcheck 2>/dev/null; then echo "✅ Service is healthy!" break fi echo "Waiting... ($i/30)" sleep 5 done - name: Run API health check run: | echo "🔍 Testing API endpoints..." # Health check curl -f http://localhost:3000/healthcheck echo "" # Check if main page loads curl -f -o /dev/null -w "%{http_code}" http://localhost:3000/ echo "" echo "✅ API health checks passed!" # ============================================ # Job 3: Run comprehensive E2E tests inside container # ============================================ comprehensive-e2e: name: Comprehensive E2E Tests runs-on: ubuntu-24.04 needs: build-test-image timeout-minutes: 60 steps: - name: Checkout repository uses: actions/checkout@v4 - name: Free disk space run: | sudo rm -rf /usr/share/dotnet || true sudo rm -rf /usr/local/lib/android || true docker system prune -af --volumes || true - name: Login to GitHub Container Registry uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Pull test image run: docker pull ${{ needs.build-test-image.outputs.image }} - name: Run E2E tests inside Docker container run: | echo "🧪 Running comprehensive E2E tests inside Docker..." docker run --rm \ --name convertx-e2e-test \ -v "${{ github.workspace }}/tests:/app/tests" \ -v "${{ github.workspace }}/test-results:/app/test-results" \ -e CI=true \ -e NODE_ENV=test \ --entrypoint /bin/bash \ ${{ needs.build-test-image.outputs.image }} \ -c " set -e echo '📋 System info:' uname -a echo '' echo '🔧 Available conversion tools:' echo ' inkscape:' \$(inkscape --version 2>/dev/null | head -1 || echo 'not found') echo ' pandoc:' \$(pandoc --version 2>/dev/null | head -1 || echo 'not found') echo ' ffmpeg:' \$(ffmpeg -version 2>/dev/null | head -1 || echo 'not found') echo ' libreoffice:' \$(soffice --version 2>/dev/null || echo 'not found') echo ' imagemagick:' \$(magick --version 2>/dev/null | head -1 || echo 'not found') echo ' calibre:' \$(ebook-convert --version 2>/dev/null | head -1 || echo 'not found') echo ' potrace:' \$(potrace -v 2>/dev/null | head -1 || echo 'not found') echo ' dasel:' \$(dasel --version 2>/dev/null || echo 'not found') echo ' resvg:' \$(resvg --version 2>/dev/null || echo 'not found') echo ' vips:' \$(vips --version 2>/dev/null || echo 'not found') echo ' pdf2zh:' \$(pdf2zh --version 2>/dev/null || echo 'not found') echo ' babeldoc:' \$(babeldoc --version 2>/dev/null || echo 'not found') echo '' echo '📦 Installing test dependencies...' cd /app bun install --frozen-lockfile || bun install echo '' echo '🧪 Running E2E tests...' # Run comprehensive tests bun test tests/e2e/comprehensive.e2e.test.ts --timeout 600000 || true # Run format matrix tests bun test tests/e2e/format-matrix.e2e.test.ts --timeout 300000 || true # Run basic converter tests bun test tests/e2e/converters.e2e.test.ts --timeout 120000 || true echo '' echo '✅ E2E tests completed!' # Copy results mkdir -p /app/test-results cp -r tests/e2e/output/* /app/test-results/ 2>/dev/null || true " - name: Upload test results uses: actions/upload-artifact@v4 if: always() with: name: e2e-test-results path: test-results/ retention-days: 7 # ============================================ # Job 4: Translation tests (使用免費翻譯服務) # 使用 Google/Bing 免費翻譯,不需要付費 API 金鑰 # ============================================ translation-tests: name: Translation Tests (Free Services) runs-on: ubuntu-24.04 needs: build-test-image if: ${{ github.event.inputs.run_translation_tests == 'true' || github.event_name == 'push' }} timeout-minutes: 30 steps: - name: Checkout repository uses: actions/checkout@v4 - name: Login to GitHub Container Registry uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Pull test image run: docker pull ${{ needs.build-test-image.outputs.image }} - name: Run translation tests run: | echo "🌍 Running translation tests (using free services: Google/Bing)..." docker run --rm \ --name convertx-translation-test \ -v "${{ github.workspace }}/tests:/app/tests" \ -v "${{ github.workspace }}/translation-results:/app/translation-results" \ -e CI=true \ -e PDFMATHTRANSLATE_SERVICE=google \ -e BABELDOC_SERVICE=google \ --entrypoint /bin/bash \ ${{ needs.build-test-image.outputs.image }} \ -c " set -e cd /app bun install --frozen-lockfile || bun install echo '🌍 Running translation tests with free services...' bun test tests/e2e/translation.e2e.test.ts --timeout 600000 || true mkdir -p /app/translation-results cp -r tests/e2e/output/translation/* /app/translation-results/ 2>/dev/null || true " - name: Upload translation results uses: actions/upload-artifact@v4 if: always() with: name: translation-test-results path: translation-results/ retention-days: 7 # ============================================ # Job 5: Cleanup test image # ============================================ cleanup: name: Cleanup Test Image runs-on: ubuntu-24.04 needs: [e2e-tests, comprehensive-e2e] if: always() permissions: packages: write steps: - name: Delete test image uses: actions/github-script@v7 continue-on-error: true with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | const tag = `test-${{ github.sha }}`; console.log(`🗑️ Attempting to delete test image with tag: ${tag}`); // Note: This requires ghcr.io API access which may need additional setup // For now, images will be cleaned up by retention policies console.log('Test images will be cleaned up by retention policies'); # ============================================ # Job 6: Test summary # ============================================ summary: name: Test Summary runs-on: ubuntu-24.04 needs: [e2e-tests, comprehensive-e2e] if: always() steps: - name: Download test results uses: actions/download-artifact@v4 with: name: e2e-test-results path: test-results/ continue-on-error: true - name: Generate summary run: | echo "# 🧪 Docker E2E Test Results" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "## Test Status" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "| Job | Status |" >> $GITHUB_STEP_SUMMARY echo "|-----|--------|" >> $GITHUB_STEP_SUMMARY echo "| E2E Tests | ${{ needs.e2e-tests.result }} |" >> $GITHUB_STEP_SUMMARY echo "| Comprehensive E2E | ${{ needs.comprehensive-e2e.result }} |" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY if [ -f "test-results/format-matrix/matrix-summary.md" ]; then echo "## Format Matrix Summary" >> $GITHUB_STEP_SUMMARY cat test-results/format-matrix/matrix-summary.md >> $GITHUB_STEP_SUMMARY fi if [ -f "test-results/comprehensive/conversion-matrix.json" ]; then echo "" >> $GITHUB_STEP_SUMMARY echo "## Conversion Matrix" >> $GITHUB_STEP_SUMMARY echo '```json' >> $GITHUB_STEP_SUMMARY head -50 test-results/comprehensive/conversion-matrix.json >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY fi echo "" >> $GITHUB_STEP_SUMMARY echo "📅 Test run completed at: $(date -u)" >> $GITHUB_STEP_SUMMARY