Skip to content

test(core): Add editor-only Docker build and local proxy for faster testing (no-changelog)#28569

Closed
mutdmour wants to merge 40 commits intomasterfrom
easier-testing
Closed

test(core): Add editor-only Docker build and local proxy for faster testing (no-changelog)#28569
mutdmour wants to merge 40 commits intomasterfrom
easier-testing

Conversation

@mutdmour
Copy link
Copy Markdown
Contributor

@mutdmour mutdmour commented Apr 16, 2026

Summary

Two independent improvements to speed up instance-AI Playwright testing iteration:

1. pnpm build:docker:editor — Editor-only Docker rebuild

Rebuilds only editor-ui (and its workspace deps like design-system, i18n) and patches the existing compiled/ directory, then re-dockerizes. Skips the full monorepo build and pnpm deploy step.

  • Requires a previous pnpm build:docker to establish the compiled/ directory
  • ~3x faster than full rebuild (1.5 min vs 4.5 min, even faster with warm turbo cache)
  • Safe because editor-ui dist is pure static assets served by Express

2. pnpm test:local:instance-ai --proxy — Record/replay against local server

Starts a standalone MockServer Docker container alongside the local n8n process, enabling record/replay of Anthropic API calls without the full container stack.

  • --proxy flag starts MockServer, wires HTTP_PROXY/HTTPS_PROXY to n8n, passes PROXY_SERVER_URL to Playwright
  • Recording mode: ANTHROPIC_API_KEY=sk-ant-... pnpm test:local:instance-ai --proxy
  • Replay mode (no API key): pnpm test:local:instance-ai --proxy
  • Container is cleaned up automatically on exit (SIGINT/SIGTERM)
  • Existing behavior without --proxy is unchanged

Files changed

File Change
scripts/build-docker-editor.mjs New — editor-only build + dockerize
package.json Add build:docker:editor script
packages/testing/playwright/scripts/run-local-instance-ai.mjs --proxy flag, MockServer lifecycle
packages/testing/playwright/scripts/run-local-isolated.mjs Pass through PROXY_SERVER_URL
packages/testing/playwright/fixtures/base.ts Local-mode proxy support in services fixture
packages/testing/playwright/tests/e2e/instance-ai/fixtures.ts Guard proxy setup for local-no-proxy mode
packages/testing/containers/index.ts Export ProxyServer

Related Linear tickets, Github issues, and Community forum posts

Review / Merge checklist

  • I have seen this code, I have run this code, and I take responsibility for this code.
  • PR title and summary are descriptive. (conventions)
  • Docs updated or follow-up ticket created.
  • Tests included.
  • PR Labeled with Backport to Beta, Backport to Stable, or Backport to v1 (if the PR is an urgent fix that needs to be backported)

🤖 PR Summary generated by AI

mutdmour and others added 30 commits April 10, 2026 13:43
Add canExecute prop to WorkflowPreview, include as query param on
iframe URL. DemoLayout conditionally establishes a WebSocket push
connection when canExecute=true. Refactor importWorkflowExact to no
longer override workflow ID to 'demo' — the ID override is moved to
callers in usePostMessageHandler so the real workflow ID flows through
when execution is enabled.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Update canExecuteOnCanvas to return true on demo route when
canExecute=true query param is present. Add canExecute prop to Canvas
and WorkflowCanvas, thread from NodeView. Add ctrl+enter shortcut
to read-only+executable keymap.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Thread canExecute prop through Canvas → CanvasNode → CanvasNodeToolbar.
Execute button visible when readOnly && canExecute. Delete, disable, and
other toolbar buttons remain hidden in read-only mode.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When NDV opens in read-only mode and the node has execution data,
default to the Output tab instead of Parameters. Avoids a flash of
disabled parameters before switching.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…utton

Show run button as disabled with tooltip when workflow has only a Chat
Trigger in the preview context. Error display and concurrent execution
handling work automatically via existing canvas node badges and iframe
executionStarted handler.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove type icons from tab labels, make tabs fill full header height,
and replace loading spinners with larger loader-circle icon (80px).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…g (no-changelog)

