agentic-qe 2.5.5 → 2.5.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. package/.claude/agents/n8n/n8n-base-agent.md +376 -0
  2. package/.claude/agents/n8n/n8n-bdd-scenario-tester.md +613 -0
  3. package/.claude/agents/n8n/n8n-chaos-tester.md +654 -0
  4. package/.claude/agents/n8n/n8n-ci-orchestrator.md +850 -0
  5. package/.claude/agents/n8n/n8n-compliance-validator.md +685 -0
  6. package/.claude/agents/n8n/n8n-expression-validator.md +560 -0
  7. package/.claude/agents/n8n/n8n-integration-test.md +602 -0
  8. package/.claude/agents/n8n/n8n-monitoring-validator.md +589 -0
  9. package/.claude/agents/n8n/n8n-node-validator.md +455 -0
  10. package/.claude/agents/n8n/n8n-performance-tester.md +630 -0
  11. package/.claude/agents/n8n/n8n-security-auditor.md +786 -0
  12. package/.claude/agents/n8n/n8n-trigger-test.md +500 -0
  13. package/.claude/agents/n8n/n8n-unit-tester.md +633 -0
  14. package/.claude/agents/n8n/n8n-version-comparator.md +567 -0
  15. package/.claude/agents/n8n/n8n-workflow-executor.md +392 -0
  16. package/.claude/skills/n8n-expression-testing/SKILL.md +434 -0
  17. package/.claude/skills/n8n-integration-testing-patterns/SKILL.md +540 -0
  18. package/.claude/skills/n8n-security-testing/SKILL.md +599 -0
  19. package/.claude/skills/n8n-trigger-testing-strategies/SKILL.md +541 -0
  20. package/.claude/skills/n8n-workflow-testing-fundamentals/SKILL.md +447 -0
  21. package/CHANGELOG.md +111 -0
  22. package/README.md +7 -4
  23. package/dist/adapters/MemoryStoreAdapter.d.ts +75 -123
  24. package/dist/adapters/MemoryStoreAdapter.d.ts.map +1 -1
  25. package/dist/adapters/MemoryStoreAdapter.js +204 -219
  26. package/dist/adapters/MemoryStoreAdapter.js.map +1 -1
  27. package/dist/agents/AccessibilityAllyAgent.d.ts.map +1 -1
  28. package/dist/agents/AccessibilityAllyAgent.js +17 -1
  29. package/dist/agents/AccessibilityAllyAgent.js.map +1 -1
  30. package/dist/agents/BaseAgent.d.ts +18 -250
  31. package/dist/agents/BaseAgent.d.ts.map +1 -1
  32. package/dist/agents/BaseAgent.js +122 -520
  33. package/dist/agents/BaseAgent.js.map +1 -1
  34. package/dist/agents/n8n/N8nAPIClient.d.ts +121 -0
  35. package/dist/agents/n8n/N8nAPIClient.d.ts.map +1 -0
  36. package/dist/agents/n8n/N8nAPIClient.js +367 -0
  37. package/dist/agents/n8n/N8nAPIClient.js.map +1 -0
  38. package/dist/agents/n8n/N8nAuditPersistence.d.ts +120 -0
  39. package/dist/agents/n8n/N8nAuditPersistence.d.ts.map +1 -0
  40. package/dist/agents/n8n/N8nAuditPersistence.js +473 -0
  41. package/dist/agents/n8n/N8nAuditPersistence.js.map +1 -0
  42. package/dist/agents/n8n/N8nBDDScenarioTesterAgent.d.ts +159 -0
  43. package/dist/agents/n8n/N8nBDDScenarioTesterAgent.d.ts.map +1 -0
  44. package/dist/agents/n8n/N8nBDDScenarioTesterAgent.js +697 -0
  45. package/dist/agents/n8n/N8nBDDScenarioTesterAgent.js.map +1 -0
  46. package/dist/agents/n8n/N8nBaseAgent.d.ts +126 -0
  47. package/dist/agents/n8n/N8nBaseAgent.d.ts.map +1 -0
  48. package/dist/agents/n8n/N8nBaseAgent.js +446 -0
  49. package/dist/agents/n8n/N8nBaseAgent.js.map +1 -0
  50. package/dist/agents/n8n/N8nCIOrchestratorAgent.d.ts +164 -0
  51. package/dist/agents/n8n/N8nCIOrchestratorAgent.d.ts.map +1 -0
  52. package/dist/agents/n8n/N8nCIOrchestratorAgent.js +610 -0
  53. package/dist/agents/n8n/N8nCIOrchestratorAgent.js.map +1 -0
  54. package/dist/agents/n8n/N8nChaosTesterAgent.d.ts +205 -0
  55. package/dist/agents/n8n/N8nChaosTesterAgent.d.ts.map +1 -0
  56. package/dist/agents/n8n/N8nChaosTesterAgent.js +729 -0
  57. package/dist/agents/n8n/N8nChaosTesterAgent.js.map +1 -0
  58. package/dist/agents/n8n/N8nComplianceValidatorAgent.d.ts +228 -0
  59. package/dist/agents/n8n/N8nComplianceValidatorAgent.d.ts.map +1 -0
  60. package/dist/agents/n8n/N8nComplianceValidatorAgent.js +986 -0
  61. package/dist/agents/n8n/N8nComplianceValidatorAgent.js.map +1 -0
  62. package/dist/agents/n8n/N8nContractTesterAgent.d.ts +213 -0
  63. package/dist/agents/n8n/N8nContractTesterAgent.d.ts.map +1 -0
  64. package/dist/agents/n8n/N8nContractTesterAgent.js +989 -0
  65. package/dist/agents/n8n/N8nContractTesterAgent.js.map +1 -0
  66. package/dist/agents/n8n/N8nExpressionValidatorAgent.d.ts +99 -0
  67. package/dist/agents/n8n/N8nExpressionValidatorAgent.d.ts.map +1 -0
  68. package/dist/agents/n8n/N8nExpressionValidatorAgent.js +632 -0
  69. package/dist/agents/n8n/N8nExpressionValidatorAgent.js.map +1 -0
  70. package/dist/agents/n8n/N8nFailureModeTesterAgent.d.ts +238 -0
  71. package/dist/agents/n8n/N8nFailureModeTesterAgent.d.ts.map +1 -0
  72. package/dist/agents/n8n/N8nFailureModeTesterAgent.js +956 -0
  73. package/dist/agents/n8n/N8nFailureModeTesterAgent.js.map +1 -0
  74. package/dist/agents/n8n/N8nIdempotencyTesterAgent.d.ts +242 -0
  75. package/dist/agents/n8n/N8nIdempotencyTesterAgent.d.ts.map +1 -0
  76. package/dist/agents/n8n/N8nIdempotencyTesterAgent.js +992 -0
  77. package/dist/agents/n8n/N8nIdempotencyTesterAgent.js.map +1 -0
  78. package/dist/agents/n8n/N8nIntegrationTestAgent.d.ts +104 -0
  79. package/dist/agents/n8n/N8nIntegrationTestAgent.d.ts.map +1 -0
  80. package/dist/agents/n8n/N8nIntegrationTestAgent.js +653 -0
  81. package/dist/agents/n8n/N8nIntegrationTestAgent.js.map +1 -0
  82. package/dist/agents/n8n/N8nMonitoringValidatorAgent.d.ts +210 -0
  83. package/dist/agents/n8n/N8nMonitoringValidatorAgent.d.ts.map +1 -0
  84. package/dist/agents/n8n/N8nMonitoringValidatorAgent.js +669 -0
  85. package/dist/agents/n8n/N8nMonitoringValidatorAgent.js.map +1 -0
  86. package/dist/agents/n8n/N8nNodeValidatorAgent.d.ts +142 -0
  87. package/dist/agents/n8n/N8nNodeValidatorAgent.d.ts.map +1 -0
  88. package/dist/agents/n8n/N8nNodeValidatorAgent.js +1090 -0
  89. package/dist/agents/n8n/N8nNodeValidatorAgent.js.map +1 -0
  90. package/dist/agents/n8n/N8nPerformanceTesterAgent.d.ts +198 -0
  91. package/dist/agents/n8n/N8nPerformanceTesterAgent.d.ts.map +1 -0
  92. package/dist/agents/n8n/N8nPerformanceTesterAgent.js +653 -0
  93. package/dist/agents/n8n/N8nPerformanceTesterAgent.js.map +1 -0
  94. package/dist/agents/n8n/N8nReplayabilityTesterAgent.d.ts +245 -0
  95. package/dist/agents/n8n/N8nReplayabilityTesterAgent.d.ts.map +1 -0
  96. package/dist/agents/n8n/N8nReplayabilityTesterAgent.js +952 -0
  97. package/dist/agents/n8n/N8nReplayabilityTesterAgent.js.map +1 -0
  98. package/dist/agents/n8n/N8nSecretsHygieneAuditorAgent.d.ts +325 -0
  99. package/dist/agents/n8n/N8nSecretsHygieneAuditorAgent.d.ts.map +1 -0
  100. package/dist/agents/n8n/N8nSecretsHygieneAuditorAgent.js +1187 -0
  101. package/dist/agents/n8n/N8nSecretsHygieneAuditorAgent.js.map +1 -0
  102. package/dist/agents/n8n/N8nSecurityAuditorAgent.d.ts +91 -0
  103. package/dist/agents/n8n/N8nSecurityAuditorAgent.d.ts.map +1 -0
  104. package/dist/agents/n8n/N8nSecurityAuditorAgent.js +825 -0
  105. package/dist/agents/n8n/N8nSecurityAuditorAgent.js.map +1 -0
  106. package/dist/agents/n8n/N8nTestHarness.d.ts +131 -0
  107. package/dist/agents/n8n/N8nTestHarness.d.ts.map +1 -0
  108. package/dist/agents/n8n/N8nTestHarness.js +456 -0
  109. package/dist/agents/n8n/N8nTestHarness.js.map +1 -0
  110. package/dist/agents/n8n/N8nTriggerTestAgent.d.ts +119 -0
  111. package/dist/agents/n8n/N8nTriggerTestAgent.d.ts.map +1 -0
  112. package/dist/agents/n8n/N8nTriggerTestAgent.js +652 -0
  113. package/dist/agents/n8n/N8nTriggerTestAgent.js.map +1 -0
  114. package/dist/agents/n8n/N8nUnitTesterAgent.d.ts +130 -0
  115. package/dist/agents/n8n/N8nUnitTesterAgent.d.ts.map +1 -0
  116. package/dist/agents/n8n/N8nUnitTesterAgent.js +522 -0
  117. package/dist/agents/n8n/N8nUnitTesterAgent.js.map +1 -0
  118. package/dist/agents/n8n/N8nVersionComparatorAgent.d.ts +201 -0
  119. package/dist/agents/n8n/N8nVersionComparatorAgent.d.ts.map +1 -0
  120. package/dist/agents/n8n/N8nVersionComparatorAgent.js +645 -0
  121. package/dist/agents/n8n/N8nVersionComparatorAgent.js.map +1 -0
  122. package/dist/agents/n8n/N8nWorkflowExecutorAgent.d.ts +120 -0
  123. package/dist/agents/n8n/N8nWorkflowExecutorAgent.d.ts.map +1 -0
  124. package/dist/agents/n8n/N8nWorkflowExecutorAgent.js +347 -0
  125. package/dist/agents/n8n/N8nWorkflowExecutorAgent.js.map +1 -0
  126. package/dist/agents/n8n/index.d.ts +119 -0
  127. package/dist/agents/n8n/index.d.ts.map +1 -0
  128. package/dist/agents/n8n/index.js +298 -0
  129. package/dist/agents/n8n/index.js.map +1 -0
  130. package/dist/agents/n8n/types.d.ts +486 -0
  131. package/dist/agents/n8n/types.d.ts.map +1 -0
  132. package/dist/agents/n8n/types.js +8 -0
  133. package/dist/agents/n8n/types.js.map +1 -0
  134. package/dist/agents/utils/generators.d.ts +30 -0
  135. package/dist/agents/utils/generators.d.ts.map +1 -0
  136. package/dist/agents/utils/generators.js +44 -0
  137. package/dist/agents/utils/generators.js.map +1 -0
  138. package/dist/agents/utils/index.d.ts +10 -0
  139. package/dist/agents/utils/index.d.ts.map +1 -0
  140. package/dist/agents/utils/index.js +19 -0
  141. package/dist/agents/utils/index.js.map +1 -0
  142. package/dist/agents/utils/validation.d.ts +72 -0
  143. package/dist/agents/utils/validation.d.ts.map +1 -0
  144. package/dist/agents/utils/validation.js +75 -0
  145. package/dist/agents/utils/validation.js.map +1 -0
  146. package/dist/cli/init/agents.d.ts.map +1 -1
  147. package/dist/cli/init/agents.js +29 -0
  148. package/dist/cli/init/agents.js.map +1 -1
  149. package/dist/cli/init/skills.d.ts.map +1 -1
  150. package/dist/cli/init/skills.js +7 -1
  151. package/dist/cli/init/skills.js.map +1 -1
  152. package/dist/core/memory/HNSWVectorMemory.js +1 -1
  153. package/dist/core/memory/SwarmMemoryManager.d.ts +114 -90
  154. package/dist/core/memory/SwarmMemoryManager.d.ts.map +1 -1
  155. package/dist/core/memory/SwarmMemoryManager.js +277 -235
  156. package/dist/core/memory/SwarmMemoryManager.js.map +1 -1
  157. package/dist/learning/baselines/StandardTaskSuite.d.ts.map +1 -1
  158. package/dist/learning/baselines/StandardTaskSuite.js +38 -0
  159. package/dist/learning/baselines/StandardTaskSuite.js.map +1 -1
  160. package/dist/mcp/server-instructions.d.ts +1 -1
  161. package/dist/mcp/server-instructions.js +1 -1
  162. package/dist/types/memory-interfaces.d.ts +76 -68
  163. package/dist/types/memory-interfaces.d.ts.map +1 -1
  164. package/dist/types/memory-interfaces.js +3 -0
  165. package/dist/types/memory-interfaces.js.map +1 -1
  166. package/docs/reference/agents.md +91 -2
  167. package/docs/reference/skills.md +97 -2
  168. package/package.json +2 -2
