From 0cb203cecd0a59199eea4c46c1dbfe15662e40ac Mon Sep 17 00:00:00 2001 From: Augusto Silva Date: Tue, 25 Aug 2026 11:19:03 +0200 Subject: [PATCH] test: attempt to run with endform --- .../setup-nodejs/safe-chain.config.json | 7 ++ .github/workflows/ci-pull-requests.yml | 16 +++-- .github/workflows/test-e2e-reusable.yml | 20 +++++- packages/testing/playwright/endform.config.ts | 8 +++ packages/testing/playwright/package.json | 1 + pnpm-lock.yaml | 64 +++++++++++++++++++ pnpm-workspace.yaml | 3 + 7 files changed, 111 insertions(+), 8 deletions(-) create mode 100644 packages/testing/playwright/endform.config.ts diff --git a/.github/actions/setup-nodejs/safe-chain.config.json b/.github/actions/setup-nodejs/safe-chain.config.json index 42bda8079046..893acf1aa83e 100644 --- a/.github/actions/setup-nodejs/safe-chain.config.json +++ b/.github/actions/setup-nodejs/safe-chain.config.json @@ -3,6 +3,13 @@ "minimumPackageAgeExclusions": [ "@n8n/*", "@n8n_io/*", + "endform", + "endform-darwin-arm64", + "endform-darwin-x86", + "endform-linux-arm64", + "endform-linux-x86", + "endform-win32-arm64", + "endform-win32-x86", "n8n", "n8n-containers", "n8n-core", diff --git a/.github/workflows/ci-pull-requests.yml b/.github/workflows/ci-pull-requests.yml index 9735a6da94f2..68f0f613cbd8 100644 --- a/.github/workflows/ci-pull-requests.yml +++ b/.github/workflows/ci-pull-requests.yml @@ -11,7 +11,7 @@ concurrency: jobs: install-and-build: name: Install & Build - runs-on: ${{ vars.RUNNER_PROVIDER == 'github' && 'ubuntu-latest' || 'blacksmith-4vcpu-ubuntu-2204' }} + runs-on: ${{ (github.repository == 'endformdev/n8n' || vars.RUNNER_PROVIDER == 'github') && 'ubuntu-latest' || 'blacksmith-4vcpu-ubuntu-2204' }} env: NODE_OPTIONS: '--max-old-space-size=7168' CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} @@ -19,11 +19,11 @@ jobs: QA_METRICS_WEBHOOK_USER: ${{ secrets.QA_METRICS_WEBHOOK_USER }} QA_METRICS_WEBHOOK_PASSWORD: ${{ secrets.QA_METRICS_WEBHOOK_PASSWORD }} outputs: - ci: ${{ fromJSON(steps.ci-filter.outputs.results).ci == true }} + ci: ${{ github.repository == 'n8n-io/n8n' && fromJSON(steps.ci-filter.outputs.results).ci == true }} runtime: ${{ fromJSON(steps.ci-filter.outputs.results).runtime == true }} - unit: ${{ fromJSON(steps.ci-filter.outputs.results).unit == true }} + unit: ${{ github.repository == 'n8n-io/n8n' && fromJSON(steps.ci-filter.outputs.results).unit == true }} e2e: ${{ fromJSON(steps.ci-filter.outputs.results).e2e == true }} - dev_server_smoke: ${{ fromJSON(steps.ci-filter.outputs.results)['dev-server-smoke'] == true }} + dev_server_smoke: ${{ github.repository == 'n8n-io/n8n' && fromJSON(steps.ci-filter.outputs.results)['dev-server-smoke'] == true }} workflows: ${{ fromJSON(steps.ci-filter.outputs.results).workflows == true }} workflow_scripts: ${{ fromJSON(steps.ci-filter.outputs.results)['workflow-scripts'] == true }} db: ${{ fromJSON(steps.ci-filter.outputs.results).db == true }} @@ -260,7 +260,7 @@ jobs: name: Prepare Docker needs: install-and-build if: >- - github.repository == 'n8n-io/n8n' && + (github.repository == 'n8n-io/n8n' || github.repository == 'endformdev/n8n') && github.event_name != 'merge_group' && (needs.install-and-build.outputs.runtime == 'true' || needs.install-and-build.outputs.e2e == 'true' @@ -270,6 +270,7 @@ jobs: uses: ./.github/workflows/prepare-docker-reusable.yml with: branch: ${{ needs.install-and-build.outputs.commit_sha }} + runner: ubuntu-latest secrets: inherit # Internal-only 1-spec fail-fast sanity check on sqlite. @@ -309,7 +310,8 @@ jobs: with: branch: ${{ needs.install-and-build.outputs.commit_sha }} test-mode: docker-artifact - test-command: ${{ github.event.pull_request.head.repo.fork == true && 'pnpm --filter=n8n-playwright test:container:sqlite:e2e --grep-invert=@licensed' || 'pnpm --filter=n8n-playwright test:container:multi-main:e2e' }} + test-command: ${{ github.event.pull_request.head.repo.fork == true && 'pnpm --filter=n8n-playwright exec endform test --organization-id=2G1ZCj7X --project=e2e --grep-invert=@licensed' || 'pnpm --filter=n8n-playwright exec endform test --organization-id=2G1ZCj7X --project=multi-main:e2e' }} + test-runner: endform workers: '1' pre-generated-matrix: ${{ needs.install-and-build.outputs.matrix }} artifact-prefix: e2e @@ -363,7 +365,7 @@ jobs: security-checks: name: Security Checks needs: install-and-build - if: needs.install-and-build.outputs.workflows == 'true' + if: needs.install-and-build.outputs.workflows == 'true' && github.repository == 'n8n-io/n8n' uses: ./.github/workflows/sec-ci-reusable.yml with: ref: ${{ needs.install-and-build.outputs.commit_sha }} diff --git a/.github/workflows/test-e2e-reusable.yml b/.github/workflows/test-e2e-reusable.yml index c3af91ba6b33..d0f4454e28b0 100644 --- a/.github/workflows/test-e2e-reusable.yml +++ b/.github/workflows/test-e2e-reusable.yml @@ -17,6 +17,11 @@ on: required: false default: 'pnpm --filter=n8n-playwright test:local' type: string + test-runner: + description: 'Test runner: playwright or endform' + required: false + default: 'playwright' + type: string workers: description: 'Number of parallel workers' required: false @@ -73,7 +78,7 @@ env: jobs: test: - runs-on: ${{ vars.RUNNER_PROVIDER == 'github' && 'ubuntu-latest' || inputs.runner }} + runs-on: ${{ (github.repository == 'endformdev/n8n' || vars.RUNNER_PROVIDER == 'github') && 'ubuntu-latest' || inputs.runner }} timeout-minutes: ${{ inputs.timeout-minutes }} permissions: contents: read @@ -149,6 +154,12 @@ jobs: - name: Run Tests if: steps.shard-args.outputs.skip != 'true' run: | + if [ "$TEST_RUNNER" = 'endform' ]; then + # shellcheck disable=SC2086 + $TEST_COMMAND $SHARD_ARGS + exit + fi + # --pass-with-no-tests makes Playwright exit 0 when the selected specs # resolve to zero runnable tests. Covers the impact-map vs current-suite # skew window: a spec the committed coverage map points at may have been @@ -161,10 +172,12 @@ jobs: env: # Protect args from template injections TEST_COMMAND: ${{ inputs.test-command }} + TEST_RUNNER: ${{ inputs.test-runner }} # Uses pre-distributed specs if orchestration enabled, otherwise falls back to Playwright sharding WORKERS: ${{ env.PLAYWRIGHT_WORKERS }} SHARD_ARGS: ${{ steps.shard-args.outputs.args }} # Args for actual test command runner + ENDFORM_API_KEY: ${{ inputs.test-runner == 'endform' && secrets.ENDFORM_API_KEY || '' }} CURRENTS_RECORD_KEY: ${{ secrets.CURRENTS_RECORD_KEY }} QA_METRICS_WEBHOOK_URL: ${{ secrets.QA_METRICS_WEBHOOK_URL }} QA_METRICS_WEBHOOK_USER: ${{ secrets.QA_METRICS_WEBHOOK_USER }} @@ -173,6 +186,11 @@ jobs: N8N_LICENSE_CERT: ${{ secrets.N8N_LICENSE_CERT }} N8N_ENCRYPTION_KEY: ${{ secrets.N8N_ENCRYPTION_KEY }} N8N_TEST_ENV: ${{ inputs.n8n-env }} + # Endform runners are remote and cannot access the job's Docker socket. For the fork's + # SQLite suite, use Playwright's existing webServer and Endform's automatic proxying. + N8N_BASE_URL: ${{ inputs.test-runner == 'endform' && github.repository == 'endformdev/n8n' && 'http://localhost:5680' || '' }} + E2E_TESTS: ${{ inputs.test-runner == 'endform' && github.repository == 'endformdev/n8n' && 'true' || '' }} + RESET_E2E_DB: ${{ inputs.test-runner == 'endform' && github.repository == 'endformdev/n8n' && 'true' || '' }} - name: Upload Shard Artifacts if: always() diff --git a/packages/testing/playwright/endform.config.ts b/packages/testing/playwright/endform.config.ts new file mode 100644 index 000000000000..d8b2addee0b6 --- /dev/null +++ b/packages/testing/playwright/endform.config.ts @@ -0,0 +1,8 @@ +/* eslint-disable import-x/no-default-export */ +import { defineEndformConfig } from 'endform'; + +export default defineEndformConfig({ + additionalFiles: ['workflows/**/*', 'fixtures/**/*', 'expectations/**/*', 'tests/**/*'], + concurrentTestLimits: [{ scope: 'within-suite-run', limit: 6 }], + environmentVariables: ['N8N_BASE_URL'], +}); diff --git a/packages/testing/playwright/package.json b/packages/testing/playwright/package.json index ee52b7454505..ebcd619be727 100644 --- a/packages/testing/playwright/package.json +++ b/packages/testing/playwright/package.json @@ -69,6 +69,7 @@ "@types/jsonwebtoken": "catalog:", "@types/lodash": "catalog:", "autocannon": "^8.0.0", + "endform": "0.75.3", "eslint-plugin-playwright": "catalog:e2e", "flatted": "catalog:", "generate-schema": "2.6.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d0735bd26a50..3492ffe8be53 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7106,6 +7106,9 @@ importers: autocannon: specifier: ^8.0.0 version: 8.0.0 + endform: + specifier: 0.75.3 + version: 0.75.3 eslint-plugin-playwright: specifier: catalog:e2e version: 2.2.2(eslint@9.29.0(jiti@2.6.1)(supports-color@8.1.1)) @@ -16502,6 +16505,40 @@ packages: end-of-stream@1.4.4: resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + endform-darwin-arm64@0.75.3: + resolution: {integrity: sha512-7CTjEjrimK47CZI5Tki+1UdDPya2KBfwR1vSBkNC/IbGFu23B9eoKpzNWq4rw6d66HagP9OCheLkwXbQ5pyHHw==} + cpu: [arm64] + os: [darwin] + + endform-darwin-x86@0.75.3: + resolution: {integrity: sha512-SbY2EIZkAtR7F7aEuWIkfqc2C7mx+qO9Jn24ecEgZF5yPl6EqNSmo3Xs9JAoUwYji4ha2LvHMUnA5zHEI07JdQ==} + cpu: [x64] + os: [darwin] + + endform-linux-arm64@0.75.3: + resolution: {integrity: sha512-akW3fFq+wC3S0/aLKzFNaWf3b0gUdop8ItVGxh9JZzDGrOGqsl4/CxzBoO5UhHQsB+BeELYpcx7SXwGMKUs8Rw==} + cpu: [arm64] + os: [linux] + + endform-linux-x86@0.75.3: + resolution: {integrity: sha512-guzjS/xY6RSA8BnjavYlPOksfE4nffTUQhkVVv+OokWyoYjwLpL/eF7aTOO0sG4EZ/6YC5rAHq0LIQ4sMs+5ng==} + cpu: [x64] + os: [linux] + + endform-win32-arm64@0.75.3: + resolution: {integrity: sha512-dbP6ok4yfDIH6ctrXXvkzuush3LWIFx1JkZdgzbhpkEQ8icfBAWqC/wnS/nEiWkSi0dGz7IGXNG+GU3Vx89ZRA==} + cpu: [arm64] + os: [win32] + + endform-win32-x86@0.75.3: + resolution: {integrity: sha512-pygvw6ifZFDH4lvlDFD1nz+5naPPdONEqfnnUFD9NBu0qiYpRV9nzkZQRSkLwEoMxJQOA3xQOUGQq9eSWzYOyQ==} + cpu: [x64] + os: [win32] + + endform@0.75.3: + resolution: {integrity: sha512-cc3YQdQiMHFS0RFQDtVflj1Cedae2rmuY/mJtwByF2GFxyMqSuPdK4GgYX7RBIdWhCSKb7IbN9Ef8pfLxjebbQ==} + hasBin: true + enhanced-resolve@5.18.2: resolution: {integrity: sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==} engines: {node: '>=10.13.0'} @@ -36359,6 +36396,33 @@ snapshots: dependencies: once: 1.4.0 + endform-darwin-arm64@0.75.3: + optional: true + + endform-darwin-x86@0.75.3: + optional: true + + endform-linux-arm64@0.75.3: + optional: true + + endform-linux-x86@0.75.3: + optional: true + + endform-win32-arm64@0.75.3: + optional: true + + endform-win32-x86@0.75.3: + optional: true + + endform@0.75.3: + optionalDependencies: + endform-darwin-arm64: 0.75.3 + endform-darwin-x86: 0.75.3 + endform-linux-arm64: 0.75.3 + endform-linux-x86: 0.75.3 + endform-win32-arm64: 0.75.3 + endform-win32-x86: 0.75.3 + enhanced-resolve@5.18.2: dependencies: graceful-fs: 4.2.11 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 5e61b8ba4dce..3b2e071281a1 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -34,6 +34,9 @@ minimumReleaseAgeExclude: - '@ai-sdk/anthropic' # Security patch (Aikido) newer than the minimumReleaseAge window; allow it in. - '@xmldom/xmldom' + # Endform releases need immediate validation against the PR E2E suite. + - endform + - 'endform-*' packages: - packages/*