Adds a Playwright e2e test that captures the bug where the last node in
the instance AI workflow preview stays in "running" state (spinning
border) after execution completes. The test sends a specific prompt to
build and execute a 3-node workflow, then asserts that no canvas nodes
remain with the .running CSS class.

Includes InstanceAiPage page object, navigation helper, and test
fixtures with N8N_ENABLED_MODULES=instance-ai.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ionFinished (no-changelog)

The event relay watcher only forwarded the last event in the log, so when
Vue coalesced multiple ref updates into one callback, intermediate events
(e.g. nodeExecuteAfter for the last node) were silently dropped. This left
the iframe's executing-node queue with a stale entry, keeping the last node
in spinning/running state after the workflow finished.

- Track relayed event count so every new event is forwarded, even when the
  watcher fires once for multiple log additions.
- Keep the eventLog intact when executionFinished arrives (instead of
  clearing it immediately) so the relay can forward pending events before
  sending the synthetic executionFinished.
- Add clearEventLog() to useExecutionPushEvents, called by the relay after
  all pending events have been forwarded.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add 16 Playwright e2e tests across 6 spec files covering instance AI
workflow preview, artifacts, timeline, sidebar, confirmations, and
chat basics. Wire up proxy-aware fetch in the AI SDK model creation
so MockServer can intercept Anthropic API calls for recording/replay.

- Expand InstanceAiPage page object with 30+ locators
- Add InstanceAiSidebar component page object
- Add data-test-id to preview close button
- Add getProxyFetch() to model-factory.ts and instance-ai.service.ts
  so @ai-sdk/anthropic respects HTTP_PROXY in e2e containers
- Rewrite fixtures with proxy service recording support
- Replace single execution-state test with comprehensive suite

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…hangelog)

Add two-tier trace replay system that records tool I/O during e2e test
recording and replays with bidirectional ID remapping in CI. This enables
deterministic replay of complex multi-step agent tests where tool execution
produces dynamic IDs.

- New trace-replay.ts: IdRemapper (ID-field-aware), TraceIndex (per-role
  cursors), TraceWriter, JSONL I/O helpers, PURE_REPLAY_TOOLS set
- Modified langsmith-tracing.ts: replayWrapTool (Tier 1: real execution +
  ID remap), pureReplayWrapTool (Tier 2: pure replay for external deps),
  recordWrapTool, createTraceReplayOnlyContext stub for non-LangSmith envs
- New test-only controller endpoints: POST/GET/DELETE /test/tool-trace
  with slug-scoped storage for parallel test isolation
- Updated fixture: records trace.jsonl during recording, loads for replay,
  slug-scoped activate/retrieve/clear lifecycle
- 23 unit tests for IdRemapper and TraceIndex
- Recorded trace.jsonl files for all 15 instance AI test expectations

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…log)

Add subString body matching on the system prompt to disambiguate LLM call
types (title generation vs orchestrator vs sub-agent) during proxy replay.
Without this, sequential expectations could be served to the wrong call
when the call order differs between recording and replay.

Re-record all expectations with the body matcher and remove debug logging
from trace replay wrappers.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When re-recording with a real API key, always use record mode (never
load old trace events into the backend). Previously, existing trace
files would cause the backend to enter replay mode during re-recording,
resulting in trace.jsonl files with only a header and no tool calls.

Re-record all trace.jsonl files with proper tool call events.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Re-record all proxy expectations after fixing the recording mode logic.
Expectations now have subString body matchers on the system prompt and
trace.jsonl files have proper tool call events.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The proxy's sequential mode sets the last expectation as unlimited (fallback
for extra agent turns). Previously this applied to the last file alphabetically
which could be a community_nodes GET. Now it finds the last /v1/messages
POST expectation specifically.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…elog)

Background task completion triggers `startInternalFollowUpRun`, which
creates a new trace context. Previously each context got a fresh
TraceIndex with cursor at 0, so the follow-up run's first tool call
(e.g. list-workflows) would mismatch the first trace event
(build-workflow-with-agent) and throw.

