packages/nodes-base/TESTING_PROMPT_WORKFLOW.md
You are an expert AI agent specialized in writing comprehensive, reliable workflow unit tests for n8n nodes in the @packages/nodes-base folder. Your task is to create thorough test suites that use .workflow.json files and NodeTestHarness to test complete workflow execution scenarios.
pnpm test for running tests. Example: `cd packages/nodes-base/ && pnpm test TestFileNameimport { NodeTestHarness } from '@nodes-testing/node-test-harness';
import nock from 'nock';
describe('NodeName', () => {
describe('Run Test Workflow', () => {
beforeAll(() => {
const mock = nock('https://api.example.com');
mock.post('/endpoint').reply(200, mockResponse);
mock.get('/data').reply(200, mockData);
});
new NodeTestHarness().setupTests();
});
});
describe('NodeName', () => {
const credentials = {
nodeApi: {
accessToken: 'test-token',
baseUrl: 'https://api.example.com',
},
};
describe('Run Test Workflow', () => {
beforeAll(() => {
const mock = nock(credentials.nodeApi.baseUrl);
mock.post('/users').reply(200, userCreateResponse);
});
new NodeTestHarness().setupTests({
credentials,
workflowFiles: ['workflow.json'],
assertBinaryData: true
});
});
});
{
"name": "NodeName Test Workflow",
"nodes": [
{
"parameters": {},
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [0, 0],
"id": "trigger-id",
"name": "When clicking 'Execute Workflow'"
},
{
"parameters": {
"operation": "create",
"resource": "user",
"name": "Test User",
"email": "[email protected]"
},
"type": "n8n-nodes-base.nodeName",
"typeVersion": 1,
"position": [200, 0],
"id": "node-id",
"name": "Node Operation",
"credentials": {
"nodeApi": {
"id": "credential-id",
"name": "Test Credentials"
}
}
}
],
"pinData": {
"Node Operation": [
{
"json": {
"id": "123",
"name": "Test User",
"email": "[email protected]",
"status": "active"
}
}
]
},
"connections": {
"When clicking 'Execute Workflow'": {
"main": [
[
{
"node": "Node Operation",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
}
}
{
"displayName": "Parameter Name",
"name": "parameterName",
"type": "string|number|boolean|options",
"default": "defaultValue",
"required": true
}
{
"displayName": "Additional Fields",
"name": "additionalFields",
"type": "collection",
"default": {},
"options": [
{
"displayName": "Custom Field",
"name": "customField",
"type": "string",
"default": ""
}
]
}
{
"displayName": "Fields to Set",
"name": "fields",
"type": "fixedCollection",
"typeOptions": {
"multipleValues": true
},
"options": [
{
"name": "values",
"displayName": "Values",
"values": [
{
"displayName": "Name",
"name": "name",
"type": "string",
"default": ""
}
]
}
]
}
beforeAll(() => {
const mock = nock('https://api.example.com');
// Mock GET request
mock.get('/users')
.reply(200, {
users: [
{ id: 1, name: 'User 1' },
{ id: 2, name: 'User 2' }
]
});
// Mock POST request
mock.post('/users', {
name: 'Test User',
email: '[email protected]'
})
.reply(201, {
id: 123,
name: 'Test User',
email: '[email protected]',
status: 'active'
});
// Mock error responses
mock.get('/error-endpoint')
.reply(500, { error: 'Internal Server Error' });
});
beforeAll(() => {
const mock = nock('https://api.example.com');
// Mock with headers
mock.get('/protected-endpoint')
.matchHeader('Authorization', 'Bearer test-token')
.reply(200, { data: 'protected' });
// Mock with query parameters
mock.get('/search')
.query({ q: 'test', limit: 10 })
.reply(200, { results: [] });
// Mock with request body validation
mock.post('/validate', (body) => {
return body.name && body.email;
})
.reply(200, { valid: true });
});
Some workflows require credentials for NodeHarness. If the execution result of a test is null it means that workflow has invalid inputs. Very often it's misconfigured credentials.
const credentials = {
googleAnalyticsOAuth2: {
scope: '',
oauthTokenData: {
access_token: 'ACCESSTOKEN',
},
}
}
const credentials = {
aws: {
region: 'eu-central-1',
accessKeyId: 'test',
secretAccessKey: 'test',
},
}
wordpressApi: {
url: 'https://myblog.com',
allowUnauthorizedCerts: false,
username: 'nodeqa',
password: 'fake-password',
},
const credentials = {
telegramApi: {
accessToken: 'testToken',
baseUrl: 'https://api.telegram.org',
},
};
{
"pinData": {
"Upload Node": [
{
"json": {
"fileId": "123",
"fileName": "test.txt",
"fileSize": 1024,
"mimeType": "text/plain"
},
"binary": {
"data": {
"data": "base64data",
"mimeType": "text/plain",
"fileName": "test.txt"
}
}
}
]
}
}
new NodeTestHarness().setupTests({
credentials,
workflowFiles: ['binary.workflow.json'],
assertBinaryData: true
});
{
"pinData": {
"Error Node": [
{
"json": {
"error": "User not found",
"message": "Invalid request",
"code": 404
}
}
]
}
}
beforeAll(() => {
const mock = nock('https://api.example.com');
mock.get('/users/nonexistent')
.reply(404, { error: 'User not found' });
});
{
"parameters": {
"rules": {
"values": [
{
"conditions": {
"conditions": [
{
"leftValue": "={{ $json.status }}",
"rightValue": "active",
"operator": {
"type": "string",
"operation": "equals"
}
}
]
},
"outputKey": "Active Users"
}
]
}
}
}
{
"parameters": {
"fields": {
"values": [
{
"name": "processed",
"stringValue": "true"
},
{
"name": "timestamp",
"stringValue": "={{ new Date().toISOString() }}"
}
]
}
}
}
{
"parameters": {
"jsCode": "return [\n { id: 1, name: 'Item 1' },\n { id: 2, name: 'Item 2' }\n]"
}
}
{
"credentials": {
"openAiApi": {
"id": "openai-cred-id",
"name": "OpenAI API Key"
}
}
}
{
"credentials": {
"slackOAuth2Api": {
"id": "slack-oauth-id",
"name": "Slack OAuth2"
}
}
}
{
"credentials": {
"postgres": {
"id": "postgres-cred-id",
"name": "PostgreSQL Database"
}
}
}
Always include tests for:
n8n-nodes-base.manualTriggerimport { NodeTestHarness } from '@nodes-testing/node-test-harness';
import nock from 'nock';
describe('NodeName', () => {
const credentials = {
nodeApi: {
accessToken: 'test-token',
baseUrl: 'https://api.example.com',
},
};
describe('Basic Operations', () => {
beforeAll(() => {
const mock = nock(credentials.nodeApi.baseUrl);
mock.get('/users')
.reply(200, {
users: [
{ id: 1, name: 'User 1', email: '[email protected]' },
{ id: 2, name: 'User 2', email: '[email protected]' }
]
});
mock.post('/users', {
name: 'Test User',
email: '[email protected]'
})
.reply(201, {
id: 123,
name: 'Test User',
email: '[email protected]',
status: 'active'
});
});
new NodeTestHarness().setupTests({
credentials,
workflowFiles: ['basic.workflow.json']
});
});
describe('Error Handling', () => {
beforeAll(() => {
const mock = nock(credentials.nodeApi.baseUrl);
mock.get('/users')
.reply(500, { error: 'Internal Server Error' });
});
new NodeTestHarness().setupTests({
credentials,
workflowFiles: ['error.workflow.json']
});
});
describe('Binary Data Operations', () => {
beforeAll(() => {
const mock = nock(credentials.nodeApi.baseUrl);
mock.post('/upload')
.reply(200, {
fileId: '123',
fileName: 'test.txt',
fileSize: 1024,
mimeType: 'text/plain'
});
});
new NodeTestHarness().setupTests({
credentials,
workflowFiles: ['binary.workflow.json'],
assertBinaryData: true
});
});
});