From a071931b28a1676401383f4ae26c7c1d1edcd426 Mon Sep 17 00:00:00 2001 From: Augusto Silva Date: Thu, 10 Sep 2026 15:23:08 +0200 Subject: [PATCH 01/23] chore: add Endform as a pnpm dependency --- packages/testing/playwright/package.json | 1 + pnpm-lock.yaml | 67 ++++++++++++++++++++++++ pnpm-workspace.yaml | 1 + 3 files changed, 69 insertions(+) diff --git a/packages/testing/playwright/package.json b/packages/testing/playwright/package.json index bf4d533742c6..f52f30b15ea1 100644 --- a/packages/testing/playwright/package.json +++ b/packages/testing/playwright/package.json @@ -75,6 +75,7 @@ "autocannon": "^8.0.0", "axe-core": "^4.13.0", "axe-html-reporter": "^2.2.11", + "endform": "catalog:", "eslint-plugin-playwright": "catalog:e2e", "flatted": "catalog:", "generate-schema": "2.6.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e733578946fe..97f6f4171976 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -500,6 +500,9 @@ catalogs: electron: specifier: 41.10.4 version: 41.10.4 + endform: + specifier: 0.76.0 + version: 0.76.0 eslint: specifier: 9.29.0 version: 9.29.0 @@ -7647,6 +7650,9 @@ importers: axe-html-reporter: specifier: ^2.2.11 version: 2.2.11(axe-core@4.13.0) + endform: + specifier: 'catalog:' + version: 0.76.0 eslint-plugin-playwright: specifier: catalog:e2e version: 2.2.2(eslint@9.29.0(jiti@2.6.1)(supports-color@8.1.1)) @@ -17582,6 +17588,40 @@ packages: end-of-stream@1.4.4: resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + endform-darwin-arm64@0.76.0: + resolution: {integrity: sha512-uspKKhg6K9u01d3gETnrENNB42s+Oj0JmAgDuA/Ij+/H3g4rvLaShAwIUUf6MQgUwg7oHJGppYz0bgzlrLFcag==} + cpu: [arm64] + os: [darwin] + + endform-darwin-x86@0.76.0: + resolution: {integrity: sha512-eGS8aCru2i7EVdCYmwcz414LPGstzo9bN2/C7cy56QIaIHi71HCccVMIAHWXxgCQcE2/8WoAtcB6OVUB450Rqg==} + cpu: [x64] + os: [darwin] + + endform-linux-arm64@0.76.0: + resolution: {integrity: sha512-V0naw5K33GmQW7yDsZvqCvTi9n5jT1gJpCeYGu70tB7NiOZVGFuOlepqSOZ0ZBzE0KJ2t85eMZj8ocdSuVVQJA==} + cpu: [arm64] + os: [linux] + + endform-linux-x86@0.76.0: + resolution: {integrity: sha512-y4qt59+1rG/H1F7tZZ90fiTPbujHwVzpZE5UynpY/ffxxBkN2mU40y4BricSKX/mfyG0vey8Vp12A+u3evNrYQ==} + cpu: [x64] + os: [linux] + + endform-win32-arm64@0.76.0: + resolution: {integrity: sha512-x+YXkZqmeCW9gcABctk7L7chYYoXA55+XOF56K6iEsiZh/dLpGF6ALpGmVmIlGo9kC5ADnvSqsKlxTO/kJZ+tQ==} + cpu: [arm64] + os: [win32] + + endform-win32-x86@0.76.0: + resolution: {integrity: sha512-yCYi3kheL57pURP56QYl508oI1QK7rDWh1a7jy+YZ749MWKo4XlqJx/I04tMzYKAWYkKtfC2frTjoOY63m1CIQ==} + cpu: [x64] + os: [win32] + + endform@0.76.0: + resolution: {integrity: sha512-qh5PWJ2CuFVEGObkt8OBvk5vmUNo0ET3MWst3GXLqgl/F6GEMW1sqgBdETmtJT8dUe4rIdVPzlpxobpq1Ch+4Q==} + hasBin: true + engine.io-client@6.6.6: resolution: {integrity: sha512-iY6QdftLQ9pyiPoX082bpf/u1UewnOaJrtJIF9T0++QB34lZrj0uP+Q/bj8AlUsAxqhnkTV2BS8SBZSxOmoV5Q==} @@ -37727,6 +37767,33 @@ snapshots: dependencies: once: 1.4.0 + endform-darwin-arm64@0.76.0: + optional: true + + endform-darwin-x86@0.76.0: + optional: true + + endform-linux-arm64@0.76.0: + optional: true + + endform-linux-x86@0.76.0: + optional: true + + endform-win32-arm64@0.76.0: + optional: true + + endform-win32-x86@0.76.0: + optional: true + + endform@0.76.0: + optionalDependencies: + endform-darwin-arm64: 0.76.0 + endform-darwin-x86: 0.76.0 + endform-linux-arm64: 0.76.0 + endform-linux-x86: 0.76.0 + endform-win32-arm64: 0.76.0 + endform-win32-x86: 0.76.0 + engine.io-client@6.6.6(bufferutil@4.0.9)(supports-color@8.1.1)(utf-8-validate@5.0.10): dependencies: '@socket.io/component-emitter': 3.1.2 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 28c2ca3af7a4..19b5c69e54df 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -286,6 +286,7 @@ catalog: yaml: 2.8.3 zod: 3.25.76 zod-to-json-schema: 3.23.3 + endform: 0.76.0 catalogMode: strict From ede7c238227d6ec90ccb866bd9aec2b259213288 Mon Sep 17 00:00:00 2001 From: Augusto Silva Date: Thu, 10 Sep 2026 15:31:16 +0200 Subject: [PATCH 02/23] test: configure Endform for a serial local-backend baseline --- packages/testing/playwright/endform.config.ts | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 packages/testing/playwright/endform.config.ts diff --git a/packages/testing/playwright/endform.config.ts b/packages/testing/playwright/endform.config.ts new file mode 100644 index 000000000000..058159f865a3 --- /dev/null +++ b/packages/testing/playwright/endform.config.ts @@ -0,0 +1,7 @@ +/* eslint-disable import-x/no-default-export */ +import { defineEndformConfig } from 'endform'; + +export default defineEndformConfig({ + concurrentTestLimits: [{ scope: 'within-suite-run', limit: 1 }], + environmentVariables: ['N8N_BASE_URL', 'RESET_E2E_DB'], +}); From 9dd4a996e48350172173917dbf2bc25eb5fcd019 Mon Sep 17 00:00:00 2001 From: Augusto Silva Date: Thu, 10 Sep 2026 16:07:02 +0200 Subject: [PATCH 03/23] ci: compare Playwright and Endform with one existing test --- .github/workflows/endform-experiment.yml | 97 ++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 .github/workflows/endform-experiment.yml diff --git a/.github/workflows/endform-experiment.yml b/.github/workflows/endform-experiment.yml new file mode 100644 index 000000000000..4fa25d972021 --- /dev/null +++ b/.github/workflows/endform-experiment.yml @@ -0,0 +1,97 @@ +name: 'Endform: Incremental experiment' + +on: + push: + branches: [augustoccesar/endform-integration] + +permissions: + contents: read + +jobs: + baseline: + if: github.repository == 'endformdev/n8n' + name: '${{ matrix.runner }}: one home-page test' + runs-on: ubuntu-latest + timeout-minutes: 45 + strategy: + fail-fast: false + max-parallel: 1 + matrix: + runner: [playwright, endform] + env: + NODE_OPTIONS: '--max-old-space-size=6144' + N8N_BASE_URL: http://localhost:5680 + RESET_E2E_DB: 'true' + N8N_SKIP_LICENSES: 'true' + PLAYWRIGHT_BROWSERS_PATH: '${{ github.workspace }}/packages/testing/playwright/.playwright-browsers' + steps: + - name: Checkout + uses: useblacksmith/checkout@bcec731f1eb1367240608d1c889a75b96db6ec53 # v1.5.0 + + - name: Install dependencies + uses: ./.github/actions/setup-nodejs + with: + build-command: '' + + - name: Build + run: pnpm build > build.log 2>&1 + + - name: Record versions + working-directory: packages/testing/playwright + run: | + git rev-parse HEAD + node --version + pnpm --version + pnpm exec playwright --version + pnpm exec endform --version + + - name: Check types and lint + working-directory: packages/testing/playwright + run: | + pnpm typecheck > typecheck.log 2>&1 + pnpm lint > lint.log 2>&1 + + - name: Install Chromium + if: matrix.runner == 'playwright' + working-directory: packages/testing/playwright + run: pnpm exec playwright install chromium --with-deps + + - name: Run one existing test + working-directory: packages/testing/playwright + env: + TEST_RUNNER: '${{ matrix.runner }}' + ENDFORM_API_KEY: "${{ matrix.runner == 'endform' && secrets.ENDFORM_API_KEY || '' }}" + run: | + args=(test --project=e2e tests/e2e/building-blocks/workflow-entry-points.spec.ts --grep='should navigate from home$' --retries=0) + if [ "$TEST_RUNNER" = endform ]; then + args+=(--organization-id=2G1ZCj7X) + else + args+=(--workers=1) + fi + pnpm exec "$TEST_RUNNER" "${args[@]}" > experiment.log 2>&1 + + - name: Show log tails + if: always() + run: | + for log in build.log packages/testing/playwright/{typecheck,lint,experiment}.log; do + if [ -f "$log" ]; then + echo "::group::$log" + tail -n 50 "$log" + echo '::endgroup::' + fi + done + + - name: Preserve evidence + if: always() + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: 'endform-experiment-${{ matrix.runner }}-${{ github.run_attempt }}' + retention-days: 30 + path: | + build.log + packages/testing/playwright/experiment.log + packages/testing/playwright/typecheck.log + packages/testing/playwright/lint.log + packages/testing/playwright/test-results/ + packages/testing/playwright/test-results.json + packages/testing/playwright/playwright-report/ From adaad3783b3fb89af2c48a1bd3db9ebefbd6a4da Mon Sep 17 00:00:00 2001 From: Augusto Silva Date: Thu, 10 Sep 2026 17:17:21 +0200 Subject: [PATCH 04/23] test: wait for backend readiness before global setup The CI control failed with "Cannot POST /rest/e2e/reset". The favicon check allowed setup to start before routes were ready. Change to use the readiness endpoint to wait for initialization. --- packages/testing/playwright/playwright.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/testing/playwright/playwright.config.ts b/packages/testing/playwright/playwright.config.ts index 66f1395cedd2..14b61975d11f 100644 --- a/packages/testing/playwright/playwright.config.ts +++ b/packages/testing/playwright/playwright.config.ts @@ -70,7 +70,7 @@ if (BACKEND_URL && !SKIP_WEB_SERVER) { } webServer.push({ command: 'pnpm --dir ../../.. start', - url: `${BACKEND_URL}/favicon.ico`, + url: `${BACKEND_URL}/healthz/readiness`, timeout: 30000, reuseExistingServer: IS_DEV ? false : true, env: { From cd18bb08c88140697298caff2fb537314189def3 Mon Sep 17 00:00:00 2001 From: Augusto Silva Date: Fri, 11 Sep 2026 09:48:28 +0200 Subject: [PATCH 05/23] test: allow 30 seconds for Endform navigation The Endform trace showed frontend startup progressing after the 10-second navigation timeout. Increase only remote navigation to 30 seconds to test whether startup completes. Keep control timing and retries unchanged. --- .github/workflows/endform-experiment.yml | 1 + packages/testing/playwright/endform.config.ts | 2 +- packages/testing/playwright/playwright.config.ts | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/endform-experiment.yml b/.github/workflows/endform-experiment.yml index 4fa25d972021..38634820e85a 100644 --- a/.github/workflows/endform-experiment.yml +++ b/.github/workflows/endform-experiment.yml @@ -60,6 +60,7 @@ jobs: working-directory: packages/testing/playwright env: TEST_RUNNER: '${{ matrix.runner }}' + E2E_REMOTE_RUNNER: "${{ matrix.runner == 'endform' && 'true' || 'false' }}" ENDFORM_API_KEY: "${{ matrix.runner == 'endform' && secrets.ENDFORM_API_KEY || '' }}" run: | args=(test --project=e2e tests/e2e/building-blocks/workflow-entry-points.spec.ts --grep='should navigate from home$' --retries=0) diff --git a/packages/testing/playwright/endform.config.ts b/packages/testing/playwright/endform.config.ts index 058159f865a3..3c2ff616a566 100644 --- a/packages/testing/playwright/endform.config.ts +++ b/packages/testing/playwright/endform.config.ts @@ -3,5 +3,5 @@ import { defineEndformConfig } from 'endform'; export default defineEndformConfig({ concurrentTestLimits: [{ scope: 'within-suite-run', limit: 1 }], - environmentVariables: ['N8N_BASE_URL', 'RESET_E2E_DB'], + environmentVariables: ['N8N_BASE_URL', 'RESET_E2E_DB', 'E2E_REMOTE_RUNNER'], }); diff --git a/packages/testing/playwright/playwright.config.ts b/packages/testing/playwright/playwright.config.ts index 14b61975d11f..8cbf16ed60fd 100644 --- a/packages/testing/playwright/playwright.config.ts +++ b/packages/testing/playwright/playwright.config.ts @@ -130,7 +130,7 @@ export default defineConfig({ headless: process.env.SHOW_BROWSER !== 'true', viewport: MACBOOK_WINDOW_SIZE, actionTimeout: 20000, // TODO: We might need to make this dynamic for container tests if we have low resource containers etc - navigationTimeout: 10000, + navigationTimeout: process.env.E2E_REMOTE_RUNNER === 'true' ? 30000 : 10000, currentsFixturesEnabled: !!process.env.CI, }, From 32e54083ea9b5c44cca7dfdb09890d5d324e8dda Mon Sep 17 00:00:00 2001 From: Augusto Silva Date: Fri, 11 Sep 2026 10:14:08 +0200 Subject: [PATCH 06/23] ci: expand the Endform comparison to workflow entry points --- .github/workflows/endform-experiment.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/endform-experiment.yml b/.github/workflows/endform-experiment.yml index 38634820e85a..943c1fd132f6 100644 --- a/.github/workflows/endform-experiment.yml +++ b/.github/workflows/endform-experiment.yml @@ -10,7 +10,7 @@ permissions: jobs: baseline: if: github.repository == 'endformdev/n8n' - name: '${{ matrix.runner }}: one home-page test' + name: '${{ matrix.runner }}: workflow entry points' runs-on: ubuntu-latest timeout-minutes: 45 strategy: @@ -56,14 +56,14 @@ jobs: working-directory: packages/testing/playwright run: pnpm exec playwright install chromium --with-deps - - name: Run one existing test + - name: Run workflow entry points working-directory: packages/testing/playwright env: TEST_RUNNER: '${{ matrix.runner }}' E2E_REMOTE_RUNNER: "${{ matrix.runner == 'endform' && 'true' || 'false' }}" ENDFORM_API_KEY: "${{ matrix.runner == 'endform' && secrets.ENDFORM_API_KEY || '' }}" run: | - args=(test --project=e2e tests/e2e/building-blocks/workflow-entry-points.spec.ts --grep='should navigate from home$' --retries=0) + args=(test --project=e2e tests/e2e/building-blocks/workflow-entry-points.spec.ts --retries=0) if [ "$TEST_RUNNER" = endform ]; then args+=(--organization-id=2G1ZCj7X) else From fa9422cae698b779fda83621ad8ee060ed6fff98 Mon Sep 17 00:00:00 2001 From: Augusto Silva Date: Fri, 11 Sep 2026 10:26:38 +0200 Subject: [PATCH 07/23] test: include workflow fixtures in Endform uploads Both import tests failed because their JSON files were missing on remote runners. Include the workflows directory so runtime file reads can find the fixtures. --- packages/testing/playwright/endform.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/testing/playwright/endform.config.ts b/packages/testing/playwright/endform.config.ts index 3c2ff616a566..16858702d016 100644 --- a/packages/testing/playwright/endform.config.ts +++ b/packages/testing/playwright/endform.config.ts @@ -2,6 +2,7 @@ import { defineEndformConfig } from 'endform'; export default defineEndformConfig({ + additionalFiles: ['workflows/**/*'], concurrentTestLimits: [{ scope: 'within-suite-run', limit: 1 }], environmentVariables: ['N8N_BASE_URL', 'RESET_E2E_DB', 'E2E_REMOTE_RUNNER'], }); From 369ae98b16f61ee31afc4bac8bbe6881a215da7e Mon Sep 17 00:00:00 2001 From: Augusto Silva Date: Fri, 11 Sep 2026 10:36:10 +0200 Subject: [PATCH 08/23] ci: add credential CRUD to the Endform comparison Both runners passed all five workflow entry-point tests. Add the existing credential CRUD spec for 19 tests total. --- .github/workflows/endform-experiment.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/endform-experiment.yml b/.github/workflows/endform-experiment.yml index 943c1fd132f6..65d6ab4ca0f6 100644 --- a/.github/workflows/endform-experiment.yml +++ b/.github/workflows/endform-experiment.yml @@ -10,7 +10,7 @@ permissions: jobs: baseline: if: github.repository == 'endformdev/n8n' - name: '${{ matrix.runner }}: workflow entry points' + name: '${{ matrix.runner }}: entry points and credentials' runs-on: ubuntu-latest timeout-minutes: 45 strategy: @@ -56,14 +56,14 @@ jobs: working-directory: packages/testing/playwright run: pnpm exec playwright install chromium --with-deps - - name: Run workflow entry points + - name: Run entry points and credentials working-directory: packages/testing/playwright env: TEST_RUNNER: '${{ matrix.runner }}' E2E_REMOTE_RUNNER: "${{ matrix.runner == 'endform' && 'true' || 'false' }}" ENDFORM_API_KEY: "${{ matrix.runner == 'endform' && secrets.ENDFORM_API_KEY || '' }}" run: | - args=(test --project=e2e tests/e2e/building-blocks/workflow-entry-points.spec.ts --retries=0) + args=(test --project=e2e tests/e2e/building-blocks/workflow-entry-points.spec.ts tests/e2e/credentials/crud.spec.ts --retries=0) if [ "$TEST_RUNNER" = endform ]; then args+=(--organization-id=2G1ZCj7X) else From fa77113a37db0ea07a9a0484cab0aee8d88a8cc1 Mon Sep 17 00:00:00 2001 From: Augusto Silva Date: Fri, 11 Sep 2026 11:10:34 +0200 Subject: [PATCH 09/23] test: run two Endform tests concurrently Both runners passed all 19 tests with serial execution. Raise the Endform concurrency limit from one to two. --- packages/testing/playwright/endform.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/testing/playwright/endform.config.ts b/packages/testing/playwright/endform.config.ts index 16858702d016..4af60ea8d983 100644 --- a/packages/testing/playwright/endform.config.ts +++ b/packages/testing/playwright/endform.config.ts @@ -3,6 +3,6 @@ import { defineEndformConfig } from 'endform'; export default defineEndformConfig({ additionalFiles: ['workflows/**/*'], - concurrentTestLimits: [{ scope: 'within-suite-run', limit: 1 }], + concurrentTestLimits: [{ scope: 'within-suite-run', limit: 2 }], environmentVariables: ['N8N_BASE_URL', 'RESET_E2E_DB', 'E2E_REMOTE_RUNNER'], }); From 202182f05ab0f080b4c934b7953fbdc9abb4b2bb Mon Sep 17 00:00:00 2001 From: Augusto Silva Date: Fri, 11 Sep 2026 11:43:09 +0200 Subject: [PATCH 10/23] test: run four Endform tests concurrently All 19 tests passed with two concurrent Endform tests. Raise the limit to four to check parallel execution --- packages/testing/playwright/endform.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/testing/playwright/endform.config.ts b/packages/testing/playwright/endform.config.ts index 4af60ea8d983..5a8b07c14d23 100644 --- a/packages/testing/playwright/endform.config.ts +++ b/packages/testing/playwright/endform.config.ts @@ -3,6 +3,6 @@ import { defineEndformConfig } from 'endform'; export default defineEndformConfig({ additionalFiles: ['workflows/**/*'], - concurrentTestLimits: [{ scope: 'within-suite-run', limit: 2 }], + concurrentTestLimits: [{ scope: 'within-suite-run', limit: 4 }], environmentVariables: ['N8N_BASE_URL', 'RESET_E2E_DB', 'E2E_REMOTE_RUNNER'], }); From f4e4f69ff1787648de805ddb1f0664308ea397d9 Mon Sep 17 00:00:00 2001 From: Augusto Silva Date: Fri, 11 Sep 2026 11:58:12 +0200 Subject: [PATCH 11/23] test: add canvas actions Both runners passed all 19 tests at Endform concurrency four. Add nine existing tests for node search and canvas actions. --- .github/workflows/endform-experiment.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/endform-experiment.yml b/.github/workflows/endform-experiment.yml index 65d6ab4ca0f6..78a16c7b18b8 100644 --- a/.github/workflows/endform-experiment.yml +++ b/.github/workflows/endform-experiment.yml @@ -10,7 +10,7 @@ permissions: jobs: baseline: if: github.repository == 'endformdev/n8n' - name: '${{ matrix.runner }}: entry points and credentials' + name: '${{ matrix.runner }}: entry points, credentials, and canvas' runs-on: ubuntu-latest timeout-minutes: 45 strategy: @@ -56,14 +56,14 @@ jobs: working-directory: packages/testing/playwright run: pnpm exec playwright install chromium --with-deps - - name: Run entry points and credentials + - name: Run entry points, credentials, and canvas working-directory: packages/testing/playwright env: TEST_RUNNER: '${{ matrix.runner }}' E2E_REMOTE_RUNNER: "${{ matrix.runner == 'endform' && 'true' || 'false' }}" ENDFORM_API_KEY: "${{ matrix.runner == 'endform' && secrets.ENDFORM_API_KEY || '' }}" run: | - args=(test --project=e2e tests/e2e/building-blocks/workflow-entry-points.spec.ts tests/e2e/credentials/crud.spec.ts --retries=0) + args=(test --project=e2e tests/e2e/building-blocks/workflow-entry-points.spec.ts tests/e2e/credentials/crud.spec.ts tests/e2e/building-blocks/canvas-actions.spec.ts --retries=0) if [ "$TEST_RUNNER" = endform ]; then args+=(--organization-id=2G1ZCj7X) else From 67978daa77d2b9731c4613524c6fac3d9c7f276e Mon Sep 17 00:00:00 2001 From: Augusto Silva Date: Fri, 11 Sep 2026 12:16:37 +0200 Subject: [PATCH 12/23] test: add node configuration Both runners passed all 28 tests. Add seven tests for parameter inputs and field assignments. --- .github/workflows/endform-experiment.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/endform-experiment.yml b/.github/workflows/endform-experiment.yml index 78a16c7b18b8..7fbc078f6447 100644 --- a/.github/workflows/endform-experiment.yml +++ b/.github/workflows/endform-experiment.yml @@ -10,7 +10,7 @@ permissions: jobs: baseline: if: github.repository == 'endformdev/n8n' - name: '${{ matrix.runner }}: entry points, credentials, and canvas' + name: '${{ matrix.runner }}: entry points, credentials, canvas, and node configuration' runs-on: ubuntu-latest timeout-minutes: 45 strategy: @@ -56,14 +56,14 @@ jobs: working-directory: packages/testing/playwright run: pnpm exec playwright install chromium --with-deps - - name: Run entry points, credentials, and canvas + - name: Run entry points, credentials, canvas, and node configuration working-directory: packages/testing/playwright env: TEST_RUNNER: '${{ matrix.runner }}' E2E_REMOTE_RUNNER: "${{ matrix.runner == 'endform' && 'true' || 'false' }}" ENDFORM_API_KEY: "${{ matrix.runner == 'endform' && secrets.ENDFORM_API_KEY || '' }}" run: | - args=(test --project=e2e tests/e2e/building-blocks/workflow-entry-points.spec.ts tests/e2e/credentials/crud.spec.ts tests/e2e/building-blocks/canvas-actions.spec.ts --retries=0) + args=(test --project=e2e tests/e2e/building-blocks/workflow-entry-points.spec.ts tests/e2e/credentials/crud.spec.ts tests/e2e/building-blocks/canvas-actions.spec.ts tests/e2e/building-blocks/node-details-configuration.spec.ts --retries=0) if [ "$TEST_RUNNER" = endform ]; then args+=(--organization-id=2G1ZCj7X) else From 677170b6501770baa9d8d86684832fd0979102cb Mon Sep 17 00:00:00 2001 From: Augusto Silva Date: Fri, 11 Sep 2026 12:35:15 +0200 Subject: [PATCH 13/23] test: add workflow execution to the Endform experiment Both runners passed all 35 tests. Add nine active tests for manual, webhook, and partial execution. --- .github/workflows/endform-experiment.yml | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/.github/workflows/endform-experiment.yml b/.github/workflows/endform-experiment.yml index 7fbc078f6447..6ebd114149e6 100644 --- a/.github/workflows/endform-experiment.yml +++ b/.github/workflows/endform-experiment.yml @@ -10,7 +10,7 @@ permissions: jobs: baseline: if: github.repository == 'endformdev/n8n' - name: '${{ matrix.runner }}: entry points, credentials, canvas, and node configuration' + name: '${{ matrix.runner }}: incremental suite' runs-on: ubuntu-latest timeout-minutes: 45 strategy: @@ -56,14 +56,22 @@ jobs: working-directory: packages/testing/playwright run: pnpm exec playwright install chromium --with-deps - - name: Run entry points, credentials, canvas, and node configuration + - name: Run incremental suite working-directory: packages/testing/playwright env: TEST_RUNNER: '${{ matrix.runner }}' E2E_REMOTE_RUNNER: "${{ matrix.runner == 'endform' && 'true' || 'false' }}" ENDFORM_API_KEY: "${{ matrix.runner == 'endform' && secrets.ENDFORM_API_KEY || '' }}" run: | - args=(test --project=e2e tests/e2e/building-blocks/workflow-entry-points.spec.ts tests/e2e/credentials/crud.spec.ts tests/e2e/building-blocks/canvas-actions.spec.ts tests/e2e/building-blocks/node-details-configuration.spec.ts --retries=0) + args=( + test --project=e2e + tests/e2e/building-blocks/workflow-entry-points.spec.ts + tests/e2e/credentials/crud.spec.ts + tests/e2e/building-blocks/canvas-actions.spec.ts + tests/e2e/building-blocks/node-details-configuration.spec.ts + tests/e2e/workflows/editor/execution/execution.spec.ts + --retries=0 + ) if [ "$TEST_RUNNER" = endform ]; then args+=(--organization-id=2G1ZCj7X) else From d4b266ea020d950a2feffdeaacbea90de9c7d922 Mon Sep 17 00:00:00 2001 From: Augusto Silva Date: Fri, 11 Sep 2026 13:49:37 +0200 Subject: [PATCH 14/23] test: add user sessions to the Endform experiment Both runners passed all 44 active tests. Add eight tests for API authentication and separate user sessions. --- .github/workflows/endform-experiment.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/endform-experiment.yml b/.github/workflows/endform-experiment.yml index 6ebd114149e6..d2c3ab55c41b 100644 --- a/.github/workflows/endform-experiment.yml +++ b/.github/workflows/endform-experiment.yml @@ -70,6 +70,7 @@ jobs: tests/e2e/building-blocks/canvas-actions.spec.ts tests/e2e/building-blocks/node-details-configuration.spec.ts tests/e2e/workflows/editor/execution/execution.spec.ts + tests/e2e/building-blocks/user-service.spec.ts --retries=0 ) if [ "$TEST_RUNNER" = endform ]; then From 7fa3c2845fba3a65aaa15fbac01f9f247f4ffc39 Mon Sep 17 00:00:00 2001 From: Augusto Silva Date: Fri, 11 Sep 2026 14:19:36 +0200 Subject: [PATCH 15/23] test: allow 90 seconds for remote test execution The session test exceeded 60 seconds on Endform. Its five page loads took about 50 seconds in total. All role assertions completed without errors in the trace. Raise the remote test budget to 90 seconds. --- packages/testing/playwright/playwright.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/testing/playwright/playwright.config.ts b/packages/testing/playwright/playwright.config.ts index 8cbf16ed60fd..925920c83f18 100644 --- a/packages/testing/playwright/playwright.config.ts +++ b/packages/testing/playwright/playwright.config.ts @@ -112,7 +112,7 @@ export default defineConfig({ forbidOnly: IS_CI, retries: IS_CI ? 2 : 0, workers: WORKERS, - timeout: 60000, + timeout: process.env.E2E_REMOTE_RUNNER === 'true' ? 90000 : 60000, expect: { timeout: EXPECT_TIMEOUT, }, From 1fd9ae9c21ac96ea659a730073c566b1b9d23225 Mon Sep 17 00:00:00 2001 From: Augusto Silva Date: Fri, 11 Sep 2026 14:49:19 +0200 Subject: [PATCH 16/23] test: compare runners at concurrency four Both runners passed all 52 active tests. Increase Playwright from one worker to four. Keep Endform concurrency and the test set unchanged. --- .github/workflows/endform-experiment.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/endform-experiment.yml b/.github/workflows/endform-experiment.yml index d2c3ab55c41b..bab1bfa73d5c 100644 --- a/.github/workflows/endform-experiment.yml +++ b/.github/workflows/endform-experiment.yml @@ -76,7 +76,7 @@ jobs: if [ "$TEST_RUNNER" = endform ]; then args+=(--organization-id=2G1ZCj7X) else - args+=(--workers=1) + args+=(--workers=4) fi pnpm exec "$TEST_RUNNER" "${args[@]}" > experiment.log 2>&1 From 5bb503dc0a02d7df885606722eaf390dc4b3f734 Mon Sep 17 00:00:00 2001 From: Augusto Silva Date: Mon, 14 Sep 2026 09:37:29 +0200 Subject: [PATCH 17/23] test: match navigation limits in the runner comparison Three Playwright tests exceeded the 10-second navigation limit with four workers. Endform passed with a 30-second limit. Set a 30-second navigation limit for both experiment runners. --- .github/workflows/endform-experiment.yml | 1 + packages/testing/playwright/playwright.config.ts | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/endform-experiment.yml b/.github/workflows/endform-experiment.yml index bab1bfa73d5c..7ac95e3a31f6 100644 --- a/.github/workflows/endform-experiment.yml +++ b/.github/workflows/endform-experiment.yml @@ -60,6 +60,7 @@ jobs: working-directory: packages/testing/playwright env: TEST_RUNNER: '${{ matrix.runner }}' + E2E_NAVIGATION_TIMEOUT: '30000' E2E_REMOTE_RUNNER: "${{ matrix.runner == 'endform' && 'true' || 'false' }}" ENDFORM_API_KEY: "${{ matrix.runner == 'endform' && secrets.ENDFORM_API_KEY || '' }}" run: | diff --git a/packages/testing/playwright/playwright.config.ts b/packages/testing/playwright/playwright.config.ts index 925920c83f18..6cdb881a650b 100644 --- a/packages/testing/playwright/playwright.config.ts +++ b/packages/testing/playwright/playwright.config.ts @@ -130,7 +130,10 @@ export default defineConfig({ headless: process.env.SHOW_BROWSER !== 'true', viewport: MACBOOK_WINDOW_SIZE, actionTimeout: 20000, // TODO: We might need to make this dynamic for container tests if we have low resource containers etc - navigationTimeout: process.env.E2E_REMOTE_RUNNER === 'true' ? 30000 : 10000, + navigationTimeout: Number( + process.env.E2E_NAVIGATION_TIMEOUT ?? + (process.env.E2E_REMOTE_RUNNER === 'true' ? 30000 : 10000), + ), currentsFixturesEnabled: !!process.env.CI, }, From 7adea29b0c0c374a757b0d2bdb8a545080428b06 Mon Sep 17 00:00:00 2001 From: Augusto Silva Date: Mon, 14 Sep 2026 10:10:41 +0200 Subject: [PATCH 18/23] test: narrow global request interception URL predicate handlers make Playwright intercept every request. Replace the health and version predicates with URL patterns. Keep their path matching and mocked responses unchanged. --- .../testing/playwright/config/intercepts.ts | 66 +++++++++---------- 1 file changed, 32 insertions(+), 34 deletions(-) diff --git a/packages/testing/playwright/config/intercepts.ts b/packages/testing/playwright/config/intercepts.ts index c67979285c08..50ec5fb5090d 100644 --- a/packages/testing/playwright/config/intercepts.ts +++ b/packages/testing/playwright/config/intercepts.ts @@ -116,8 +116,9 @@ export async function setupDefaultInterceptors(target: BrowserContext) { }); // Pathname /api/health + // Use URL patterns so Playwright does not intercept unrelated asset requests. await target.route( - (url) => url.pathname.endsWith('/api/health'), + /^https?:\/\/[^/?#]+\/(?:[^?#]*\/)?api\/health(?:[?#].*)?$/, async (route: Route) => { await route.fulfill({ contentType: 'application/json', @@ -127,37 +128,34 @@ export async function setupDefaultInterceptors(target: BrowserContext) { ); // Pathname /api/versions/* - await target.route( - (url) => url.pathname.startsWith('/api/versions/'), - async (route: Route) => { - await route.fulfill({ - contentType: 'application/json', - body: JSON.stringify([ - { - name: '1.45.1', - createdAt: '2023-08-18T11:53:12.857Z', - hasSecurityIssue: null, - hasSecurityFix: null, - securityIssueFixVersion: null, - hasBreakingChange: null, - documentationUrl: 'https://docs.n8n.io/release-notes/#n8n131', - nodes: [], - description: 'Includes bug fixes', - }, - { - name: '1.0.5', - createdAt: '2023-07-24T10:54:56.097Z', - hasSecurityIssue: false, - hasSecurityFix: null, - securityIssueFixVersion: null, - hasBreakingChange: true, - documentationUrl: 'https://docs.n8n.io/release-notes/#n8n104', - nodes: [], - description: - 'Includes core functionality and bug fixes', - }, - ]), - }); - }, - ); + await target.route(/^https?:\/\/[^/?#]+\/api\/versions\//, async (route: Route) => { + await route.fulfill({ + contentType: 'application/json', + body: JSON.stringify([ + { + name: '1.45.1', + createdAt: '2023-08-18T11:53:12.857Z', + hasSecurityIssue: null, + hasSecurityFix: null, + securityIssueFixVersion: null, + hasBreakingChange: null, + documentationUrl: 'https://docs.n8n.io/release-notes/#n8n131', + nodes: [], + description: 'Includes bug fixes', + }, + { + name: '1.0.5', + createdAt: '2023-07-24T10:54:56.097Z', + hasSecurityIssue: false, + hasSecurityFix: null, + securityIssueFixVersion: null, + hasBreakingChange: true, + documentationUrl: 'https://docs.n8n.io/release-notes/#n8n104', + nodes: [], + description: + 'Includes core functionality and bug fixes', + }, + ]), + }); + }); } From 0152328ebe602450c8d1379b7fb34799e75908ce Mon Sep 17 00:00:00 2001 From: Augusto Silva Date: Mon, 14 Sep 2026 10:39:02 +0200 Subject: [PATCH 19/23] test: isolate Endform catch-all routing overhead The session trace still records 1,407 request continuations. A catch-all handler adds trace headers to browser requests. Remove that handler only in the Endform experiment. Keep targeted mocks and Playwright traces. Use the next run to measure its cost. --- .github/workflows/endform-experiment.yml | 1 + packages/testing/playwright/fixtures/base.ts | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/.github/workflows/endform-experiment.yml b/.github/workflows/endform-experiment.yml index 7ac95e3a31f6..c2750fff5967 100644 --- a/.github/workflows/endform-experiment.yml +++ b/.github/workflows/endform-experiment.yml @@ -61,6 +61,7 @@ jobs: env: TEST_RUNNER: '${{ matrix.runner }}' E2E_NAVIGATION_TIMEOUT: '30000' + E2E_DISABLE_CATCH_ALL_ROUTE: "${{ matrix.runner == 'endform' && 'true' || 'false' }}" E2E_REMOTE_RUNNER: "${{ matrix.runner == 'endform' && 'true' || 'false' }}" ENDFORM_API_KEY: "${{ matrix.runner == 'endform' && secrets.ENDFORM_API_KEY || '' }}" run: | diff --git a/packages/testing/playwright/fixtures/base.ts b/packages/testing/playwright/fixtures/base.ts index 5a9503532d45..f11601ce727d 100644 --- a/packages/testing/playwright/fixtures/base.ts +++ b/packages/testing/playwright/fixtures/base.ts @@ -214,6 +214,10 @@ export const test = base.extend< }, n8n: async ({ context, backendUrl, frontendUrl }, use, testInfo) => { + if (process.env.E2E_DISABLE_CATCH_ALL_ROUTE === 'true') { + // Measure catch-all routing overhead while retaining the targeted API mocks. + await context.unroute('**'); + } await setupDefaultInterceptors(context); const page = await context.newPage(); From 8047373360701d3f9ecd30635e106d6b07348e04 Mon Sep 17 00:00:00 2001 From: Augusto Silva Date: Mon, 14 Sep 2026 11:58:42 +0200 Subject: [PATCH 20/23] test: restore tracing after the routing experiment The trace confirms catch-all routing was removed. Request continuations fell from 1,407 to zero. Suite duration changed only from 8.2 to 8.1 minutes. Remove the diagnostic override. Restore normal tracing because no material speed gain was shown. --- .github/workflows/endform-experiment.yml | 1 - packages/testing/playwright/fixtures/base.ts | 4 ---- 2 files changed, 5 deletions(-) diff --git a/.github/workflows/endform-experiment.yml b/.github/workflows/endform-experiment.yml index c2750fff5967..7ac95e3a31f6 100644 --- a/.github/workflows/endform-experiment.yml +++ b/.github/workflows/endform-experiment.yml @@ -61,7 +61,6 @@ jobs: env: TEST_RUNNER: '${{ matrix.runner }}' E2E_NAVIGATION_TIMEOUT: '30000' - E2E_DISABLE_CATCH_ALL_ROUTE: "${{ matrix.runner == 'endform' && 'true' || 'false' }}" E2E_REMOTE_RUNNER: "${{ matrix.runner == 'endform' && 'true' || 'false' }}" ENDFORM_API_KEY: "${{ matrix.runner == 'endform' && secrets.ENDFORM_API_KEY || '' }}" run: | diff --git a/packages/testing/playwright/fixtures/base.ts b/packages/testing/playwright/fixtures/base.ts index f11601ce727d..5a9503532d45 100644 --- a/packages/testing/playwright/fixtures/base.ts +++ b/packages/testing/playwright/fixtures/base.ts @@ -214,10 +214,6 @@ export const test = base.extend< }, n8n: async ({ context, backendUrl, frontendUrl }, use, testInfo) => { - if (process.env.E2E_DISABLE_CATCH_ALL_ROUTE === 'true') { - // Measure catch-all routing overhead while retaining the targeted API mocks. - await context.unroute('**'); - } await setupDefaultInterceptors(context); const page = await context.newPage(); From d1bb77c54f4c8889ee80f48638e43a8db04632a6 Mon Sep 17 00:00:00 2001 From: Augusto Silva Date: Mon, 14 Sep 2026 12:08:31 +0200 Subject: [PATCH 21/23] test: measure video recording overhead Page-load traces show delays beyond the main asset transfers. Disable video recording for both experiment runners. Keep traces, screenshots, tests, concurrency and timeouts unchanged. Use the next run to measure recording overhead. Preserve video recording by default outside the experiment. --- .github/workflows/endform-experiment.yml | 1 + packages/testing/playwright/playwright.config.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/endform-experiment.yml b/.github/workflows/endform-experiment.yml index 7ac95e3a31f6..58db12b3482e 100644 --- a/.github/workflows/endform-experiment.yml +++ b/.github/workflows/endform-experiment.yml @@ -61,6 +61,7 @@ jobs: env: TEST_RUNNER: '${{ matrix.runner }}' E2E_NAVIGATION_TIMEOUT: '30000' + E2E_RECORD_VIDEO: 'false' E2E_REMOTE_RUNNER: "${{ matrix.runner == 'endform' && 'true' || 'false' }}" ENDFORM_API_KEY: "${{ matrix.runner == 'endform' && secrets.ENDFORM_API_KEY || '' }}" run: | diff --git a/packages/testing/playwright/playwright.config.ts b/packages/testing/playwright/playwright.config.ts index 6cdb881a650b..aa460497dcdf 100644 --- a/packages/testing/playwright/playwright.config.ts +++ b/packages/testing/playwright/playwright.config.ts @@ -124,7 +124,7 @@ export default defineConfig({ use: { baseURL: WEB_SERVER_URL, trace: 'on', - video: 'on', + video: process.env.E2E_RECORD_VIDEO === 'false' ? 'off' : 'on', screenshot: 'on', testIdAttribute: 'data-test-id', headless: process.env.SHOW_BROWSER !== 'true', From 9cfad6f83977dab06b0392bea6792cc44b5ecbd5 Mon Sep 17 00:00:00 2001 From: Augusto Silva Date: Mon, 14 Sep 2026 13:36:44 +0200 Subject: [PATCH 22/23] test: restore video after the performance experiment Disabling video showed no Endform runtime improvement. Remove the experimental switch and restore recording. Preserve debugging evidence while investigating page-load delays. --- .github/workflows/endform-experiment.yml | 1 - packages/testing/playwright/playwright.config.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/endform-experiment.yml b/.github/workflows/endform-experiment.yml index 58db12b3482e..7ac95e3a31f6 100644 --- a/.github/workflows/endform-experiment.yml +++ b/.github/workflows/endform-experiment.yml @@ -61,7 +61,6 @@ jobs: env: TEST_RUNNER: '${{ matrix.runner }}' E2E_NAVIGATION_TIMEOUT: '30000' - E2E_RECORD_VIDEO: 'false' E2E_REMOTE_RUNNER: "${{ matrix.runner == 'endform' && 'true' || 'false' }}" ENDFORM_API_KEY: "${{ matrix.runner == 'endform' && secrets.ENDFORM_API_KEY || '' }}" run: | diff --git a/packages/testing/playwright/playwright.config.ts b/packages/testing/playwright/playwright.config.ts index aa460497dcdf..6cdb881a650b 100644 --- a/packages/testing/playwright/playwright.config.ts +++ b/packages/testing/playwright/playwright.config.ts @@ -124,7 +124,7 @@ export default defineConfig({ use: { baseURL: WEB_SERVER_URL, trace: 'on', - video: process.env.E2E_RECORD_VIDEO === 'false' ? 'off' : 'on', + video: 'on', screenshot: 'on', testIdAttribute: 'data-test-id', headless: process.env.SHOW_BROWSER !== 'true', From a67ff8c15c0cf4b3a1f4274f68c30512294ec1fa Mon Sep 17 00:00:00 2001 From: Augusto Silva Date: Mon, 14 Sep 2026 13:44:35 +0200 Subject: [PATCH 23/23] test: record backend capacity during runner comparisons Capture host and process resource usage during the test step. Record the backend listener PID to identify n8n usage. Preserve measurements with the existing run artifacts. Keep concurrency at four to establish a scaling baseline. --- .github/workflows/endform-experiment.yml | 32 ++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/.github/workflows/endform-experiment.yml b/.github/workflows/endform-experiment.yml index 7ac95e3a31f6..2e04c3d0ecc5 100644 --- a/.github/workflows/endform-experiment.yml +++ b/.github/workflows/endform-experiment.yml @@ -56,6 +56,11 @@ jobs: working-directory: packages/testing/playwright run: pnpm exec playwright install chromium --with-deps + - name: Install resource monitor + run: | + sudo apt-get update -qq + sudo apt-get install -y sysstat procps iproute2 + - name: Run incremental suite working-directory: packages/testing/playwright env: @@ -64,6 +69,30 @@ jobs: E2E_REMOTE_RUNNER: "${{ matrix.runner == 'endform' && 'true' || 'false' }}" ENDFORM_API_KEY: "${{ matrix.runner == 'endform' && secrets.ENDFORM_API_KEY || '' }}" run: | + export TZ=UTC + { + echo "Logical CPUs: $(nproc)" + free -m + echo 'The first vmstat sample contains averages since boot.' + } > host-resources.log + vmstat -w -t 5 >> host-resources.log & + host_monitor_pid=$! + pidstat -h -u -r -d -p ALL 5 > process-resources.log & + process_monitor_pid=$! + ( + while true; do + date -u '+%Y-%m-%dT%H:%M:%SZ' + ss -ltnp 'sport = :5680' + sleep 5 + done + ) > backend-listener.log & + listener_monitor_pid=$! + stop_monitors() { + kill "$host_monitor_pid" "$process_monitor_pid" "$listener_monitor_pid" 2>/dev/null || true + wait "$host_monitor_pid" "$process_monitor_pid" "$listener_monitor_pid" 2>/dev/null || true + } + trap stop_monitors EXIT + args=( test --project=e2e tests/e2e/building-blocks/workflow-entry-points.spec.ts @@ -103,6 +132,9 @@ jobs: packages/testing/playwright/experiment.log packages/testing/playwright/typecheck.log packages/testing/playwright/lint.log + packages/testing/playwright/host-resources.log + packages/testing/playwright/process-resources.log + packages/testing/playwright/backend-listener.log packages/testing/playwright/test-results/ packages/testing/playwright/test-results.json packages/testing/playwright/playwright-report/