diff --git a/.github/WORKFLOW_FIXES.md b/.github/WORKFLOW_FIXES.md new file mode 100644 index 0000000..2fb6d46 --- /dev/null +++ b/.github/WORKFLOW_FIXES.md @@ -0,0 +1,87 @@ +# GitHub Actions Workflow Fixes + +## Summary of Changes + +### 1. Fixed ci.yml (Lines 236 & 261) +**Problem**: Unrecognized named-value 'secrets' in conditional expressions +```yaml +# ❌ BEFORE (Invalid) +if: always() && secrets.SLACK_WEBHOOK_URL != '' + +# ✅ AFTER (Valid) +if: always() && env.SLACK_WEBHOOK_URL != '' +``` + +**Explanation**: Secrets cannot be directly referenced in conditional expressions. They must be assigned to environment variables first, then checked via `env.VARIABLE_NAME`. + +### 2. Fixed e2e-tests.yml +**Problems**: +- Used `npm install --workspaces` which isn't appropriate for this project structure +- Missing check for test existence before running +- Timeout issues (180s was too long) +- Missing individual step timeouts + +**Changes**: +- Replaced `npm install --workspaces --legacy-peer-deps` with `npm install` +- Added test existence check before running E2E tests +- Added skip step when no tests are configured +- Reduced webServer timeout from 180s to 120s +- Added 30-minute job timeout +- Added 20-minute step timeout for test execution +- Only install chromium browser (not all browsers) + +### 3. Updated Playwright Configuration +**Changes**: +- Reduced test timeout from 60s to 30s +- Reduced expect timeout from 15s to 10s +- Reduced action timeout from 15s to 10s +- Reduced navigation timeout from 30s to 20s +- Reduced webServer startup timeout from 180s to 120s + +### 4. Replaced `npm ci` with `npm install` +**Reason**: The package.json uses `file:` protocol for local packages which sometimes causes issues with `npm ci` when package-lock.json is out of sync. Using `npm install` is more forgiving and works better with the local package setup. + +**Jobs Updated**: +- lint +- test +- build +- e2e-tests +- security-scan + +## Remaining Issues to Address + +### Docker Build +The Docker build still fails due to workspace protocol. The Dockerfile already uses `npm install --legacy-peer-deps` which should work, but ensure: +1. The packages directories are properly copied before npm install +2. Consider using a .dockerignore file to exclude unnecessary files + +### E2E Test Stability +To improve E2E test reliability: +1. Add retry logic for flaky tests +2. Use `wait-on` package to ensure dev server is fully ready +3. Consider adding health check endpoint +4. Add individual test timeouts to catch hanging tests + +### Security Scan Permissions +If security scan upload fails, ensure the repository has: +- Security events write permission enabled +- Code scanning enabled in repository settings + +## Testing the Fixes + +Run workflows manually to test: +```bash +# Test lint job +gh workflow run ci.yml --ref main + +# Test E2E specifically +gh workflow run e2e-tests.yml --ref main +``` + +## Future Improvements + +1. **Caching**: Add npm cache to speed up builds +2. **Matrix Testing**: Test on multiple Node versions +3. **Conditional Jobs**: Skip Docker build on PR +4. **Slack Integration**: Set up SLACK_WEBHOOK_URL secret for notifications +5. **Test Reporting**: Add test result annotations to PRs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 03a95e1..bd21d7b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: cache: 'npm' - name: Install dependencies - run: npm ci + run: npm install - name: Run ESLint run: npm run lint:check @@ -47,7 +47,7 @@ jobs: cache: 'npm' - name: Install dependencies - run: npm ci + run: npm install - name: Run unit tests run: npm test --if-present || echo "No test script found" @@ -75,7 +75,7 @@ jobs: cache: 'npm' - name: Install dependencies - run: npm ci + run: npm install - name: Prepare build directories run: | @@ -105,6 +105,7 @@ jobs: name: E2E Tests runs-on: ubuntu-latest needs: build + timeout-minutes: 30 steps: - uses: actions/checkout@v4 @@ -115,7 +116,7 @@ jobs: cache: 'npm' - name: Install dependencies - run: npm ci + run: npm install - name: Install Playwright browsers run: npx playwright install --with-deps chromium @@ -126,12 +127,27 @@ jobs: name: dist path: dist/ + - name: Check if E2E tests exist + id: check-tests + run: | + if [ -d "e2e" ] && [ "$(ls -A e2e/*.spec.ts 2>/dev/null)" ]; then + echo "has_tests=true" >> $GITHUB_OUTPUT + else + echo "has_tests=false" >> $GITHUB_OUTPUT + fi + - name: Run E2E tests - run: npm run test:e2e --if-present || echo "No E2E tests configured" + if: steps.check-tests.outputs.has_tests == 'true' + run: npx playwright test + timeout-minutes: 20 + + - name: Skip E2E tests + if: steps.check-tests.outputs.has_tests == 'false' + run: echo "No E2E tests configured - skipping" - name: Upload test results uses: actions/upload-artifact@v4 - if: always() + if: always() && steps.check-tests.outputs.has_tests == 'true' with: name: playwright-report path: playwright-report/ @@ -154,7 +170,7 @@ jobs: cache: 'npm' - name: Install dependencies - run: npm ci + run: npm install - name: Run npm audit run: npm audit --audit-level=moderate || true @@ -233,7 +249,7 @@ jobs: - name: Notify deployment uses: 8398a7/action-slack@v3 - if: always() && secrets.SLACK_WEBHOOK_URL != '' + if: always() && env.SLACK_WEBHOOK_URL != '' with: status: ${{ job.status }} text: 'Staging deployment ${{ job.status }}' @@ -258,7 +274,7 @@ jobs: - name: Notify deployment uses: 8398a7/action-slack@v3 - if: always() && secrets.SLACK_WEBHOOK_URL != '' + if: always() && env.SLACK_WEBHOOK_URL != '' with: status: ${{ job.status }} text: 'Production deployment ${{ job.status }}' diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 1b50f4c..f1cecdf 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -5,6 +5,7 @@ on: branches: [ main, develop ] pull_request: branches: [ main, develop ] + workflow_dispatch: jobs: test: @@ -21,17 +22,32 @@ jobs: cache: 'npm' - name: Install dependencies - run: npm install --workspaces --legacy-peer-deps + run: npm install - name: Install Playwright Browsers - run: npx playwright install --with-deps + run: npx playwright install --with-deps chromium + + - name: Check if E2E tests exist + id: check-tests + run: | + if [ -d "e2e" ] && [ "$(ls -A e2e/*.spec.ts 2>/dev/null)" ]; then + echo "has_tests=true" >> $GITHUB_OUTPUT + else + echo "has_tests=false" >> $GITHUB_OUTPUT + fi - name: Run Playwright tests - run: npm run test:e2e + if: steps.check-tests.outputs.has_tests == 'true' + run: npx playwright test + timeout-minutes: 30 + + - name: Skip E2E tests + if: steps.check-tests.outputs.has_tests == 'false' + run: echo "No E2E tests configured - skipping" - name: Upload Playwright Report uses: actions/upload-artifact@v4 - if: always() + if: always() && steps.check-tests.outputs.has_tests == 'true' with: name: playwright-report path: playwright-report/ @@ -39,7 +55,7 @@ jobs: - name: Upload Test Results uses: actions/upload-artifact@v4 - if: always() + if: always() && steps.check-tests.outputs.has_tests == 'true' with: name: test-results path: test-results/ diff --git a/playwright.config.ts b/playwright.config.ts index 0800afc..ece187c 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -7,16 +7,16 @@ export default defineConfig({ retries: process.env.CI ? 2 : 0, workers: process.env.CI ? 1 : undefined, reporter: 'html', - timeout: 60000, + timeout: 30000, expect: { - timeout: 15000, + timeout: 10000, }, use: { baseURL: 'http://localhost:5000', trace: 'on-first-retry', screenshot: 'only-on-failure', - actionTimeout: 15000, - navigationTimeout: 30000, + actionTimeout: 10000, + navigationTimeout: 20000, }, projects: [ @@ -30,7 +30,7 @@ export default defineConfig({ command: 'npm run dev', url: 'http://localhost:5000', reuseExistingServer: !process.env.CI, - timeout: 180000, + timeout: 120000, stdout: 'pipe', stderr: 'pipe', },