@@ -0,0 +1,434 @@
1
+ ---
2
+ name: n8n-expression-testing
3
+ description: "n8n expression syntax validation, context-aware testing, common pitfalls detection, and performance optimization. Use when validating n8n expressions and data transformations."
4
+ category: n8n-testing
5
+ priority: high
6
+ tokenEstimate: 1000
7
+ agents: [n8n-expression-validator]
8
+ implementation_status: production
9
+ optimization_version: 1.0
10
+ last_optimized: 2025-12-15
11
+ dependencies: []
12
+ quick_reference_card: true
13
+ tags: [n8n, expressions, javascript, data-transformation, validation]
14
+ ---
15
+
16
+ # n8n Expression Testing
17
+
18
+ <default_to_action>
19
+ When testing n8n expressions:
20
+ 1. VALIDATE syntax before execution
21
+ 2. TEST with multiple context scenarios
22
+ 3. CHECK for null/undefined handling
23
+ 4. VERIFY type safety
24
+ 5. SCAN for security vulnerabilities
25
+
26
+ **Quick Expression Checklist:**
27
+ - Valid JavaScript syntax
28
+ - Context variables properly referenced ($json, $node)
29
+ - Null-safe access patterns (?., ??)
30
+ - No dangerous functions (eval, Function)
31
+ - Efficient for large data sets
32
+
33
+ **Common Pitfalls:**
34
+ - Accessing nested properties without null checks
35
+ - Type coercion issues
36
+ - Missing fallback values
37
+ - Inefficient array operations
38
+ </default_to_action>
39
+
40
+ ## Quick Reference Card
41
+
42
+ ### n8n Expression Syntax
43
+
44
+ | Pattern | Example | Description |
45
+ |---------|---------|-------------|
46
+ | Basic access | `{{ $json.field }}` | Access JSON field |
47
+ | Nested access | `{{ $json.user.email }}` | Access nested property |
48
+ | Array access | `{{ $json.items[0] }}` | Access array element |
49
+ | Node reference | `{{ $node["Name"].json.id }}` | Access other node's data |
50
+ | Method call | `{{ $json.name.toLowerCase() }}` | Call string method |
51
+ | Conditional | `{{ $json.x ? "yes" : "no" }}` | Ternary expression |
52
+
53
+ ### Context Variables
54
+
55
+ | Variable | Description | Example |
56
+ |----------|-------------|---------|
57
+ | `$json` | Current item data | `{{ $json.email }}` |
58
+ | `$node["Name"]` | Other node's data | `{{ $node["HTTP"].json.body }}` |
59
+ | `$items()` | Multiple items | `{{ $items("Node", 0, 0).json }}` |
60
+ | `$now` | Current timestamp | `{{ $now.toISO() }}` |
61
+ | `$today` | Today's date | `{{ $today }}` |
62
+ | `$runIndex` | Run iteration | `{{ $runIndex }}` |
63
+ | `$workflow` | Workflow info | `{{ $workflow.name }}` |
64
+
65
+ ---
66
+
67
+ ## Expression Syntax Patterns
68
+
69
+ ### Safe Data Access
70
+
71
+ ```javascript
72
+ // BAD: Can fail if nested objects are null
73
+ {{ $json.user.profile.email }}
74
+
75
+ // GOOD: Optional chaining with fallback
76
+ {{ $json.user?.profile?.email ?? '' }}
77
+
78
+ // BAD: Array access without bounds check
79
+ {{ $json.items[0].name }}
80
+
81
+ // GOOD: Safe array access
82
+ {{ $json.items?.[0]?.name ?? 'No items' }}
83
+ ```
84
+
85
+ ### Type Conversions
86
+
87
+ ```javascript
88
+ // String to Number
89
+ {{ parseInt($json.quantity, 10) }}
90
+ {{ parseFloat($json.price) }}
91
+ {{ Number($json.value) }}
92
+
93
+ // Number to String
94
+ {{ String($json.id) }}
95
+ {{ $json.amount.toString() }}
96
+ {{ $json.count.toFixed(2) }}
97
+
98
+ // Date handling
99
+ {{ new Date($json.timestamp).toISOString() }}
100
+ {{ DateTime.fromISO($json.date).toFormat('yyyy-MM-dd') }}
101
+
102
+ // Boolean conversion
103
+ {{ Boolean($json.active) }}
104
+ {{ $json.enabled === 'true' }}
105
+ ```
106
+
107
+ ### String Operations
108
+
109
+ ```javascript
110
+ // Case conversion
111
+ {{ $json.name.toLowerCase() }}
112
+ {{ $json.name.toUpperCase() }}
113
+ {{ $json.name.charAt(0).toUpperCase() + $json.name.slice(1) }}
114
+
115
+ // String manipulation
116
+ {{ $json.text.trim() }}
117
+ {{ $json.text.replace(/\s+/g, ' ') }}
118
+ {{ $json.text.substring(0, 100) }}
119
+
120
+ // Template strings
121
+ {{ `Hello, ${$json.firstName} ${$json.lastName}!` }}
122
+ {{ `Order #${$json.orderId} - ${$json.status}` }}
123
+ ```
124
+
125
+ ### Array Operations
126
+
127
+ ```javascript
128
+ // Mapping
129
+ {{ $json.items.map(item => item.name) }}
130
+ {{ $json.items.map(item => ({ id: item.id, total: item.price * item.qty })) }}
131
+
132
+ // Filtering
133
+ {{ $json.items.filter(item => item.active) }}
134
+ {{ $json.items.filter(item => item.price > 100) }}
135
+
136
+ // Reducing
137
+ {{ $json.items.reduce((sum, item) => sum + item.price, 0) }}
138
+ {{ $json.items.reduce((acc, item) => ({ ...acc, [item.id]: item }), {}) }}
139
+
140
+ // Finding
141
+ {{ $json.items.find(item => item.id === $json.targetId) }}
142
+ {{ $json.items.findIndex(item => item.name === 'target') }}
143
+
144
+ // Joining
145
+ {{ $json.tags.join(', ') }}
146
+ {{ $json.items.map(i => i.name).join(' | ') }}
147
+ ```
148
+
149
+ ---
150
+
151
+ ## Validation Patterns
152
+
153
+ ```typescript
154
+ // Validate expression syntax
155
+ function validateExpressionSyntax(expression: string): ValidationResult {
156
+ // Remove n8n template markers
157
+ const code = expression.replace(/\{\{|\}\}/g, '').trim();
158
+
159
+ try {
160
+ // Check if valid JavaScript
161
+ new Function(`return (${code})`);
162
+ return { valid: true };
163
+ } catch (error) {
164
+ return {
165
+ valid: false,
166
+ error: error.message,
167
+ suggestion: suggestFix(error.message, code)
168
+ };
169
+ }
170
+ }
171
+
172
+ // Validate context variables
173
+ function validateContextVariables(expression: string): string[] {
174
+ const contextVars = ['$json', '$node', '$items', '$now', '$today', '$runIndex', '$workflow'];
175
+ const usedVars = [];
176
+ const invalidVars = [];
177
+
178
+ // Find all $ prefixed variables
179
+ const varPattern = /\$\w+/g;
180
+ let match;
181
+
182
+ while ((match = varPattern.exec(expression)) !== null) {
183
+ const varName = match[0];
184
+ if (contextVars.some(cv => varName.startsWith(cv))) {
185
+ usedVars.push(varName);
186
+ } else {
187
+ invalidVars.push(varName);
188
+ }
189
+ }
190
+
191
+ return { usedVars, invalidVars };
192
+ }
193
+
194
+ // Test expression with sample data
195
+ function testExpression(expression: string, context: any): TestResult {
196
+ const code = expression.replace(/\{\{|\}\}/g, '').trim();
197
+
198
+ try {
199
+ // Create function with context
200
+ const fn = new Function('$json', '$node', '$items', '$now', '$today',
201
+ `return (${code})`);
202
+
203
+ const result = fn(
204
+ context.$json || {},
205
+ context.$node || {},
206
+ context.$items || (() => ({})),
207
+ context.$now || new Date(),
208
+ context.$today || new Date()
209
+ );
210
+
211
+ return { success: true, result };
212
+ } catch (error) {
213
+ return { success: false, error: error.message };
214
+ }
215
+ }
216
+ ```
217
+
218
+ ---
219
+
220
+ ## Common Errors and Fixes
221
+
222
+ ### Undefined Property Access
223
+
224
+ ```javascript
225
+ // ERROR: Cannot read property 'email' of undefined
226
+ {{ $json.user.email }}
227
+
228
+ // FIX 1: Optional chaining
229
+ {{ $json.user?.email }}
230
+
231
+ // FIX 2: With fallback
232
+ {{ $json.user?.email ?? 'no-email@example.com' }}
233
+
234
+ // FIX 3: Conditional
235
+ {{ $json.user ? $json.user.email : '' }}
236
+ ```
237
+
238
+ ### Type Errors
239
+
240
+ ```javascript
241
+ // ERROR: toLowerCase is not a function (when null)
242
+ {{ $json.name.toLowerCase() }}
243
+
244
+ // FIX: Null check first
245
+ {{ $json.name?.toLowerCase() ?? '' }}
246
+
247
+ // ERROR: toFixed is not a function (string instead of number)
248
+ {{ $json.price.toFixed(2) }}
249
+
250
+ // FIX: Parse as number first
251
+ {{ parseFloat($json.price).toFixed(2) }}
252
+
253
+ // ERROR: map is not a function (not an array)
254
+ {{ $json.items.map(i => i.name) }}
255
+
256
+ // FIX: Ensure array
257
+ {{ (Array.isArray($json.items) ? $json.items : []).map(i => i.name) }}
258
+ ```
259
+
260
+ ### Node Reference Errors
261
+
262
+ ```javascript
263
+ // ERROR: Node "Previous Node" not found
264
+ {{ $node["Previous Node"].json.data }}
265
+
266
+ // FIX: Use exact node name (case-sensitive)
267
+ {{ $node["Previous Node1"].json.data }}
268
+
269
+ // FIX: Add fallback for safety
270
+ {{ $node["Previous Node"]?.json?.data ?? {} }}
271
+ ```
272
+
273
+ ---
274
+
275
+ ## Security Patterns
276
+
277
+ ### Dangerous Functions to Avoid
278
+
279
+ ```javascript
280
+ // DANGEROUS: Never use eval
281
+ {{ eval($json.code) }}
282
+
283
+ // DANGEROUS: Dynamic function creation
284
+ {{ new Function($json.code)() }}
285
+
286
+ // DANGEROUS: setTimeout with string
287
+ {{ setTimeout($json.code, 1000) }}
288
+
289
+ // SAFE: Use explicit operations instead
290
+ {{ $json.value * 2 }}
291
+ {{ JSON.parse($json.jsonString) }}
292
+ ```
293
+
294
+ ### Input Validation
295
+
296
+ ```javascript
297
+ // Validate email format
298
+ {{ /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test($json.email) ? $json.email : '' }}
299
+
300
+ // Sanitize for HTML (basic)
301
+ {{ $json.text.replace(/[<>&"']/g, c => ({
302
+ '<': '&lt;', '>': '&gt;', '&': '&amp;', '"': '&quot;', "'": '&#39;'
303
+ }[c])) }}
304
+
305
+ // Limit string length
306
+ {{ $json.input.substring(0, 1000) }}
307
+
308
+ // Validate number range
309
+ {{ Math.min(Math.max(parseInt($json.value), 0), 100) }}
310
+ ```
311
+
312
+ ---
313
+
314
+ ## Performance Optimization
315
+
316
+ ### Efficient Array Operations
317
+
318
+ ```javascript
319
+ // SLOW: Multiple iterations
320
+ {{ $json.items.filter(i => i.active).map(i => i.name).join(', ') }}
321
+
322
+ // FASTER: Single reduce
323
+ {{ $json.items.reduce((acc, i) => i.active ? (acc ? `${acc}, ${i.name}` : i.name) : acc, '') }}
324
+
325
+ // SLOW: Nested loops
326
+ {{ $json.items.map(i => $json.categories.find(c => c.id === i.categoryId)) }}
327
+
328
+ // FASTER: Create lookup map first (in Code node)
329
+ const categoryMap = Object.fromEntries($json.categories.map(c => [c.id, c]));
330
+ return $json.items.map(i => categoryMap[i.categoryId]);
331
+ ```
332
+
333
+ ### Avoid in Expressions
334
+
335
+ ```javascript
336
+ // AVOID: Complex logic in expressions
337
+ {{ $json.items.reduce((acc, item) => {
338
+ const category = $json.categories.find(c => c.id === item.catId);
339
+ if (category && category.active) {
340
+ acc.push({ ...item, categoryName: category.name });
341
+ }
342
+ return acc;
343
+ }, []) }}
344
+
345
+ // BETTER: Move to Code node for complex transformations
346
+ ```
347
+
348
+ ---
349
+
350
+ ## Testing Patterns
351
+
352
+ ```typescript
353
+ // Expression test suite
354
+ const expressionTests = [
355
+ {
356
+ name: 'Basic property access',
357
+ expression: '{{ $json.name }}',
358
+ context: { $json: { name: 'John' } },
359
+ expected: 'John'
360
+ },
361
+ {
362
+ name: 'Nested with optional chaining',
363
+ expression: '{{ $json.user?.email ?? "default" }}',
364
+ context: { $json: { user: null } },
365
+ expected: 'default'
366
+ },
367
+ {
368
+ name: 'Array mapping',
369
+ expression: '{{ $json.items.map(i => i.id).join(",") }}',
370
+ context: { $json: { items: [{ id: 1 }, { id: 2 }] } },
371
+ expected: '1,2'
372
+ },
373
+ {
374
+ name: 'Conditional expression',
375
+ expression: '{{ $json.score >= 70 ? "Pass" : "Fail" }}',
376
+ context: { $json: { score: 85 } },
377
+ expected: 'Pass'
378
+ },
379
+ {
380
+ name: 'Node reference',
381
+ expression: '{{ $node["Previous"].json.result }}',
382
+ context: { $node: { Previous: { json: { result: 'success' } } } },
383
+ expected: 'success'
384
+ }
385
+ ];
386
+
387
+ // Run tests
388
+ for (const test of expressionTests) {
389
+ const result = testExpression(test.expression, test.context);
390
+ console.log(`${test.name}: ${result.result === test.expected ? 'PASS' : 'FAIL'}`);
391
+ }
392
+ ```
393
+
394
+ ---
395
+
396
+ ## Agent Coordination
397
+
398
+ ### Memory Namespace
399
+ ```
400
+ aqe/n8n/expressions/
401
+ ├── validations/* - Expression validation results
402
+ ├── patterns/* - Discovered expression patterns
403
+ ├── errors/* - Common error catalog
404
+ └── optimizations/* - Performance suggestions
405
+ ```
406
+
407
+ ### Fleet Coordination
408
+ ```typescript
409
+ // Coordinate expression validation with workflow testing
410
+ await Task("Validate expressions", {
411
+ workflowId: "wf-123",
412
+ validateAll: true,
413
+ testWithSampleData: true
414
+ }, "n8n-expression-validator");
415
+ ```
416
+
417
+ ---
418
+
419
+ ## Related Skills
420
+ - [n8n-workflow-testing-fundamentals](../n8n-workflow-testing-fundamentals/) - Workflow testing
421
+ - [n8n-security-testing](../n8n-security-testing/) - Security validation
422
+
423
+ ---
424
+
425
+ ## Remember
426
+
427
+ **n8n expressions are JavaScript-like** with special context variables ($json, $node, etc.). Testing requires:
428
+ - Syntax validation
429
+ - Context variable verification
430
+ - Null safety checks
431
+ - Type compatibility
432
+ - Security scanning
433
+
434
+ **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).