Testing Strategy
Relevant source files
The following files were used as context for generating this wiki page:
- AGENTS.md
- CONTRIBUTING.md
- packages/@n8n/ai-workflow-builder.ee/src/subgraphs/test/integration/techniques.json
- packages/@n8n/ai-workflow-builder.ee/src/tools/best-practices/data-analysis.ts
- packages/@n8n/ai-workflow-builder.ee/src/tools/best-practices/data-transformation.ts
- packages/@n8n/ai-workflow-builder.ee/src/tools/best-practices/triage.ts
- packages/cli/test/integration/access-control/resource-access-matrix.test.ts
- packages/nodes-base/TESTING_PROMPT.md
- packages/nodes-base/TESTING_PROMPT_WORKFLOW.md
- packages/testing/playwright/AI-TEST-CHEAT-SHEET.md
- packages/testing/playwright/CONTRIBUTING.md
- packages/testing/playwright/README.md
- packages/testing/playwright/tests/cli-workflows/README.md
- packages/testing/playwright/tests/ui/29-templates.spec.ts
The n8n project employs a multi-layered testing strategy to ensure code quality, prevent regressions, and maintain compatibility. The strategy encompasses unit tests for isolated components, integration tests for combined functionality, and end-to-end (E2E) tests for user-facing scenarios. The primary testing frameworks are Jest and Vitest for unit/integration tests and Playwright for E2E tests.
Testing is a mandatory part of the contribution process, with requirements for unit tests, workflow tests for nodes, and UI tests where applicable. The project uses pnpm workspaces, and tests are typically run from within the specific package directory.
Sources: CONTRIBUTING.md:200-207, AGENTS.md:126-132
Test Suite Overview
The test suite is organized into several categories, each serving a distinct purpose.
| Test Type | Framework | Purpose | Key Tooling |
|---|---|---|---|
| Unit Tests | Jest / Vitest | Test individual functions, classes, and backend components in isolation. | jest-mock-extended, nock |
| Integration Tests | Jest / Vitest | Verify interactions between different modules, such as API controllers and database access. | supertest, NodeTestHarness |
| E2E Tests | Playwright | Validate complete user workflows and UI interactions in a browser environment. | Page Object Model, Composables |
| Workflow Tests | Playwright | Execute n8n workflows and validate their output, often using schema validation. | workflowConfig.json |
Sources: AGENTS.md:126-132, CONTRIBUTING.md:213-230, packages/nodes-base/TESTING_PROMPT.md:1, packages/testing/playwright/tests/cli-workflows/README.md:1
Running Tests
Different commands are available to run specific parts of the test suite.
| Command | Description |
|---|---|
pnpm test | Runs unit tests. When run in a package folder, it only runs tests for that package. |
pnpm test:affected | Runs tests based on what has changed since the last commit. |
pnpm --filter=n8n-playwright test:local | Runs Playwright E2E tests against a local server. |
pnpm test:workflows | Runs the dedicated workflow testing framework. |
Sources: AGENTS.md:40-46, CONTRIBUTING.md:214-220, packages/testing/playwright/tests/cli-workflows/README.md:28-37
Unit and Integration Testing
Unit and integration tests for backend components, especially nodes, are written using Jest or Vitest. The core principle is to mock all external dependencies to ensure tests are reliable and isolated.
Sources: AGENTS.md:127-128, packages/nodes-base/TESTING_PROMPT.md:24
Node Unit Testing
Node unit tests focus on verifying the logic of a single node. This involves mocking n8n's core interfaces and any external API calls.
Mocking Strategies
- Core Interfaces:
jest-mock-extendedis used to create deep mocks of core interfaces likeIExecuteFunctions. - External APIs:
jest.spyOnis used for internal API functions, whilenockis preferred for mocking external HTTP requests.
This diagram illustrates the mocking process in a typical node unit test.
Key Test Categories
- Happy Path: Normal operation with valid inputs.
- Error Handling: Invalid inputs, API failures, and credential errors.
- Edge Cases: Empty data, null values, and boundary conditions.
- Binary Data: File uploads and downloads.
- Data Transformation: Correct processing of input to output.
Sources: packages/nodes-base/TESTING_PROMPT.md:27-35
Workflow-Based Integration Testing
For more comprehensive node testing, the NodeTestHarness is used. This approach executes an entire .workflow.json file, providing a higher-level integration test that verifies how nodes interact within a complete workflow.
This method requires:
- A
.workflow.jsonfile defining the nodes, their parameters, and connections. pinDatawithin the JSON to specify the expected output of each node for validation.nockto mock any external API calls made by the workflow.
The NodeTestHarness automatically sets up and runs these workflow tests.
// Example of NodeTestHarness setup
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
import nock from 'nock';
describe('MyNode Workflow Test', () => {
beforeAll(() => {
nock('https://api.example.com')
.post('/endpoint')
.reply(200, { success: true });
});
new NodeTestHarness().setupTests();
});
Source: packages/nodes-base/TESTING_PROMPT_WORKFLOW.md:15-24
End-to-End (E2E) Testing with Playwright
E2E tests simulate real user interactions in a browser, ensuring the frontend and backend work together correctly. The project uses Playwright for its powerful features like auto-waits, parallel execution, and rich reporting.
Sources: CONTRIBUTING.md:222-224, packages/testing/playwright/tests/cli-workflows/README.md:10-15
E2E Architecture
The Playwright test suite follows a layered architecture to promote separation of concerns, reusability, and readability.
This diagram shows the four-layer architecture for UI testing.
- Tests (
*.spec.ts): Contain the high-level test scenarios, written to be as readable as possible. They orchestrate calls to Composables. - Composables (
*Composer.ts): Encapsulate complex, multi-page business workflows (e.g., creating and executing a workflow). - Page Objects (
*Page.ts): Model a single page or component of the UI. They contain element locators and simple, single-action methods. - BasePage (
BasePage.ts): Provides common utility methods used by all Page Objects (e.g.,clickByTestId).
Sources: packages/testing/playwright/CONTRIBUTING.md:39-45, packages/testing/playwright/AI-TEST-CHEAT-SHEET.md:100-108
Lexical Conventions and Naming
Strict conventions are followed for file and method naming to maintain consistency.
| Type | Pattern | Example |
|---|---|---|
| Page Objects | {PageName}Page.ts | CredentialsPage.ts |
| Composables | {Domain}Composer.ts | WorkflowComposer.ts |
| Test Files | {number}-{feature}.spec.ts | 29-templates.spec.ts |
Source: packages/testing/playwright/CONTRIBUTING.md:136-141
Page Object methods are categorized into three types:
- Element Getters: Synchronous methods that return a Playwright
Locator.
Source: packages/testing/playwright/CONTRIBUTING.md:61-63// From CanvasPage.ts nodeByName(nodeName: string): Locator { return this.page.locator(`[data-test-id="canvas-node"][data-node-name="${nodeName}"]`); } - Simple Actions: Asynchronous methods that perform a single user action and return
void.
Source: packages/testing/playwright/CONTRIBUTING.md:77-79// From CanvasPage.ts async openNode(nodeName: string): Promise<void> { await this.nodeByName(nodeName).dblclick(); } - Query Methods: Asynchronous methods that retrieve data from the page.
Source: packages/testing/playwright/CONTRIBUTING.md:83-99// From CanvasPage.ts async getPinnedNodeNames(): Promise<string[]> { // ... logic to extract names return names; }
Writing E2E Tests
Tests should use the highest-level abstractions possible. Instead of interacting with page objects directly, tests should call methods on composable classes.
// Good example of a UI test using a Composable
test('should execute workflow', async ({ n8n }) => {
await n8n.start.fromBlankCanvas();
await n8n.canvas.addNode('Manual Trigger');
await n8n.canvas.addNode('Set');
// Use a composable for the multi-step execution and notification check
await n8n.workflowComposer.executeWorkflowAndWaitForNotification('Success');
});
Source: packages/testing/playwright/AI-TEST-CHEAT-SHEET.md:32-37
Workflow Testing Framework
A specialized framework, built on Playwright, is used to test a large suite of n8n workflows. Its primary goal is to ensure correctness, maintain API compatibility, and prevent regressions.
Sources: packages/testing/playwright/tests/cli-workflows/README.md:5-9
How It Works
The framework executes workflows defined in a workflowConfig.json file and validates their execution. It has two primary modes:
- Basic Run: Executes workflows and checks for runtime errors.
- Schema Mode: In addition to checking for errors, it validates the structure of the workflow's output against a saved JSON schema snapshot. This is crucial for detecting breaking changes in node outputs or external APIs without being sensitive to dynamic data values.
This flow chart outlines the process of adding a new workflow test.
Configuration
The behavior of the workflow testing framework is controlled by workflowConfig.json.
| Field | Description | Example |
|---|---|---|
workflowId | The ID of the workflow, matching the filename. | "123" |
status | ACTIVE to run the test, SKIPPED to ignore it. | "ACTIVE" |
enableSchemaValidation | (Optional) Enables schema validation for the workflow. Defaults to true. | true |
skipReason | (Optional) A reason for skipping the test. | "API is down" |
ticketReference | (Optional) A reference to a tracking ticket. | "JIRA-123" |
Source: packages/testing/playwright/tests/cli-workflows/README.md:84-103
Access Control Testing
Integration tests are used to verify the resource access control matrix. These tests ensure that users with different roles and permissions can only perform the actions they are authorized for. The tests for this are structured by creating users, assigning them custom roles with specific scopes, and then attempting various API actions to assert the expected outcome (success or failure).
For example, a test case for a "Workflow Read-Only" role would verify that a user can GET /workflows/:id (200 OK) but cannot PATCH /workflows/:id (403 Forbidden).
// Example from resource-access-matrix.test.ts
describe('Workflow Read-Only Role', () => {
beforeEach(async () => {
// Link user to a project with the read-only role
await linkUserToProject(testUser, teamProject, workflowReadOnlyRole.slug);
});
test('GET /workflows/:id should return 200', async () => {
await testUserAgent.get(`/workflows/${testWorkflowId}`).expect(200);
});
test('PATCH /workflows/:id should return 403', async () => {
await testUserAgent
.patch(`/workflows/${testWorkflowId}`)
.send({ name: 'Updated Name', versionId: testWorkflowVersionId })
.expect(403);
});
});
Source: packages/cli/test/integration/access-control/resource-access-matrix.test.ts:187-213
Summary
n8n's testing strategy is comprehensive, covering multiple layers from isolated unit tests to full end-to-end user scenarios. It relies on modern tooling like Playwright and established patterns like the Page Object Model to create a robust, maintainable, and scalable test suite. Key features include a structured E2E architecture, workflow-based integration tests with NodeTestHarness, and a dedicated framework for validating workflow execution and output schemas. This rigorous approach is fundamental to maintaining the stability and reliability of the platform.