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
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:
@@ -0,0 +1,497 @@
|
||||
import type { IExecuteFunctions, IBinaryData, INodeExecutionData } from 'n8n-workflow';
|
||||
|
||||
import { Twist } from '../Twist.node';
|
||||
import * as GenericFunctions from '../GenericFunctions';
|
||||
|
||||
jest.mock('../GenericFunctions');
|
||||
|
||||
describe('Twist Node - prepareBinariesDataList usage', () => {
|
||||
let twist: Twist;
|
||||
let mockExecuteFunctions: jest.Mocked<IExecuteFunctions>;
|
||||
|
||||
beforeEach(() => {
|
||||
twist = new Twist();
|
||||
mockExecuteFunctions = {
|
||||
getInputData: jest.fn(),
|
||||
getNodeParameter: jest.fn(),
|
||||
helpers: {
|
||||
assertBinaryData: jest.fn(),
|
||||
getBinaryDataBuffer: jest.fn(),
|
||||
returnJsonArray: jest.fn(),
|
||||
},
|
||||
} as unknown as jest.Mocked<IExecuteFunctions>;
|
||||
jest.clearAllMocks();
|
||||
|
||||
// Mock the twistApiRequest to return successful responses
|
||||
(GenericFunctions.twistApiRequest as jest.Mock).mockResolvedValue({
|
||||
id: 'test-id',
|
||||
});
|
||||
});
|
||||
|
||||
describe('comment create with string binaryProperties', () => {
|
||||
it('should process comma-separated string binaryProperties', async () => {
|
||||
const items: INodeExecutionData[] = [
|
||||
{
|
||||
json: {},
|
||||
binary: {
|
||||
file1: {
|
||||
data: Buffer.from('data1').toString('base64'),
|
||||
mimeType: 'text/plain',
|
||||
fileName: 'file1.txt',
|
||||
},
|
||||
file2: {
|
||||
data: Buffer.from('data2').toString('base64'),
|
||||
mimeType: 'text/plain',
|
||||
fileName: 'file2.txt',
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
||||
(mockExecuteFunctions.getNodeParameter as jest.Mock)
|
||||
.mockReturnValueOnce('comment')
|
||||
.mockReturnValueOnce('create')
|
||||
.mockReturnValueOnce('thread123')
|
||||
.mockReturnValueOnce('Test content')
|
||||
.mockReturnValueOnce({
|
||||
binaryProperties: 'file1, file2',
|
||||
});
|
||||
|
||||
(mockExecuteFunctions.helpers.assertBinaryData as jest.Mock).mockImplementation(
|
||||
(itemIndex: number, propertyName: string) => {
|
||||
return items[itemIndex].binary![propertyName];
|
||||
},
|
||||
);
|
||||
|
||||
(mockExecuteFunctions.helpers.getBinaryDataBuffer as jest.Mock).mockResolvedValue(
|
||||
Buffer.from('test data'),
|
||||
);
|
||||
|
||||
(mockExecuteFunctions.helpers.returnJsonArray as jest.Mock).mockImplementation(
|
||||
(data: any) => {
|
||||
return Array.isArray(data) ? data.map((item) => ({ json: item })) : [{ json: data }];
|
||||
},
|
||||
);
|
||||
|
||||
const result = await twist.execute.call(mockExecuteFunctions);
|
||||
|
||||
expect(result[0]).toHaveLength(1);
|
||||
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledTimes(2);
|
||||
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(0, 'file1');
|
||||
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(0, 'file2');
|
||||
});
|
||||
|
||||
it('should handle single string binaryProperty', async () => {
|
||||
const items: INodeExecutionData[] = [
|
||||
{
|
||||
json: {},
|
||||
binary: {
|
||||
singleFile: {
|
||||
data: Buffer.from('data').toString('base64'),
|
||||
mimeType: 'text/plain',
|
||||
fileName: 'single.txt',
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
||||
(mockExecuteFunctions.getNodeParameter as jest.Mock)
|
||||
.mockReturnValueOnce('comment')
|
||||
.mockReturnValueOnce('create')
|
||||
.mockReturnValueOnce('thread123')
|
||||
.mockReturnValueOnce('Test content')
|
||||
.mockReturnValueOnce({
|
||||
binaryProperties: 'singleFile',
|
||||
});
|
||||
|
||||
(mockExecuteFunctions.helpers.assertBinaryData as jest.Mock).mockImplementation(
|
||||
(itemIndex: number, propertyName: string) => {
|
||||
return items[itemIndex].binary![propertyName];
|
||||
},
|
||||
);
|
||||
|
||||
(mockExecuteFunctions.helpers.getBinaryDataBuffer as jest.Mock).mockResolvedValue(
|
||||
Buffer.from('test data'),
|
||||
);
|
||||
|
||||
(mockExecuteFunctions.helpers.returnJsonArray as jest.Mock).mockImplementation(
|
||||
(data: any) => {
|
||||
return Array.isArray(data) ? data.map((item) => ({ json: item })) : [{ json: data }];
|
||||
},
|
||||
);
|
||||
|
||||
const result = await twist.execute.call(mockExecuteFunctions);
|
||||
|
||||
expect(result[0]).toHaveLength(1);
|
||||
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledTimes(1);
|
||||
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(0, 'singleFile');
|
||||
});
|
||||
});
|
||||
|
||||
describe('comment create with string[] binaryProperties', () => {
|
||||
it('should process string array binaryProperties', async () => {
|
||||
const items: INodeExecutionData[] = [
|
||||
{
|
||||
json: {},
|
||||
binary: {
|
||||
doc1: {
|
||||
data: Buffer.from('data1').toString('base64'),
|
||||
mimeType: 'application/pdf',
|
||||
fileName: 'doc1.pdf',
|
||||
},
|
||||
doc2: {
|
||||
data: Buffer.from('data2').toString('base64'),
|
||||
mimeType: 'application/pdf',
|
||||
fileName: 'doc2.pdf',
|
||||
},
|
||||
doc3: {
|
||||
data: Buffer.from('data3').toString('base64'),
|
||||
mimeType: 'application/pdf',
|
||||
fileName: 'doc3.pdf',
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
||||
(mockExecuteFunctions.getNodeParameter as jest.Mock)
|
||||
.mockReturnValueOnce('comment')
|
||||
.mockReturnValueOnce('create')
|
||||
.mockReturnValueOnce('thread123')
|
||||
.mockReturnValueOnce('Test content')
|
||||
.mockReturnValueOnce({
|
||||
binaryProperties: ['doc1', 'doc2', 'doc3'],
|
||||
});
|
||||
|
||||
(mockExecuteFunctions.helpers.assertBinaryData as jest.Mock).mockImplementation(
|
||||
(itemIndex: number, propertyName: string) => {
|
||||
return items[itemIndex].binary![propertyName];
|
||||
},
|
||||
);
|
||||
|
||||
(mockExecuteFunctions.helpers.getBinaryDataBuffer as jest.Mock).mockResolvedValue(
|
||||
Buffer.from('test data'),
|
||||
);
|
||||
|
||||
(mockExecuteFunctions.helpers.returnJsonArray as jest.Mock).mockImplementation(
|
||||
(data: any) => {
|
||||
return Array.isArray(data) ? data.map((item) => ({ json: item })) : [{ json: data }];
|
||||
},
|
||||
);
|
||||
|
||||
const result = await twist.execute.call(mockExecuteFunctions);
|
||||
|
||||
expect(result[0]).toHaveLength(1);
|
||||
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledTimes(3);
|
||||
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(0, 'doc1');
|
||||
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(0, 'doc2');
|
||||
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(0, 'doc3');
|
||||
});
|
||||
});
|
||||
|
||||
describe('comment create with IBinaryData binaryProperties', () => {
|
||||
it('should process single IBinaryData object', async () => {
|
||||
const binaryData: IBinaryData = {
|
||||
data: Buffer.from('data').toString('base64'),
|
||||
mimeType: 'image/png',
|
||||
fileName: 'image.png',
|
||||
};
|
||||
|
||||
const items: INodeExecutionData[] = [
|
||||
{
|
||||
json: {},
|
||||
binary: {},
|
||||
},
|
||||
];
|
||||
|
||||
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
||||
(mockExecuteFunctions.getNodeParameter as jest.Mock)
|
||||
.mockReturnValueOnce('comment')
|
||||
.mockReturnValueOnce('create')
|
||||
.mockReturnValueOnce('thread123')
|
||||
.mockReturnValueOnce('Test content')
|
||||
.mockReturnValueOnce({
|
||||
binaryProperties: binaryData,
|
||||
});
|
||||
|
||||
(mockExecuteFunctions.helpers.assertBinaryData as jest.Mock).mockReturnValue(binaryData);
|
||||
|
||||
(mockExecuteFunctions.helpers.getBinaryDataBuffer as jest.Mock).mockResolvedValue(
|
||||
Buffer.from('test data'),
|
||||
);
|
||||
|
||||
(mockExecuteFunctions.helpers.returnJsonArray as jest.Mock).mockImplementation(
|
||||
(data: any) => {
|
||||
return Array.isArray(data) ? data.map((item) => ({ json: item })) : [{ json: data }];
|
||||
},
|
||||
);
|
||||
|
||||
const result = await twist.execute.call(mockExecuteFunctions);
|
||||
|
||||
expect(result[0]).toHaveLength(1);
|
||||
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledTimes(1);
|
||||
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(0, binaryData);
|
||||
});
|
||||
});
|
||||
|
||||
describe('comment create with IBinaryData[] binaryProperties', () => {
|
||||
it('should process IBinaryData array', async () => {
|
||||
const binaryDataArray: IBinaryData[] = [
|
||||
{
|
||||
data: Buffer.from('data1').toString('base64'),
|
||||
mimeType: 'text/plain',
|
||||
fileName: 'file1.txt',
|
||||
},
|
||||
{
|
||||
data: Buffer.from('data2').toString('base64'),
|
||||
mimeType: 'image/jpeg',
|
||||
fileName: 'image.jpg',
|
||||
},
|
||||
];
|
||||
|
||||
const items: INodeExecutionData[] = [
|
||||
{
|
||||
json: {},
|
||||
binary: {},
|
||||
},
|
||||
];
|
||||
|
||||
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
||||
(mockExecuteFunctions.getNodeParameter as jest.Mock)
|
||||
.mockReturnValueOnce('comment')
|
||||
.mockReturnValueOnce('create')
|
||||
.mockReturnValueOnce('thread123')
|
||||
.mockReturnValueOnce('Test content')
|
||||
.mockReturnValueOnce({
|
||||
binaryProperties: binaryDataArray,
|
||||
});
|
||||
|
||||
(mockExecuteFunctions.helpers.assertBinaryData as jest.Mock).mockImplementation(
|
||||
(_: number, data: any) => {
|
||||
if (typeof data === 'object') return data;
|
||||
return binaryDataArray[0];
|
||||
},
|
||||
);
|
||||
|
||||
(mockExecuteFunctions.helpers.getBinaryDataBuffer as jest.Mock).mockResolvedValue(
|
||||
Buffer.from('test data'),
|
||||
);
|
||||
|
||||
(mockExecuteFunctions.helpers.returnJsonArray as jest.Mock).mockImplementation(
|
||||
(data: any) => {
|
||||
return Array.isArray(data) ? data.map((item) => ({ json: item })) : [{ json: data }];
|
||||
},
|
||||
);
|
||||
|
||||
const result = await twist.execute.call(mockExecuteFunctions);
|
||||
|
||||
expect(result[0]).toHaveLength(1);
|
||||
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('messageConversation create with binaryProperties', () => {
|
||||
it('should process string binaryProperties in messageConversation', async () => {
|
||||
const items: INodeExecutionData[] = [
|
||||
{
|
||||
json: {},
|
||||
binary: {
|
||||
attachment: {
|
||||
data: Buffer.from('data').toString('base64'),
|
||||
mimeType: 'application/pdf',
|
||||
fileName: 'report.pdf',
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
||||
(mockExecuteFunctions.getNodeParameter as jest.Mock)
|
||||
.mockReturnValueOnce('messageConversation')
|
||||
.mockReturnValueOnce('create')
|
||||
.mockReturnValueOnce('workspace123')
|
||||
.mockReturnValueOnce('conversation123')
|
||||
.mockReturnValueOnce('Test message')
|
||||
.mockReturnValueOnce({
|
||||
binaryProperties: 'attachment',
|
||||
});
|
||||
|
||||
(mockExecuteFunctions.helpers.assertBinaryData as jest.Mock).mockImplementation(
|
||||
(itemIndex: number, propertyName: string) => {
|
||||
return items[itemIndex].binary![propertyName];
|
||||
},
|
||||
);
|
||||
|
||||
(mockExecuteFunctions.helpers.getBinaryDataBuffer as jest.Mock).mockResolvedValue(
|
||||
Buffer.from('test data'),
|
||||
);
|
||||
|
||||
(mockExecuteFunctions.helpers.returnJsonArray as jest.Mock).mockImplementation(
|
||||
(data: any) => {
|
||||
return Array.isArray(data) ? data.map((item) => ({ json: item })) : [{ json: data }];
|
||||
},
|
||||
);
|
||||
|
||||
const result = await twist.execute.call(mockExecuteFunctions);
|
||||
|
||||
expect(result[0]).toHaveLength(1);
|
||||
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(0, 'attachment');
|
||||
});
|
||||
|
||||
it('should process IBinaryData[] in messageConversation', async () => {
|
||||
const binaryDataArray: IBinaryData[] = [
|
||||
{
|
||||
data: Buffer.from('data1').toString('base64'),
|
||||
mimeType: 'text/csv',
|
||||
fileName: 'data.csv',
|
||||
},
|
||||
{
|
||||
data: Buffer.from('data2').toString('base64'),
|
||||
mimeType: 'application/zip',
|
||||
fileName: 'archive.zip',
|
||||
},
|
||||
];
|
||||
|
||||
const items: INodeExecutionData[] = [
|
||||
{
|
||||
json: {},
|
||||
binary: {},
|
||||
},
|
||||
];
|
||||
|
||||
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
||||
(mockExecuteFunctions.getNodeParameter as jest.Mock)
|
||||
.mockReturnValueOnce('messageConversation')
|
||||
.mockReturnValueOnce('create')
|
||||
.mockReturnValueOnce('workspace123')
|
||||
.mockReturnValueOnce('conversation123')
|
||||
.mockReturnValueOnce('Test message')
|
||||
.mockReturnValueOnce({
|
||||
binaryProperties: binaryDataArray,
|
||||
});
|
||||
|
||||
(mockExecuteFunctions.helpers.assertBinaryData as jest.Mock).mockImplementation(
|
||||
(_: number, data: any) => {
|
||||
if (typeof data === 'object') return data;
|
||||
return binaryDataArray[0];
|
||||
},
|
||||
);
|
||||
|
||||
(mockExecuteFunctions.helpers.getBinaryDataBuffer as jest.Mock).mockResolvedValue(
|
||||
Buffer.from('test data'),
|
||||
);
|
||||
|
||||
(mockExecuteFunctions.helpers.returnJsonArray as jest.Mock).mockImplementation(
|
||||
(data: any) => {
|
||||
return Array.isArray(data) ? data.map((item) => ({ json: item })) : [{ json: data }];
|
||||
},
|
||||
);
|
||||
|
||||
const result = await twist.execute.call(mockExecuteFunctions);
|
||||
|
||||
expect(result[0]).toHaveLength(1);
|
||||
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('thread create with binaryProperties', () => {
|
||||
it('should process string binaryProperties in thread', async () => {
|
||||
const items: INodeExecutionData[] = [
|
||||
{
|
||||
json: {},
|
||||
binary: {
|
||||
doc1: {
|
||||
data: Buffer.from('data1').toString('base64'),
|
||||
mimeType: 'application/pdf',
|
||||
fileName: 'spec.pdf',
|
||||
},
|
||||
doc2: {
|
||||
data: Buffer.from('data2').toString('base64'),
|
||||
mimeType: 'application/pdf',
|
||||
fileName: 'design.pdf',
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
||||
(mockExecuteFunctions.getNodeParameter as jest.Mock)
|
||||
.mockReturnValueOnce('thread')
|
||||
.mockReturnValueOnce('create')
|
||||
.mockReturnValueOnce('channel123')
|
||||
.mockReturnValueOnce('Test Thread')
|
||||
.mockReturnValueOnce('Thread content')
|
||||
.mockReturnValueOnce({
|
||||
binaryProperties: 'doc1, doc2',
|
||||
});
|
||||
|
||||
(mockExecuteFunctions.helpers.assertBinaryData as jest.Mock).mockImplementation(
|
||||
(itemIndex: number, propertyName: string) => {
|
||||
return items[itemIndex].binary![propertyName];
|
||||
},
|
||||
);
|
||||
|
||||
(mockExecuteFunctions.helpers.getBinaryDataBuffer as jest.Mock).mockResolvedValue(
|
||||
Buffer.from('test data'),
|
||||
);
|
||||
|
||||
(mockExecuteFunctions.helpers.returnJsonArray as jest.Mock).mockImplementation(
|
||||
(data: any) => {
|
||||
return Array.isArray(data) ? data.map((item) => ({ json: item })) : [{ json: data }];
|
||||
},
|
||||
);
|
||||
|
||||
const result = await twist.execute.call(mockExecuteFunctions);
|
||||
|
||||
expect(result[0]).toHaveLength(1);
|
||||
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledTimes(2);
|
||||
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(0, 'doc1');
|
||||
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(0, 'doc2');
|
||||
});
|
||||
|
||||
it('should process single IBinaryData in thread', async () => {
|
||||
const binaryData: IBinaryData = {
|
||||
data: Buffer.from('data').toString('base64'),
|
||||
mimeType: 'text/markdown',
|
||||
fileName: 'README.md',
|
||||
};
|
||||
|
||||
const items: INodeExecutionData[] = [
|
||||
{
|
||||
json: {},
|
||||
binary: {},
|
||||
},
|
||||
];
|
||||
|
||||
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
||||
(mockExecuteFunctions.getNodeParameter as jest.Mock)
|
||||
.mockReturnValueOnce('thread')
|
||||
.mockReturnValueOnce('create')
|
||||
.mockReturnValueOnce('channel123')
|
||||
.mockReturnValueOnce('Test Thread')
|
||||
.mockReturnValueOnce('Thread content')
|
||||
.mockReturnValueOnce({
|
||||
binaryProperties: binaryData,
|
||||
});
|
||||
|
||||
(mockExecuteFunctions.helpers.assertBinaryData as jest.Mock).mockReturnValue(binaryData);
|
||||
|
||||
(mockExecuteFunctions.helpers.getBinaryDataBuffer as jest.Mock).mockResolvedValue(
|
||||
Buffer.from('test data'),
|
||||
);
|
||||
|
||||
(mockExecuteFunctions.helpers.returnJsonArray as jest.Mock).mockImplementation(
|
||||
(data: any) => {
|
||||
return Array.isArray(data) ? data.map((item) => ({ json: item })) : [{ json: data }];
|
||||
},
|
||||
);
|
||||
|
||||
const result = await twist.execute.call(mockExecuteFunctions);
|
||||
|
||||
expect(result[0]).toHaveLength(1);
|
||||
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(0, binaryData);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user