Fix: store a shared TraceIndex/IdRemapper per test slug on the service.
All runs within the same slug reuse the same instances, preserving
cursor state across the initial run and any follow-up runs.

This fixes the two confirmation e2e tests that rely on suspend/resume.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…(no-changelog)

waitForAssistantResponse only waited for the first message element to appear
(streaming start), not for the agent to finish. Sidebar operations then raced
against the still-running agent. New waitForResponseComplete waits for the send
button to reappear, which only renders when isStreaming becomes false.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…s between tests (no-changelog)

Two preview tests failed because their recorded proxy expectations contained
stale LLM responses from previous tests' background task follow-ups. The
fixture now cancels leftover background tasks before each test via a new
test-only endpoint, preventing future cross-test contamination.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ET (no-changelog)

MockServer proxy connections intermittently reset when 4 parallel workers
load expectations simultaneously. Add withRetry helper with exponential
backoff (3 retries, 500ms base) and re-throw on failure instead of
silently swallowing the error.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ation (no-changelog)

Positional selectors (.last()) break when parallel tests create threads in
shared containers. Switch to getThreadByTitle() with LLM-generated titles
from recordings. Also handle missing expectations directories gracefully.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The instance AI workflow preview iframe needs its own push connection to
receive execution events when the user runs a workflow from the preview.
Three issues were preventing this from working:

1. The iframe shared sessionStorage with the parent page (same origin),
   so both got the same pushRef. When the iframe's WebSocket connected,
   the backend replaced the parent's connection — and vice versa —
   meaning execution completion events were lost.

2. The pushConnection store's URL was captured once at store creation,
   so any pushRef change after store creation had no effect.

3. DemoLayout eagerly set activeExecutionId to null at mount time, but
   isWorkflowRunning treats null as "execution starting", which left the
   run button disabled with a loading spinner before the user could click.

Fixed by generating a unique pushRef when DemoLayout detects it's running
in an iframe, making the push connection URL reactive, and only setting
activeExecutionId to null when the iframe is in read-only relay mode.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…angelog)

Add comprehensive Playwright tests covering manual execution from the
instance AI workflow preview iframe:
- Run button visibility after preview opens
- Full workflow execution with success indicators
- Per-node execution from the canvas node toolbar
- NDV output panel display after execution
- Re-running a workflow after a successful first run

Adds InstanceAiPage page object methods for interacting with execution UI
inside the preview iframe (run button, per-node execute, success
indicators, NDV output).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Strip WebSocket diagnostic logging that was used during development to
diagnose the iframe push connection bug.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…nExecute

When the iframe receives a workflow via postMessage, the post-import handler
re-set activeExecutionId to null so the iframe stays receptive to push events
relayed from the parent. But isWorkflowRunning treats null as "execution
starting", which left the run button disabled with a loading state when
canExecute was enabled.

Apply the same canExecute check we added to DemoLayout — only re-set
activeExecutionId to null in read-only relay mode, not when the user can
trigger executions directly.

Also fix the NDV output panel selector (output-panel, not ndv-output-panel)
which is the wrapper data-test-id used by NodeDetailsViewV2.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… (no-changelog)

Re-record proxy expectations for the instance AI workflow execution tests
so they can replay deterministically in CI without hitting the real
Anthropic API.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…review

In executable preview mode, workflows with only a Chat Trigger no longer
show a disabled execute button with a tooltip. Instead the button is
hidden entirely and the "Open chat" button opens the logs panel so users
can interact with the workflow via chat.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
# Conflicts:
#	packages/@n8n/agents/src/runtime/model-factory.ts
#	packages/@n8n/instance-ai/src/tracing/__tests__/trace-replay.test.ts
#	packages/@n8n/instance-ai/src/tracing/langsmith-tracing.ts
#	packages/@n8n/instance-ai/src/tracing/trace-replay.ts
#	packages/@n8n/instance-ai/src/types.ts
#	packages/cli/src/modules/instance-ai/instance-ai.service.ts
#	packages/frontend/editor-ui/src/features/ai/instanceAi/__tests__/useEventRelay.test.ts
#	packages/frontend/editor-ui/src/features/ai/instanceAi/useEventRelay.ts
#	packages/testing/containers/services/proxy.ts
#	packages/testing/playwright/expectations/instance-ai/should-auto-open-preview-panel-when-workflow-is-built/trace.jsonl
#	packages/testing/playwright/expectations/instance-ai/should-close-preview-panel-via-close-button/trace.jsonl
#	packages/testing/playwright/expectations/instance-ai/should-display-canvas-nodes-in-preview-iframe/trace.jsonl
#	packages/testing/playwright/helpers/NavigationHelper.ts
#	packages/testing/playwright/pages/InstanceAiPage.ts
#	packages/testing/playwright/tests/e2e/instance-ai/fixtures.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…gelog)

