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,94 @@
/* eslint-disable n8n-nodes-base/node-param-display-name-miscased */
import mysql2 from 'mysql2/promise';
import type { ILoadOptionsFunctions, INodeListSearchResult } from 'n8n-workflow';
import { searchTables } from '../../v1/GenericFunctions';
jest.mock('mysql2/promise');
describe('MySQL / v1 / Generic Functions', () => {
let mockLoadOptionsFunctions: ILoadOptionsFunctions;
beforeEach(() => {
jest.resetAllMocks();
mockLoadOptionsFunctions = {
getCredentials: jest.fn().mockResolvedValue({
database: 'test_db',
}),
} as unknown as ILoadOptionsFunctions;
});
describe('searchTables', () => {
it('should return matching tables', async () => {
const mockRows = [{ table_name: 'users' }, { table_name: 'products' }];
const mockQuery = jest.fn().mockResolvedValue([mockRows]);
const mockEnd = jest.fn().mockResolvedValue(undefined);
(mysql2.createConnection as jest.Mock).mockResolvedValue({
query: mockQuery,
end: mockEnd,
});
const result: INodeListSearchResult = await searchTables.call(
mockLoadOptionsFunctions,
'user',
);
expect(result).toEqual({
results: [
{ name: 'users', value: 'users' },
{ name: 'products', value: 'products' },
],
});
expect(mockQuery).toHaveBeenCalledWith(
`SELECT table_name
FROM information_schema.tables
WHERE table_schema = ?
AND table_name LIKE ?
ORDER BY table_name`,
['test_db', '%user%'],
);
expect(mockEnd).toHaveBeenCalled();
});
it('should handle empty search query', async () => {
const mockRows: any[] = [];
const mockQuery = jest.fn().mockResolvedValue([mockRows]);
const mockEnd = jest.fn().mockResolvedValue(undefined);
(mysql2.createConnection as jest.Mock).mockResolvedValue({
query: mockQuery,
end: mockEnd,
});
const result = await searchTables.call(mockLoadOptionsFunctions);
expect(result).toEqual({ results: [] });
expect(mockQuery).toHaveBeenCalledWith(
`SELECT table_name
FROM information_schema.tables
WHERE table_schema = ?
AND table_name LIKE ?
ORDER BY table_name`,
['test_db', '%%'],
);
expect(mockEnd).toHaveBeenCalled();
});
it('should handle database errors', async () => {
const mockError = new Error('Database connection failed');
(mysql2.createConnection as jest.Mock).mockRejectedValue(mockError);
await expect(searchTables.call(mockLoadOptionsFunctions)).rejects.toThrow(
'Database connection failed',
);
});
});
});
@@ -0,0 +1,21 @@
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
import { mock } from 'jest-mock-extended';
import type { Connection, QueryResult } from 'mysql2/promise';
const mockConnection = mock<Connection>();
const createConnection = jest.fn().mockReturnValue(mockConnection);
jest.mock('mysql2/promise', () => ({ createConnection }));
describe('Test MySqlV1, executeQuery', () => {
mockConnection.query.mockResolvedValue([{ success: true } as unknown as QueryResult, []]);
new NodeTestHarness().setupTests({
workflowFiles: ['executeQuery.workflow.json'],
customAssertions() {
expect(mockConnection.query).toHaveBeenCalledTimes(1);
expect(mockConnection.query).toHaveBeenCalledWith(
"select * from family_parents where (parent_email = 'parent1@mail.com' or parent_email = 'parent2@mail.com') and parent_email <> '';",
);
},
});
});
@@ -0,0 +1,127 @@
{
"name": "mysql v1 resolve expression copy",
"nodes": [
{
"parameters": {},
"id": "d6d9fbcc-d8bc-4f79-8e00-3acf8ffb12de",
"name": "When clicking \"Execute Workflow\"",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [
460,
460
]
},
{
"parameters": {
"operation": "executeQuery",
"query": "select * from family_parents where (parent_email = {{ \"'\" + $json['Parent 1 email'] + \"'\" }} or parent_email = {{ \"'\" + $json['Parent 2 email'] + \"'\"}}) and parent_email <> '';\n"
},
"id": "faefc24c-91b4-4b10-85a6-b3cecbceee08",
"name": "Get matching families",
"type": "n8n-nodes-base.mySql",
"typeVersion": 1,
"position": [
900,
460
],
"credentials": {
"mySql": {
"id": "93",
"name": "MySQL account"
}
}
},
{
"parameters": {},
"id": "29c30f6e-9f5f-4b3a-80c4-2da762e96bd9",
"name": "No Operation, do nothing1",
"type": "n8n-nodes-base.noOp",
"typeVersion": 1,
"position": [
1120,
460
]
},
{
"parameters": {
"fields": {
"values": [
{
"name": "Parent 1 email",
"stringValue": "parent1@mail.com"
},
{
"name": "Parent 2 email",
"stringValue": "parent2@mail.com"
}
]
},
"include": "none",
"options": {}
},
"id": "54c7bbf9-dabc-421b-85b2-7c3006f5ee61",
"name": "Edit Fields",
"type": "n8n-nodes-base.set",
"typeVersion": 3.2,
"position": [
680,
460
]
}
],
"pinData": {
"No Operation, do nothing1": [
{
"json": {
"success": true
}
}
]
},
"connections": {
"When clicking \"Execute Workflow\"": {
"main": [
[
{
"node": "Edit Fields",
"type": "main",
"index": 0
}
]
]
},
"Get matching families": {
"main": [
[
{
"node": "No Operation, do nothing1",
"type": "main",
"index": 0
}
]
]
},
"Edit Fields": {
"main": [
[
{
"node": "Get matching families",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "aeb01d24-c117-405a-875f-909ea8ccdc16",
"id": "GlTwlHZfQwNjbeqv",
"meta": {
"instanceId": "b888bd11cd1ddbb95450babf3e199556799d999b896f650de768b8370ee50363"
},
"tags": []
}