first commit
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled

This commit is contained in:
2026-03-17 16:22:57 +03:30
commit 3d5eaf9445
15349 changed files with 2847338 additions and 0 deletions
@@ -0,0 +1,5 @@
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
describe('Test Merge Node', () => {
new NodeTestHarness().setupTests();
});
@@ -0,0 +1,143 @@
{
"name": "merge tests",
"nodes": [
{
"parameters": {},
"id": "9f880c6f-b5e0-4453-b1d7-550beb1febe8",
"name": "When clicking \"Execute Workflow\"",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [820, 380]
},
{
"parameters": {
"data": [
{
"id": 1
},
{
"id": 2
},
{
"id": 3
}
]
},
"id": "263d9c7f-32d4-4112-b271-73d09b73809a",
"name": "Code",
"type": "n8n-nodes-testing.testData",
"typeVersion": 1,
"position": [1020, 220]
},
{
"parameters": {},
"id": "82ff69e1-596b-48dd-b724-388ef454a822",
"name": "Merge",
"type": "n8n-nodes-base.merge",
"typeVersion": 1,
"position": [1280, 360]
},
{
"parameters": {
"data": [
{
"id": 4
},
{
"id": 5
},
{
"id": 6
}
]
},
"id": "3defcf5a-ec5e-4d23-a1f6-a99b7362a241",
"name": "Code1",
"type": "n8n-nodes-testing.testData",
"typeVersion": 1,
"position": [1040, 540]
}
],
"pinData": {
"Merge": [
{
"json": {
"id": 1
}
},
{
"json": {
"id": 2
}
},
{
"json": {
"id": 3
}
},
{
"json": {
"id": 4
}
},
{
"json": {
"id": 5
}
},
{
"json": {
"id": 6
}
}
]
},
"connections": {
"When clicking \"Execute Workflow\"": {
"main": [
[
{
"node": "Code",
"type": "main",
"index": 0
},
{
"node": "Code1",
"type": "main",
"index": 0
}
]
]
},
"Code": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 0
}
]
]
},
"Code1": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 1
}
]
]
}
},
"active": false,
"settings": {},
"versionId": "7082c0c9-60ab-4bcb-adbd-89e56e0bddd6",
"id": "107",
"meta": {
"instanceId": "36203ea1ce3cef713fa25999bd9874ae26b9e4c2c3a90a365f2882a154d031d0"
},
"tags": []
}
@@ -0,0 +1,138 @@
{
"meta": {
"templateCredsSetupCompleted": true,
"instanceId": "8d731d98fab18fb8e68289d44c50faa5d5c5378aedc3f892abdd7d5d3b7061c5"
},
"nodes": [
{
"parameters": {
"fields": {
"values": [
{
"name": "one",
"stringValue": "={{ $('Code').item.json.id }}"
},
{
"name": "two",
"stringValue": "={{ $('Code1').item.json.id }}"
}
]
},
"options": {}
},
"id": "853f9e11-e59b-4f21-81ba-08ec2d69c87a",
"name": "Edit Fields",
"type": "n8n-nodes-base.set",
"typeVersion": 3.2,
"position": [900, 580]
},
{
"parameters": {},
"id": "8310a9da-b02b-4a77-80d4-7c2de5bcbae8",
"name": "When clicking \"Execute Workflow\"",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [180, 600]
},
{
"parameters": {
"data": [
{
"id": 1
}
]
},
"id": "0f1fb40d-0c6c-455d-bb3b-0c0fa818e063",
"name": "Code",
"type": "n8n-nodes-testing.testData",
"typeVersion": 1,
"position": [420, 520]
},
{
"parameters": {
"data": [
{
"id": 2
}
]
},
"id": "873fcccc-86c1-40fd-bdae-2bb31e971382",
"name": "Code1",
"type": "n8n-nodes-testing.testData",
"typeVersion": 1,
"position": [420, 680]
},
{
"parameters": {
"mode": "chooseBranch",
"output": "empty"
},
"id": "b81a2372-9f8b-4899-b2fd-c581bcf930d8",
"name": "Merge3",
"type": "n8n-nodes-base.merge",
"typeVersion": 2,
"position": [700, 580]
}
],
"connections": {
"When clicking \"Execute Workflow\"": {
"main": [
[
{
"node": "Code",
"type": "main",
"index": 0
},
{
"node": "Code1",
"type": "main",
"index": 0
}
]
]
},
"Code": {
"main": [
[
{
"node": "Merge3",
"type": "main",
"index": 0
}
]
]
},
"Code1": {
"main": [
[
{
"node": "Merge3",
"type": "main",
"index": 1
}
]
]
},
"Merge3": {
"main": [
[
{
"node": "Edit Fields",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {
"Edit Fields": [
{
"json": {
"one": "1",
"two": "2"
}
}
]
}
}
@@ -0,0 +1,194 @@
{
"name": "merge tests",
"nodes": [
{
"parameters": {},
"id": "9f880c6f-b5e0-4453-b1d7-550beb1febe8",
"name": "When clicking \"Execute Workflow\"",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [820, 380]
},
{
"parameters": {
"data": [
{
"id": 1
},
{
"id": 2
},
{
"id": 3
}
]
},
"id": "263d9c7f-32d4-4112-b271-73d09b73809a",
"name": "Code",
"type": "n8n-nodes-testing.testData",
"typeVersion": 1,
"position": [1020, 220]
},
{
"parameters": {
"data": [
{
"id": 4
},
{
"id": 5
},
{
"id": 6
}
]
},
"id": "3defcf5a-ec5e-4d23-a1f6-a99b7362a241",
"name": "Code1",
"type": "n8n-nodes-testing.testData",
"typeVersion": 1,
"position": [1040, 540]
},
{
"parameters": {
"mode": "chooseBranch"
},
"id": "7120cd6f-29f3-4f5b-aa25-babebd6335d3",
"name": "Merge",
"type": "n8n-nodes-base.merge",
"typeVersion": 2,
"position": [1300, 240]
},
{
"parameters": {
"mode": "chooseBranch",
"output": "input2"
},
"id": "5dbe68d4-bf2f-40ea-a9ae-ee83b4030fa5",
"name": "Merge1",
"type": "n8n-nodes-base.merge",
"typeVersion": 2,
"position": [1300, 380]
},
{
"parameters": {
"mode": "chooseBranch",
"output": "empty"
},
"id": "3b2885c3-5c2e-4972-910a-50ff8e173d11",
"name": "Merge2",
"type": "n8n-nodes-base.merge",
"typeVersion": 2,
"position": [1300, 520]
}
],
"pinData": {
"Merge": [
{
"json": {
"id": 1
}
},
{
"json": {
"id": 2
}
},
{
"json": {
"id": 3
}
}
],
"Merge1": [
{
"json": {
"id": 4
}
},
{
"json": {
"id": 5
}
},
{
"json": {
"id": 6
}
}
],
"Merge2": [
{
"json": {}
}
]
},
"connections": {
"When clicking \"Execute Workflow\"": {
"main": [
[
{
"node": "Code",
"type": "main",
"index": 0
},
{
"node": "Code1",
"type": "main",
"index": 0
}
]
]
},
"Code": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 0
},
{
"node": "Merge1",
"type": "main",
"index": 0
},
{
"node": "Merge2",
"type": "main",
"index": 0
}
]
]
},
"Code1": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 1
},
{
"node": "Merge1",
"type": "main",
"index": 1
},
{
"node": "Merge2",
"type": "main",
"index": 1
}
]
]
}
},
"active": false,
"settings": {},
"versionId": "dc43b494-33dc-4671-9004-e5e53170732c",
"id": "107",
"meta": {
"instanceId": "36203ea1ce3cef713fa25999bd9874ae26b9e4c2c3a90a365f2882a154d031d0"
},
"tags": []
}
@@ -0,0 +1,518 @@
{
"name": "merge tests",
"nodes": [
{
"parameters": {},
"id": "9f880c6f-b5e0-4453-b1d7-550beb1febe8",
"name": "When clicking \"Execute Workflow\"",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [700, 660]
},
{
"parameters": {
"data": [
{
"id": 1,
"data": "a",
"input": 1,
"text": "foo"
},
{
"id": 2,
"data": "b",
"input": 1,
"text": "foo"
}
]
},
"id": "263d9c7f-32d4-4112-b271-73d09b73809a",
"name": "Code",
"type": "n8n-nodes-testing.testData",
"typeVersion": 1,
"position": [900, 540]
},
{
"parameters": {
"data": [
{
"id": 1,
"data": "c",
"input": 2,
"tag": "second"
},
{
"id": 2,
"data": "d",
"input": 2,
"tag": "second"
},
{
"id": 3,
"data": "e",
"input": 2,
"tag": "second"
}
]
},
"id": "3defcf5a-ec5e-4d23-a1f6-a99b7362a241",
"name": "Code1",
"type": "n8n-nodes-testing.testData",
"typeVersion": 1,
"position": [900, 780]
},
{
"parameters": {
"mode": "combine",
"mergeByFields": {
"values": [
{
"field1": "id",
"field2": "id"
}
]
},
"options": {}
},
"id": "7120cd6f-29f3-4f5b-aa25-babebd6335d3",
"name": "Merge",
"type": "n8n-nodes-base.merge",
"typeVersion": 2,
"position": [1320, 140]
},
{
"parameters": {
"mode": "combine",
"mergeByFields": {
"values": [
{
"field1": "id",
"field2": "id"
}
]
},
"joinMode": "keepNonMatches",
"options": {}
},
"id": "1d6973e5-0716-4d47-85ef-298d3f86bb9d",
"name": "Merge1",
"type": "n8n-nodes-base.merge",
"typeVersion": 2,
"position": [1320, 280]
},
{
"parameters": {
"mode": "combine",
"mergeByFields": {
"values": [
{
"field1": "id",
"field2": "id"
}
]
},
"joinMode": "keepEverything",
"options": {}
},
"id": "dd75b8c0-21bf-460f-9920-644a467ed356",
"name": "Merge2",
"type": "n8n-nodes-base.merge",
"typeVersion": 2,
"position": [1320, 420]
},
{
"parameters": {
"mode": "combine",
"mergeByFields": {
"values": [
{
"field1": "id",
"field2": "id"
}
]
},
"joinMode": "enrichInput1",
"options": {}
},
"id": "3545877d-6e4f-437e-b91f-4c792d714e73",
"name": "Merge3",
"type": "n8n-nodes-base.merge",
"typeVersion": 2,
"position": [1320, 560]
},
{
"parameters": {
"mode": "combine",
"mergeByFields": {
"values": [
{
"field1": "id",
"field2": "id"
}
]
},
"joinMode": "enrichInput2",
"options": {}
},
"id": "4b6ac099-6e6f-4e91-bcfe-74d7524fad54",
"name": "Merge4",
"type": "n8n-nodes-base.merge",
"typeVersion": 2,
"position": [1320, 740]
},
{
"parameters": {
"mode": "combine",
"mergeByFields": {
"values": [
{
"field1": "id",
"field2": "id"
}
]
},
"outputDataFrom": "input1",
"options": {}
},
"id": "fb4fef36-26ea-4fc0-b6e9-a4b2781c94fa",
"name": "Merge5",
"type": "n8n-nodes-base.merge",
"typeVersion": 2,
"position": [1320, 900]
},
{
"parameters": {
"mode": "combine",
"mergeByFields": {
"values": [
{
"field1": "id",
"field2": "id"
}
]
},
"outputDataFrom": "input2",
"options": {}
},
"id": "0b4fbaaa-cf0b-4da5-b35f-da3f49409965",
"name": "Merge6",
"type": "n8n-nodes-base.merge",
"typeVersion": 2,
"position": [1320, 1040]
},
{
"parameters": {
"mode": "combine",
"mergeByFields": {
"values": [
{
"field1": "id",
"field2": "id"
}
]
},
"options": {
"clashHandling": {
"values": {
"resolveClash": "addSuffix"
}
}
}
},
"id": "25489a7a-74c1-48d5-a03d-1bbd2aba2abe",
"name": "Merge7",
"type": "n8n-nodes-base.merge",
"typeVersion": 2,
"position": [1320, 1200]
}
],
"pinData": {
"Merge": [
{
"json": {
"id": 1,
"data": "c",
"input": 2,
"text": "foo",
"tag": "second"
}
},
{
"json": {
"id": 2,
"data": "d",
"input": 2,
"text": "foo",
"tag": "second"
}
}
],
"Merge1": [
{
"json": {
"id": 3,
"data": "e",
"input": 2,
"tag": "second",
"_source": "input2"
}
}
],
"Merge2": [
{
"json": {
"id": 1,
"data": "c",
"input": 2,
"text": "foo",
"tag": "second"
}
},
{
"json": {
"id": 2,
"data": "d",
"input": 2,
"text": "foo",
"tag": "second"
}
},
{
"json": {
"id": 3,
"data": "e",
"input": 2,
"tag": "second"
}
}
],
"Merge3": [
{
"json": {
"id": 1,
"data": "c",
"input": 2,
"text": "foo",
"tag": "second"
}
},
{
"json": {
"id": 2,
"data": "d",
"input": 2,
"text": "foo",
"tag": "second"
}
}
],
"Merge4": [
{
"json": {
"id": 1,
"data": "a",
"input": 1,
"text": "foo",
"tag": "second"
}
},
{
"json": {
"id": 2,
"data": "b",
"input": 1,
"text": "foo",
"tag": "second"
}
},
{
"json": {
"id": 3,
"data": "e",
"input": 2,
"tag": "second"
}
}
],
"Merge5": [
{
"json": {
"id": 1,
"data": "a",
"input": 1,
"text": "foo"
}
},
{
"json": {
"id": 2,
"data": "b",
"input": 1,
"text": "foo"
}
}
],
"Merge6": [
{
"json": {
"id": 1,
"data": "c",
"input": 2,
"tag": "second"
}
},
{
"json": {
"id": 2,
"data": "d",
"input": 2,
"tag": "second"
}
}
],
"Merge7": [
{
"json": {
"id_1": 1,
"data_1": "a",
"input_1": 1,
"text_1": "foo",
"id_2": 1,
"data_2": "c",
"input_2": 2,
"tag_2": "second"
}
},
{
"json": {
"id_1": 2,
"data_1": "b",
"input_1": 1,
"text_1": "foo",
"id_2": 2,
"data_2": "d",
"input_2": 2,
"tag_2": "second"
}
}
]
},
"connections": {
"When clicking \"Execute Workflow\"": {
"main": [
[
{
"node": "Code",
"type": "main",
"index": 0
},
{
"node": "Code1",
"type": "main",
"index": 0
}
]
]
},
"Code": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 0
},
{
"node": "Merge1",
"type": "main",
"index": 0
},
{
"node": "Merge2",
"type": "main",
"index": 0
},
{
"node": "Merge3",
"type": "main",
"index": 0
},
{
"node": "Merge4",
"type": "main",
"index": 0
},
{
"node": "Merge5",
"type": "main",
"index": 0
},
{
"node": "Merge6",
"type": "main",
"index": 0
},
{
"node": "Merge7",
"type": "main",
"index": 0
}
]
]
},
"Code1": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 1
},
{
"node": "Merge3",
"type": "main",
"index": 1
},
{
"node": "Merge2",
"type": "main",
"index": 1
},
{
"node": "Merge1",
"type": "main",
"index": 1
},
{
"node": "Merge4",
"type": "main",
"index": 1
},
{
"node": "Merge5",
"type": "main",
"index": 1
},
{
"node": "Merge6",
"type": "main",
"index": 1
},
{
"node": "Merge7",
"type": "main",
"index": 1
}
]
]
}
},
"active": false,
"settings": {},
"versionId": "8bad6701-bb00-4617-b1d5-bd24145eadaf",
"id": "107",
"meta": {
"instanceId": "36203ea1ce3cef713fa25999bd9874ae26b9e4c2c3a90a365f2882a154d031d0"
},
"tags": []
}
@@ -0,0 +1,246 @@
{
"name": "merge tests",
"nodes": [
{
"parameters": {},
"id": "9f880c6f-b5e0-4453-b1d7-550beb1febe8",
"name": "When clicking \"Execute Workflow\"",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [840, 360]
},
{
"parameters": {
"data": [
{
"id": 1,
"data": "a",
"input": 1
},
{
"id": 2,
"data": "b",
"input": 1
}
]
},
"id": "263d9c7f-32d4-4112-b271-73d09b73809a",
"name": "Code",
"type": "n8n-nodes-testing.testData",
"typeVersion": 1,
"position": [1040, 200]
},
{
"parameters": {
"data": [
{
"id": 1,
"data": "c",
"input": 2
},
{
"id": 2,
"data": "d",
"input": 2
},
{
"id": 3,
"data": "e",
"input": 2
}
]
},
"id": "3defcf5a-ec5e-4d23-a1f6-a99b7362a241",
"name": "Code1",
"type": "n8n-nodes-testing.testData",
"typeVersion": 1,
"position": [1060, 520]
},
{
"parameters": {
"mode": "combine",
"combinationMode": "mergeByPosition",
"options": {
"clashHandling": {
"values": {
"resolveClash": "addSuffix"
}
}
}
},
"id": "7120cd6f-29f3-4f5b-aa25-babebd6335d3",
"name": "Merge",
"type": "n8n-nodes-base.merge",
"typeVersion": 2,
"position": [1260, 200]
},
{
"parameters": {
"mode": "combine",
"combinationMode": "mergeByPosition",
"options": {
"clashHandling": {
"values": {
"resolveClash": "preferInput1"
}
}
}
},
"id": "b40fdf2e-7527-4954-84fe-464a762f8957",
"name": "Merge1",
"type": "n8n-nodes-base.merge",
"typeVersion": 2,
"position": [1260, 380]
},
{
"parameters": {
"mode": "combine",
"combinationMode": "mergeByPosition",
"options": {
"clashHandling": {
"values": {
"resolveClash": "preferInput2"
}
},
"includeUnpaired": true
}
},
"id": "daca2305-691a-45c2-9010-34a9ef5a783f",
"name": "Merge2",
"type": "n8n-nodes-base.merge",
"typeVersion": 2,
"position": [1260, 540]
}
],
"pinData": {
"Merge": [
{
"json": {
"id_1": 1,
"data_1": "a",
"input_1": 1,
"id_2": 1,
"data_2": "c",
"input_2": 2
}
},
{
"json": {
"id_1": 2,
"data_1": "b",
"input_1": 1,
"id_2": 2,
"data_2": "d",
"input_2": 2
}
}
],
"Merge1": [
{
"json": {
"id": 1,
"data": "a",
"input": 1
}
},
{
"json": {
"id": 2,
"data": "b",
"input": 1
}
}
],
"Merge2": [
{
"json": {
"id": 1,
"data": "c",
"input": 2
}
},
{
"json": {
"id": 2,
"data": "d",
"input": 2
}
},
{
"json": {
"id": 3,
"data": "e",
"input": 2
}
}
]
},
"connections": {
"When clicking \"Execute Workflow\"": {
"main": [
[
{
"node": "Code",
"type": "main",
"index": 0
},
{
"node": "Code1",
"type": "main",
"index": 0
}
]
]
},
"Code": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 0
},
{
"node": "Merge1",
"type": "main",
"index": 0
},
{
"node": "Merge2",
"type": "main",
"index": 0
}
]
]
},
"Code1": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 1
},
{
"node": "Merge1",
"type": "main",
"index": 1
},
{
"node": "Merge2",
"type": "main",
"index": 1
}
]
]
}
},
"active": false,
"settings": {},
"versionId": "c61ce62f-d995-46bb-900a-8b3edf95a858",
"id": "107",
"meta": {
"instanceId": "36203ea1ce3cef713fa25999bd9874ae26b9e4c2c3a90a365f2882a154d031d0"
},
"tags": []
}
@@ -0,0 +1,281 @@
{
"name": "merge tests",
"nodes": [
{
"parameters": {},
"id": "9f880c6f-b5e0-4453-b1d7-550beb1febe8",
"name": "When clicking \"Execute Workflow\"",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [820, 380]
},
{
"parameters": {
"data": [
{
"id": 1,
"data": "a",
"input": 1
},
{
"id": 2,
"data": "b",
"input": 1
}
]
},
"id": "263d9c7f-32d4-4112-b271-73d09b73809a",
"name": "Code",
"type": "n8n-nodes-testing.testData",
"typeVersion": 1,
"position": [1020, 220]
},
{
"parameters": {
"data": [
{
"id": 1,
"data": "c",
"input": 2
},
{
"id": 2,
"data": "d",
"input": 2
}
]
},
"id": "3defcf5a-ec5e-4d23-a1f6-a99b7362a241",
"name": "Code1",
"type": "n8n-nodes-testing.testData",
"typeVersion": 1,
"position": [1040, 540]
},
{
"parameters": {
"mode": "combine",
"combinationMode": "multiplex",
"options": {
"clashHandling": {
"values": {
"resolveClash": "addSuffix"
}
}
}
},
"id": "7120cd6f-29f3-4f5b-aa25-babebd6335d3",
"name": "Merge",
"type": "n8n-nodes-base.merge",
"typeVersion": 2,
"position": [1260, 220]
},
{
"parameters": {
"mode": "combine",
"combinationMode": "multiplex",
"options": {
"clashHandling": {
"values": {
"resolveClash": "preferInput1"
}
}
}
},
"id": "1ec4a466-432d-43f8-b6c0-3cc02cf32f6f",
"name": "Merge1",
"type": "n8n-nodes-base.merge",
"typeVersion": 2,
"position": [1260, 360]
},
{
"parameters": {
"mode": "combine",
"combinationMode": "multiplex",
"options": {
"clashHandling": {
"values": {
"resolveClash": "preferInput2"
}
}
}
},
"id": "fb671be6-b476-4302-984f-0c973839581b",
"name": "Merge2",
"type": "n8n-nodes-base.merge",
"typeVersion": 2,
"position": [1260, 500]
}
],
"pinData": {
"Merge": [
{
"json": {
"id_1": 1,
"data_1": "a",
"input_1": 1,
"id_2": 1,
"data_2": "c",
"input_2": 2
}
},
{
"json": {
"id_1": 1,
"data_1": "a",
"input_1": 1,
"id_2": 2,
"data_2": "d",
"input_2": 2
}
},
{
"json": {
"id_1": 2,
"data_1": "b",
"input_1": 1,
"id_2": 1,
"data_2": "c",
"input_2": 2
}
},
{
"json": {
"id_1": 2,
"data_1": "b",
"input_1": 1,
"id_2": 2,
"data_2": "d",
"input_2": 2
}
}
],
"Merge1": [
{
"json": {
"id": 1,
"data": "a",
"input": 1
}
},
{
"json": {
"id": 2,
"data": "b",
"input": 1
}
},
{
"json": {
"id": 1,
"data": "a",
"input": 1
}
},
{
"json": {
"id": 2,
"data": "b",
"input": 1
}
}
],
"Merge2": [
{
"json": {
"id": 1,
"data": "c",
"input": 2
}
},
{
"json": {
"id": 2,
"data": "d",
"input": 2
}
},
{
"json": {
"id": 1,
"data": "c",
"input": 2
}
},
{
"json": {
"id": 2,
"data": "d",
"input": 2
}
}
]
},
"connections": {
"When clicking \"Execute Workflow\"": {
"main": [
[
{
"node": "Code",
"type": "main",
"index": 0
},
{
"node": "Code1",
"type": "main",
"index": 0
}
]
]
},
"Code": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 0
},
{
"node": "Merge1",
"type": "main",
"index": 0
},
{
"node": "Merge2",
"type": "main",
"index": 0
}
]
]
},
"Code1": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 1
},
{
"node": "Merge1",
"type": "main",
"index": 1
},
{
"node": "Merge2",
"type": "main",
"index": 1
}
]
]
}
},
"active": false,
"settings": {},
"versionId": "0cab5d94-90b7-4024-ad58-af9cafb46a21",
"id": "107",
"meta": {
"instanceId": "36203ea1ce3cef713fa25999bd9874ae26b9e4c2c3a90a365f2882a154d031d0"
},
"tags": []
}
@@ -0,0 +1,612 @@
{
"name": "merge fix",
"nodes": [
{
"parameters": {},
"id": "94003e55-6c4e-492f-802a-49f4fb5b5f4b",
"name": "When clicking Execute workflow",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [120, 940]
},
{
"parameters": {
"data": [
{
"id": 1,
"first_name": "John",
"last_name": "Doe"
},
{
"id": 2,
"first_name": "Jane",
"last_name": "Smith"
},
{
"id": 3,
"first_name": "Michael",
"last_name": "Johnson"
},
{
"id": 4,
"first_name": "Emily",
"last_name": "Davis"
},
{
"id": 5,
"first_name": "Robert",
"last_name": "Taylor"
},
{
"id": 6,
"first_name": "Olivia",
"last_name": "Martin"
},
{
"id": 7,
"first_name": "William",
"last_name": "Brown"
},
{
"id": 8,
"first_name": "Sophia",
"last_name": "Anderson"
},
{
"id": 9,
"first_name": "Daniel",
"last_name": "Wilson"
},
{
"id": 10,
"first_name": "Ava",
"last_name": "Miller"
}
]
},
"id": "da82fbb0-b689-4c4e-b310-303361e8411c",
"name": "Mock data A",
"type": "n8n-nodes-testing.testData",
"typeVersion": 1,
"position": [340, 840]
},
{
"parameters": {
"data": []
},
"id": "493ecb02-52e7-43b7-8c73-d45a3f7e76f6",
"name": "Mock data B",
"type": "n8n-nodes-testing.testData",
"typeVersion": 1,
"position": [340, 1040]
},
{
"parameters": {
"mode": "combine",
"mergeByFields": {
"values": [
{
"field1": "id",
"field2": "id"
}
]
},
"joinMode": "keepNonMatches",
"options": {}
},
"id": "d0c0f123-1461-4b78-9cf8-6410440430d3",
"name": "Merge",
"type": "n8n-nodes-base.merge",
"typeVersion": 2.1,
"position": [700, 500]
},
{
"parameters": {
"mode": "combine",
"mergeByFields": {
"values": [
{
"field1": "id",
"field2": "id"
}
]
},
"joinMode": "keepNonMatches",
"options": {}
},
"id": "5093ec3e-c987-44c7-815f-279ea7842db5",
"name": "Merge1",
"type": "n8n-nodes-base.merge",
"typeVersion": 2.1,
"position": [700, 680]
},
{
"parameters": {
"mode": "combine",
"mergeByFields": {
"values": [
{
"field1": "id",
"field2": "id"
}
]
},
"joinMode": "keepNonMatches",
"outputDataFrom": "input1",
"options": {}
},
"id": "0453bb35-3971-4a23-93b7-31853e4634fb",
"name": "Merge2",
"type": "n8n-nodes-base.merge",
"typeVersion": 2.1,
"position": [700, 880]
},
{
"parameters": {
"mode": "combine",
"mergeByFields": {
"values": [
{
"field1": "id",
"field2": "id"
}
]
},
"joinMode": "keepNonMatches",
"outputDataFrom": "input1",
"options": {}
},
"id": "f09c9327-4557-406b-8ae0-db851055dd08",
"name": "Merge3",
"type": "n8n-nodes-base.merge",
"typeVersion": 2.1,
"position": [700, 1060],
"alwaysOutputData": true
},
{
"parameters": {
"mode": "combine",
"mergeByFields": {
"values": [
{
"field1": "id",
"field2": "id"
}
]
},
"joinMode": "keepNonMatches",
"outputDataFrom": "input2",
"options": {}
},
"id": "d5bc6ee7-141e-4eba-a9aa-cb866b177b89",
"name": "Merge4",
"type": "n8n-nodes-base.merge",
"typeVersion": 2.1,
"position": [700, 1280],
"alwaysOutputData": true
},
{
"parameters": {
"mode": "combine",
"mergeByFields": {
"values": [
{
"field1": "id",
"field2": "id"
}
]
},
"joinMode": "keepNonMatches",
"outputDataFrom": "input2",
"options": {}
},
"id": "4c881679-3f76-491a-a2c9-e35e4c9e28ff",
"name": "Merge5",
"type": "n8n-nodes-base.merge",
"typeVersion": 2.1,
"position": [700, 1460],
"alwaysOutputData": true
}
],
"pinData": {
"Merge": [
{
"json": {
"id": 1,
"first_name": "John",
"last_name": "Doe"
}
},
{
"json": {
"id": 2,
"first_name": "Jane",
"last_name": "Smith"
}
},
{
"json": {
"id": 3,
"first_name": "Michael",
"last_name": "Johnson"
}
},
{
"json": {
"id": 4,
"first_name": "Emily",
"last_name": "Davis"
}
},
{
"json": {
"id": 5,
"first_name": "Robert",
"last_name": "Taylor"
}
},
{
"json": {
"id": 6,
"first_name": "Olivia",
"last_name": "Martin"
}
},
{
"json": {
"id": 7,
"first_name": "William",
"last_name": "Brown"
}
},
{
"json": {
"id": 8,
"first_name": "Sophia",
"last_name": "Anderson"
}
},
{
"json": {
"id": 9,
"first_name": "Daniel",
"last_name": "Wilson"
}
},
{
"json": {
"id": 10,
"first_name": "Ava",
"last_name": "Miller"
}
}
],
"Merge1": [
{
"json": {
"id": 1,
"first_name": "John",
"last_name": "Doe"
}
},
{
"json": {
"id": 2,
"first_name": "Jane",
"last_name": "Smith"
}
},
{
"json": {
"id": 3,
"first_name": "Michael",
"last_name": "Johnson"
}
},
{
"json": {
"id": 4,
"first_name": "Emily",
"last_name": "Davis"
}
},
{
"json": {
"id": 5,
"first_name": "Robert",
"last_name": "Taylor"
}
},
{
"json": {
"id": 6,
"first_name": "Olivia",
"last_name": "Martin"
}
},
{
"json": {
"id": 7,
"first_name": "William",
"last_name": "Brown"
}
},
{
"json": {
"id": 8,
"first_name": "Sophia",
"last_name": "Anderson"
}
},
{
"json": {
"id": 9,
"first_name": "Daniel",
"last_name": "Wilson"
}
},
{
"json": {
"id": 10,
"first_name": "Ava",
"last_name": "Miller"
}
}
],
"Merge2": [
{
"json": {
"id": 1,
"first_name": "John",
"last_name": "Doe"
}
},
{
"json": {
"id": 2,
"first_name": "Jane",
"last_name": "Smith"
}
},
{
"json": {
"id": 3,
"first_name": "Michael",
"last_name": "Johnson"
}
},
{
"json": {
"id": 4,
"first_name": "Emily",
"last_name": "Davis"
}
},
{
"json": {
"id": 5,
"first_name": "Robert",
"last_name": "Taylor"
}
},
{
"json": {
"id": 6,
"first_name": "Olivia",
"last_name": "Martin"
}
},
{
"json": {
"id": 7,
"first_name": "William",
"last_name": "Brown"
}
},
{
"json": {
"id": 8,
"first_name": "Sophia",
"last_name": "Anderson"
}
},
{
"json": {
"id": 9,
"first_name": "Daniel",
"last_name": "Wilson"
}
},
{
"json": {
"id": 10,
"first_name": "Ava",
"last_name": "Miller"
}
}
],
"Merge3": [
{
"json": {}
}
],
"Merge4": [
{
"json": {}
}
],
"Merge5": [
{
"json": {
"id": 1,
"first_name": "John",
"last_name": "Doe"
}
},
{
"json": {
"id": 2,
"first_name": "Jane",
"last_name": "Smith"
}
},
{
"json": {
"id": 3,
"first_name": "Michael",
"last_name": "Johnson"
}
},
{
"json": {
"id": 4,
"first_name": "Emily",
"last_name": "Davis"
}
},
{
"json": {
"id": 5,
"first_name": "Robert",
"last_name": "Taylor"
}
},
{
"json": {
"id": 6,
"first_name": "Olivia",
"last_name": "Martin"
}
},
{
"json": {
"id": 7,
"first_name": "William",
"last_name": "Brown"
}
},
{
"json": {
"id": 8,
"first_name": "Sophia",
"last_name": "Anderson"
}
},
{
"json": {
"id": 9,
"first_name": "Daniel",
"last_name": "Wilson"
}
},
{
"json": {
"id": 10,
"first_name": "Ava",
"last_name": "Miller"
}
}
]
},
"connections": {
"When clicking Execute workflow": {
"main": [
[
{
"node": "Mock data A",
"type": "main",
"index": 0
},
{
"node": "Mock data B",
"type": "main",
"index": 0
}
]
]
},
"Mock data A": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 0
},
{
"node": "Merge1",
"type": "main",
"index": 1
},
{
"node": "Merge2",
"type": "main",
"index": 0
},
{
"node": "Merge3",
"type": "main",
"index": 1
},
{
"node": "Merge4",
"type": "main",
"index": 0
},
{
"node": "Merge5",
"type": "main",
"index": 1
}
]
]
},
"Mock data B": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 1
},
{
"node": "Merge1",
"type": "main",
"index": 0
},
{
"node": "Merge2",
"type": "main",
"index": 1
},
{
"node": "Merge3",
"type": "main",
"index": 0
},
{
"node": "Merge4",
"type": "main",
"index": 1
},
{
"node": "Merge5",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "54329e46-4d05-491a-919c-e156e77d6d11",
"meta": {
"templateCredsSetupCompleted": true,
"instanceId": "b888bd11cd1ddbb95450babf3e199556799d999b896f650de768b8370ee50363"
},
"id": "WbgpQNak2tO6spx2",
"tags": []
}
@@ -0,0 +1,214 @@
{
"name": "do not error on missing keys",
"nodes": [
{
"parameters": {},
"id": "c7c0cf66-790a-4da7-81c8-ba9e4bbcec9a",
"name": "When clicking \"Execute Workflow\"",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [720, 300]
},
{
"parameters": {
"data": [
{
"id": 1
},
{
"id": 2
},
{
"id": 3
},
{
"id": 4
}
]
},
"id": "cec18624-ced0-4de1-8987-d4b184b136b9",
"name": "Code",
"type": "n8n-nodes-testing.testData",
"typeVersion": 1,
"position": [1020, 200]
},
{
"parameters": {
"data": []
},
"id": "754d549c-82ce-4625-ba2b-6f8edcbf715e",
"name": "Code1",
"type": "n8n-nodes-testing.testData",
"typeVersion": 1,
"position": [1020, 400]
},
{
"parameters": {},
"id": "551ed574-607a-4d98-9b06-350df92c805e",
"name": "No Operation, do nothing",
"type": "n8n-nodes-base.noOp",
"typeVersion": 1,
"position": [1540, 200]
},
{
"parameters": {},
"id": "00e75760-d88e-413c-b276-c759db72411f",
"name": "No Operation, do nothing1",
"type": "n8n-nodes-base.noOp",
"typeVersion": 1,
"position": [1540, 380]
},
{
"parameters": {
"mode": "combine",
"mergeByFields": {
"values": [
{
"field1": "idd",
"field2": "idd"
}
]
},
"options": {}
},
"id": "2d412290-4c43-40a6-be78-946602749aa1",
"name": "Merge1",
"type": "n8n-nodes-base.merge",
"typeVersion": 2.1,
"position": [1340, 520],
"alwaysOutputData": true
},
{
"parameters": {
"mode": "combine",
"mergeByFields": {
"values": [
{
"field1": "idd",
"field2": "idd"
}
]
},
"options": {}
},
"id": "b6f05b31-3ca0-48c4-a5ec-c7f81dc7957f",
"name": "Merge2",
"type": "n8n-nodes-base.merge",
"typeVersion": 2,
"position": [1320, 160],
"continueOnFail": true
}
],
"pinData": {
"No Operation, do nothing1": [
{
"json": {}
}
],
"No Operation, do nothing": [
{
"json": {
"id": 1
}
},
{
"json": {
"id": 2
}
},
{
"json": {
"id": 3
}
},
{
"json": {
"id": 4
}
}
]
},
"connections": {
"When clicking \"Execute Workflow\"": {
"main": [
[
{
"node": "Code",
"type": "main",
"index": 0
},
{
"node": "Code1",
"type": "main",
"index": 0
}
]
]
},
"Code": {
"main": [
[
{
"node": "Merge1",
"type": "main",
"index": 0
},
{
"node": "Merge2",
"type": "main",
"index": 0
}
]
]
},
"Code1": {
"main": [
[
{
"node": "Merge1",
"type": "main",
"index": 1
},
{
"node": "Merge2",
"type": "main",
"index": 1
}
]
]
},
"No Operation, do nothing1": {
"main": [[]]
},
"Merge1": {
"main": [
[
{
"node": "No Operation, do nothing1",
"type": "main",
"index": 0
}
]
]
},
"Merge2": {
"main": [
[
{
"node": "No Operation, do nothing",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {},
"versionId": "d0ebcbdd-b57d-495e-8f84-b9500d25c384",
"id": "8",
"meta": {
"instanceId": "6ebec4953fe56f1c009e7c3b107578b375137523af057073c0b5da17350651bd"
},
"tags": []
}
@@ -0,0 +1,322 @@
import {
loadAlaSqlSandbox,
resetSandboxCache,
runAlaSqlInSandbox,
} from '../../v3/helpers/sandbox-utils';
describe('combineBySql sandbox (isolated-vm)', () => {
describe('loadAlaSqlSandbox', () => {
beforeEach(() => {
resetSandboxCache();
});
afterEach(() => {
resetSandboxCache();
});
it('should return a context with alasql available', async () => {
const context = await loadAlaSqlSandbox();
const result = await context.eval('typeof alasql', { copy: true });
expect(result).toBe('function');
});
it('should return the same cached context on subsequent calls', async () => {
const context1 = await loadAlaSqlSandbox();
const context2 = await loadAlaSqlSandbox();
expect(context1).toBe(context2);
});
it('should recreate the sandbox after resetSandboxCache', async () => {
const context1 = await loadAlaSqlSandbox();
resetSandboxCache();
const context2 = await loadAlaSqlSandbox();
expect(context1).not.toBe(context2);
});
});
describe('runAlaSqlInSandbox isolation', () => {
beforeAll(() => {
resetSandboxCache();
});
afterAll(() => {
resetSandboxCache();
});
// ── Host API access ────────────────────────────────────────────────────
it('should not expose require inside the sandbox', async () => {
const context = await loadAlaSqlSandbox();
await expect(
context.eval('(function() { return typeof require; })()', { copy: true }),
).resolves.toBe('undefined');
});
it('should not expose process inside the sandbox', async () => {
const context = await loadAlaSqlSandbox();
await expect(
context.eval('(function() { return typeof process; })()', { copy: true }),
).resolves.toBe('undefined');
});
it('should not expose __dirname inside the sandbox', async () => {
const context = await loadAlaSqlSandbox();
await expect(
context.eval('(function() { return typeof __dirname; })()', { copy: true }),
).resolves.toBe('undefined');
});
it('should not expose __filename inside the sandbox', async () => {
const context = await loadAlaSqlSandbox();
await expect(
context.eval('(function() { return typeof __filename; })()', { copy: true }),
).resolves.toBe('undefined');
});
it('should not expose global inside the sandbox', async () => {
const context = await loadAlaSqlSandbox();
await expect(
context.eval('(function() { return typeof global; })()', { copy: true }),
).resolves.toBe('undefined');
});
it('should not expose Buffer inside the sandbox', async () => {
const context = await loadAlaSqlSandbox();
await expect(
context.eval('(function() { return typeof Buffer; })()', { copy: true }),
).resolves.toBe('undefined');
});
// ── File system access ─────────────────────────────────────────────────
it('should block FROM FILE() SQL clause (no fs in browser bundle)', async () => {
const context = await loadAlaSqlSandbox();
await expect(
runAlaSqlInSandbox(
context,
[[{ id: 1 }]],
"SELECT * FROM FILE('/etc/passwd', {headers: false})",
),
).rejects.toThrow();
});
it('should block ATTACH CSV FILE attempts', async () => {
const context = await loadAlaSqlSandbox();
await expect(
runAlaSqlInSandbox(
context,
[[{ id: 1 }]],
"ATTACH CSV '/etc/passwd' AS secret; SELECT * FROM secret",
),
).rejects.toThrow();
});
// ── Code evaluation / function injection ───────────────────────────────
it('should block CREATE FUNCTION from accessing host APIs', async () => {
const context = await loadAlaSqlSandbox();
// Even if a user crafts a SQL function, require is not in scope inside the isolate
await expect(
runAlaSqlInSandbox(
context,
[[{ id: 1 }]],
'SELECT id FROM input1 WHERE alasql(\'CREATE FUNCTION danger() RETURNS STRING BEGIN RETURN typeof require END; SELECT danger() FROM [{"x":1}]\')',
),
).rejects.toThrow();
});
it('should return "undefined" for require even when called via a SQL function', async () => {
const context = await loadAlaSqlSandbox();
// CREATE FUNCTION compiles a JS body require must still be absent
await expect(
runAlaSqlInSandbox(
context,
[[{ id: 1 }]],
"SELECT alasql('CREATE FUNCTION getRequire() RETURNS STRING BEGIN RETURN typeof require END') FROM input1",
),
).rejects.toThrow();
});
it('should block eval() inside the sandbox from escaping isolation', async () => {
const context = await loadAlaSqlSandbox();
// eval exists in V8 but must not be able to reach host-side objects
const result = (await context.eval(
`(function() {
try { return eval('typeof require'); }
catch(e) { return 'error: ' + e.message; }
})()`,
{ copy: true },
)) as string;
// Either eval is blocked or require is still undefined inside eval'd code
expect(result === 'undefined' || result.startsWith('error:')).toBe(true);
});
it('should block alasql arrow-operator prototype traversal from reaching host globals', async () => {
const context = await loadAlaSqlSandbox();
// process is unavailable in the isolate, the inner call silently fails, resulting in an empty object
const result = await runAlaSqlInSandbox(
context,
[[{ id: 1 }]],
'SELECT {}.constructor->constructor->[call](\'\',\'return {result: process.getBuiltinModule("child_process").execSync("id").toString()}\') AS r FROM input1',
);
expect(result).toEqual([{}]);
});
it('should block Function constructor from reaching host APIs', async () => {
const context = await loadAlaSqlSandbox();
const result = (await context.eval(
`(function() {
try { return new Function('return typeof require')(); }
catch(e) { return 'error: ' + e.message; }
})()`,
{ copy: true },
)) as string;
expect(result === 'undefined' || result.startsWith('error:')).toBe(true);
});
// ── Prototype pollution ────────────────────────────────────────────────
it('should contain prototype pollution within the isolate heap', async () => {
const context = await loadAlaSqlSandbox();
// Pollute Object.prototype inside the sandbox
await context.eval('Object.prototype.__polluted = true', { copy: true });
// Host-side Object.prototype must be untouched
expect(({} as Record<string, unknown>).__polluted).toBeUndefined();
});
it('should have alasql.fn frozen after sandbox initialisation', async () => {
const context = await loadAlaSqlSandbox();
const isFrozen = (await context.eval('Object.isFrozen(alasql.fn)', {
copy: true,
})) as boolean;
expect(isFrozen).toBe(true);
});
it('should not allow a CREATE FUNCTION', async () => {
const context = await loadAlaSqlSandbox();
await expect(
runAlaSqlInSandbox(
context,
[[{ x: 1 }]],
'CREATE FUNCTION double(n) RETURNS NUMBER BEGIN RETURN n * 2 END; SELECT double(x) AS v FROM input1',
),
).rejects.toThrow();
await expect(
runAlaSqlInSandbox(context, [[{ x: 1 }]], 'SELECT double(x) AS v FROM input1'),
).rejects.toThrow();
});
// ── Resource limits ────────────────────────────────────────────────────
it('should enforce the CPU timeout on an infinite loop', async () => {
const context = await loadAlaSqlSandbox();
await expect(
context.eval('(function() { while(true) {} })()', { timeout: 100, copy: true }),
).rejects.toThrow();
});
});
describe('runAlaSqlInSandbox SQL execution', () => {
beforeAll(() => {
resetSandboxCache();
});
afterAll(() => {
resetSandboxCache();
});
it('should execute a basic SELECT query', async () => {
const context = await loadAlaSqlSandbox();
const result = await runAlaSqlInSandbox(
context,
[
[
{ name: 'Alice', age: 30 },
{ name: 'Bob', age: 25 },
],
],
'SELECT * FROM input1',
);
expect(result).toEqual([
{ name: 'Alice', age: 30 },
{ name: 'Bob', age: 25 },
]);
});
it('should execute a JOIN query across two inputs', async () => {
const context = await loadAlaSqlSandbox();
const result = await runAlaSqlInSandbox(
context,
[
[
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
],
[
{ userId: 1, score: 100 },
{ userId: 2, score: 200 },
],
],
'SELECT input1.name, input2.score FROM input1 LEFT JOIN input2 ON input1.id = input2.userId',
);
expect(result).toEqual([
{ name: 'Alice', score: 100 },
{ name: 'Bob', score: 200 },
]);
});
it('should execute a WHERE filter', async () => {
const context = await loadAlaSqlSandbox();
const result = await runAlaSqlInSandbox(
context,
[
[
{ id: 1, val: 10 },
{ id: 2, val: 20 },
{ id: 3, val: 30 },
],
],
'SELECT * FROM input1 WHERE val > 15',
);
expect(result).toEqual([
{ id: 2, val: 20 },
{ id: 3, val: 30 },
]);
});
it('should return an empty array for a query with no results', async () => {
const context = await loadAlaSqlSandbox();
const result = await runAlaSqlInSandbox(
context,
[[{ id: 1 }]],
'SELECT * FROM input1 WHERE id = 999',
);
expect(result).toEqual([]);
});
it('should throw a meaningful error for invalid SQL', async () => {
const context = await loadAlaSqlSandbox();
await expect(runAlaSqlInSandbox(context, [[{ id: 1 }]], 'THIS IS NOT SQL')).rejects.toThrow();
});
it('should clean up its database after each execution', async () => {
const context = await loadAlaSqlSandbox();
const countBefore = (await context.eval('Object.keys(alasql.databases).length', {
copy: true,
})) as number;
await runAlaSqlInSandbox(context, [[{ id: 1 }]], 'SELECT * FROM input1');
await runAlaSqlInSandbox(context, [[{ id: 2 }]], 'SELECT * FROM input1');
const countAfter = (await context.eval('Object.keys(alasql.databases).length', {
copy: true,
})) as number;
// Database count must not grow each invocation cleans up after itself
expect(countAfter).toBe(countBefore);
});
});
});
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,92 @@
import type { IDataObject, INodeExecutionData, IPairedItemData } from 'n8n-workflow';
import { modifySelectQuery, rowToExecutionData } from '../../v3/helpers/utils';
describe('rowToExecutionData', () => {
test('should return empty json and pairedItem when input is empty', () => {
const input: IDataObject = {};
const result = rowToExecutionData(input);
expect(result).toEqual({ json: {}, pairedItem: [] });
});
test('should separate json properties and pairedItem properties', () => {
const input: IDataObject = {
key1: 'value1',
key2: 42,
pairedItem1: { item: 0, input: undefined } as IPairedItemData,
pairedItem2: { item: 0, input: 1 } as IPairedItemData,
};
const expectedOutput: INodeExecutionData = {
json: { key1: 'value1', key2: 42 },
pairedItem: [
{ item: 0, input: undefined },
{ item: 0, input: 1 },
],
};
expect(rowToExecutionData(input)).toEqual(expectedOutput);
});
test('should ignore undefined pairedItem values', () => {
const input: IDataObject = {
key: 'value',
pairedItem1: { item: 0, input: undefined } as IPairedItemData,
pairedItem2: undefined,
};
const expectedOutput: INodeExecutionData = {
json: { key: 'value' },
pairedItem: [{ item: 0, input: undefined }],
};
expect(rowToExecutionData(input)).toEqual(expectedOutput);
});
test('should handle only json properties without pairedItem', () => {
const input: IDataObject = {
name: 'Alice',
age: 30,
};
const expectedOutput: INodeExecutionData = {
json: { name: 'Alice', age: 30 },
pairedItem: [],
};
expect(rowToExecutionData(input)).toEqual(expectedOutput);
});
});
describe('modifySelectQuery', () => {
test('should return the original query if no SELECT match is found', () => {
const query = 'UPDATE table SET column = 1';
expect(modifySelectQuery(query, 2)).toBe(query);
});
test('should return the original query if SELECT * is used', () => {
const query = 'SELECT * FROM input1';
expect(modifySelectQuery(query, 2)).toBe(query);
});
test('should append pairedItem columns when input tables exist', () => {
const query = 'SELECT column1, column2 FROM input1 WHERE input1.id = table.id';
const modifiedQuery = modifySelectQuery(query, 2);
expect(modifiedQuery).toBe(
'SELECT column1, column2, input1.pairedItem AS pairedItem1 FROM input1 WHERE input1.id = table.id',
);
});
test('should handle multiple input tables correctly', () => {
const query = 'SELECT column1 FROM input1 LEFT JOIN input2 ON input1.name = input2.name';
const modifiedQuery = modifySelectQuery(query, 2);
expect(modifiedQuery).toBe(
'SELECT column1, input1.pairedItem AS pairedItem1, input2.pairedItem AS pairedItem2 FROM input1 LEFT JOIN input2 ON input1.name = input2.name',
);
});
test('should not modify query if no input tables are found', () => {
const query = 'SELECT column1 FROM table';
expect(modifySelectQuery(query, 2)).toBe(query);
});
});