Files
n8n-enterprise-unlocked/packages/nodes-base/nodes/Github/__tests__/GenericFunctions.test.ts

185 lines
5.1 KiB
TypeScript

import type { IExecuteFunctions, IHookFunctions } from 'n8n-workflow';
import { NodeApiError, NodeOperationError } from 'n8n-workflow';
import {
githubApiRequest,
getFileSha,
githubApiRequestAllItems,
isBase64,
validateJSON,
} from '../GenericFunctions';
const mockExecuteHookFunctions = {
getNodeParameter: jest.fn().mockImplementation((param: string) => {
if (param === 'authentication') return 'accessToken';
return undefined;
}),
getCredentials: jest.fn().mockResolvedValue({
server: 'https://api.github.com',
}),
helpers: {
requestWithAuthentication: jest.fn(),
},
getCurrentNodeParameter: jest.fn(),
getWebhookName: jest.fn(),
getWebhookDescription: jest.fn(),
getNodeWebhookUrl: jest.fn(),
getNode: jest.fn().mockReturnValue({
id: 'test-node-id',
name: 'test-node',
}),
} as unknown as IExecuteFunctions | IHookFunctions;
describe('GenericFunctions', () => {
beforeEach(() => {
jest.clearAllMocks();
});
describe('githubApiRequest', () => {
it('should make a successful API request', async () => {
const method = 'GET';
const endpoint = '/repos/test-owner/test-repo';
const body = {};
const responseData = { id: 123, name: 'test-repo' };
(mockExecuteHookFunctions.helpers.requestWithAuthentication as jest.Mock).mockResolvedValue(
responseData,
);
const result = await githubApiRequest.call(mockExecuteHookFunctions, method, endpoint, body);
expect(result).toEqual(responseData);
expect(mockExecuteHookFunctions.helpers.requestWithAuthentication).toHaveBeenCalledWith(
'githubApi',
{
method: 'GET',
headers: { 'User-Agent': 'n8n' },
body: {},
qs: undefined,
uri: 'https://api.github.com/repos/test-owner/test-repo',
json: true,
},
);
});
it('should throw a NodeApiError on API failure', async () => {
const method = 'GET';
const endpoint = '/repos/test-owner/test-repo';
const body = {};
const error = new Error('API Error');
(mockExecuteHookFunctions.helpers.requestWithAuthentication as jest.Mock).mockRejectedValue(
error,
);
await expect(
githubApiRequest.call(mockExecuteHookFunctions, method, endpoint, body),
).rejects.toThrow(NodeApiError);
});
});
describe('getFileSha', () => {
it('should return the SHA of a file', async () => {
const owner = 'test-owner';
const repository = 'test-repo';
const filePath = 'README.md';
const branch = 'main';
const responseData = { sha: 'abc123' };
(mockExecuteHookFunctions.helpers.requestWithAuthentication as jest.Mock).mockResolvedValue(
responseData,
);
const result = await getFileSha.call(
mockExecuteHookFunctions,
owner,
repository,
filePath,
branch,
);
expect(result).toBe('abc123');
expect(mockExecuteHookFunctions.helpers.requestWithAuthentication).toHaveBeenCalledWith(
'githubApi',
{
method: 'GET',
headers: { 'User-Agent': 'n8n' },
body: {},
qs: { ref: 'main' },
uri: 'https://api.github.com/repos/test-owner/test-repo/contents/README.md',
json: true,
},
);
});
it('should throw a NodeOperationError if SHA is missing', async () => {
const owner = 'test-owner';
const repository = 'test-repo';
const filePath = 'README.md';
const responseData = {};
(mockExecuteHookFunctions.helpers.requestWithAuthentication as jest.Mock).mockResolvedValue(
responseData,
);
await expect(
getFileSha.call(mockExecuteHookFunctions, owner, repository, filePath),
).rejects.toThrow(NodeOperationError);
});
});
describe('githubApiRequestAllItems', () => {
it('should fetch all items with pagination', async () => {
const method = 'GET';
const endpoint = '/repos/test-owner/test-repo/issues';
const body = {};
const query = { state: 'open' };
const responseData1 = [{ id: 1, title: 'Issue 1' }];
const responseData2 = [{ id: 2, title: 'Issue 2' }];
(mockExecuteHookFunctions.helpers.requestWithAuthentication as jest.Mock)
.mockResolvedValueOnce({ headers: { link: 'next' }, body: responseData1 })
.mockResolvedValueOnce({ headers: {}, body: responseData2 });
const result = await githubApiRequestAllItems.call(
mockExecuteHookFunctions,
method,
endpoint,
body,
query,
);
expect(result).toEqual([...responseData1, ...responseData2]);
expect(mockExecuteHookFunctions.helpers.requestWithAuthentication).toHaveBeenCalledTimes(2);
});
});
describe('isBase64', () => {
it('should return true for valid Base64 strings', () => {
expect(isBase64('aGVsbG8gd29ybGQ=')).toBe(true);
expect(isBase64('Zm9vYmFy')).toBe(true);
});
it('should return false for invalid Base64 strings', () => {
expect(isBase64('not base64')).toBe(false);
expect(isBase64('123!@#')).toBe(false);
});
});
describe('validateJSON', () => {
it('should return parsed JSON for valid JSON strings', () => {
const jsonString = '{"key": "value"}';
const result = validateJSON(jsonString);
expect(result).toEqual({ key: 'value' });
});
it('should return undefined for invalid JSON strings', () => {
const invalidJsonString = 'not json';
const result = validateJSON(invalidJsonString);
expect(result).toBeUndefined();
});
});
});