mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 18:12:04 +00:00
feat(Okta Node): Add Okta Node (#10278)
Co-authored-by: Giulio Andreini <g.andreini@gmail.com> Co-authored-by: Elias Meire <elias@meire.dev>
This commit is contained in:
375
packages/nodes-base/nodes/Okta/test/UserFunctions.test.ts
Normal file
375
packages/nodes-base/nodes/Okta/test/UserFunctions.test.ts
Normal file
@@ -0,0 +1,375 @@
|
||||
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);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user