diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml new file mode 100644 index 00000000..9c45edfc --- /dev/null +++ b/.github/workflows/e2e.yml @@ -0,0 +1,56 @@ +name: E2E (Playwright) + +# Runs only on-demand for now. Spinning a full DreamFactory stack in GH +# Actions requires a shared df-docker image + secrets wiring that doesn't +# exist yet; wiring it up is tracked as a follow-up. Until then this job +# is driven by manual dispatch (pass a target URL) or a nightly cron +# against a long-running instance (URL in the E2E_NIGHTLY_URL secret). +on: + schedule: + - cron: '0 7 * * *' + workflow_dispatch: + inputs: + target_url: + description: 'Base URL to run E2E against (e.g. http://crucible.example:8080)' + required: true + +jobs: + smoke: + runs-on: ubuntu-latest + timeout-minutes: 20 + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 22.x + cache: 'npm' + + - run: npm ci + + - name: Install Playwright Browsers + run: npx playwright install chromium --with-deps + + - name: Resolve target URL + id: target + run: | + if [ -n "${{ github.event.inputs.target_url }}" ]; then + echo "url=${{ github.event.inputs.target_url }}" >> "$GITHUB_OUTPUT" + else + echo "url=${{ secrets.E2E_NIGHTLY_URL }}" >> "$GITHUB_OUTPUT" + fi + + - name: Run Playwright tests + env: + PLAYWRIGHT_BASE_URL: ${{ steps.target.outputs.url }} + DF_ADMIN_EMAIL: ${{ secrets.E2E_ADMIN_EMAIL || 'admin@dreamfactory.com' }} + DF_ADMIN_PASSWORD: ${{ secrets.E2E_ADMIN_PASSWORD || 'passwordpassword' }} + run: npm run e2e + + - uses: actions/upload-artifact@v4 + if: always() + with: + name: playwright-report + path: playwright-report/ + retention-days: 7 diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index ff1329d4..08e5b3a6 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -25,4 +25,8 @@ jobs: node-version: ${{ matrix.node-version }} cache: 'npm' - run: npm ci + # `test:ci` runs only the specs that currently pass. The rest are + # quarantined by jest.config.ci.js until the @ngneat/transloco ESM + # migration is completed. New tests should be added to that config. + - run: npm run test:ci - run: npm run build --if-present diff --git a/.gitignore b/.gitignore index 86d31fec..da8ec06a 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,9 @@ testem.log Thumbs.db .config/ + +# Playwright +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ diff --git a/e2e/_findings.spec.ts b/e2e/_findings.spec.ts new file mode 100644 index 00000000..48d4bdf4 --- /dev/null +++ b/e2e/_findings.spec.ts @@ -0,0 +1,285 @@ +/** + * Discovery run. Not a regression gate — this spec is designed to FAIL + * loudly on anything that isn't working so we get a concrete bug list. + * Do not add to jest.config.ci or the nightly Playwright workflow. + * + * Strategy: simulate a new admin working through the most common journeys + * on a vanilla dev-docker instance. Each step records what it saw; the + * final console report lists every deviation from expected. + */ +import { test, expect, Page } from '@playwright/test'; +import { loginAsAdmin, waitForAppReady } from './fixtures/admin-login'; + +type Finding = { + journey: string; + step: string; + detail: string; +}; +const findings: Finding[] = []; +function report(journey: string, step: string, detail: string) { + findings.push({ journey, step, detail }); + console.log(` [${journey}] ${step}: ${detail}`); +} + +async function clickNavByText( + page: Page, + label: string, + journey: string +): Promise { + // Sidebar entries are
wrappers with a