mirror of
https://github.com/n8n-io/n8n.git
synced 2026-05-27 14:57:21 +02:00
fix(Facebook Graph API Node): Clarify endpoints that accept binary uploads (#30903)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
73ccc82a19
commit
54c8eab2e4
|
|
@ -258,7 +258,8 @@ export class FacebookGraphApi implements INodeType {
|
|||
},
|
||||
default: false,
|
||||
required: true,
|
||||
description: 'Whether binary data should be sent as body',
|
||||
hint: 'Page <code>/photos</code> and <code>/videos</code> edges accept binary uploads. Instagram container endpoints (e.g. <code>/media</code>) require <code>image_url</code> or <code>video_url</code> as Query Parameters instead.',
|
||||
description: 'Whether to upload binary data as multipart/form-data',
|
||||
},
|
||||
{
|
||||
displayName: 'Input Binary Field',
|
||||
|
|
@ -276,7 +277,7 @@ export class FacebookGraphApi implements INodeType {
|
|||
},
|
||||
hint: 'The name of the input binary field containing the file to be uploaded',
|
||||
description:
|
||||
'For Form-Data Multipart, they can be provided in the format: <code>"sendKey1:binaryProperty1,sendKey2:binaryProperty2</code>',
|
||||
'For Form-Data Multipart, multiple files can be provided in the format: <code>sendKey1:binaryProperty1,sendKey2:binaryProperty2</code>',
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,109 @@
|
|||
import type { MockProxy } from 'jest-mock-extended';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import type { IBinaryData, IExecuteFunctions } from 'n8n-workflow';
|
||||
|
||||
import { FacebookGraphApi } from '../FacebookGraphApi.node';
|
||||
|
||||
describe('FacebookGraphApi node — binary upload', () => {
|
||||
let mockExecuteFunctions: MockProxy<IExecuteFunctions>;
|
||||
let node: FacebookGraphApi;
|
||||
|
||||
const binaryDataBuffer = Buffer.from('fake-image-bytes');
|
||||
const binaryDescriptor: IBinaryData = {
|
||||
data: 'base64data',
|
||||
mimeType: 'image/png',
|
||||
fileName: 'photo.png',
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
mockExecuteFunctions = mock<IExecuteFunctions>();
|
||||
node = new FacebookGraphApi();
|
||||
|
||||
mockExecuteFunctions.getInputData.mockReturnValue([
|
||||
{ json: {}, binary: { data: binaryDescriptor } },
|
||||
]);
|
||||
mockExecuteFunctions.getNode.mockReturnValue({
|
||||
id: 'test-node-id',
|
||||
name: 'Facebook Graph API',
|
||||
type: 'n8n-nodes-base.facebookGraphApi',
|
||||
typeVersion: 1,
|
||||
position: [0, 0],
|
||||
parameters: {},
|
||||
});
|
||||
mockExecuteFunctions.getCredentials.mockResolvedValue({ accessToken: 'TOKEN' });
|
||||
mockExecuteFunctions.continueOnFail.mockReturnValue(false);
|
||||
mockExecuteFunctions.helpers = {
|
||||
request: jest.fn().mockResolvedValue({ id: 'photo-id' }),
|
||||
requestWithAuthentication: jest.fn(),
|
||||
assertBinaryData: jest.fn().mockReturnValue(binaryDescriptor),
|
||||
getBinaryDataBuffer: jest.fn().mockResolvedValue(binaryDataBuffer),
|
||||
} as any;
|
||||
});
|
||||
|
||||
const setParams = (overrides: Record<string, unknown> = {}) => {
|
||||
const defaults: Record<string, unknown> = {
|
||||
authType: 'accessToken',
|
||||
hostUrl: 'graph.facebook.com',
|
||||
httpRequestMethod: 'POST',
|
||||
graphApiVersion: 'v23.0',
|
||||
node: '123456',
|
||||
edge: 'photos',
|
||||
options: {},
|
||||
sendBinaryData: true,
|
||||
binaryPropertyName: 'data',
|
||||
allowUnauthorizedCerts: false,
|
||||
};
|
||||
const params = { ...defaults, ...overrides };
|
||||
mockExecuteFunctions.getNodeParameter.mockImplementation(
|
||||
(name: string) => params[name] as never,
|
||||
);
|
||||
};
|
||||
|
||||
it('builds a multipart/form-data request with the binary buffer when Send Binary File is enabled', async () => {
|
||||
setParams();
|
||||
|
||||
await node.execute.call(mockExecuteFunctions);
|
||||
|
||||
const requestMock = mockExecuteFunctions.helpers.request as jest.Mock;
|
||||
expect(requestMock).toHaveBeenCalledTimes(1);
|
||||
|
||||
const requestArg = requestMock.mock.calls[0][0];
|
||||
expect(requestArg.method).toBe('POST');
|
||||
expect(requestArg.uri).toBe('https://graph.facebook.com/v23.0/123456/photos');
|
||||
expect(requestArg.formData).toEqual({
|
||||
file: {
|
||||
value: binaryDataBuffer,
|
||||
options: {
|
||||
filename: 'photo.png',
|
||||
contentType: 'image/png',
|
||||
},
|
||||
},
|
||||
});
|
||||
// Buffer must NOT be JSON-serialized into the body.
|
||||
expect(requestArg.body).toBeUndefined();
|
||||
expect(requestArg.json).toBe(true);
|
||||
});
|
||||
|
||||
it('respects the "<formField>:<binaryProperty>" syntax for the form field name', async () => {
|
||||
setParams({ binaryPropertyName: 'source:data' });
|
||||
|
||||
await node.execute.call(mockExecuteFunctions);
|
||||
|
||||
const requestArg = (mockExecuteFunctions.helpers.request as jest.Mock).mock.calls[0][0];
|
||||
expect(Object.keys(requestArg.formData)).toEqual(['source']);
|
||||
expect(requestArg.formData.source.value).toBe(binaryDataBuffer);
|
||||
expect(mockExecuteFunctions.helpers.getBinaryDataBuffer).toHaveBeenCalledWith(0, 'data');
|
||||
});
|
||||
|
||||
it('does not attach formData when Send Binary File is disabled', async () => {
|
||||
setParams({ sendBinaryData: false });
|
||||
|
||||
await node.execute.call(mockExecuteFunctions);
|
||||
|
||||
const requestArg = (mockExecuteFunctions.helpers.request as jest.Mock).mock.calls[0][0];
|
||||
expect(requestArg.formData).toBeUndefined();
|
||||
expect(mockExecuteFunctions.helpers.assertBinaryData).not.toHaveBeenCalled();
|
||||
expect(mockExecuteFunctions.helpers.getBinaryDataBuffer).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user