mirror of
https://github.com/n8n-io/n8n.git
synced 2025-02-02 07:01:30 -08:00
fix(HTTP Request Tool Node): Fix the undefined response issue when authentication is enabled (#11343)
Co-authored-by: कारतोफ्फेलस्क्रिप्ट™ <aditya@netroy.in>
This commit is contained in:
parent
cade9b2d91
commit
094ec68d4c
|
@ -281,6 +281,7 @@ export class ToolHttpRequest implements INodeType {
|
|||
'User-Agent': undefined,
|
||||
},
|
||||
body: {},
|
||||
// We will need a full response object later to extract the headers and check the response's content type.
|
||||
returnFullResponse: true,
|
||||
};
|
||||
|
||||
|
|
|
@ -1,165 +1,240 @@
|
|||
import get from 'lodash/get';
|
||||
import type { IDataObject, IExecuteFunctions } from 'n8n-workflow';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import type { IExecuteFunctions, INode } from 'n8n-workflow';
|
||||
import { jsonParse } from 'n8n-workflow';
|
||||
|
||||
import type { N8nTool } from '../../../../utils/N8nTool';
|
||||
import { ToolHttpRequest } from '../ToolHttpRequest.node';
|
||||
|
||||
const createExecuteFunctionsMock = (parameters: IDataObject, requestMock: any) => {
|
||||
const nodeParameters = parameters;
|
||||
|
||||
return {
|
||||
getNodeParameter(parameter: string) {
|
||||
return get(nodeParameters, parameter);
|
||||
},
|
||||
getNode() {
|
||||
return {
|
||||
name: 'HTTP Request',
|
||||
};
|
||||
},
|
||||
getInputData() {
|
||||
return [{ json: {} }];
|
||||
},
|
||||
getWorkflow() {
|
||||
return {
|
||||
name: 'Test Workflow',
|
||||
};
|
||||
},
|
||||
continueOnFail() {
|
||||
return false;
|
||||
},
|
||||
addInputData() {
|
||||
return { index: 0 };
|
||||
},
|
||||
addOutputData() {
|
||||
return;
|
||||
},
|
||||
helpers: {
|
||||
httpRequest: requestMock,
|
||||
},
|
||||
} as unknown as IExecuteFunctions;
|
||||
};
|
||||
|
||||
describe('ToolHttpRequest', () => {
|
||||
let httpTool: ToolHttpRequest;
|
||||
let mockRequest: jest.Mock;
|
||||
const httpTool = new ToolHttpRequest();
|
||||
const helpers = mock<IExecuteFunctions['helpers']>();
|
||||
const executeFunctions = mock<IExecuteFunctions>({ helpers });
|
||||
|
||||
describe('Binary response', () => {
|
||||
beforeEach(() => {
|
||||
httpTool = new ToolHttpRequest();
|
||||
mockRequest = jest.fn();
|
||||
jest.resetAllMocks();
|
||||
executeFunctions.getNode.mockReturnValue(
|
||||
mock<INode>({
|
||||
type: 'n8n-nodes-base.httpRequest',
|
||||
name: 'HTTP Request',
|
||||
typeVersion: 1.1,
|
||||
}),
|
||||
);
|
||||
executeFunctions.addInputData.mockReturnValue({ index: 0 });
|
||||
});
|
||||
|
||||
it('should return the error when receiving a binary response', async () => {
|
||||
mockRequest.mockResolvedValue({
|
||||
helpers.httpRequest.mockResolvedValue({
|
||||
body: Buffer.from(''),
|
||||
headers: {
|
||||
'content-type': 'image/jpeg',
|
||||
},
|
||||
});
|
||||
|
||||
const { response } = await httpTool.supplyData.call(
|
||||
createExecuteFunctionsMock(
|
||||
{
|
||||
method: 'GET',
|
||||
url: 'https://httpbin.org/image/jpeg',
|
||||
options: {},
|
||||
placeholderDefinitions: {
|
||||
values: [],
|
||||
},
|
||||
},
|
||||
mockRequest,
|
||||
),
|
||||
0,
|
||||
);
|
||||
executeFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
||||
switch (paramName) {
|
||||
case 'method':
|
||||
return 'GET';
|
||||
case 'url':
|
||||
return 'https://httpbin.org/image/jpeg';
|
||||
case 'options':
|
||||
return {};
|
||||
case 'placeholderDefinitions.values':
|
||||
return [];
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
|
||||
const res = await (response as N8nTool).invoke('');
|
||||
const { response } = await httpTool.supplyData.call(executeFunctions, 0);
|
||||
|
||||
const res = await (response as N8nTool).invoke({});
|
||||
expect(helpers.httpRequest).toHaveBeenCalled();
|
||||
expect(res).toContain('error');
|
||||
expect(res).toContain('Binary data is not supported');
|
||||
});
|
||||
|
||||
it('should return the response text when receiving a text response', async () => {
|
||||
mockRequest.mockResolvedValue({
|
||||
helpers.httpRequest.mockResolvedValue({
|
||||
body: 'Hello World',
|
||||
headers: {
|
||||
'content-type': 'text/plain',
|
||||
},
|
||||
});
|
||||
|
||||
const { response } = await httpTool.supplyData.call(
|
||||
createExecuteFunctionsMock(
|
||||
{
|
||||
method: 'GET',
|
||||
url: 'https://httpbin.org/text/plain',
|
||||
options: {},
|
||||
placeholderDefinitions: {
|
||||
values: [],
|
||||
},
|
||||
},
|
||||
mockRequest,
|
||||
),
|
||||
0,
|
||||
);
|
||||
executeFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
||||
switch (paramName) {
|
||||
case 'method':
|
||||
return 'GET';
|
||||
case 'url':
|
||||
return 'https://httpbin.org/text/plain';
|
||||
case 'options':
|
||||
return {};
|
||||
case 'placeholderDefinitions.values':
|
||||
return [];
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
|
||||
const res = await (response as N8nTool).invoke('');
|
||||
const { response } = await httpTool.supplyData.call(executeFunctions, 0);
|
||||
|
||||
const res = await (response as N8nTool).invoke({});
|
||||
expect(helpers.httpRequest).toHaveBeenCalled();
|
||||
expect(res).toEqual('Hello World');
|
||||
});
|
||||
|
||||
it('should return the response text when receiving a text response with a charset', async () => {
|
||||
mockRequest.mockResolvedValue({
|
||||
helpers.httpRequest.mockResolvedValue({
|
||||
body: 'こんにちは世界',
|
||||
headers: {
|
||||
'content-type': 'text/plain; charset=iso-2022-jp',
|
||||
},
|
||||
});
|
||||
|
||||
const { response } = await httpTool.supplyData.call(
|
||||
createExecuteFunctionsMock(
|
||||
{
|
||||
method: 'GET',
|
||||
url: 'https://httpbin.org/text/plain',
|
||||
options: {},
|
||||
placeholderDefinitions: {
|
||||
values: [],
|
||||
},
|
||||
},
|
||||
mockRequest,
|
||||
),
|
||||
0,
|
||||
);
|
||||
executeFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
||||
switch (paramName) {
|
||||
case 'method':
|
||||
return 'GET';
|
||||
case 'url':
|
||||
return 'https://httpbin.org/text/plain';
|
||||
case 'options':
|
||||
return {};
|
||||
case 'placeholderDefinitions.values':
|
||||
return [];
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
|
||||
const res = await (response as N8nTool).invoke('');
|
||||
const { response } = await httpTool.supplyData.call(executeFunctions, 0);
|
||||
|
||||
const res = await (response as N8nTool).invoke({});
|
||||
expect(helpers.httpRequest).toHaveBeenCalled();
|
||||
expect(res).toEqual('こんにちは世界');
|
||||
});
|
||||
|
||||
it('should return the response object when receiving a JSON response', async () => {
|
||||
const mockJson = { hello: 'world' };
|
||||
|
||||
mockRequest.mockResolvedValue({
|
||||
body: mockJson,
|
||||
helpers.httpRequest.mockResolvedValue({
|
||||
body: JSON.stringify(mockJson),
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
const { response } = await httpTool.supplyData.call(
|
||||
createExecuteFunctionsMock(
|
||||
{
|
||||
method: 'GET',
|
||||
url: 'https://httpbin.org/json',
|
||||
options: {},
|
||||
placeholderDefinitions: {
|
||||
values: [],
|
||||
},
|
||||
},
|
||||
mockRequest,
|
||||
),
|
||||
0,
|
||||
);
|
||||
executeFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
||||
switch (paramName) {
|
||||
case 'method':
|
||||
return 'GET';
|
||||
case 'url':
|
||||
return 'https://httpbin.org/json';
|
||||
case 'options':
|
||||
return {};
|
||||
case 'placeholderDefinitions.values':
|
||||
return [];
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
|
||||
const res = await (response as N8nTool).invoke('');
|
||||
const { response } = await httpTool.supplyData.call(executeFunctions, 0);
|
||||
|
||||
const res = await (response as N8nTool).invoke({});
|
||||
expect(helpers.httpRequest).toHaveBeenCalled();
|
||||
expect(jsonParse(res)).toEqual(mockJson);
|
||||
});
|
||||
|
||||
it('should handle authentication with predefined credentials', async () => {
|
||||
helpers.httpRequestWithAuthentication.mockResolvedValue({
|
||||
body: 'Hello World',
|
||||
headers: {
|
||||
'content-type': 'text/plain',
|
||||
},
|
||||
});
|
||||
|
||||
executeFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
||||
switch (paramName) {
|
||||
case 'method':
|
||||
return 'GET';
|
||||
case 'url':
|
||||
return 'https://httpbin.org/text/plain';
|
||||
case 'authentication':
|
||||
return 'predefinedCredentialType';
|
||||
case 'nodeCredentialType':
|
||||
return 'linearApi';
|
||||
case 'options':
|
||||
return {};
|
||||
case 'placeholderDefinitions.values':
|
||||
return [];
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
|
||||
const { response } = await httpTool.supplyData.call(executeFunctions, 0);
|
||||
|
||||
const res = await (response as N8nTool).invoke({});
|
||||
|
||||
expect(res).toEqual('Hello World');
|
||||
|
||||
expect(helpers.httpRequestWithAuthentication).toHaveBeenCalledWith(
|
||||
'linearApi',
|
||||
expect.objectContaining({
|
||||
returnFullResponse: true,
|
||||
}),
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle authentication with generic credentials', async () => {
|
||||
helpers.httpRequest.mockResolvedValue({
|
||||
body: 'Hello World',
|
||||
headers: {
|
||||
'content-type': 'text/plain',
|
||||
},
|
||||
});
|
||||
|
||||
executeFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
||||
switch (paramName) {
|
||||
case 'method':
|
||||
return 'GET';
|
||||
case 'url':
|
||||
return 'https://httpbin.org/text/plain';
|
||||
case 'authentication':
|
||||
return 'genericCredentialType';
|
||||
case 'genericAuthType':
|
||||
return 'httpBasicAuth';
|
||||
case 'options':
|
||||
return {};
|
||||
case 'placeholderDefinitions.values':
|
||||
return [];
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
|
||||
executeFunctions.getCredentials.mockResolvedValue({
|
||||
user: 'username',
|
||||
password: 'password',
|
||||
});
|
||||
|
||||
const { response } = await httpTool.supplyData.call(executeFunctions, 0);
|
||||
|
||||
const res = await (response as N8nTool).invoke({});
|
||||
|
||||
expect(res).toEqual('Hello World');
|
||||
|
||||
expect(helpers.httpRequest).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
returnFullResponse: true,
|
||||
auth: expect.objectContaining({
|
||||
username: 'username',
|
||||
password: 'password',
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -109,12 +109,11 @@ const predefinedCredentialRequest = async (ctx: IExecuteFunctions, itemIndex: nu
|
|||
const additionalOptions = getOAuth2AdditionalParameters(predefinedType);
|
||||
|
||||
return async (options: IHttpRequestOptions) => {
|
||||
return await ctx.helpers.requestWithAuthentication.call(
|
||||
return await ctx.helpers.httpRequestWithAuthentication.call(
|
||||
ctx,
|
||||
predefinedType,
|
||||
options,
|
||||
additionalOptions && { oauth2: additionalOptions },
|
||||
itemIndex,
|
||||
);
|
||||
};
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue