1
1
mirror of https://github.com/n8n-io/n8n.git synced 2024-10-08 10:39:01 +03:00

test(Spreadsheet File Node): Unit tests (no-changelog) (#5385)

* ️test setup

* ️fix  'testData' implicitly has an 'any' type.

*  test github action file binary data reading

*  checking for output binary equality

*  writing files to different formats

*  reading spreadsheet with different options

* ️improve workflow file path replacement

* 🐛 fixing string.at() not supported in node 14.

* 🐛 trying to fix github action test error

*  fix for empty binary

*  switch for binary test

* ️test helpers now return/compare json and binary (if not empty))

*  removed commented console log

---------

Co-authored-by: Michael Kret <michael.k@radency.com>
This commit is contained in:
Marcus 2023-02-09 09:00:29 +01:00 committed by GitHub
parent 94f2b2a26f
commit 74fc1414d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 449 additions and 5 deletions

View File

@ -0,0 +1,171 @@
import * as Helpers from '../../../test/nodes/Helpers';
import type { WorkflowTestData } from '../../../test/nodes/types';
import { executeWorkflow } from '../../../test/nodes/ExecuteWorkflow';
import path from 'path';
describe('Execute Spreadsheet File Node', () => {
beforeEach(async () => {
await Helpers.initBinaryDataManager();
});
// replace workflow json 'Read Binary File' node's filePath to local file
const workflow = Helpers.readJsonFileSync('nodes/SpreadsheetFile/test/workflow.json');
const node = workflow.nodes.find((n: any) => n.name === 'Read Binary File');
node.parameters.filePath = path.join(__dirname, 'spreadsheet.csv');
const tests: WorkflowTestData[] = [
{
description: 'execute workflow.json',
input: {
workflowData: workflow,
},
output: {
nodeData: {
'Read From File': [
[
{
json: { A: 1, B: 2, C: 3 },
},
{
json: { A: 4, B: 5, C: 6 },
},
],
],
'Read From File Range': [
[
{
json: { '1': 4, '2': 5 },
},
],
],
'Read From File no Header Row': [
[
{
json: {
row: ['A', 'B', 'C'],
},
},
{
json: {
row: [1, 2, 3],
},
},
{
json: {
row: [4, 5, 6],
},
},
],
],
'Read From File Raw Data': [
[
{
json: { A: '1', B: '2', C: '3' },
},
{
json: { A: '4', B: '5', C: '6' },
},
],
],
'Read From File Read as String': [
[
{
json: { A: 1, B: 2, C: 3 },
},
{
json: { A: 4, B: 5, C: 6 },
},
],
],
'Write To File CSV': [
[
{
json: {},
binary: {
data: {
mimeType: 'text/csv',
fileType: 'text',
fileExtension: 'csv',
data: '77u/QSxCLEMKMSwyLDMKNCw1LDYK',
fileName: 'spreadsheet.csv',
fileSize: '21 B',
},
},
},
],
],
'Write To File HTML': [
[
{
json: {},
binary: {
data: {
mimeType: 'text/html',
fileType: 'text',
fileExtension: 'html',
data: 'PGh0bWw+PGhlYWQ+PG1ldGEgY2hhcnNldD0idXRmLTgiLz48dGl0bGU+U2hlZXRKUyBUYWJsZSBFeHBvcnQ8L3RpdGxlPjwvaGVhZD48Ym9keT48dGFibGU+PHRyPjx0ZCBkYXRhLXQ9InMiIGRhdGEtdj0iQSIgaWQ9InNqcy1BMSI+QTwvdGQ+PHRkIGRhdGEtdD0icyIgZGF0YS12PSJCIiBpZD0ic2pzLUIxIj5CPC90ZD48dGQgZGF0YS10PSJzIiBkYXRhLXY9IkMiIGlkPSJzanMtQzEiPkM8L3RkPjwvdHI+PHRyPjx0ZCBkYXRhLXQ9Im4iIGRhdGEtdj0iMSIgaWQ9InNqcy1BMiI+MTwvdGQ+PHRkIGRhdGEtdD0ibiIgZGF0YS12PSIyIiBpZD0ic2pzLUIyIj4yPC90ZD48dGQgZGF0YS10PSJuIiBkYXRhLXY9IjMiIGlkPSJzanMtQzIiPjM8L3RkPjwvdHI+PHRyPjx0ZCBkYXRhLXQ9Im4iIGRhdGEtdj0iNCIgaWQ9InNqcy1BMyI+NDwvdGQ+PHRkIGRhdGEtdD0ibiIgZGF0YS12PSI1IiBpZD0ic2pzLUIzIj41PC90ZD48dGQgZGF0YS10PSJuIiBkYXRhLXY9IjYiIGlkPSJzanMtQzMiPjY8L3RkPjwvdHI+PC90YWJsZT48L2JvZHk+PC9odG1sPg==',
fileName: 'spreadsheet.html',
fileSize: '535 B',
},
},
},
],
],
// ODS file has slight differences every time it's created
//
'Write To File RTF': [
[
{
json: {},
binary: {
data: {
mimeType: 'application/rtf',
fileExtension: 'rtf',
data: 'e1xydGYxXGFuc2lcdHJvd2RcdHJhdXRvZml0MVxjZWxseDFcY2VsbHgyXGNlbGx4M1xwYXJkXGludGJsIEFcY2VsbCBCXGNlbGwgQ1xjZWxsXHBhcmRcaW50Ymxccm93XHRyb3dkXHRyYXV0b2ZpdDFcY2VsbHgxXGNlbGx4MlxjZWxseDNccGFyZFxpbnRibCAxXGNlbGwgMlxjZWxsIDNcY2VsbFxwYXJkXGludGJsXHJvd1x0cm93ZFx0cmF1dG9maXQxXGNlbGx4MVxjZWxseDJcY2VsbHgzXHBhcmRcaW50YmwgNFxjZWxsIDVcY2VsbCA2XGNlbGxccGFyZFxpbnRibFxyb3d9',
fileName: 'spreadsheet.rtf',
fileSize: '267 B',
},
},
},
],
],
'Write To File XLS': [
[
{
json: {},
binary: {
data: {
mimeType: 'application/vnd.ms-excel',
fileExtension: 'xls',
data: '0M8R4KGxGuEAAAAAAAAAAAAAAAAAAAAAPgADAP7/CQAGAAAAAAAAAAAAAAABAAAAAgAAAAAAAAAAEAAAAQAAAAEAAAD+////AAAAAAAAAAD////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////9/////v////7///8EAAAABQAAAP7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7///8CAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAAAARAAAAEgAAABMAAAD+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+/////v////7////+////UgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQABQH//////////wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAUAAAAAAAABAFMAaAAzADMAdABKADUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEgACAf////8CAAAA/////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAFcAbwByAGsA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',
fileName: 'spreadsheet.xls',
fileSize: '3.58 kB',
},
},
},
],
],
},
},
},
];
const nodeTypes = Helpers.setup(tests);
for (const testData of tests) {
// eslint-disable-next-line @typescript-eslint/no-loop-func
test(testData.description, async () => {
// execute workflow
const { result } = await executeWorkflow(testData, nodeTypes);
// check if result node data matches expected test data
const resultNodeData = Helpers.getResultNodeData(result, testData);
resultNodeData.forEach(({ nodeName, resultData }) =>
expect(resultData).toEqual(testData.output.nodeData[nodeName]),
);
expect(result.finished).toEqual(true);
});
}
});

View File

@ -0,0 +1,3 @@
A,B,C
1,2,3
4,5,6
1 A B C
2 1 2 3
3 4 5 6

View File

@ -0,0 +1,253 @@
{
"meta": {
"instanceId": "104a4d08d8897b8bdeb38aaca515021075e0bd8544c983c2bb8c86e6a8e6081c"
},
"nodes": [
{
"parameters": {},
"id": "087277cc-297d-4912-bd11-86626eff2d71",
"name": "When clicking \"Execute Workflow\"",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [
620,
640
]
},
{
"parameters": {
"options": {}
},
"id": "f55bc21c-c9a8-43af-bbc8-e4bdd30f0ce9",
"name": "Read From File",
"type": "n8n-nodes-base.spreadsheetFile",
"typeVersion": 1,
"position": [
1260,
640
]
},
{
"parameters": {
"filePath": "C:\\Users\\spech\\Documents\\GitHub\\n8n-master\\packages\\nodes-base\\nodes\\SpreadsheetFile\\test\\spreadsheet.csv"
},
"id": "d7620053-eb3d-43dd-b2cd-d60d9a08a9cc",
"name": "Read Binary File",
"type": "n8n-nodes-base.readBinaryFile",
"typeVersion": 1,
"position": [
840,
640
]
},
{
"parameters": {
"operation": "toFile",
"fileFormat": "csv",
"options": {}
},
"id": "21bc49fe-1e6b-46d6-a04d-cb474d138e02",
"name": "Write To File CSV",
"type": "n8n-nodes-base.spreadsheetFile",
"typeVersion": 1,
"position": [
1580,
280
]
},
{
"parameters": {
"operation": "toFile",
"fileFormat": "html",
"options": {}
},
"id": "a4c2c717-5a9d-4fd6-8450-6bb78e233c05",
"name": "Write To File HTML",
"type": "n8n-nodes-base.spreadsheetFile",
"typeVersion": 1,
"position": [
1580,
460
]
},
{
"parameters": {
"operation": "toFile",
"fileFormat": "ods",
"options": {}
},
"id": "58e5a423-0477-44df-a505-6b8a40dbf275",
"name": "Write To File ODS",
"type": "n8n-nodes-base.spreadsheetFile",
"typeVersion": 1,
"position": [
1580,
640
]
},
{
"parameters": {
"operation": "toFile",
"fileFormat": "rtf",
"options": {}
},
"id": "3ae6e9c5-bc0a-44e4-959e-cfc572f4179f",
"name": "Write To File RTF",
"type": "n8n-nodes-base.spreadsheetFile",
"typeVersion": 1,
"position": [
1580,
820
]
},
{
"parameters": {
"operation": "toFile",
"options": {}
},
"id": "7e6db847-d24c-4094-907d-92ffec626f68",
"name": "Write To File XLS",
"type": "n8n-nodes-base.spreadsheetFile",
"typeVersion": 1,
"position": [
1580,
1020
]
},
{
"parameters": {
"options": {
"range": "A2:B3"
}
},
"id": "48934f0d-ac10-4862-ae0c-2ea591b111e3",
"name": "Read From File Range",
"type": "n8n-nodes-base.spreadsheetFile",
"typeVersion": 1,
"position": [
1060,
520
]
},
{
"parameters": {
"options": {
"headerRow": false
}
},
"id": "dea6f3f6-f2fb-472e-97b2-8a0c0a36bc4d",
"name": "Read From File no Header Row",
"type": "n8n-nodes-base.spreadsheetFile",
"typeVersion": 1,
"position": [
1060,
320
]
},
{
"parameters": {
"options": {
"rawData": true
}
},
"id": "38ed33fc-6906-4b09-8376-937ef3ca99be",
"name": "Read From File Raw Data",
"type": "n8n-nodes-base.spreadsheetFile",
"typeVersion": 1,
"position": [
1060,
740
]
},
{
"parameters": {
"options": {
"readAsString": true
}
},
"id": "ffe09dc8-9b7a-4baf-bd03-bd65bbce2590",
"name": "Read From File Read as String",
"type": "n8n-nodes-base.spreadsheetFile",
"typeVersion": 1,
"position": [
1060,
940
]
}
],
"connections": {
"When clicking \"Execute Workflow\"": {
"main": [
[
{
"node": "Read Binary File",
"type": "main",
"index": 0
}
]
]
},
"Read From File": {
"main": [
[
{
"node": "Write To File CSV",
"type": "main",
"index": 0
},
{
"node": "Write To File HTML",
"type": "main",
"index": 0
},
{
"node": "Write To File ODS",
"type": "main",
"index": 0
},
{
"node": "Write To File RTF",
"type": "main",
"index": 0
},
{
"node": "Write To File XLS",
"type": "main",
"index": 0
}
]
]
},
"Read Binary File": {
"main": [
[
{
"node": "Read From File",
"type": "main",
"index": 0
},
{
"node": "Read From File Range",
"type": "main",
"index": 0
},
{
"node": "Read From File no Header Row",
"type": "main",
"index": 0
},
{
"node": "Read From File Raw Data",
"type": "main",
"index": 0
},
{
"node": "Read From File Read as String",
"type": "main",
"index": 0
}
]
]
}
}
}

View File

@ -34,7 +34,7 @@ describe('Execute Airtable Node', () => {
},
output: {
nodeData: {
Airtable: [[...records]],
Airtable: [[...records.map((r) => ({ json: r }))]],
},
},
},

View File

@ -1,5 +1,5 @@
import { readFileSync, readdirSync } from 'fs';
import { Credentials, loadClassInIsolation } from 'n8n-core';
import { readFileSync, readdirSync, mkdtempSync } from 'fs';
import { BinaryDataManager, Credentials, loadClassInIsolation } from 'n8n-core';
import {
ICredentialDataDecryptedObject,
ICredentialsHelper,
@ -27,6 +27,8 @@ import {
import { executeWorkflow } from './ExecuteWorkflow';
import { WorkflowTestData } from './types';
import path from 'path';
import { tmpdir } from 'os';
import { isEmpty } from 'lodash';
export class CredentialsHelper extends ICredentialsHelper {
async authenticate(
@ -156,6 +158,17 @@ const loadKnownNodes = (): Record<string, LoadingDetails> => {
return knownNodes!;
};
export async function initBinaryDataManager(mode: 'default' | 'filesystem' = 'default') {
const temporaryDir = mkdtempSync(path.join(tmpdir(), 'n8n'));
await BinaryDataManager.init({
mode,
availableModes: mode,
localStoragePath: temporaryDir,
binaryDataTTL: 1,
persistedBinaryDataTTL: 1,
});
}
export function setup(testData: Array<WorkflowTestData> | WorkflowTestData) {
if (!Array.isArray(testData)) {
testData = [testData];
@ -204,7 +217,11 @@ export function getResultNodeData(result: IRun, testData: WorkflowTestData) {
if (nodeData.data === undefined) {
return null;
}
return nodeData.data.main[0]!.map((entry) => entry.json);
return nodeData.data.main[0]!.map((entry) => {
if (entry.binary && isEmpty(entry.binary)) delete entry.binary;
delete entry.pairedItem;
return entry;
});
});
return {
nodeName,
@ -241,7 +258,7 @@ export const workflowToTests = (workflowFiles: string[]) => {
}
const nodeData = Object.keys(workflowData.pinData).reduce(
(acc, key) => {
const data = (workflowData.pinData[key] as IDataObject[]).map((item) => item.json);
const data = workflowData.pinData[key] as IDataObject[];
acc[key] = [data as IDataObject[]];
return acc;
},