mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
add unit test for other functions in generic function file
This commit is contained in:
parent
c667116c4b
commit
9fa69852f1
|
@ -0,0 +1,121 @@
|
|||
import type { INodeExecutionData, IN8nHttpFullResponse, JsonObject } from 'n8n-workflow';
|
||||
import { NodeApiError } from 'n8n-workflow';
|
||||
|
||||
import { handleErrorPostReceive } from '../GenericFunctions';
|
||||
|
||||
describe('handleErrorPostReceive', () => {
|
||||
let mockContext: any;
|
||||
let mockGetNode: jest.Mock;
|
||||
let mockNodeParameter: jest.Mock;
|
||||
|
||||
beforeEach(() => {
|
||||
mockGetNode = jest.fn().mockReturnValue('mockNode');
|
||||
|
||||
mockNodeParameter = jest.fn();
|
||||
|
||||
mockContext = {
|
||||
getNode: mockGetNode,
|
||||
getNodeParameter: mockNodeParameter,
|
||||
};
|
||||
});
|
||||
|
||||
test('should throw error when status code starts with 4 (ResourceNotFoundException for group get operation)', async () => {
|
||||
const response: IN8nHttpFullResponse = {
|
||||
statusCode: 404,
|
||||
body: {
|
||||
__type: 'ResourceNotFoundException',
|
||||
message: 'Group not found',
|
||||
},
|
||||
headers: {},
|
||||
};
|
||||
mockNodeParameter.mockReturnValueOnce('group');
|
||||
mockNodeParameter.mockReturnValueOnce('get');
|
||||
const data: INodeExecutionData[] = [];
|
||||
|
||||
await expect(handleErrorPostReceive.call(mockContext, data, response)).rejects.toThrowError(
|
||||
new NodeApiError(mockGetNode(), response as unknown as JsonObject, {
|
||||
message: 'The group you are requesting could not be found.',
|
||||
description: 'Adjust the "Group" parameter setting to retrieve the group correctly.',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
test('should throw error when status code starts with 5 (EntityAlreadyExists for group create operation)', async () => {
|
||||
const response: IN8nHttpFullResponse = {
|
||||
statusCode: 500,
|
||||
body: {
|
||||
__type: 'EntityAlreadyExists',
|
||||
message: 'Group already exists',
|
||||
},
|
||||
headers: {},
|
||||
};
|
||||
mockNodeParameter.mockReturnValueOnce('group');
|
||||
mockNodeParameter.mockReturnValueOnce('create');
|
||||
|
||||
const data: INodeExecutionData[] = [];
|
||||
|
||||
await expect(handleErrorPostReceive.call(mockContext, data, response)).rejects.toThrowError(
|
||||
new NodeApiError(mockGetNode(), response as unknown as JsonObject, {
|
||||
message: 'The group you are trying to create already exists',
|
||||
description: 'Adjust the "Group Name" parameter setting to create the group correctly.',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
test('should not throw error when status code does not start with 4 or 5', async () => {
|
||||
const response: IN8nHttpFullResponse = {
|
||||
statusCode: 200,
|
||||
body: {},
|
||||
headers: {},
|
||||
};
|
||||
|
||||
const data: INodeExecutionData[] = [];
|
||||
|
||||
const result = await handleErrorPostReceive.call(mockContext, data, response);
|
||||
expect(result).toEqual(data);
|
||||
});
|
||||
|
||||
test('should throw error for user create operation when UsernameExistsException occurs', async () => {
|
||||
const response: IN8nHttpFullResponse = {
|
||||
statusCode: 400,
|
||||
body: {
|
||||
__type: 'UsernameExistsException',
|
||||
message: 'User account already exists',
|
||||
},
|
||||
headers: {},
|
||||
};
|
||||
mockNodeParameter.mockReturnValueOnce('user');
|
||||
mockNodeParameter.mockReturnValueOnce('create');
|
||||
|
||||
const data: INodeExecutionData[] = [];
|
||||
|
||||
await expect(handleErrorPostReceive.call(mockContext, data, response)).rejects.toThrowError(
|
||||
new NodeApiError(mockGetNode(), response as unknown as JsonObject, {
|
||||
message: 'The user you are trying to create already exists',
|
||||
description: 'Adjust the "User Name" parameter setting to create the user correctly.',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
test('should throw error for user delete operation when UserNotFoundException occurs', async () => {
|
||||
const response: IN8nHttpFullResponse = {
|
||||
statusCode: 404,
|
||||
body: {
|
||||
__type: 'UserNotFoundException',
|
||||
message: 'User not found',
|
||||
},
|
||||
headers: {},
|
||||
};
|
||||
mockNodeParameter.mockReturnValueOnce('user');
|
||||
mockNodeParameter.mockReturnValueOnce('delete');
|
||||
|
||||
const data: INodeExecutionData[] = [];
|
||||
|
||||
await expect(handleErrorPostReceive.call(mockContext, data, response)).rejects.toThrowError(
|
||||
new NodeApiError(mockGetNode(), response as unknown as JsonObject, {
|
||||
message: 'The user you are requesting could not be found.',
|
||||
description: 'Adjust the "User" parameter setting to retrieve the post correctly.',
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
141
packages/nodes-base/nodes/Aws/Cognito/test/PresendFilter.test.ts
Normal file
141
packages/nodes-base/nodes/Aws/Cognito/test/PresendFilter.test.ts
Normal file
|
@ -0,0 +1,141 @@
|
|||
import { presendFilter } from '../GenericFunctions';
|
||||
import { NodeOperationError } from 'n8n-workflow';
|
||||
|
||||
describe('presendFilter', () => {
|
||||
let mockContext: any;
|
||||
|
||||
beforeEach(() => {
|
||||
mockContext = {
|
||||
getNodeParameter: jest.fn(),
|
||||
getNode: jest.fn(() => ({
|
||||
name: 'TestNode',
|
||||
})),
|
||||
};
|
||||
});
|
||||
|
||||
test('should return request options with applied filter when all parameters are provided', async () => {
|
||||
mockContext.getNodeParameter.mockImplementation((param: string) => {
|
||||
if (param === 'additionalFields') {
|
||||
return { filterAttribute: 'name', filterType: 'exactMatch', filterValue: 'John' };
|
||||
}
|
||||
return {};
|
||||
});
|
||||
|
||||
const requestOptions = {
|
||||
method: 'POST' as const,
|
||||
url: '/example-endpoint',
|
||||
body: {},
|
||||
headers: {},
|
||||
};
|
||||
|
||||
const result = await presendFilter.call(mockContext, requestOptions);
|
||||
|
||||
expect(result.body).toBe(
|
||||
JSON.stringify({
|
||||
Filter: 'name = "John"',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
test('should throw an error if any filter parameter is missing', async () => {
|
||||
mockContext.getNodeParameter.mockImplementation((param: string) => {
|
||||
if (param === 'additionalFields') {
|
||||
return { filterAttribute: 'name', filterType: 'exactMatch' };
|
||||
}
|
||||
return {};
|
||||
});
|
||||
|
||||
const requestOptions = {
|
||||
method: 'POST' as const,
|
||||
url: '/example-endpoint',
|
||||
body: {},
|
||||
headers: {},
|
||||
};
|
||||
|
||||
await expect(presendFilter.call(mockContext, requestOptions)).rejects.toThrow(
|
||||
new NodeOperationError(
|
||||
mockContext.getNode(),
|
||||
'Please provide Filter Attribute, Filter Type, and Filter Value to use filtering.',
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
test('should parse requestOptions.body if it is a string', async () => {
|
||||
mockContext.getNodeParameter.mockImplementation((param: string) => {
|
||||
if (param === 'additionalFields') {
|
||||
return { filterAttribute: 'name', filterType: 'startsWith', filterValue: 'Jo' };
|
||||
}
|
||||
return {};
|
||||
});
|
||||
|
||||
const requestOptions = {
|
||||
method: 'POST' as const,
|
||||
url: '/example-endpoint',
|
||||
body: '{"key":"value"}',
|
||||
headers: {},
|
||||
};
|
||||
|
||||
const result = await presendFilter.call(mockContext, requestOptions);
|
||||
|
||||
expect(result.body).toBe(
|
||||
JSON.stringify({
|
||||
key: 'value',
|
||||
Filter: 'name ^= "Jo"',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
test('should not parse requestOptions.body if it is already an object', async () => {
|
||||
mockContext.getNodeParameter.mockImplementation((param: string) => {
|
||||
if (param === 'additionalFields') {
|
||||
return {
|
||||
filterAttribute: 'email',
|
||||
filterType: 'exactMatch',
|
||||
filterValue: 'test@example.com',
|
||||
};
|
||||
}
|
||||
return {};
|
||||
});
|
||||
|
||||
const requestOptions = {
|
||||
method: 'POST' as const,
|
||||
url: '/example-endpoint',
|
||||
body: { key: 'value' },
|
||||
headers: {},
|
||||
};
|
||||
|
||||
const result = await presendFilter.call(mockContext, requestOptions);
|
||||
|
||||
expect(result.body).toBe(
|
||||
JSON.stringify({
|
||||
key: 'value',
|
||||
Filter: 'email = "test@example.com"',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
test('should handle unsupported filterType values by defaulting to the provided filterType', async () => {
|
||||
mockContext.getNodeParameter.mockImplementation((param: string) => {
|
||||
if (param === 'additionalFields') {
|
||||
return { filterAttribute: 'name', filterType: 'unknownType', filterValue: 'John' };
|
||||
}
|
||||
return {};
|
||||
});
|
||||
|
||||
const requestOptions = {
|
||||
method: 'POST' as const,
|
||||
url: '/example-endpoint',
|
||||
body: { key: 'value' },
|
||||
headers: {},
|
||||
};
|
||||
|
||||
const result = await presendFilter.call(mockContext, requestOptions);
|
||||
|
||||
expect(result.body).toBe(
|
||||
JSON.stringify({
|
||||
key: 'value',
|
||||
Filter: 'name unknownType "John"',
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,68 @@
|
|||
import { presendOptions } from '../GenericFunctions';
|
||||
import { NodeOperationError } from 'n8n-workflow';
|
||||
|
||||
describe('presendOptions', () => {
|
||||
let mockContext: any;
|
||||
|
||||
beforeEach(() => {
|
||||
mockContext = {
|
||||
getNodeParameter: jest.fn(),
|
||||
getNode: jest.fn(() => ({
|
||||
name: 'TestNode',
|
||||
})),
|
||||
};
|
||||
});
|
||||
|
||||
test('should return request options if at least one option is provided', async () => {
|
||||
mockContext.getNodeParameter.mockReturnValueOnce({
|
||||
Description: 'This is a description',
|
||||
});
|
||||
|
||||
const requestOptions = {
|
||||
method: 'POST' as const,
|
||||
url: '/example-endpoint',
|
||||
body: {},
|
||||
headers: {},
|
||||
};
|
||||
|
||||
const result = await presendOptions.call(mockContext, requestOptions);
|
||||
|
||||
expect(result).toEqual(requestOptions);
|
||||
});
|
||||
|
||||
test('should throw an error if no options are provided', async () => {
|
||||
mockContext.getNodeParameter.mockReturnValueOnce({});
|
||||
|
||||
const requestOptions = {
|
||||
method: 'POST' as const,
|
||||
url: '/example-endpoint',
|
||||
body: {},
|
||||
headers: {},
|
||||
};
|
||||
|
||||
await expect(presendOptions.call(mockContext, requestOptions)).rejects.toThrow(
|
||||
new NodeOperationError(
|
||||
mockContext.getNode(),
|
||||
'At least one of the options (Description, Precedence, Path, or RoleArn) must be provided to update the group.',
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
test('should throw an error if options are empty but other parameters are set', async () => {
|
||||
mockContext.getNodeParameter.mockReturnValueOnce({});
|
||||
|
||||
const requestOptions = {
|
||||
method: 'POST' as const,
|
||||
url: '/example-endpoint',
|
||||
body: {},
|
||||
headers: {},
|
||||
};
|
||||
|
||||
await expect(presendOptions.call(mockContext, requestOptions)).rejects.toThrow(
|
||||
new NodeOperationError(
|
||||
mockContext.getNode(),
|
||||
'At least one of the options (Description, Precedence, Path, or RoleArn) must be provided to update the group.',
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,97 @@
|
|||
import { presendPath } from '../GenericFunctions';
|
||||
import { NodeOperationError } from 'n8n-workflow';
|
||||
|
||||
describe('presendPath', () => {
|
||||
let mockContext: any;
|
||||
let mockGetNodeParameter: jest.Mock;
|
||||
|
||||
beforeEach(() => {
|
||||
mockGetNodeParameter = jest.fn();
|
||||
mockContext = {
|
||||
getNodeParameter: mockGetNodeParameter,
|
||||
getNode: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
test('should return request options when path is valid', async () => {
|
||||
mockGetNodeParameter.mockReturnValueOnce('/valid/path/');
|
||||
|
||||
const requestOptions = {
|
||||
method: 'POST' as const,
|
||||
url: '/example-endpoint',
|
||||
headers: {},
|
||||
body: {},
|
||||
};
|
||||
|
||||
const result = await presendPath.call(mockContext, requestOptions);
|
||||
|
||||
expect(result).toEqual(requestOptions);
|
||||
});
|
||||
|
||||
test('should throw an error if path is too short', async () => {
|
||||
mockGetNodeParameter.mockReturnValueOnce('');
|
||||
|
||||
const requestOptions = {
|
||||
method: 'POST' as const,
|
||||
url: '/example-endpoint',
|
||||
headers: {},
|
||||
body: {},
|
||||
};
|
||||
|
||||
await expect(presendPath.call(mockContext, requestOptions)).rejects.toThrow(
|
||||
new NodeOperationError(mockContext.getNode(), 'Path must be between 1 and 512 characters.'),
|
||||
);
|
||||
});
|
||||
|
||||
test('should throw an error if path is too long', async () => {
|
||||
mockGetNodeParameter.mockReturnValueOnce('/' + 'a'.repeat(513) + '/');
|
||||
|
||||
const requestOptions = {
|
||||
method: 'POST' as const,
|
||||
url: '/example-endpoint',
|
||||
headers: {},
|
||||
body: {},
|
||||
};
|
||||
|
||||
await expect(presendPath.call(mockContext, requestOptions)).rejects.toThrow(
|
||||
new NodeOperationError(mockContext.getNode(), 'Path must be between 1 and 512 characters.'),
|
||||
);
|
||||
});
|
||||
|
||||
test('should throw an error if path does not start and end with a slash', async () => {
|
||||
// Mocking the return value of getNodeParameter for the path
|
||||
mockGetNodeParameter.mockReturnValueOnce('invalidpath');
|
||||
|
||||
const requestOptions = {
|
||||
method: 'POST' as const,
|
||||
url: '/example-endpoint',
|
||||
headers: {},
|
||||
body: {},
|
||||
};
|
||||
|
||||
await expect(presendPath.call(mockContext, requestOptions)).rejects.toThrow(
|
||||
new NodeOperationError(
|
||||
mockContext.getNode(),
|
||||
'Path must begin and end with a forward slash and contain valid ASCII characters.',
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
test('should throw an error if path contains invalid characters', async () => {
|
||||
mockGetNodeParameter.mockReturnValueOnce('/invalid!path');
|
||||
|
||||
const requestOptions = {
|
||||
method: 'POST' as const,
|
||||
url: '/example-endpoint',
|
||||
headers: {},
|
||||
body: {},
|
||||
};
|
||||
|
||||
await expect(presendPath.call(mockContext, requestOptions)).rejects.toThrow(
|
||||
new NodeOperationError(
|
||||
mockContext.getNode(),
|
||||
'Path must begin and end with a forward slash and contain valid ASCII characters.',
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,48 @@
|
|||
import { presendStringifyBody } from '../GenericFunctions';
|
||||
describe('presendStringifyBody', () => {
|
||||
let mockContext: any;
|
||||
|
||||
beforeEach(() => {
|
||||
mockContext = {
|
||||
getNodeParameter: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
test('should stringify requestOptions.body when it is an object', async () => {
|
||||
const requestOptions = {
|
||||
method: 'POST' as const,
|
||||
url: '/example-endpoint',
|
||||
body: { key: 'value' },
|
||||
headers: {},
|
||||
};
|
||||
|
||||
const result = await presendStringifyBody.call(mockContext, requestOptions);
|
||||
|
||||
expect(result.body).toBe(JSON.stringify({ key: 'value' }));
|
||||
});
|
||||
|
||||
test('should not modify requestOptions if body is undefined', async () => {
|
||||
const requestOptions = {
|
||||
method: 'POST' as const,
|
||||
url: '/example-endpoint',
|
||||
body: undefined,
|
||||
headers: {},
|
||||
};
|
||||
|
||||
const result = await presendStringifyBody.call(mockContext, requestOptions);
|
||||
|
||||
expect(result.body).toBeUndefined();
|
||||
});
|
||||
|
||||
test('should handle an empty body gracefully', async () => {
|
||||
const requestOptions = {
|
||||
method: 'POST' as const,
|
||||
url: '/example-endpoint',
|
||||
body: {},
|
||||
headers: {},
|
||||
};
|
||||
|
||||
const result = await presendStringifyBody.call(mockContext, requestOptions);
|
||||
expect(result.body).toBe('{}');
|
||||
});
|
||||
});
|
|
@ -0,0 +1,88 @@
|
|||
import { processAttributes } from '../GenericFunctions';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
|
||||
describe('processAttributes', () => {
|
||||
let mockContext: any;
|
||||
let mockGetNodeParameter: jest.Mock;
|
||||
|
||||
beforeEach(() => {
|
||||
mockGetNodeParameter = jest.fn();
|
||||
mockContext = {
|
||||
getNodeParameter: mockGetNodeParameter,
|
||||
};
|
||||
});
|
||||
|
||||
test('should process attributes correctly and update the request body', async () => {
|
||||
mockGetNodeParameter.mockReturnValueOnce([
|
||||
{ Name: 'email', Value: 'test@example.com' },
|
||||
{ Name: 'custom:role', Value: 'admin' },
|
||||
]);
|
||||
|
||||
const requestOptions = {
|
||||
method: 'POST' as const,
|
||||
url: '/example-endpoint',
|
||||
headers: {
|
||||
'X-Amz-Target': 'ExampleService.Action',
|
||||
},
|
||||
body: JSON.stringify({ UserPoolId: 'mockPoolId' }),
|
||||
};
|
||||
|
||||
const updatedRequestOptions = await processAttributes.call(mockContext, requestOptions);
|
||||
|
||||
const expectedBody = {
|
||||
UserPoolId: 'mockPoolId',
|
||||
UserAttributes: [
|
||||
{ Name: 'email', Value: 'test@example.com' },
|
||||
{ Name: 'custom:role', Value: 'admin' },
|
||||
],
|
||||
};
|
||||
|
||||
expect(updatedRequestOptions.body).toBe(JSON.stringify(expectedBody));
|
||||
});
|
||||
|
||||
test('should throw an error if the body cannot be parsed as JSON', async () => {
|
||||
const requestOptions = {
|
||||
method: 'POST' as const,
|
||||
url: '/example-endpoint',
|
||||
headers: {},
|
||||
body: 'invalid json body',
|
||||
};
|
||||
|
||||
await expect(processAttributes.call(mockContext, requestOptions)).rejects.toThrow(
|
||||
new ApplicationError('Invalid JSON body: Unable to parse.'),
|
||||
);
|
||||
});
|
||||
|
||||
test('should throw an error if the body is not a string or object', async () => {
|
||||
const requestOptions = {
|
||||
method: 'POST' as const,
|
||||
url: '/example-endpoint',
|
||||
headers: {},
|
||||
body: undefined,
|
||||
};
|
||||
|
||||
await expect(processAttributes.call(mockContext, requestOptions)).rejects.toThrow(
|
||||
new ApplicationError('Invalid request body: Expected a JSON string or object.'),
|
||||
);
|
||||
});
|
||||
|
||||
test('should process attributes with custom prefix correctly', async () => {
|
||||
mockGetNodeParameter.mockReturnValueOnce([{ Name: 'custom:age', Value: '30' }]);
|
||||
|
||||
const requestOptions = {
|
||||
method: 'POST' as const,
|
||||
url: '/example-endpoint',
|
||||
headers: {},
|
||||
body: JSON.stringify({ UserPoolId: 'mockPoolId' }),
|
||||
};
|
||||
|
||||
const updatedRequestOptions = await processAttributes.call(mockContext, requestOptions);
|
||||
|
||||
const expectedBody = {
|
||||
UserPoolId: 'mockPoolId',
|
||||
UserAttributes: [{ Name: 'custom:age', Value: '30' }],
|
||||
};
|
||||
|
||||
expect(updatedRequestOptions.body).toBe(JSON.stringify(expectedBody));
|
||||
});
|
||||
});
|
174
packages/nodes-base/nodes/Aws/Cognito/test/SearchGroups.test.ts
Normal file
174
packages/nodes-base/nodes/Aws/Cognito/test/SearchGroups.test.ts
Normal file
|
@ -0,0 +1,174 @@
|
|||
import type { ILoadOptionsFunctions } from 'n8n-workflow';
|
||||
|
||||
import { searchGroups, awsRequest } from '../GenericFunctions';
|
||||
|
||||
interface AwsResponse {
|
||||
Groups: Array<{ GroupName: string }>;
|
||||
NextToken?: string;
|
||||
}
|
||||
|
||||
jest.mock('../GenericFunctions', () => ({
|
||||
awsRequest: jest.fn(),
|
||||
searchGroups: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('searchGroups', () => {
|
||||
const mockGetNodeParameter = jest.fn();
|
||||
const mockAwsRequest = awsRequest as jest.Mock;
|
||||
const mockSearchGroups = searchGroups as jest.Mock;
|
||||
|
||||
const mockContext = {
|
||||
getNodeParameter: mockGetNodeParameter,
|
||||
} as unknown as ILoadOptionsFunctions;
|
||||
|
||||
beforeEach(() => {
|
||||
mockGetNodeParameter.mockClear();
|
||||
mockAwsRequest.mockClear();
|
||||
mockSearchGroups.mockClear();
|
||||
});
|
||||
|
||||
it('should throw an error if User Pool ID is missing', async () => {
|
||||
mockGetNodeParameter.mockReturnValueOnce(undefined);
|
||||
mockSearchGroups.mockRejectedValueOnce(new Error('User Pool ID is required to search groups'));
|
||||
|
||||
await expect(searchGroups.call(mockContext)).rejects.toThrow(
|
||||
'User Pool ID is required to search groups',
|
||||
);
|
||||
});
|
||||
|
||||
it('should make a POST request to search groups and return results', async () => {
|
||||
mockGetNodeParameter.mockReturnValueOnce('mockUserPoolId');
|
||||
mockAwsRequest.mockResolvedValueOnce({
|
||||
Groups: [{ GroupName: 'Admin' }, { GroupName: 'User' }],
|
||||
NextToken: 'nextTokenValue',
|
||||
});
|
||||
|
||||
mockSearchGroups.mockImplementation(async (filter, nextToken) => {
|
||||
const awsResponse: AwsResponse = await mockAwsRequest({
|
||||
url: '',
|
||||
method: 'POST',
|
||||
headers: { 'X-Amz-Target': 'AWSCognitoIdentityProviderService.ListGroups' },
|
||||
body: JSON.stringify({
|
||||
UserPoolId: 'mockUserPoolId',
|
||||
MaxResults: 60,
|
||||
NextToken: nextToken,
|
||||
}),
|
||||
});
|
||||
|
||||
const groups = awsResponse.Groups.map((group: any) => ({
|
||||
name: group.GroupName,
|
||||
value: group.GroupName,
|
||||
}));
|
||||
|
||||
return {
|
||||
results: groups,
|
||||
paginationToken: awsResponse.NextToken,
|
||||
};
|
||||
});
|
||||
|
||||
const response = await searchGroups.call(mockContext, 'Admin');
|
||||
|
||||
expect(mockAwsRequest).toHaveBeenCalledWith({
|
||||
url: '',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-Amz-Target': 'AWSCognitoIdentityProviderService.ListGroups',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
UserPoolId: 'mockUserPoolId',
|
||||
MaxResults: 60,
|
||||
NextToken: undefined,
|
||||
}),
|
||||
});
|
||||
|
||||
expect(response).toEqual({
|
||||
results: [
|
||||
{ name: 'Admin', value: 'Admin' },
|
||||
{ name: 'User', value: 'User' },
|
||||
],
|
||||
paginationToken: 'nextTokenValue',
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle pagination and return all results', async () => {
|
||||
// Mock the response for the first page
|
||||
mockAwsRequest
|
||||
.mockResolvedValueOnce({
|
||||
Groups: [{ GroupName: 'Admin' }, { GroupName: 'User' }],
|
||||
NextToken: 'nextTokenValue',
|
||||
})
|
||||
// Mock the response for the second page
|
||||
.mockResolvedValueOnce({
|
||||
Groups: [{ GroupName: 'Manager' }],
|
||||
NextToken: undefined,
|
||||
});
|
||||
|
||||
mockGetNodeParameter.mockReturnValueOnce('mockUserPoolId');
|
||||
mockGetNodeParameter.mockReturnValueOnce(false);
|
||||
mockGetNodeParameter.mockReturnValueOnce(10);
|
||||
|
||||
// Simulate the actual logic in searchGroups:
|
||||
mockSearchGroups.mockImplementation(async () => {
|
||||
let allResults: any[] = [];
|
||||
let nextToken: string | undefined;
|
||||
do {
|
||||
const response: AwsResponse = await mockAwsRequest({
|
||||
url: '',
|
||||
method: 'POST',
|
||||
headers: { 'X-Amz-Target': 'AWSCognitoIdentityProviderService.ListGroups' },
|
||||
body: JSON.stringify({
|
||||
UserPoolId: 'mockUserPoolId',
|
||||
MaxResults: 60,
|
||||
NextToken: nextToken,
|
||||
}),
|
||||
});
|
||||
|
||||
if (response.Groups) {
|
||||
allResults = allResults.concat(
|
||||
response.Groups.map((group: any) => ({
|
||||
name: group.GroupName,
|
||||
value: group.GroupName,
|
||||
})),
|
||||
);
|
||||
}
|
||||
|
||||
nextToken = response.NextToken;
|
||||
} while (nextToken);
|
||||
|
||||
return {
|
||||
results: allResults,
|
||||
paginationToken: nextToken,
|
||||
};
|
||||
});
|
||||
|
||||
const result = await searchGroups.call(mockContext, '');
|
||||
|
||||
expect(mockAwsRequest).toHaveBeenCalledTimes(2);
|
||||
|
||||
expect(result).toEqual({
|
||||
results: [
|
||||
{ name: 'Admin', value: 'Admin' },
|
||||
{ name: 'User', value: 'User' },
|
||||
{ name: 'Manager', value: 'Manager' },
|
||||
],
|
||||
paginationToken: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it('should return empty results if no groups are found', async () => {
|
||||
mockGetNodeParameter.mockReturnValueOnce('mockUserPoolId');
|
||||
mockAwsRequest.mockResolvedValueOnce({
|
||||
Groups: [],
|
||||
NextToken: undefined,
|
||||
});
|
||||
|
||||
mockSearchGroups.mockResolvedValueOnce({
|
||||
results: [],
|
||||
paginationToken: undefined,
|
||||
});
|
||||
|
||||
const response = await searchGroups.call(mockContext);
|
||||
|
||||
expect(response).toEqual({ results: [] });
|
||||
});
|
||||
});
|
|
@ -0,0 +1,161 @@
|
|||
import type { ILoadOptionsFunctions } from 'n8n-workflow';
|
||||
|
||||
import { searchUserPools, awsRequest } from '../GenericFunctions';
|
||||
|
||||
interface AwsResponse {
|
||||
UserPools: Array<{ Name: string; Id: string }>;
|
||||
NextToken?: string;
|
||||
}
|
||||
|
||||
jest.mock('../GenericFunctions', () => ({
|
||||
awsRequest: jest.fn(),
|
||||
searchUserPools: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('searchUserPools', () => {
|
||||
const mockGetNodeParameter = jest.fn();
|
||||
const mockAwsRequest = awsRequest as jest.Mock;
|
||||
const mockSearchUserPools = searchUserPools as jest.Mock;
|
||||
|
||||
const mockContext = {
|
||||
getNodeParameter: mockGetNodeParameter,
|
||||
} as unknown as ILoadOptionsFunctions;
|
||||
|
||||
beforeEach(() => {
|
||||
mockGetNodeParameter.mockClear();
|
||||
mockAwsRequest.mockClear();
|
||||
mockSearchUserPools.mockClear();
|
||||
});
|
||||
|
||||
it('should make a POST request to search user pools and return results', async () => {
|
||||
mockAwsRequest.mockResolvedValueOnce({
|
||||
UserPools: [
|
||||
{ Name: 'UserPool1', Id: 'userPoolId1' },
|
||||
{ Name: 'UserPool2', Id: 'userPoolId2' },
|
||||
],
|
||||
NextToken: 'nextTokenValue',
|
||||
});
|
||||
|
||||
mockSearchUserPools.mockImplementation(async (filter, nextToken) => {
|
||||
const awsResponse: AwsResponse = await mockAwsRequest({
|
||||
url: '',
|
||||
method: 'POST',
|
||||
headers: { 'X-Amz-Target': 'AWSCognitoIdentityProviderService.ListUserPools' },
|
||||
body: JSON.stringify({
|
||||
MaxResults: 60,
|
||||
NextToken: nextToken,
|
||||
}),
|
||||
});
|
||||
|
||||
const userPools = awsResponse.UserPools.map((pool: any) => ({
|
||||
name: pool.Name,
|
||||
value: pool.Id,
|
||||
}));
|
||||
|
||||
return {
|
||||
results: userPools,
|
||||
paginationToken: awsResponse.NextToken,
|
||||
};
|
||||
});
|
||||
|
||||
const response = await searchUserPools.call(mockContext, '');
|
||||
|
||||
expect(mockAwsRequest).toHaveBeenCalledWith({
|
||||
url: '',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-Amz-Target': 'AWSCognitoIdentityProviderService.ListUserPools',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
MaxResults: 60,
|
||||
NextToken: undefined,
|
||||
}),
|
||||
});
|
||||
|
||||
expect(response).toEqual({
|
||||
results: [
|
||||
{ name: 'UserPool1', value: 'userPoolId1' },
|
||||
{ name: 'UserPool2', value: 'userPoolId2' },
|
||||
],
|
||||
paginationToken: 'nextTokenValue',
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle pagination and return all results', async () => {
|
||||
mockAwsRequest
|
||||
.mockResolvedValueOnce({
|
||||
UserPools: [
|
||||
{ Name: 'UserPool1', Id: 'userPoolId1' },
|
||||
{ Name: 'UserPool2', Id: 'userPoolId2' },
|
||||
],
|
||||
NextToken: 'nextTokenValue',
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
UserPools: [{ Name: 'UserPool3', Id: 'userPoolId3' }],
|
||||
NextToken: undefined,
|
||||
});
|
||||
|
||||
mockGetNodeParameter.mockReturnValueOnce(false);
|
||||
mockGetNodeParameter.mockReturnValueOnce(10);
|
||||
mockSearchUserPools.mockImplementation(async () => {
|
||||
let allResults: any[] = [];
|
||||
let nextToken: string | undefined;
|
||||
do {
|
||||
const response: AwsResponse = await mockAwsRequest({
|
||||
url: '',
|
||||
method: 'POST',
|
||||
headers: { 'X-Amz-Target': 'AWSCognitoIdentityProviderService.ListUserPools' },
|
||||
body: JSON.stringify({
|
||||
MaxResults: 60,
|
||||
NextToken: nextToken,
|
||||
}),
|
||||
});
|
||||
|
||||
if (response.UserPools) {
|
||||
allResults = allResults.concat(
|
||||
response.UserPools.map((pool: any) => ({
|
||||
name: pool.Name,
|
||||
value: pool.Id,
|
||||
})),
|
||||
);
|
||||
}
|
||||
|
||||
nextToken = response.NextToken;
|
||||
} while (nextToken);
|
||||
|
||||
return {
|
||||
results: allResults,
|
||||
paginationToken: nextToken,
|
||||
};
|
||||
});
|
||||
|
||||
const result = await searchUserPools.call(mockContext, '');
|
||||
|
||||
expect(mockAwsRequest).toHaveBeenCalledTimes(2);
|
||||
|
||||
expect(result).toEqual({
|
||||
results: [
|
||||
{ name: 'UserPool1', value: 'userPoolId1' },
|
||||
{ name: 'UserPool2', value: 'userPoolId2' },
|
||||
{ name: 'UserPool3', value: 'userPoolId3' },
|
||||
],
|
||||
paginationToken: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it('should return empty results if no user pools are found', async () => {
|
||||
mockAwsRequest.mockResolvedValueOnce({
|
||||
UserPools: [],
|
||||
NextToken: undefined,
|
||||
});
|
||||
|
||||
mockSearchUserPools.mockResolvedValueOnce({
|
||||
results: [],
|
||||
paginationToken: undefined,
|
||||
});
|
||||
|
||||
const response = await searchUserPools.call(mockContext);
|
||||
|
||||
expect(response).toEqual({ results: [] });
|
||||
});
|
||||
});
|
176
packages/nodes-base/nodes/Aws/Cognito/test/SearchUsers.test.ts
Normal file
176
packages/nodes-base/nodes/Aws/Cognito/test/SearchUsers.test.ts
Normal file
|
@ -0,0 +1,176 @@
|
|||
import type { ILoadOptionsFunctions } from 'n8n-workflow';
|
||||
|
||||
import { searchUsers, awsRequest } from '../GenericFunctions';
|
||||
|
||||
interface AwsResponse {
|
||||
Users: Array<{ Username: string; Attributes: Array<{ Name: string; Value: string }> }>;
|
||||
NextToken?: string;
|
||||
}
|
||||
|
||||
jest.mock('../GenericFunctions', () => ({
|
||||
awsRequest: jest.fn(),
|
||||
searchUsers: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('searchUsers', () => {
|
||||
const mockGetNodeParameter = jest.fn();
|
||||
const mockAwsRequest = awsRequest as jest.Mock;
|
||||
const mockSearchUsers = searchUsers as jest.Mock;
|
||||
|
||||
const mockContext = {
|
||||
getNodeParameter: mockGetNodeParameter,
|
||||
} as unknown as ILoadOptionsFunctions;
|
||||
|
||||
beforeEach(() => {
|
||||
mockGetNodeParameter.mockClear();
|
||||
mockAwsRequest.mockClear();
|
||||
mockSearchUsers.mockClear();
|
||||
});
|
||||
|
||||
it('should throw an error if User Pool ID is missing', async () => {
|
||||
mockGetNodeParameter.mockReturnValueOnce(undefined);
|
||||
mockSearchUsers.mockRejectedValueOnce(new Error('User Pool ID is required to search users'));
|
||||
|
||||
await expect(searchUsers.call(mockContext)).rejects.toThrow(
|
||||
'User Pool ID is required to search users',
|
||||
);
|
||||
});
|
||||
|
||||
it('should make a POST request to search users and return results', async () => {
|
||||
mockGetNodeParameter.mockReturnValueOnce({ value: 'mockUserPoolId' });
|
||||
mockAwsRequest.mockResolvedValueOnce({
|
||||
Users: [
|
||||
{ Username: 'user1', Attributes: [{ Name: 'email', Value: 'user1@example.com' }] },
|
||||
{ Username: 'user2', Attributes: [{ Name: 'email', Value: 'user2@example.com' }] },
|
||||
],
|
||||
NextToken: 'nextTokenValue',
|
||||
});
|
||||
|
||||
mockSearchUsers.mockImplementation(async (filter, nextToken) => {
|
||||
const awsResponse: AwsResponse = await mockAwsRequest({
|
||||
url: '',
|
||||
method: 'POST',
|
||||
headers: { 'X-Amz-Target': 'AWSCognitoIdentityProviderService.ListUsers' },
|
||||
body: JSON.stringify({
|
||||
UserPoolId: 'mockUserPoolId',
|
||||
MaxResults: 60,
|
||||
NextToken: nextToken,
|
||||
}),
|
||||
});
|
||||
|
||||
const users = awsResponse.Users.map((user: any) => ({
|
||||
name: user.Attributes?.find((attr: any) => attr.Name === 'email')?.Value || user.Username,
|
||||
value: user.Username,
|
||||
}));
|
||||
|
||||
return {
|
||||
results: users,
|
||||
paginationToken: awsResponse.NextToken,
|
||||
};
|
||||
});
|
||||
|
||||
const response = await searchUsers.call(mockContext, 'user1');
|
||||
|
||||
expect(mockAwsRequest).toHaveBeenCalledWith({
|
||||
url: '',
|
||||
method: 'POST',
|
||||
headers: { 'X-Amz-Target': 'AWSCognitoIdentityProviderService.ListUsers' },
|
||||
body: JSON.stringify({
|
||||
UserPoolId: 'mockUserPoolId',
|
||||
MaxResults: 60,
|
||||
NextToken: undefined,
|
||||
}),
|
||||
});
|
||||
|
||||
expect(response).toEqual({
|
||||
results: [
|
||||
{ name: 'user1@example.com', value: 'user1' },
|
||||
{ name: 'user2@example.com', value: 'user2' },
|
||||
],
|
||||
paginationToken: 'nextTokenValue',
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle pagination and return all results', async () => {
|
||||
mockAwsRequest
|
||||
.mockResolvedValueOnce({
|
||||
Users: [
|
||||
{ Username: 'user1', Attributes: [{ Name: 'email', Value: 'user1@example.com' }] },
|
||||
{ Username: 'user2', Attributes: [{ Name: 'email', Value: 'user2@example.com' }] },
|
||||
],
|
||||
NextToken: 'nextTokenValue',
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
Users: [{ Username: 'user3', Attributes: [{ Name: 'email', Value: 'user3@example.com' }] }],
|
||||
NextToken: undefined,
|
||||
});
|
||||
|
||||
mockGetNodeParameter.mockReturnValueOnce('mockUserPoolId');
|
||||
mockGetNodeParameter.mockReturnValueOnce(false);
|
||||
mockGetNodeParameter.mockReturnValueOnce(10);
|
||||
|
||||
mockSearchUsers.mockImplementation(async () => {
|
||||
let allResults: any[] = [];
|
||||
let nextToken: string | undefined;
|
||||
do {
|
||||
const response: AwsResponse = await mockAwsRequest({
|
||||
url: '',
|
||||
method: 'POST',
|
||||
headers: { 'X-Amz-Target': 'AWSCognitoIdentityProviderService.ListUsers' },
|
||||
body: JSON.stringify({
|
||||
UserPoolId: 'mockUserPoolId',
|
||||
MaxResults: 60,
|
||||
NextToken: nextToken,
|
||||
}),
|
||||
});
|
||||
|
||||
if (response.Users) {
|
||||
allResults = allResults.concat(
|
||||
response.Users.map((user: any) => ({
|
||||
name:
|
||||
user.Attributes?.find((attr: any) => attr.Name === 'email')?.Value || user.Username,
|
||||
value: user.Username,
|
||||
})),
|
||||
);
|
||||
}
|
||||
|
||||
nextToken = response.NextToken;
|
||||
} while (nextToken);
|
||||
|
||||
return {
|
||||
results: allResults,
|
||||
paginationToken: nextToken,
|
||||
};
|
||||
});
|
||||
|
||||
const result = await searchUsers.call(mockContext, '');
|
||||
|
||||
expect(mockAwsRequest).toHaveBeenCalledTimes(2);
|
||||
|
||||
expect(result).toEqual({
|
||||
results: [
|
||||
{ name: 'user1@example.com', value: 'user1' },
|
||||
{ name: 'user2@example.com', value: 'user2' },
|
||||
{ name: 'user3@example.com', value: 'user3' },
|
||||
],
|
||||
paginationToken: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it('should return empty results if no users are found', async () => {
|
||||
mockGetNodeParameter.mockReturnValueOnce('mockUserPoolId');
|
||||
mockAwsRequest.mockResolvedValueOnce({
|
||||
Users: [],
|
||||
NextToken: undefined,
|
||||
});
|
||||
|
||||
mockSearchUsers.mockResolvedValueOnce({
|
||||
results: [],
|
||||
paginationToken: undefined,
|
||||
});
|
||||
|
||||
const response = await searchUsers.call(mockContext);
|
||||
|
||||
expect(response).toEqual({ results: [] });
|
||||
});
|
||||
});
|
Loading…
Reference in a new issue