These additions (requireInstanceAiEnabled guard, message validation) were
already moved to a different location on this branch.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
mutdmour and others added 3 commits April 14, 2026 16:41
…on (no-changelog)

The disabled-reason tooltip on the run button is no longer needed — chat
trigger workflows now hide the button entirely and show Open chat instead.
Also fix duplicate IconLucideLoaderCircle import in design-system icons.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- useChatState: stop watch when push connection times out to prevent dangling listeners
- usePostMessageHandler.test: make window.parent mock configurable for safe restoration
- NodeSettings: re-evaluate default tab when active node changes (was one-time snapshot)
- instance-ai-workflow-execution test: wait for re-execution to actually run before asserting
- InstanceAiPage: restore preview interaction methods lost during master merge

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…esting (no-changelog)

Two independent improvements to speed up instance-AI Playwright testing:

1. `pnpm build:docker:editor` — Rebuilds only editor-ui and patches the
   existing compiled/ directory, then re-dockerizes. Skips the full monorepo
   build for frontend-only iterations.

2. `pnpm test:local:instance-ai --proxy` — Starts a standalone MockServer
   container alongside the local n8n process, enabling record/replay of
   Anthropic API calls without the full container stack.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 16, 2026

Performance Comparison

Comparing currentlatest master14-day baseline

Memory consumption baseline with starter plan resources

Metric Current Latest Master Baseline (avg) vs Master vs Baseline Status
memory-rss-baseline 281.23 MB 290.22 MB (σ 47.80) -3.1%
memory-heap-used-baseline 114.36 MB 114.20 MB (σ 0.47) +0.1%

docker-stats

Metric Current Latest Master Baseline (avg) vs Master vs Baseline Status
docker-image-size-n8n 1269.76 MB 1269.76 MB (σ 0.00) +0.0%
docker-image-size-runners 386.00 MB 391.20 MB (σ 9.93) -1.3%

Idle baseline with Instance AI module loaded

Metric Current Latest Master Baseline (avg) vs Master vs Baseline Status
instance-ai-heap-used-baseline 186.89 MB 186.40 MB (σ 0.27) +0.3% ⚠️
instance-ai-rss-baseline 344.37 MB 362.79 MB (σ 23.42) -5.1%
How to read this table
  • Current: This PR's value (or latest master if PR perf tests haven't run)
  • Latest Master: Most recent nightly master measurement
  • Baseline: Rolling 14-day average from master
  • vs Master: PR impact (current vs latest master)
  • vs Baseline: Drift from baseline (current vs rolling avg)
  • Status: ✅ within 1σ | ⚠️ 1-2σ | 🔴 >2σ regression

…ort (no-changelog)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@mutdmour mutdmour marked this pull request as ready for review April 16, 2026 13:38
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 7 files

