Files
n8n-mcp/scripts/test-code-node-enhancements.ts
czlonkowski 99e74cf22a fix: correct misleading Code node documentation based on real-world testing
Critical fixes based on Claude Desktop feedback:

1. Fixed crypto documentation: require('crypto') IS available despite editor warnings
   - Added clear examples of crypto usage
   - Updated validation to guide correct require() usage

2. Clarified $helpers vs standalone functions
   - $getWorkflowStaticData() is standalone, NOT $helpers.getWorkflowStaticData()
   - Added validation to catch incorrect usage (prevents '$helpers is not defined' errors)
   - Enhanced examples showing proper $helpers availability checks

3. Fixed JMESPath numeric literal documentation
   - n8n requires backticks around numbers in filters: [?age >= `18`]
   - Added multiple examples and validation to detect missing backticks
   - Prevents 'JMESPath syntax error' that Claude Desktop encountered

4. Fixed webhook data access gotcha
   - Webhook payload is at items[0].json.body, NOT items[0].json
   - Added dedicated 'Webhook Data Access' section with clear examples
   - Created process_webhook_data task template
   - Added validation to detect incorrect webhook data access patterns

All fixes based on production workflows TaNqYoZNNeHC4Hne and JZ9urD7PNClDZ1bm

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-10 09:22:34 +02:00

203 lines
5.8 KiB
TypeScript
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env npx tsx
/**
* Test script for Code node enhancements
* Tests:
* 1. Code node documentation in tools_documentation
* 2. Enhanced validation for Code nodes
* 3. Code node examples
* 4. Code node task templates
*/
import { EnhancedConfigValidator } from '../src/services/enhanced-config-validator.js';
import { ExampleGenerator } from '../src/services/example-generator.js';
import { TaskTemplates } from '../src/services/task-templates.js';
import { getToolDocumentation } from '../src/mcp/tools-documentation.js';
console.log('🧪 Testing Code Node Enhancements\n');
// Test 1: Code node documentation
console.log('1⃣ Testing Code Node Documentation');
console.log('=====================================');
const codeNodeDocs = getToolDocumentation('code_node_guide', 'essentials');
console.log('✅ Code node documentation available');
console.log('First 500 chars:', codeNodeDocs.substring(0, 500) + '...\n');
// Test 2: Code node validation
console.log('2⃣ Testing Code Node Validation');
console.log('=====================================');
// Test cases
const validationTests = [
{
name: 'Empty code',
config: {
language: 'javaScript',
jsCode: ''
}
},
{
name: 'No return statement',
config: {
language: 'javaScript',
jsCode: 'const data = items;'
}
},
{
name: 'Invalid return format',
config: {
language: 'javaScript',
jsCode: 'return "hello";'
}
},
{
name: 'Valid code',
config: {
language: 'javaScript',
jsCode: 'return [{json: {result: "success"}}];'
}
},
{
name: 'Python with external library',
config: {
language: 'python',
pythonCode: 'import pandas as pd\nreturn [{"json": {"result": "fail"}}]'
}
},
{
name: 'Code with $json in wrong mode',
config: {
language: 'javaScript',
jsCode: 'const value = $json.field;\nreturn [{json: {value}}];'
}
},
{
name: 'Code with security issue',
config: {
language: 'javaScript',
jsCode: 'const result = eval(item.json.code);\nreturn [{json: {result}}];'
}
}
];
for (const test of validationTests) {
console.log(`\nTest: ${test.name}`);
const result = EnhancedConfigValidator.validateWithMode(
'nodes-base.code',
test.config,
[
{ name: 'language', type: 'options', options: ['javaScript', 'python'] },
{ name: 'jsCode', type: 'string' },
{ name: 'pythonCode', type: 'string' },
{ name: 'mode', type: 'options', options: ['runOnceForAllItems', 'runOnceForEachItem'] }
],
'operation',
'ai-friendly'
);
console.log(` Valid: ${result.valid}`);
if (result.errors.length > 0) {
console.log(` Errors: ${result.errors.map(e => e.message).join(', ')}`);
}
if (result.warnings.length > 0) {
console.log(` Warnings: ${result.warnings.map(w => w.message).join(', ')}`);
}
if (result.suggestions.length > 0) {
console.log(` Suggestions: ${result.suggestions.join(', ')}`);
}
}
// Test 3: Code node examples
console.log('\n\n3⃣ Testing Code Node Examples');
console.log('=====================================');
const codeExamples = ExampleGenerator.getExamples('nodes-base.code');
console.log('Available examples:', Object.keys(codeExamples));
console.log('\nMinimal example:');
console.log(JSON.stringify(codeExamples.minimal, null, 2));
console.log('\nCommon example preview:');
console.log(codeExamples.common?.jsCode?.substring(0, 200) + '...');
// Test 4: Code node task templates
console.log('\n\n4⃣ Testing Code Node Task Templates');
console.log('=====================================');
const codeNodeTasks = [
'transform_data',
'custom_ai_tool',
'aggregate_data',
'batch_process_with_api',
'error_safe_transform',
'async_data_processing',
'python_data_analysis'
];
for (const taskName of codeNodeTasks) {
const template = TaskTemplates.getTemplate(taskName);
if (template) {
console.log(`\n✅ ${taskName}:`);
console.log(` Description: ${template.description}`);
console.log(` Language: ${template.configuration.language || 'javaScript'}`);
console.log(` Code preview: ${template.configuration.jsCode?.substring(0, 100) || template.configuration.pythonCode?.substring(0, 100)}...`);
} else {
console.log(`\n❌ ${taskName}: Template not found`);
}
}
// Test 5: Validate a complex Code node configuration
console.log('\n\n5⃣ Testing Complex Code Node Validation');
console.log('==========================================');
const complexCode = {
language: 'javaScript',
mode: 'runOnceForEachItem',
jsCode: `// Complex validation test
try {
const email = $json.email;
const response = await $helpers.httpRequest({
method: 'POST',
url: 'https://api.example.com/validate',
body: { email }
});
return [{
json: {
...response,
validated: true
}
}];
} catch (error) {
return [{
json: {
error: error.message,
validated: false
}
}];
}`,
onError: 'continueRegularOutput',
retryOnFail: true,
maxTries: 3
};
const complexResult = EnhancedConfigValidator.validateWithMode(
'nodes-base.code',
complexCode,
[
{ name: 'language', type: 'options', options: ['javaScript', 'python'] },
{ name: 'jsCode', type: 'string' },
{ name: 'mode', type: 'options', options: ['runOnceForAllItems', 'runOnceForEachItem'] },
{ name: 'onError', type: 'options' },
{ name: 'retryOnFail', type: 'boolean' },
{ name: 'maxTries', type: 'number' }
],
'operation',
'strict'
);
console.log('Complex code validation:');
console.log(` Valid: ${complexResult.valid}`);
console.log(` Errors: ${complexResult.errors.length}`);
console.log(` Warnings: ${complexResult.warnings.length}`);
console.log(` Suggestions: ${complexResult.suggestions.length}`);
console.log('\n✅ All Code node enhancement tests completed!');