mirror of
https://github.com/n8n-io/n8n.git
synced 2024-11-15 00:54:06 -08:00
376 lines
11 KiB
TypeScript
376 lines
11 KiB
TypeScript
|
import type {
|
||
|
DeclarativeRestApiSettings,
|
||
|
IDataObject,
|
||
|
IExecuteFunctions,
|
||
|
IExecutePaginationFunctions,
|
||
|
IExecuteSingleFunctions,
|
||
|
ILoadOptionsFunctions,
|
||
|
IN8nHttpFullResponse,
|
||
|
INodeExecutionData,
|
||
|
} from 'n8n-workflow';
|
||
|
import {
|
||
|
getCursorPaginator,
|
||
|
getUsers,
|
||
|
oktaApiRequest,
|
||
|
simplifyGetAllResponse,
|
||
|
simplifyGetResponse,
|
||
|
} from '../UserFunctions';
|
||
|
|
||
|
describe('oktaApiRequest', () => {
|
||
|
const mockGetCredentials = jest.fn();
|
||
|
const mockHttpRequestWithAuthentication = jest.fn();
|
||
|
|
||
|
const mockContext = {
|
||
|
getCredentials: mockGetCredentials,
|
||
|
helpers: {
|
||
|
httpRequestWithAuthentication: mockHttpRequestWithAuthentication,
|
||
|
},
|
||
|
} as unknown as IExecuteFunctions;
|
||
|
|
||
|
beforeEach(() => {
|
||
|
mockGetCredentials.mockClear();
|
||
|
mockHttpRequestWithAuthentication.mockClear();
|
||
|
});
|
||
|
|
||
|
it('should make a GET request and return data', async () => {
|
||
|
mockGetCredentials.mockResolvedValue({ url: 'https://okta.example.com' });
|
||
|
mockHttpRequestWithAuthentication.mockResolvedValue([
|
||
|
{ profile: { firstName: 'John', lastName: 'Doe' }, id: '1' },
|
||
|
]);
|
||
|
|
||
|
const response = await oktaApiRequest.call(mockContext, 'GET', 'users');
|
||
|
|
||
|
expect(mockGetCredentials).toHaveBeenCalledWith('oktaApi');
|
||
|
expect(mockHttpRequestWithAuthentication).toHaveBeenCalledWith('oktaApi', {
|
||
|
headers: { 'Content-Type': 'application/json' },
|
||
|
method: 'GET',
|
||
|
body: undefined,
|
||
|
qs: undefined,
|
||
|
url: 'https://okta.example.com/api/v1/users',
|
||
|
json: true,
|
||
|
});
|
||
|
expect(response).toEqual([{ profile: { firstName: 'John', lastName: 'Doe' }, id: '1' }]);
|
||
|
});
|
||
|
|
||
|
// Tests for error handling
|
||
|
it('should handle errors from oktaApiRequest', async () => {
|
||
|
mockHttpRequestWithAuthentication.mockRejectedValue(new Error('Network error'));
|
||
|
|
||
|
await expect(oktaApiRequest.call(mockContext, 'GET', 'users')).rejects.toThrow('Network error');
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('getUsers', () => {
|
||
|
const mockOktaApiRequest = jest.fn();
|
||
|
const mockContext = {
|
||
|
getCredentials: jest.fn().mockResolvedValue({ url: 'https://okta.example.com' }),
|
||
|
helpers: {
|
||
|
httpRequestWithAuthentication: mockOktaApiRequest,
|
||
|
},
|
||
|
} as unknown as ILoadOptionsFunctions;
|
||
|
|
||
|
beforeEach(() => {
|
||
|
mockOktaApiRequest.mockClear();
|
||
|
});
|
||
|
|
||
|
it('should return users with filtering', async () => {
|
||
|
mockOktaApiRequest.mockResolvedValue([
|
||
|
{ profile: { login: 'John@example.com' }, id: '1' },
|
||
|
{ profile: { login: 'Jane@example.com' }, id: '2' },
|
||
|
]);
|
||
|
|
||
|
const response = await getUsers.call(mockContext, 'john');
|
||
|
|
||
|
expect(response).toEqual({
|
||
|
results: [{ name: 'John@example.com', value: '1' }],
|
||
|
});
|
||
|
});
|
||
|
|
||
|
it('should return all users when no filter is applied', async () => {
|
||
|
mockOktaApiRequest.mockResolvedValue([
|
||
|
{ profile: { login: 'John@example.com' }, id: '1' },
|
||
|
{ profile: { login: 'Jane@example.com' }, id: '2' },
|
||
|
]);
|
||
|
|
||
|
const response = await getUsers.call(mockContext);
|
||
|
|
||
|
expect(response).toEqual({
|
||
|
results: [
|
||
|
{ name: 'John@example.com', value: '1' },
|
||
|
{ name: 'Jane@example.com', value: '2' },
|
||
|
],
|
||
|
});
|
||
|
});
|
||
|
|
||
|
// Tests for empty results
|
||
|
it('should handle empty results from oktaApiRequest', async () => {
|
||
|
mockOktaApiRequest.mockResolvedValue([]);
|
||
|
|
||
|
const response = await getUsers.call(mockContext);
|
||
|
|
||
|
expect(response).toEqual({
|
||
|
results: [],
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('simplifyGetAllResponse', () => {
|
||
|
const mockGetNodeParameter = jest.fn();
|
||
|
const mockContext = {
|
||
|
getNodeParameter: mockGetNodeParameter,
|
||
|
} as unknown as IExecuteSingleFunctions;
|
||
|
const mockResponse = jest.fn() as unknown as IN8nHttpFullResponse;
|
||
|
|
||
|
const items: INodeExecutionData[] = [
|
||
|
{
|
||
|
json: [
|
||
|
{
|
||
|
id: '01',
|
||
|
status: 'ACTIVE',
|
||
|
created: '2023-01-01T00:00:00.000Z',
|
||
|
activated: '2023-01-01T00:00:01.000Z',
|
||
|
lastLogin: null,
|
||
|
lastUpdated: '2023-01-01T00:00:01.000Z',
|
||
|
passwordChanged: null,
|
||
|
some_item: 'some_value',
|
||
|
profile: {
|
||
|
firstName: 'John',
|
||
|
lastName: 'Doe',
|
||
|
login: 'john.doe@example.com',
|
||
|
email: 'john.doe@example.com',
|
||
|
some_profile_item: 'some_profile_value',
|
||
|
},
|
||
|
},
|
||
|
] as unknown as IDataObject,
|
||
|
},
|
||
|
];
|
||
|
|
||
|
beforeEach(() => {
|
||
|
mockGetNodeParameter.mockClear();
|
||
|
});
|
||
|
|
||
|
it('should return items unchanged when simplify parameter is not set', async () => {
|
||
|
mockGetNodeParameter.mockReturnValueOnce(false);
|
||
|
|
||
|
const expectedResult: INodeExecutionData[] = [
|
||
|
{
|
||
|
json: {
|
||
|
id: '01',
|
||
|
status: 'ACTIVE',
|
||
|
created: '2023-01-01T00:00:00.000Z',
|
||
|
activated: '2023-01-01T00:00:01.000Z',
|
||
|
lastLogin: null,
|
||
|
lastUpdated: '2023-01-01T00:00:01.000Z',
|
||
|
passwordChanged: null,
|
||
|
some_item: 'some_value',
|
||
|
profile: {
|
||
|
firstName: 'John',
|
||
|
lastName: 'Doe',
|
||
|
login: 'john.doe@example.com',
|
||
|
email: 'john.doe@example.com',
|
||
|
some_profile_item: 'some_profile_value',
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
];
|
||
|
|
||
|
const result = await simplifyGetAllResponse.call(mockContext, items, mockResponse);
|
||
|
expect(result).toEqual(expectedResult);
|
||
|
});
|
||
|
|
||
|
it('should simplify items correctly', async () => {
|
||
|
mockGetNodeParameter.mockReturnValueOnce(true);
|
||
|
|
||
|
const expectedResult: INodeExecutionData[] = [
|
||
|
{
|
||
|
json: {
|
||
|
id: '01',
|
||
|
status: 'ACTIVE',
|
||
|
created: '2023-01-01T00:00:00.000Z',
|
||
|
activated: '2023-01-01T00:00:01.000Z',
|
||
|
lastLogin: null,
|
||
|
lastUpdated: '2023-01-01T00:00:01.000Z',
|
||
|
passwordChanged: null,
|
||
|
profile: {
|
||
|
firstName: 'John',
|
||
|
lastName: 'Doe',
|
||
|
login: 'john.doe@example.com',
|
||
|
email: 'john.doe@example.com',
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
];
|
||
|
|
||
|
const result = await simplifyGetAllResponse.call(mockContext, items, mockResponse);
|
||
|
expect(result).toEqual(expectedResult);
|
||
|
});
|
||
|
|
||
|
it('should return an empty array when items is an empty array', async () => {
|
||
|
mockGetNodeParameter.mockReturnValueOnce(false);
|
||
|
|
||
|
const emptyArrayItems: INodeExecutionData[] = [];
|
||
|
|
||
|
const result = await simplifyGetAllResponse.call(mockContext, emptyArrayItems, mockResponse);
|
||
|
expect(result).toEqual([]);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('simplifyGetResponse', () => {
|
||
|
const mockGetNodeParameter = jest.fn();
|
||
|
const mockContext = {
|
||
|
getNodeParameter: mockGetNodeParameter,
|
||
|
} as unknown as IExecuteSingleFunctions;
|
||
|
const mockResponse = jest.fn() as unknown as IN8nHttpFullResponse;
|
||
|
|
||
|
const items: INodeExecutionData[] = [
|
||
|
{
|
||
|
json: {
|
||
|
id: '01',
|
||
|
status: 'ACTIVE',
|
||
|
created: '2023-01-01T00:00:00.000Z',
|
||
|
activated: '2023-01-01T00:00:01.000Z',
|
||
|
lastLogin: null,
|
||
|
lastUpdated: '2023-01-01T00:00:01.000Z',
|
||
|
passwordChanged: null,
|
||
|
some_item: 'some_value',
|
||
|
profile: {
|
||
|
firstName: 'John',
|
||
|
lastName: 'Doe',
|
||
|
login: 'john.doe@example.com',
|
||
|
email: 'john.doe@example.com',
|
||
|
some_profile_item: 'some_profile_value',
|
||
|
},
|
||
|
} as unknown as IDataObject,
|
||
|
},
|
||
|
];
|
||
|
beforeEach(() => {
|
||
|
mockGetNodeParameter.mockClear();
|
||
|
});
|
||
|
|
||
|
it('should return the item unchanged when simplify parameter is not set', async () => {
|
||
|
mockGetNodeParameter.mockReturnValueOnce(false);
|
||
|
|
||
|
const expectedResult: INodeExecutionData[] = [
|
||
|
{
|
||
|
json: {
|
||
|
id: '01',
|
||
|
status: 'ACTIVE',
|
||
|
created: '2023-01-01T00:00:00.000Z',
|
||
|
activated: '2023-01-01T00:00:01.000Z',
|
||
|
lastLogin: null,
|
||
|
lastUpdated: '2023-01-01T00:00:01.000Z',
|
||
|
passwordChanged: null,
|
||
|
some_item: 'some_value',
|
||
|
profile: {
|
||
|
firstName: 'John',
|
||
|
lastName: 'Doe',
|
||
|
login: 'john.doe@example.com',
|
||
|
email: 'john.doe@example.com',
|
||
|
some_profile_item: 'some_profile_value',
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
];
|
||
|
|
||
|
const result = await simplifyGetResponse.call(mockContext, items, mockResponse);
|
||
|
expect(result).toEqual(expectedResult);
|
||
|
});
|
||
|
|
||
|
it('should simplify the item correctly', async () => {
|
||
|
mockGetNodeParameter.mockReturnValueOnce(true);
|
||
|
|
||
|
const expectedResult: INodeExecutionData[] = [
|
||
|
{
|
||
|
json: {
|
||
|
id: '01',
|
||
|
status: 'ACTIVE',
|
||
|
created: '2023-01-01T00:00:00.000Z',
|
||
|
activated: '2023-01-01T00:00:01.000Z',
|
||
|
lastLogin: null,
|
||
|
lastUpdated: '2023-01-01T00:00:01.000Z',
|
||
|
passwordChanged: null,
|
||
|
profile: {
|
||
|
firstName: 'John',
|
||
|
lastName: 'Doe',
|
||
|
login: 'john.doe@example.com',
|
||
|
email: 'john.doe@example.com',
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
];
|
||
|
|
||
|
const result = await simplifyGetResponse.call(mockContext, items, mockResponse);
|
||
|
expect(result).toEqual(expectedResult);
|
||
|
});
|
||
|
});
|
||
|
describe('getCursorPaginator', () => {
|
||
|
let mockContext: IExecutePaginationFunctions;
|
||
|
let mockRequestOptions: DeclarativeRestApiSettings.ResultOptions;
|
||
|
const baseUrl = 'https://api.example.com';
|
||
|
|
||
|
beforeEach(() => {
|
||
|
mockContext = {
|
||
|
getNodeParameter: jest.fn(),
|
||
|
makeRoutingRequest: jest.fn(),
|
||
|
} as unknown as IExecutePaginationFunctions;
|
||
|
|
||
|
mockRequestOptions = {
|
||
|
options: {
|
||
|
qs: {},
|
||
|
},
|
||
|
} as DeclarativeRestApiSettings.ResultOptions;
|
||
|
});
|
||
|
|
||
|
it('should return all items when returnAll is true', async () => {
|
||
|
const mockResponseData: INodeExecutionData[] = [
|
||
|
{ json: { id: 1 }, headers: { link: `<${baseUrl}?after=cursor1>` } },
|
||
|
{ json: { id: 2 }, headers: { link: `<${baseUrl}?after=cursor2>` } },
|
||
|
{ json: { id: 3 }, headers: { link: `<${baseUrl}>` } },
|
||
|
];
|
||
|
|
||
|
(mockContext.getNodeParameter as jest.Mock).mockReturnValue(true);
|
||
|
(mockContext.makeRoutingRequest as jest.Mock)
|
||
|
.mockResolvedValueOnce([mockResponseData[0]])
|
||
|
.mockResolvedValueOnce([mockResponseData[1]])
|
||
|
.mockResolvedValueOnce([mockResponseData[2]]);
|
||
|
|
||
|
const paginator = getCursorPaginator().bind(mockContext);
|
||
|
const result = await paginator(mockRequestOptions);
|
||
|
|
||
|
expect(result).toEqual(mockResponseData);
|
||
|
expect(mockContext.getNodeParameter).toHaveBeenCalledWith('returnAll', true);
|
||
|
expect(mockContext.makeRoutingRequest).toHaveBeenCalledTimes(3);
|
||
|
});
|
||
|
|
||
|
it('should return items until nextCursor is undefined', async () => {
|
||
|
const mockResponseData: INodeExecutionData[] = [
|
||
|
{ json: { id: 1 }, headers: { link: `<${baseUrl}?after=cursor1>` } },
|
||
|
{ json: { id: 2 }, headers: { link: `<${baseUrl}>` } },
|
||
|
];
|
||
|
|
||
|
(mockContext.getNodeParameter as jest.Mock).mockReturnValue(true);
|
||
|
(mockContext.makeRoutingRequest as jest.Mock)
|
||
|
.mockResolvedValueOnce([mockResponseData[0]])
|
||
|
.mockResolvedValueOnce([mockResponseData[1]]);
|
||
|
|
||
|
const paginator = getCursorPaginator().bind(mockContext);
|
||
|
const result = await paginator(mockRequestOptions);
|
||
|
|
||
|
expect(result).toEqual(mockResponseData);
|
||
|
expect(mockContext.getNodeParameter).toHaveBeenCalledWith('returnAll', true);
|
||
|
expect(mockContext.makeRoutingRequest).toHaveBeenCalledTimes(2);
|
||
|
});
|
||
|
|
||
|
it('should handle empty response data', async () => {
|
||
|
(mockContext.getNodeParameter as jest.Mock).mockReturnValue(true);
|
||
|
(mockContext.makeRoutingRequest as jest.Mock).mockResolvedValue([]);
|
||
|
|
||
|
const paginator = getCursorPaginator().bind(mockContext);
|
||
|
const result = await paginator(mockRequestOptions);
|
||
|
|
||
|
expect(result).toEqual([]);
|
||
|
expect(mockContext.getNodeParameter).toHaveBeenCalledWith('returnAll', true);
|
||
|
expect(mockContext.makeRoutingRequest).toHaveBeenCalledTimes(1);
|
||
|
});
|
||
|
});
|