mirror of
https://github.com/n8n-io/n8n.git
synced 2026-05-28 23:37:00 +02:00
1546 lines
48 KiB
TypeScript
1546 lines
48 KiB
TypeScript
import { mockDeep } from 'jest-mock-extended';
|
|
import type { IExecuteFunctions, INode, INodeExecutionData } from 'n8n-workflow';
|
|
import { EditImage } from '../EditImage.node';
|
|
|
|
const createTestBuffer = () =>
|
|
Buffer.from([
|
|
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
|
|
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0x15, 0xc4,
|
|
0x89, 0x00, 0x00, 0x00, 0x0a, 0x49, 0x44, 0x41, 0x54, 0x78, 0x9c, 0x63, 0x00, 0x01, 0x00, 0x00,
|
|
0x05, 0x00, 0x01, 0x0d, 0x0a, 0x2d, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae,
|
|
0x42, 0x60, 0x82,
|
|
]);
|
|
|
|
const mockGmInstance: any = {
|
|
background: jest.fn(function (this: any) {
|
|
return this;
|
|
}),
|
|
blur: jest.fn(function (this: any) {
|
|
return this;
|
|
}),
|
|
borderColor: jest.fn(function (this: any) {
|
|
return this;
|
|
}),
|
|
border: jest.fn(function (this: any) {
|
|
return this;
|
|
}),
|
|
compose: jest.fn(function (this: any) {
|
|
return this;
|
|
}),
|
|
geometry: jest.fn(function (this: any) {
|
|
return this;
|
|
}),
|
|
composite: jest.fn(function (this: any) {
|
|
return this;
|
|
}),
|
|
crop: jest.fn(function (this: any) {
|
|
return this;
|
|
}),
|
|
drawCircle: jest.fn(function (this: any) {
|
|
return this;
|
|
}),
|
|
drawLine: jest.fn(function (this: any) {
|
|
return this;
|
|
}),
|
|
drawRectangle: jest.fn(function (this: any) {
|
|
return this;
|
|
}),
|
|
fill: jest.fn(function (this: any) {
|
|
return this;
|
|
}),
|
|
font: jest.fn(function (this: any) {
|
|
return this;
|
|
}),
|
|
fontSize: jest.fn(function (this: any) {
|
|
return this;
|
|
}),
|
|
drawText: jest.fn(function (this: any) {
|
|
return this;
|
|
}),
|
|
identify: jest.fn(function (this: any, callback: any) {
|
|
callback(null, { width: 100, height: 100, format: 'PNG' });
|
|
return this;
|
|
}),
|
|
quality: jest.fn(function (this: any) {
|
|
return this;
|
|
}),
|
|
resize: jest.fn(function (this: any) {
|
|
return this;
|
|
}),
|
|
rotate: jest.fn(function (this: any) {
|
|
return this;
|
|
}),
|
|
setFormat: jest.fn(function (this: any) {
|
|
return this;
|
|
}),
|
|
shear: jest.fn(function (this: any) {
|
|
return this;
|
|
}),
|
|
stream: jest.fn(function (this: any) {
|
|
return this;
|
|
}),
|
|
transparent: jest.fn(function (this: any) {
|
|
return this;
|
|
}),
|
|
toBuffer: jest.fn(function (this: any, callback: any) {
|
|
callback(null, createTestBuffer());
|
|
return this;
|
|
}),
|
|
autoOrient: jest.fn(function (this: any) {
|
|
return this;
|
|
}),
|
|
out: jest.fn(function (this: any) {
|
|
return this;
|
|
}),
|
|
};
|
|
|
|
jest.mock('gm', () => jest.fn(() => mockGmInstance));
|
|
|
|
describe('EditImage Node', () => {
|
|
let editImageNode: EditImage;
|
|
const mockExecuteFunctions = mockDeep<IExecuteFunctions>();
|
|
let mockNode: INode;
|
|
|
|
beforeEach(() => {
|
|
jest.clearAllMocks();
|
|
editImageNode = new EditImage();
|
|
mockNode = {
|
|
id: 'test-node-id',
|
|
name: 'EditImage',
|
|
type: 'n8n-nodes-base.editImage',
|
|
typeVersion: 1,
|
|
position: [0, 0],
|
|
parameters: {},
|
|
};
|
|
|
|
mockExecuteFunctions.getNode.mockReturnValue(mockNode);
|
|
mockExecuteFunctions.continueOnFail.mockReturnValue(false);
|
|
mockExecuteFunctions.helpers.assertBinaryData.mockReturnValue(undefined as any);
|
|
});
|
|
|
|
describe('dataPropertyName parameter', () => {
|
|
it('should handle IBinaryData type', async () => {
|
|
const testBuffer = createTestBuffer();
|
|
const binaryData = {
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
};
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: {},
|
|
binary: {
|
|
data: binaryData,
|
|
},
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'blur';
|
|
if (paramName === 'dataPropertyName') return binaryData;
|
|
if (paramName === 'blur') return 5;
|
|
if (paramName === 'sigma') return 2;
|
|
return {};
|
|
});
|
|
|
|
mockExecuteFunctions.helpers.getBinaryDataBuffer.mockResolvedValue(testBuffer);
|
|
mockExecuteFunctions.helpers.prepareBinaryData.mockResolvedValue({
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
});
|
|
|
|
const result = await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(result[0]).toHaveLength(1);
|
|
expect(result[0][0].binary).toHaveProperty('data');
|
|
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(0, binaryData);
|
|
});
|
|
|
|
it('should handle string type for custom property', async () => {
|
|
const testBuffer = createTestBuffer();
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: {},
|
|
binary: {
|
|
customImageProperty: {
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
},
|
|
},
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'information';
|
|
if (paramName === 'dataPropertyName') return 'customImageProperty';
|
|
return {};
|
|
});
|
|
|
|
mockExecuteFunctions.helpers.getBinaryDataBuffer.mockResolvedValue(testBuffer);
|
|
|
|
await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(
|
|
0,
|
|
'customImageProperty',
|
|
);
|
|
expect(mockExecuteFunctions.helpers.getBinaryDataBuffer).toHaveBeenCalledWith(
|
|
0,
|
|
'customImageProperty',
|
|
);
|
|
});
|
|
|
|
it('should handle string type for default "data" property', async () => {
|
|
const testBuffer = createTestBuffer();
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: {},
|
|
binary: {
|
|
data: {
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
},
|
|
},
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'information';
|
|
if (paramName === 'dataPropertyName') return 'data';
|
|
return {};
|
|
});
|
|
|
|
mockExecuteFunctions.helpers.getBinaryDataBuffer.mockResolvedValue(testBuffer);
|
|
|
|
await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(0, 'data');
|
|
expect(mockExecuteFunctions.helpers.getBinaryDataBuffer).toHaveBeenCalledWith(0, 'data');
|
|
});
|
|
|
|
it('should throw error when binary data is missing', async () => {
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: {},
|
|
binary: {},
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'blur';
|
|
if (paramName === 'dataPropertyName') return 'missingProperty';
|
|
if (paramName === 'blur') return 5;
|
|
if (paramName === 'sigma') return 2;
|
|
return {};
|
|
});
|
|
|
|
const error = new Error('Binary data missing');
|
|
mockExecuteFunctions.helpers.assertBinaryData.mockImplementation(() => {
|
|
throw error;
|
|
});
|
|
|
|
await expect(editImageNode.execute.call(mockExecuteFunctions)).rejects.toThrow();
|
|
});
|
|
});
|
|
|
|
describe('destinationKey option', () => {
|
|
it('should use destinationKey for output property', async () => {
|
|
const testBuffer = createTestBuffer();
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: { id: 1 },
|
|
binary: {
|
|
data: {
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
},
|
|
},
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string, _: number) => {
|
|
if (paramName === 'operation') return 'blur';
|
|
if (paramName === 'dataPropertyName') return 'data';
|
|
if (paramName === 'blur') return 5;
|
|
if (paramName === 'sigma') return 2;
|
|
if (paramName === 'options') {
|
|
return {
|
|
destinationKey: 'processedImage',
|
|
};
|
|
}
|
|
return {};
|
|
});
|
|
|
|
mockExecuteFunctions.helpers.getBinaryDataBuffer.mockResolvedValue(testBuffer);
|
|
mockExecuteFunctions.helpers.prepareBinaryData.mockResolvedValue({
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
});
|
|
|
|
const result = await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(result[0]).toHaveLength(1);
|
|
expect(result[0][0].binary).toHaveProperty('processedImage');
|
|
expect(result[0][0].json).toEqual({ id: 1 });
|
|
});
|
|
|
|
it('should default output to input property name when destinationKey not specified', async () => {
|
|
const testBuffer = createTestBuffer();
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: { id: 1 },
|
|
binary: {
|
|
imageData: {
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
},
|
|
},
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'blur';
|
|
if (paramName === 'dataPropertyName') return 'imageData';
|
|
if (paramName === 'blur') return 5;
|
|
if (paramName === 'sigma') return 2;
|
|
if (paramName === 'options') return {};
|
|
return {};
|
|
});
|
|
|
|
mockExecuteFunctions.helpers.getBinaryDataBuffer.mockResolvedValue(testBuffer);
|
|
mockExecuteFunctions.helpers.prepareBinaryData.mockResolvedValue({
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
});
|
|
|
|
const result = await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(result[0]).toHaveLength(1);
|
|
expect(result[0][0].binary).toHaveProperty('imageData');
|
|
});
|
|
});
|
|
|
|
describe('data preservation', () => {
|
|
it('should preserve existing binary data when processing', async () => {
|
|
const testBuffer = createTestBuffer();
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: { id: 1 },
|
|
binary: {
|
|
data: {
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
},
|
|
otherFile: {
|
|
data: 'other-data',
|
|
mimeType: 'text/plain',
|
|
fileName: 'other.txt',
|
|
},
|
|
},
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'blur';
|
|
if (paramName === 'dataPropertyName') return 'data';
|
|
if (paramName === 'blur') return 5;
|
|
if (paramName === 'sigma') return 2;
|
|
if (paramName === 'options') return {};
|
|
return {};
|
|
});
|
|
|
|
mockExecuteFunctions.helpers.getBinaryDataBuffer.mockResolvedValue(testBuffer);
|
|
mockExecuteFunctions.helpers.prepareBinaryData.mockResolvedValue({
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
});
|
|
|
|
const result = await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(result[0]).toHaveLength(1);
|
|
expect(result[0][0].binary).toHaveProperty('data');
|
|
expect(result[0][0].binary).toHaveProperty('otherFile');
|
|
expect(result[0][0].binary?.otherFile).toEqual({
|
|
data: 'other-data',
|
|
mimeType: 'text/plain',
|
|
fileName: 'other.txt',
|
|
});
|
|
});
|
|
|
|
it('should preserve JSON data when processing binary', async () => {
|
|
const testBuffer = createTestBuffer();
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: { id: 1, name: 'test', metadata: { processed: false } },
|
|
binary: {
|
|
data: {
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
},
|
|
},
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'blur';
|
|
if (paramName === 'dataPropertyName') return 'data';
|
|
if (paramName === 'blur') return 5;
|
|
if (paramName === 'sigma') return 2;
|
|
if (paramName === 'options') return {};
|
|
return {};
|
|
});
|
|
|
|
mockExecuteFunctions.helpers.getBinaryDataBuffer.mockResolvedValue(testBuffer);
|
|
mockExecuteFunctions.helpers.prepareBinaryData.mockResolvedValue({
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
});
|
|
|
|
const result = await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(result[0]).toHaveLength(1);
|
|
expect(result[0][0].json).toEqual({ id: 1, name: 'test', metadata: { processed: false } });
|
|
});
|
|
});
|
|
|
|
describe('create operation', () => {
|
|
it('should create image without input binary', async () => {
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: {},
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'create';
|
|
if (paramName === 'dataPropertyName') return 'data';
|
|
if (paramName === 'backgroundColor') return '#ffffff';
|
|
if (paramName === 'width') return 100;
|
|
if (paramName === 'height') return 100;
|
|
if (paramName === 'options') {
|
|
return {
|
|
format: 'png',
|
|
};
|
|
}
|
|
return {};
|
|
});
|
|
|
|
const testBuffer = createTestBuffer();
|
|
mockExecuteFunctions.helpers.prepareBinaryData.mockResolvedValue({
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'image.png',
|
|
});
|
|
|
|
const result = await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(result[0]).toHaveLength(1);
|
|
expect(result[0][0].binary).toHaveProperty('data');
|
|
expect(mockExecuteFunctions.helpers.assertBinaryData).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('information operation', () => {
|
|
it('should return image information', async () => {
|
|
const testBuffer = createTestBuffer();
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: {},
|
|
binary: {
|
|
data: {
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
},
|
|
},
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'information';
|
|
if (paramName === 'dataPropertyName') return 'data';
|
|
return {};
|
|
});
|
|
|
|
mockExecuteFunctions.helpers.getBinaryDataBuffer.mockResolvedValue(testBuffer);
|
|
|
|
const result = await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(result[0]).toHaveLength(1);
|
|
expect(result[0][0].json).toBeDefined();
|
|
expect(result[0][0].json).toHaveProperty('width');
|
|
expect(result[0][0].json).toHaveProperty('height');
|
|
expect(result[0][0].json).toHaveProperty('format');
|
|
});
|
|
});
|
|
|
|
describe('multiple items', () => {
|
|
it('should process multiple items with different binary property names', async () => {
|
|
const testBuffer = createTestBuffer();
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: { id: 1 },
|
|
binary: {
|
|
image1: {
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test1.png',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
json: { id: 2 },
|
|
binary: {
|
|
image2: {
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test2.png',
|
|
},
|
|
},
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation(
|
|
(paramName: string, itemIndex: number) => {
|
|
if (paramName === 'operation') return 'blur';
|
|
if (paramName === 'dataPropertyName') {
|
|
return itemIndex === 0 ? 'image1' : 'image2';
|
|
}
|
|
if (paramName === 'blur') return 5;
|
|
if (paramName === 'sigma') return 2;
|
|
if (paramName === 'options') return {};
|
|
return {};
|
|
},
|
|
);
|
|
|
|
mockExecuteFunctions.helpers.getBinaryDataBuffer.mockResolvedValue(testBuffer);
|
|
mockExecuteFunctions.helpers.prepareBinaryData.mockResolvedValue({
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
});
|
|
|
|
const result = await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(result[0]).toHaveLength(2);
|
|
expect(result[0][0].binary).toHaveProperty('image1');
|
|
expect(result[0][1].binary).toHaveProperty('image2');
|
|
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(0, 'image1');
|
|
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(1, 'image2');
|
|
});
|
|
});
|
|
|
|
describe('format and quality options', () => {
|
|
it('should apply format option to output binary data', async () => {
|
|
const testBuffer = createTestBuffer();
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: {},
|
|
binary: {
|
|
data: {
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
},
|
|
},
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'blur';
|
|
if (paramName === 'dataPropertyName') return 'data';
|
|
if (paramName === 'blur') return 5;
|
|
if (paramName === 'sigma') return 2;
|
|
if (paramName === 'options') {
|
|
return {
|
|
format: 'jpeg',
|
|
quality: 80,
|
|
};
|
|
}
|
|
return {};
|
|
});
|
|
|
|
mockExecuteFunctions.helpers.getBinaryDataBuffer.mockResolvedValue(testBuffer);
|
|
mockExecuteFunctions.helpers.prepareBinaryData.mockResolvedValue({
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/jpeg',
|
|
fileExtension: 'jpeg',
|
|
fileName: 'test.jpeg',
|
|
});
|
|
|
|
const result = await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(result[0]).toHaveLength(1);
|
|
expect(result[0][0].binary?.data?.mimeType).toBe('image/jpeg');
|
|
expect(result[0][0].binary?.data?.fileExtension).toBe('jpeg');
|
|
});
|
|
|
|
it('should apply custom fileName option', async () => {
|
|
const testBuffer = createTestBuffer();
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: {},
|
|
binary: {
|
|
data: {
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
},
|
|
},
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'blur';
|
|
if (paramName === 'dataPropertyName') return 'data';
|
|
if (paramName === 'blur') return 5;
|
|
if (paramName === 'sigma') return 2;
|
|
if (paramName === 'options') {
|
|
return {
|
|
fileName: 'custom-output.png',
|
|
};
|
|
}
|
|
return {};
|
|
});
|
|
|
|
mockExecuteFunctions.helpers.getBinaryDataBuffer.mockResolvedValue(testBuffer);
|
|
mockExecuteFunctions.helpers.prepareBinaryData.mockResolvedValue({
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'custom-output.png',
|
|
});
|
|
|
|
const result = await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(result[0]).toHaveLength(1);
|
|
expect(result[0][0].binary?.data?.fileName).toBe('custom-output.png');
|
|
});
|
|
});
|
|
|
|
describe('error handling', () => {
|
|
it('should return error in json when continueOnFail is true', async () => {
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: {},
|
|
binary: {},
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.continueOnFail.mockReturnValue(true);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'blur';
|
|
if (paramName === 'dataPropertyName') return 'missingProperty';
|
|
if (paramName === 'blur') return 5;
|
|
if (paramName === 'sigma') return 2;
|
|
return {};
|
|
});
|
|
|
|
const error = new Error('Binary data missing');
|
|
mockExecuteFunctions.helpers.assertBinaryData.mockImplementation(() => {
|
|
throw error;
|
|
});
|
|
|
|
const result = await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(result[0]).toHaveLength(1);
|
|
expect(result[0][0].json).toHaveProperty('error');
|
|
expect(result[0][0].json.error).toBe('Binary data missing');
|
|
expect(result[0][0].pairedItem).toEqual({ item: 0 });
|
|
});
|
|
|
|
it('should throw error when continueOnFail is false', async () => {
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: {},
|
|
binary: {},
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.continueOnFail.mockReturnValue(false);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'blur';
|
|
if (paramName === 'dataPropertyName') return 'missingProperty';
|
|
if (paramName === 'blur') return 5;
|
|
if (paramName === 'sigma') return 2;
|
|
return {};
|
|
});
|
|
|
|
const error = new Error('Binary data missing');
|
|
mockExecuteFunctions.helpers.assertBinaryData.mockImplementation(() => {
|
|
throw error;
|
|
});
|
|
|
|
await expect(editImageNode.execute.call(mockExecuteFunctions)).rejects.toThrow(
|
|
'Binary data missing',
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('operations with IBinaryData', () => {
|
|
it('should handle information operation with IBinaryData', async () => {
|
|
const testBuffer = createTestBuffer();
|
|
const binaryData = {
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
};
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: {},
|
|
binary: {
|
|
data: binaryData,
|
|
},
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'information';
|
|
if (paramName === 'dataPropertyName') return binaryData;
|
|
return {};
|
|
});
|
|
|
|
mockExecuteFunctions.helpers.getBinaryDataBuffer.mockResolvedValue(testBuffer);
|
|
|
|
const result = await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(result[0]).toHaveLength(1);
|
|
expect(result[0][0].json).toHaveProperty('width');
|
|
expect(result[0][0].json).toHaveProperty('height');
|
|
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(0, binaryData);
|
|
expect(mockExecuteFunctions.helpers.getBinaryDataBuffer).toHaveBeenCalledWith(0, binaryData);
|
|
});
|
|
|
|
it('should handle crop operation with IBinaryData', async () => {
|
|
const testBuffer = createTestBuffer();
|
|
const binaryData = {
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
};
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: {},
|
|
binary: {
|
|
data: binaryData,
|
|
},
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'crop';
|
|
if (paramName === 'dataPropertyName') return binaryData;
|
|
if (paramName === 'width') return 100;
|
|
if (paramName === 'height') return 100;
|
|
if (paramName === 'positionX') return 0;
|
|
if (paramName === 'positionY') return 0;
|
|
if (paramName === 'options') return {};
|
|
return {};
|
|
});
|
|
|
|
mockExecuteFunctions.helpers.getBinaryDataBuffer.mockResolvedValue(testBuffer);
|
|
mockExecuteFunctions.helpers.prepareBinaryData.mockResolvedValue({
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
});
|
|
|
|
const result = await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(result[0]).toHaveLength(1);
|
|
expect(result[0][0].binary).toHaveProperty('data');
|
|
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(0, binaryData);
|
|
});
|
|
|
|
it('should handle text operation with IBinaryData', async () => {
|
|
const testBuffer = createTestBuffer();
|
|
const binaryData = {
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
};
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: {},
|
|
binary: {
|
|
data: binaryData,
|
|
},
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'text';
|
|
if (paramName === 'dataPropertyName') return binaryData;
|
|
if (paramName === 'text') return 'Hello';
|
|
if (paramName === 'fontSize') return 18;
|
|
if (paramName === 'fontColor') return '#000000';
|
|
if (paramName === 'positionX') return 10;
|
|
if (paramName === 'positionY') return 10;
|
|
if (paramName === 'lineLength') return 80;
|
|
if (paramName === 'options') return { font: 'Arial' };
|
|
return {};
|
|
});
|
|
|
|
mockExecuteFunctions.helpers.getBinaryDataBuffer.mockResolvedValue(testBuffer);
|
|
mockExecuteFunctions.helpers.prepareBinaryData.mockResolvedValue({
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
});
|
|
|
|
const result = await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(result[0]).toHaveLength(1);
|
|
expect(result[0][0].binary).toHaveProperty('data');
|
|
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(0, binaryData);
|
|
});
|
|
|
|
it('should use destinationKey with IBinaryData', async () => {
|
|
const testBuffer = createTestBuffer();
|
|
const binaryData = {
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
};
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: {},
|
|
binary: {
|
|
data: binaryData,
|
|
},
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'blur';
|
|
if (paramName === 'dataPropertyName') return binaryData;
|
|
if (paramName === 'blur') return 5;
|
|
if (paramName === 'sigma') return 2;
|
|
if (paramName === 'options') return { destinationKey: 'output' };
|
|
return {};
|
|
});
|
|
|
|
mockExecuteFunctions.helpers.getBinaryDataBuffer.mockResolvedValue(testBuffer);
|
|
mockExecuteFunctions.helpers.prepareBinaryData.mockResolvedValue({
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
});
|
|
|
|
const result = await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(result[0]).toHaveLength(1);
|
|
expect(result[0][0].binary).toHaveProperty('output');
|
|
});
|
|
|
|
it('should read from both main and composite binary properties', async () => {
|
|
const testBuffer = createTestBuffer();
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: {},
|
|
binary: {
|
|
mainImage: {
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'main.png',
|
|
},
|
|
overlayImage: {
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'overlay.png',
|
|
},
|
|
},
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'composite';
|
|
if (paramName === 'dataPropertyName') return 'mainImage';
|
|
if (paramName === 'dataPropertyNameComposite') return 'overlayImage';
|
|
if (paramName === 'operator') return 'Over';
|
|
if (paramName === 'positionX') return 0;
|
|
if (paramName === 'positionY') return 0;
|
|
if (paramName === 'options') return {};
|
|
return {};
|
|
});
|
|
|
|
mockExecuteFunctions.helpers.getBinaryDataBuffer.mockResolvedValue(testBuffer);
|
|
mockExecuteFunctions.helpers.prepareBinaryData.mockResolvedValue({
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
});
|
|
|
|
await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(0, 'mainImage');
|
|
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(0, 'overlayImage');
|
|
});
|
|
});
|
|
|
|
describe('all operations with string and IBinaryData', () => {
|
|
it('should handle border operation with string dataPropertyName', async () => {
|
|
const testBuffer = createTestBuffer();
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: {},
|
|
binary: {
|
|
data: {
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
},
|
|
},
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'border';
|
|
if (paramName === 'dataPropertyName') return 'data';
|
|
if (paramName === 'borderColor') return '#000000';
|
|
if (paramName === 'borderWidth') return 10;
|
|
if (paramName === 'borderHeight') return 10;
|
|
if (paramName === 'options') return {};
|
|
return {};
|
|
});
|
|
|
|
mockExecuteFunctions.helpers.getBinaryDataBuffer.mockResolvedValue(testBuffer);
|
|
mockExecuteFunctions.helpers.prepareBinaryData.mockResolvedValue({
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
});
|
|
|
|
const result = await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(result[0]).toHaveLength(1);
|
|
expect(result[0][0].binary).toHaveProperty('data');
|
|
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(0, 'data');
|
|
});
|
|
|
|
it('should handle border operation with IBinaryData dataPropertyName', async () => {
|
|
const testBuffer = createTestBuffer();
|
|
const binaryData = {
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
};
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: {},
|
|
binary: { data: binaryData },
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'border';
|
|
if (paramName === 'dataPropertyName') return binaryData;
|
|
if (paramName === 'borderColor') return '#000000';
|
|
if (paramName === 'borderWidth') return 10;
|
|
if (paramName === 'borderHeight') return 10;
|
|
if (paramName === 'options') return {};
|
|
return {};
|
|
});
|
|
|
|
mockExecuteFunctions.helpers.getBinaryDataBuffer.mockResolvedValue(testBuffer);
|
|
mockExecuteFunctions.helpers.prepareBinaryData.mockResolvedValue({
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
});
|
|
|
|
const result = await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(result[0]).toHaveLength(1);
|
|
expect(result[0][0].binary).toHaveProperty('data');
|
|
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(0, binaryData);
|
|
});
|
|
|
|
it('should handle draw operation with string dataPropertyName', async () => {
|
|
const testBuffer = createTestBuffer();
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: {},
|
|
binary: {
|
|
imageFile: {
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
},
|
|
},
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'draw';
|
|
if (paramName === 'dataPropertyName') return 'imageFile';
|
|
if (paramName === 'primitive') return 'rectangle';
|
|
if (paramName === 'color') return '#ff0000';
|
|
if (paramName === 'startPositionX') return 10;
|
|
if (paramName === 'startPositionY') return 10;
|
|
if (paramName === 'endPositionX') return 100;
|
|
if (paramName === 'endPositionY') return 100;
|
|
if (paramName === 'cornerRadius') return 5;
|
|
if (paramName === 'options') return {};
|
|
return {};
|
|
});
|
|
|
|
mockExecuteFunctions.helpers.getBinaryDataBuffer.mockResolvedValue(testBuffer);
|
|
mockExecuteFunctions.helpers.prepareBinaryData.mockResolvedValue({
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
});
|
|
|
|
const result = await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(result[0]).toHaveLength(1);
|
|
expect(result[0][0].binary).toHaveProperty('imageFile');
|
|
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(0, 'imageFile');
|
|
});
|
|
|
|
it('should handle draw operation with IBinaryData dataPropertyName', async () => {
|
|
const testBuffer = createTestBuffer();
|
|
const binaryData = {
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
};
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: {},
|
|
binary: { data: binaryData },
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'draw';
|
|
if (paramName === 'dataPropertyName') return binaryData;
|
|
if (paramName === 'primitive') return 'circle';
|
|
if (paramName === 'color') return '#0000ff';
|
|
if (paramName === 'startPositionX') return 50;
|
|
if (paramName === 'startPositionY') return 50;
|
|
if (paramName === 'endPositionX') return 75;
|
|
if (paramName === 'endPositionY') return 75;
|
|
if (paramName === 'options') return {};
|
|
return {};
|
|
});
|
|
|
|
mockExecuteFunctions.helpers.getBinaryDataBuffer.mockResolvedValue(testBuffer);
|
|
mockExecuteFunctions.helpers.prepareBinaryData.mockResolvedValue({
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
});
|
|
|
|
const result = await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(result[0]).toHaveLength(1);
|
|
expect(result[0][0].binary).toHaveProperty('data');
|
|
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(0, binaryData);
|
|
});
|
|
|
|
it('should handle rotate operation with string dataPropertyName', async () => {
|
|
const testBuffer = createTestBuffer();
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: {},
|
|
binary: {
|
|
photo: {
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
},
|
|
},
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'rotate';
|
|
if (paramName === 'dataPropertyName') return 'photo';
|
|
if (paramName === 'rotate') return 45;
|
|
if (paramName === 'backgroundColor') return '#ffffff';
|
|
if (paramName === 'options') return {};
|
|
return {};
|
|
});
|
|
|
|
mockExecuteFunctions.helpers.getBinaryDataBuffer.mockResolvedValue(testBuffer);
|
|
mockExecuteFunctions.helpers.prepareBinaryData.mockResolvedValue({
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
});
|
|
|
|
const result = await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(result[0]).toHaveLength(1);
|
|
expect(result[0][0].binary).toHaveProperty('photo');
|
|
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(0, 'photo');
|
|
});
|
|
|
|
it('should handle rotate operation with IBinaryData dataPropertyName', async () => {
|
|
const testBuffer = createTestBuffer();
|
|
const binaryData = {
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
};
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: {},
|
|
binary: { data: binaryData },
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'rotate';
|
|
if (paramName === 'dataPropertyName') return binaryData;
|
|
if (paramName === 'rotate') return 90;
|
|
if (paramName === 'backgroundColor') return '#000000';
|
|
if (paramName === 'options') return {};
|
|
return {};
|
|
});
|
|
|
|
mockExecuteFunctions.helpers.getBinaryDataBuffer.mockResolvedValue(testBuffer);
|
|
mockExecuteFunctions.helpers.prepareBinaryData.mockResolvedValue({
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
});
|
|
|
|
const result = await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(result[0]).toHaveLength(1);
|
|
expect(result[0][0].binary).toHaveProperty('data');
|
|
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(0, binaryData);
|
|
});
|
|
|
|
it('should handle resize operation with string dataPropertyName', async () => {
|
|
const testBuffer = createTestBuffer();
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: {},
|
|
binary: {
|
|
image: {
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
},
|
|
},
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'resize';
|
|
if (paramName === 'dataPropertyName') return 'image';
|
|
if (paramName === 'width') return 200;
|
|
if (paramName === 'height') return 200;
|
|
if (paramName === 'resizeOption') return 'maximumArea';
|
|
if (paramName === 'options') return {};
|
|
return {};
|
|
});
|
|
|
|
mockExecuteFunctions.helpers.getBinaryDataBuffer.mockResolvedValue(testBuffer);
|
|
mockExecuteFunctions.helpers.prepareBinaryData.mockResolvedValue({
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
});
|
|
|
|
const result = await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(result[0]).toHaveLength(1);
|
|
expect(result[0][0].binary).toHaveProperty('image');
|
|
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(0, 'image');
|
|
});
|
|
|
|
it('should handle resize operation with IBinaryData dataPropertyName', async () => {
|
|
const testBuffer = createTestBuffer();
|
|
const binaryData = {
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
};
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: {},
|
|
binary: { data: binaryData },
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'resize';
|
|
if (paramName === 'dataPropertyName') return binaryData;
|
|
if (paramName === 'width') return 150;
|
|
if (paramName === 'height') return 150;
|
|
if (paramName === 'resizeOption') return 'ignoreAspectRatio';
|
|
if (paramName === 'options') return {};
|
|
return {};
|
|
});
|
|
|
|
mockExecuteFunctions.helpers.getBinaryDataBuffer.mockResolvedValue(testBuffer);
|
|
mockExecuteFunctions.helpers.prepareBinaryData.mockResolvedValue({
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
});
|
|
|
|
const result = await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(result[0]).toHaveLength(1);
|
|
expect(result[0][0].binary).toHaveProperty('data');
|
|
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(0, binaryData);
|
|
});
|
|
|
|
it('should handle shear operation with string dataPropertyName', async () => {
|
|
const testBuffer = createTestBuffer();
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: {},
|
|
binary: {
|
|
myImage: {
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
},
|
|
},
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'shear';
|
|
if (paramName === 'dataPropertyName') return 'myImage';
|
|
if (paramName === 'degreesX') return 20;
|
|
if (paramName === 'degreesY') return 10;
|
|
if (paramName === 'options') return {};
|
|
return {};
|
|
});
|
|
|
|
mockExecuteFunctions.helpers.getBinaryDataBuffer.mockResolvedValue(testBuffer);
|
|
mockExecuteFunctions.helpers.prepareBinaryData.mockResolvedValue({
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
});
|
|
|
|
const result = await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(result[0]).toHaveLength(1);
|
|
expect(result[0][0].binary).toHaveProperty('myImage');
|
|
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(0, 'myImage');
|
|
});
|
|
|
|
it('should handle shear operation with IBinaryData dataPropertyName', async () => {
|
|
const testBuffer = createTestBuffer();
|
|
const binaryData = {
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
};
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: {},
|
|
binary: { data: binaryData },
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'shear';
|
|
if (paramName === 'dataPropertyName') return binaryData;
|
|
if (paramName === 'degreesX') return 15;
|
|
if (paramName === 'degreesY') return 5;
|
|
if (paramName === 'options') return {};
|
|
return {};
|
|
});
|
|
|
|
mockExecuteFunctions.helpers.getBinaryDataBuffer.mockResolvedValue(testBuffer);
|
|
mockExecuteFunctions.helpers.prepareBinaryData.mockResolvedValue({
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
});
|
|
|
|
const result = await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(result[0]).toHaveLength(1);
|
|
expect(result[0][0].binary).toHaveProperty('data');
|
|
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(0, binaryData);
|
|
});
|
|
|
|
it('should handle transparent operation with string dataPropertyName', async () => {
|
|
const testBuffer = createTestBuffer();
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: {},
|
|
binary: {
|
|
picture: {
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
},
|
|
},
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'transparent';
|
|
if (paramName === 'dataPropertyName') return 'picture';
|
|
if (paramName === 'color') return '#ffffff';
|
|
if (paramName === 'options') return {};
|
|
return {};
|
|
});
|
|
|
|
mockExecuteFunctions.helpers.getBinaryDataBuffer.mockResolvedValue(testBuffer);
|
|
mockExecuteFunctions.helpers.prepareBinaryData.mockResolvedValue({
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
});
|
|
|
|
const result = await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(result[0]).toHaveLength(1);
|
|
expect(result[0][0].binary).toHaveProperty('picture');
|
|
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(0, 'picture');
|
|
});
|
|
|
|
it('should handle transparent operation with IBinaryData dataPropertyName', async () => {
|
|
const testBuffer = createTestBuffer();
|
|
const binaryData = {
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
};
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: {},
|
|
binary: { data: binaryData },
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'transparent';
|
|
if (paramName === 'dataPropertyName') return binaryData;
|
|
if (paramName === 'color') return '#00ff00';
|
|
if (paramName === 'options') return {};
|
|
return {};
|
|
});
|
|
|
|
mockExecuteFunctions.helpers.getBinaryDataBuffer.mockResolvedValue(testBuffer);
|
|
mockExecuteFunctions.helpers.prepareBinaryData.mockResolvedValue({
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
});
|
|
|
|
const result = await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(result[0]).toHaveLength(1);
|
|
expect(result[0][0].binary).toHaveProperty('data');
|
|
expect(mockExecuteFunctions.helpers.assertBinaryData).toHaveBeenCalledWith(0, binaryData);
|
|
});
|
|
});
|
|
|
|
describe('multiStep operation', () => {
|
|
it('should process multiple operations in sequence', async () => {
|
|
const testBuffer = createTestBuffer();
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: {},
|
|
binary: {
|
|
data: {
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
},
|
|
},
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'multiStep';
|
|
if (paramName === 'dataPropertyName') return 'data';
|
|
if (paramName === 'operations') {
|
|
return {
|
|
operations: [
|
|
{
|
|
operation: 'blur',
|
|
blur: 5,
|
|
sigma: 2,
|
|
},
|
|
{
|
|
operation: 'rotate',
|
|
rotate: 90,
|
|
backgroundColor: '#ffffff',
|
|
},
|
|
],
|
|
};
|
|
}
|
|
if (paramName === 'options') return {};
|
|
return {};
|
|
});
|
|
|
|
mockExecuteFunctions.helpers.getBinaryDataBuffer.mockResolvedValue(testBuffer);
|
|
mockExecuteFunctions.helpers.prepareBinaryData.mockResolvedValue({
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
});
|
|
|
|
const result = await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(result[0]).toHaveLength(1);
|
|
expect(result[0][0].binary).toHaveProperty('data');
|
|
});
|
|
});
|
|
|
|
describe('autoOrient', () => {
|
|
it('should call autoOrient when loading an existing image', async () => {
|
|
const testBuffer = createTestBuffer();
|
|
const items: INodeExecutionData[] = [
|
|
{
|
|
json: {},
|
|
binary: {
|
|
data: {
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
fileName: 'test.png',
|
|
},
|
|
},
|
|
},
|
|
];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'blur';
|
|
if (paramName === 'dataPropertyName') return 'data';
|
|
if (paramName === 'blur') return 5;
|
|
if (paramName === 'sigma') return 2;
|
|
return {};
|
|
});
|
|
|
|
mockExecuteFunctions.helpers.getBinaryDataBuffer.mockResolvedValue(testBuffer);
|
|
mockExecuteFunctions.helpers.prepareBinaryData.mockResolvedValue({
|
|
data: testBuffer.toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
});
|
|
|
|
await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(mockGmInstance.autoOrient).toHaveBeenCalled();
|
|
expect(mockGmInstance.out).toHaveBeenCalledWith('-orient', 'TopLeft');
|
|
});
|
|
|
|
it('should not call autoOrient for create operation', async () => {
|
|
const items: INodeExecutionData[] = [{ json: {} }];
|
|
|
|
mockExecuteFunctions.getInputData.mockReturnValue(items);
|
|
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
if (paramName === 'operation') return 'create';
|
|
if (paramName === 'dataPropertyName') return 'data';
|
|
if (paramName === 'width') return 100;
|
|
if (paramName === 'height') return 100;
|
|
if (paramName === 'backgroundColor') return 'white';
|
|
return {};
|
|
});
|
|
|
|
mockExecuteFunctions.helpers.prepareBinaryData.mockResolvedValue({
|
|
data: createTestBuffer().toString('base64'),
|
|
mimeType: 'image/png',
|
|
fileExtension: 'png',
|
|
});
|
|
|
|
await editImageNode.execute.call(mockExecuteFunctions);
|
|
|
|
expect(mockGmInstance.autoOrient).not.toHaveBeenCalled();
|
|
expect(mockGmInstance.out).not.toHaveBeenCalledWith('-orient', 'TopLeft');
|
|
});
|
|
});
|
|
});
|