Architecture diagram
sequenceDiagram
    participant Dev as Developer
    participant Runner as Test Runner (run-local-instance-ai)
    participant Docker as MockServer Container
    participant n8n as Local n8n Process
    participant PW as Playwright
    participant Ext as Anthropic API

    Note over Dev,Ext: NEW: Local Instance-AI Test Flow with --proxy

    Dev->>Runner: pnpm test:local:instance-ai --proxy
    
    Runner->>Docker: NEW: docker run -d (MockServer)
    Docker-->>Runner: Mapped Port (proxyUrl)
    
    loop NEW: waitForProxy
        Runner->>Docker: curl /mockserver/status
    end

    Runner->>n8n: CHANGED: Start with HTTP_PROXY=proxyUrl
    Note over n8n: Sets NODE_TLS_REJECT_UNAUTHORIZED=0

    Runner->>PW: Start Tests (env: PROXY_SERVER_URL)
    
    PW->>n8n: Trigger AI Workflow
    
    n8n->>Docker: NEW: Intercept Outbound Request
    
    alt NEW: Recording Mode (ANTHROPIC_API_KEY set)
        Docker->>Ext: Forward to real API
        Ext-->>Docker: 200 OK
        Docker->>Docker: Persist expectation to disk
    else NEW: Replay Mode (No API Key)
        Docker->>Docker: Match request against disk cache
    end
    
    Docker-->>n8n: Return proxied response
    n8n-->>PW: Success
    
    PW-->>Runner: Test Completion
    
    Runner->>Docker: NEW: docker rm -f (Cleanup on Exit/SIGINT)
Loading

mutdmour and others added 6 commits April 16, 2026 15:57
…hangelog)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…elog)

registerChatWebhook now waits for push connection before proceeding.
Without this mock, tests timeout waiting for isConnected to become true.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…log)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 17, 2026

Bundle Report

Changes will increase total bundle size by 2.91kB (0.01%) ⬆️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
editor-ui-esm 45.76MB 2.91kB (0.01%) ⬆️

Affected Assets, Files, and Routes:

view changes for bundle: editor-ui-esm

Assets Changed:

Asset Name Size Change Total Size Change (%)
assets/useCanvasMapping-*.js 413 bytes 463.71kB 0.09%
assets/InstanceAiView-*.js 26 bytes 347.71kB 0.01%
assets/usePostMessageHandler-*.js 797 bytes 137.85kB 0.58%
assets/NodeView-*.js 183 bytes 137.42kB 0.13%
assets/useRootStore-*.js 82 bytes 131.33kB 0.06%
assets/NodeSettings-*.js 422 bytes 85.02kB 0.5%
assets/pushConnection.store-*.js 38 bytes 10.14kB 0.38%
assets/WorkflowPreview-*.js 213 bytes 8.18kB 2.67%
assets/DemoLayout-*.js 735 bytes 3.51kB 26.52% ⚠️

Files in assets/useCanvasMapping-*.js:

  • ./src/features/workflows/canvas/components/elements/nodes/CanvasNodeToolbar.vue → Total Size: 382 bytes

  • ./src/features/workflows/canvas/components/Canvas.vue → Total Size: 351 bytes

  • ./src/features/workflows/canvas/components/elements/nodes/CanvasNode.vue → Total Size: 352 bytes

Files in assets/InstanceAiView-*.js:

  • ./src/features/ai/instanceAi/components/InstanceAiWorkflowPreview.vue → Total Size: 394 bytes

Files in assets/usePostMessageHandler-*.js:

  • ./src/app/composables/useWorkflowImport.ts → Total Size: 989 bytes

  • ./src/app/composables/usePostMessageHandler.ts → Total Size: 5.54kB

  • ./src/features/execution/logs/composables/useChatState.ts → Total Size: 7.46kB

Files in assets/NodeView-*.js:

  • ./src/features/workflows/canvas/components/WorkflowCanvas.vue → Total Size: 355 bytes

  • ./src/app/views/NodeView.vue → Total Size: 298 bytes

Files in assets/NodeSettings-*.js:

  • ./src/features/ndv/settings/components/NodeSettings.vue → Total Size: 371 bytes

Files in assets/pushConnection.store-*.js:

  • ./src/app/stores/pushConnection.store.ts → Total Size: 4.33kB

Files in assets/WorkflowPreview-*.js:

  • ./src/app/components/WorkflowPreview.vue → Total Size: 331 bytes

Files in assets/DemoLayout-*.js:

  • ./src/features/execution/logs/components/DemoFooter.vue → Total Size: 158 bytes

  • ./src/app/layouts/DemoLayout.vue → Total Size: 135 bytes

@mutdmour mutdmour closed this Apr 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant