🎯

n8n-expression-testing

🎯Skill

from proffesor-for-testing/agentic-qe

VibeIndex|
What it does

n8n-expression-testing skill from proffesor-for-testing/agentic-qe

n8n-expression-testing

Installation

Install skill:
npx skills add https://github.com/proffesor-for-testing/agentic-qe --skill n8n-expression-testing
5
AddedJan 27, 2026

Skill Details

SKILL.md

"n8n expression syntax validation, context-aware testing, common pitfalls detection, and performance optimization. Use when validating n8n expressions and data transformations."

Overview

# n8n Expression Testing

When testing n8n expressions:

  1. VALIDATE syntax before execution
  2. TEST with multiple context scenarios
  3. CHECK for null/undefined handling
  4. VERIFY type safety
  5. SCAN for security vulnerabilities

Quick Expression Checklist:

  • Valid JavaScript syntax
  • Context variables properly referenced ($json, $node)
  • Null-safe access patterns (?., ??)
  • No dangerous functions (eval, Function)
  • Efficient for large data sets

Common Pitfalls:

  • Accessing nested properties without null checks
  • Type coercion issues
  • Missing fallback values
  • Inefficient array operations

Quick Reference Card

n8n Expression Syntax

| Pattern | Example | Description |

|---------|---------|-------------|

| Basic access | {{ $json.field }} | Access JSON field |

| Nested access | {{ $json.user.email }} | Access nested property |

| Array access | {{ $json.items[0] }} | Access array element |

| Node reference | {{ $node["Name"].json.id }} | Access other node's data |

| Method call | {{ $json.name.toLowerCase() }} | Call string method |

| Conditional | {{ $json.x ? "yes" : "no" }} | Ternary expression |

Context Variables

| Variable | Description | Example |

|----------|-------------|---------|

| $json | Current item data | {{ $json.email }} |

| $node["Name"] | Other node's data | {{ $node["HTTP"].json.body }} |

| $items() | Multiple items | {{ $items("Node", 0, 0).json }} |

| $now | Current timestamp | {{ $now.toISO() }} |

| $today | Today's date | {{ $today }} |

| $runIndex | Run iteration | {{ $runIndex }} |

| $workflow | Workflow info | {{ $workflow.name }} |

---

Expression Syntax Patterns

Safe Data Access

```javascript

// BAD: Can fail if nested objects are null

{{ $json.user.profile.email }}

// GOOD: Optional chaining with fallback

{{ $json.user?.profile?.email ?? '' }}

// BAD: Array access without bounds check

{{ $json.items[0].name }}

// GOOD: Safe array access

{{ $json.items?.[0]?.name ?? 'No items' }}

```

Type Conversions

```javascript

// String to Number

{{ parseInt($json.quantity, 10) }}

{{ parseFloat($json.price) }}

{{ Number($json.value) }}

// Number to String

{{ String($json.id) }}

{{ $json.amount.toString() }}

{{ $json.count.toFixed(2) }}

// Date handling

{{ new Date($json.timestamp).toISOString() }}

{{ DateTime.fromISO($json.date).toFormat('yyyy-MM-dd') }}

// Boolean conversion

{{ Boolean($json.active) }}

{{ $json.enabled === 'true' }}

```

String Operations

```javascript

// Case conversion

{{ $json.name.toLowerCase() }}

{{ $json.name.toUpperCase() }}

{{ $json.name.charAt(0).toUpperCase() + $json.name.slice(1) }}

// String manipulation

{{ $json.text.trim() }}

{{ $json.text.replace(/\s+/g, ' ') }}

{{ $json.text.substring(0, 100) }}

// Template strings

{{ Hello, ${$json.firstName} ${$json.lastName}! }}

{{ Order #${$json.orderId} - ${$json.status} }}

```

Array Operations

```javascript

// Mapping

{{ $json.items.map(item => item.name) }}

{{ $json.items.map(item => ({ id: item.id, total: item.price * item.qty })) }}

// Filtering

{{ $json.items.filter(item => item.active) }}

{{ $json.items.filter(item => item.price > 100) }}

// Reducing

{{ $json.items.reduce((sum, item) => sum + item.price, 0) }}

{{ $json.items.reduce((acc, item) => ({ ...acc, [item.id]: item }), {}) }}

// Finding

{{ $json.items.find(item => item.id === $json.targetId) }}

{{ $json.items.findIndex(item => item.name === 'target') }}

// Joining

{{ $json.tags.join(', ') }}

{{ $json.items.map(i => i.name).join(' | ') }}

```

---

Validation Patterns

```typescript

// Validate expression syntax

function validateExpressionSyntax(expression: string): ValidationResult {

// Remove n8n template markers

const code = expression.replace(/\{\{|\}\}/g, '').trim();

try {

// Check if valid JavaScript

new Function(return (${code}));

return { valid: true };

} catch (error) {

return {

valid: false,

error: error.message,

suggestion: suggestFix(error.message, code)

};

}

}

// Validate context variables

function validateContextVariables(expression: string): string[] {

const contextVars = ['$json', '$node', '$items', '$now', '$today', '$runIndex', '$workflow'];

const usedVars = [];

const invalidVars = [];

// Find all $ prefixed variables

const varPattern = /\$\w+/g;

let match;

while ((match = varPattern.exec(expression)) !== null) {

const varName = match[0];

if (contextVars.some(cv => varName.startsWith(cv))) {

usedVars.push(varName);

} else {

invalidVars.push(varName);

}

}

return { usedVars, invalidVars };

}

// Test expression with sample data

function testExpression(expression: string, context: any): TestResult {

const code = expression.replace(/\{\{|\}\}/g, '').trim();

try {

// Create function with context

const fn = new Function('$json', '$node', '$items', '$now', '$today',

return (${code}));

const result = fn(

context.$json || {},

context.$node || {},

context.$items || (() => ({})),

context.$now || new Date(),

context.$today || new Date()

);

return { success: true, result };

} catch (error) {

return { success: false, error: error.message };

}

}

```

---

Common Errors and Fixes

Undefined Property Access

```javascript

// ERROR: Cannot read property 'email' of undefined

{{ $json.user.email }}

// FIX 1: Optional chaining

{{ $json.user?.email }}

// FIX 2: With fallback

{{ $json.user?.email ?? 'no-email@example.com' }}

// FIX 3: Conditional

{{ $json.user ? $json.user.email : '' }}

```

Type Errors

```javascript

// ERROR: toLowerCase is not a function (when null)

{{ $json.name.toLowerCase() }}

// FIX: Null check first

{{ $json.name?.toLowerCase() ?? '' }}

// ERROR: toFixed is not a function (string instead of number)

{{ $json.price.toFixed(2) }}

// FIX: Parse as number first

{{ parseFloat($json.price).toFixed(2) }}

// ERROR: map is not a function (not an array)

{{ $json.items.map(i => i.name) }}

// FIX: Ensure array

{{ (Array.isArray($json.items) ? $json.items : []).map(i => i.name) }}

```

Node Reference Errors

```javascript

// ERROR: Node "Previous Node" not found

{{ $node["Previous Node"].json.data }}

// FIX: Use exact node name (case-sensitive)

{{ $node["Previous Node1"].json.data }}

// FIX: Add fallback for safety

{{ $node["Previous Node"]?.json?.data ?? {} }}

```

---

Security Patterns

Dangerous Functions to Avoid

```javascript

// DANGEROUS: Never use eval

{{ eval($json.code) }}

// DANGEROUS: Dynamic function creation

{{ new Function($json.code)() }}

// DANGEROUS: setTimeout with string

{{ setTimeout($json.code, 1000) }}

// SAFE: Use explicit operations instead

{{ $json.value * 2 }}

{{ JSON.parse($json.jsonString) }}

```

Input Validation

```javascript

// Validate email format

{{ /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test($json.email) ? $json.email : '' }}

// Sanitize for HTML (basic)

{{ $json.text.replace(/[<>&"']/g, c => ({

'<': '<', '>': '>', '&': '&', '"': '"', "'": '''

}[c])) }}

// Limit string length

{{ $json.input.substring(0, 1000) }}

// Validate number range

{{ Math.min(Math.max(parseInt($json.value), 0), 100) }}

```

---

Performance Optimization

Efficient Array Operations

```javascript

// SLOW: Multiple iterations

{{ $json.items.filter(i => i.active).map(i => i.name).join(', ') }}

// FASTER: Single reduce

{{ $json.items.reduce((acc, i) => i.active ? (acc ? ${acc}, ${i.name} : i.name) : acc, '') }}

// SLOW: Nested loops

{{ $json.items.map(i => $json.categories.find(c => c.id === i.categoryId)) }}

// FASTER: Create lookup map first (in Code node)

const categoryMap = Object.fromEntries($json.categories.map(c => [c.id, c]));

return $json.items.map(i => categoryMap[i.categoryId]);

```

Avoid in Expressions

```javascript

// AVOID: Complex logic in expressions

{{ $json.items.reduce((acc, item) => {

const category = $json.categories.find(c => c.id === item.catId);

if (category && category.active) {

acc.push({ ...item, categoryName: category.name });

}

return acc;

}, []) }}

// BETTER: Move to Code node for complex transformations

```

---

Testing Patterns

```typescript

// Expression test suite

const expressionTests = [

{

name: 'Basic property access',

expression: '{{ $json.name }}',

context: { $json: { name: 'John' } },

expected: 'John'

},

{

name: 'Nested with optional chaining',

expression: '{{ $json.user?.email ?? "default" }}',

context: { $json: { user: null } },

expected: 'default'

},

{

name: 'Array mapping',

expression: '{{ $json.items.map(i => i.id).join(",") }}',

context: { $json: { items: [{ id: 1 }, { id: 2 }] } },

expected: '1,2'

},

{

name: 'Conditional expression',

expression: '{{ $json.score >= 70 ? "Pass" : "Fail" }}',

context: { $json: { score: 85 } },

expected: 'Pass'

},

{

name: 'Node reference',

expression: '{{ $node["Previous"].json.result }}',

context: { $node: { Previous: { json: { result: 'success' } } } },

expected: 'success'

}

];

// Run tests

for (const test of expressionTests) {

const result = testExpression(test.expression, test.context);

console.log(${test.name}: ${result.result === test.expected ? 'PASS' : 'FAIL'});

}

```

---

Agent Coordination

Memory Namespace

```

aqe/n8n/expressions/

β”œβ”€β”€ validations/* - Expression validation results

β”œβ”€β”€ patterns/* - Discovered expression patterns

β”œβ”€β”€ errors/* - Common error catalog

└── optimizations/* - Performance suggestions

```

Fleet Coordination

```typescript

// Coordinate expression validation with workflow testing

await Task("Validate expressions", {

workflowId: "wf-123",

validateAll: true,

testWithSampleData: true

}, "n8n-expression-validator");

```

---

Related Skills

  • [n8n-workflow-testing-fundamentals](../n8n-workflow-testing-fundamentals/) - Workflow testing
  • [n8n-security-testing](../n8n-security-testing/) - Security validation

---

Remember

n8n expressions are JavaScript-like with special context variables ($json, $node, etc.). Testing requires:

  • Syntax validation
  • Context variable verification
  • Null safety checks
  • Type compatibility
  • Security scanning

Key patterns: Use optional chaining (?.) and nullish coalescing (??) for safety. Move complex logic to Code nodes. Always test with edge cases (null, undefined, empty arrays).

More from this repository10

🎯
database-testing🎯Skill

Validates database schemas, tests data integrity, verifies migrations, checks transaction isolation, and measures query performance.

🎯
n8n-security-testing🎯Skill

Automates security vulnerability scanning and penetration testing for n8n workflows, identifying potential risks and misconfigurations.

🎯
brutal-honesty-review🎯Skill

Delivers unvarnished technical criticism with surgical precision, combining expert-level BS detection and zero-tolerance for low-quality work.

🎯
n8n-integration-testing-patterns🎯Skill

Validates n8n integration connectivity, authentication flows, and error handling across external service APIs through comprehensive testing patterns.

🎯
n8n-trigger-testing-strategies🎯Skill

Validates n8n workflow triggers by comprehensively testing webhook, schedule, polling, and event-driven mechanisms with robust payload and authentication checks.

🎯
six-thinking-hats🎯Skill

Applies Six Thinking Hats methodology to systematically analyze software testing challenges from multiple perspectives, enhancing decision-making and test strategy development.

🎯
test-environment-management🎯Skill

Provisions and manages consistent, cost-effective test environments using Docker, Kubernetes, and infrastructure as code for reliable software testing.

🎯
risk-based-testing🎯Skill

Prioritizes testing efforts by systematically assessing and ranking risks based on probability and potential impact across software components.

🎯
context-driven-testing🎯Skill

context-driven-testing skill from proffesor-for-testing/agentic-qe

🎯
shift-left-testing🎯Skill

Accelerates software quality by moving testing earlier in development, reducing defect costs through proactive validation, automated testing, and continuous improvement practices.