first commit
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
|
||||
import nock from 'nock';
|
||||
|
||||
describe('Test Github Node - Dispatch and Wait', () => {
|
||||
describe('Workflow Dispatch and Wait', () => {
|
||||
const now = 1683028800000;
|
||||
const owner = 'Owner';
|
||||
const repository = 'test-github-actions';
|
||||
const workflowId = 145370278;
|
||||
const ref = 'test-branch';
|
||||
|
||||
const usersResponse = {
|
||||
total_count: 1,
|
||||
items: [
|
||||
{
|
||||
login: owner,
|
||||
id: 1,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const repositoriesResponse = {
|
||||
total_count: 1,
|
||||
items: [
|
||||
{
|
||||
id: 3081286,
|
||||
name: repository,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const workflowsResponse = {
|
||||
total_count: 1,
|
||||
workflows: [
|
||||
{
|
||||
id: workflowId,
|
||||
node_id: 'MDg6V29ya2Zsb3cxNjEzMzU=',
|
||||
name: 'New Test Workflow',
|
||||
path: '.github/workflows/test.yaml',
|
||||
state: 'active',
|
||||
created_at: '2020-01-08T23:48:37.000-08:00',
|
||||
updated_at: '2020-01-08T23:50:21.000-08:00',
|
||||
url: `https://api.github.com/repos/${owner}/${repository}/actions/workflows/${workflowId}`,
|
||||
html_url: `https://github.com/${owner}/${repository}/blob/master/.github/workflows/test.yaml`,
|
||||
badge_url: `https://github.com/${owner}/${repository}/workflows/New%20Test%20Workflow/badge.svg`,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const refsResponse = [{ ref: `refs/heads/${ref}` }];
|
||||
|
||||
beforeAll(async () => {
|
||||
jest.useFakeTimers({ doNotFake: ['nextTick'], now });
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
const baseUrl = 'https://api.github.com';
|
||||
nock.cleanAll();
|
||||
nock(baseUrl)
|
||||
.persist()
|
||||
.defaultReplyHeaders({ 'Content-Type': 'application/json' })
|
||||
.get('/search/users')
|
||||
.query(true)
|
||||
.reply(200, usersResponse)
|
||||
.get('/search/repositories')
|
||||
.query(true)
|
||||
.reply(200, repositoriesResponse)
|
||||
.get(`/repos/${owner}/${repository}/actions/workflows`)
|
||||
.reply(200, workflowsResponse)
|
||||
.get(`/repos/${owner}/${repository}/git/refs`)
|
||||
.reply(200, refsResponse)
|
||||
.post(
|
||||
`/repos/${owner}/${repository}/actions/workflows/${workflowId}/dispatches`,
|
||||
(body) => {
|
||||
return body.ref === ref && body.inputs?.resumeUrl;
|
||||
},
|
||||
)
|
||||
.reply(200, {});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
nock.cleanAll();
|
||||
});
|
||||
|
||||
new NodeTestHarness().setupTests({
|
||||
workflowFiles: ['GithubDispatchAndWaitWorkflow.json'],
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,702 @@
|
||||
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
|
||||
import { NodeApiError, NodeOperationError } from 'n8n-workflow';
|
||||
import nock from 'nock';
|
||||
|
||||
import * as utilities from '../../../../utils/utilities';
|
||||
import { Github } from '../../Github.node';
|
||||
|
||||
describe('Test Github Node', () => {
|
||||
describe('Workflow Dispatch', () => {
|
||||
const now = 1683028800000;
|
||||
const owner = 'testOwner';
|
||||
const repository = 'testRepository';
|
||||
const workflowId = 147025216;
|
||||
const usersResponse = {
|
||||
total_count: 12,
|
||||
items: [
|
||||
{
|
||||
login: 'testOwner',
|
||||
id: 1,
|
||||
},
|
||||
],
|
||||
};
|
||||
const repositoriesResponse = {
|
||||
total_count: 40,
|
||||
items: [
|
||||
{
|
||||
id: 3081286,
|
||||
name: 'testRepository',
|
||||
},
|
||||
],
|
||||
};
|
||||
const workflowsResponse = {
|
||||
total_count: 2,
|
||||
workflows: [
|
||||
{
|
||||
id: workflowId,
|
||||
node_id: 'MDg6V29ya2Zsb3cxNjEzMzU=',
|
||||
name: 'CI',
|
||||
path: '.github/workflows/blank.yaml',
|
||||
state: 'active',
|
||||
created_at: '2020-01-08T23:48:37.000-08:00',
|
||||
updated_at: '2020-01-08T23:50:21.000-08:00',
|
||||
url: 'https://api.github.com/repos/octo-org/octo-repo/actions/workflows/161335',
|
||||
html_url: 'https://github.com/octo-org/octo-repo/blob/master/.github/workflows/161335',
|
||||
badge_url: 'https://github.com/octo-org/octo-repo/workflows/CI/badge.svg',
|
||||
},
|
||||
{
|
||||
id: 269289,
|
||||
node_id: 'MDE4OldvcmtmbG93IFNlY29uZGFyeTI2OTI4OQ==',
|
||||
name: 'Linter',
|
||||
path: '.github/workflows/linter.yaml',
|
||||
state: 'active',
|
||||
created_at: '2020-01-08T23:48:37.000-08:00',
|
||||
updated_at: '2020-01-08T23:50:21.000-08:00',
|
||||
url: 'https://api.github.com/repos/octo-org/octo-repo/actions/workflows/269289',
|
||||
html_url: 'https://github.com/octo-org/octo-repo/blob/master/.github/workflows/269289',
|
||||
badge_url: 'https://github.com/octo-org/octo-repo/workflows/Linter/badge.svg',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
beforeAll(async () => {
|
||||
jest.useFakeTimers({ doNotFake: ['nextTick'], now });
|
||||
});
|
||||
|
||||
describe('removeTrailingSlash Function', () => {
|
||||
let githubNode: Github;
|
||||
let mockExecutionContext: any;
|
||||
|
||||
beforeEach(() => {
|
||||
githubNode = new Github();
|
||||
mockExecutionContext = {
|
||||
getNode: jest.fn().mockReturnValue({ name: 'Github' }),
|
||||
getNodeParameter: jest.fn(),
|
||||
getInputData: jest.fn().mockReturnValue([{ json: {} }]),
|
||||
continueOnFail: jest.fn().mockReturnValue(false),
|
||||
getCredentials: jest.fn().mockResolvedValue({
|
||||
server: 'https://api.github.com',
|
||||
user: 'test',
|
||||
accessToken: 'test',
|
||||
}),
|
||||
helpers: {
|
||||
returnJsonArray: jest.fn().mockReturnValue([{ json: {} }]),
|
||||
requestWithAuthentication: jest.fn().mockResolvedValue({}),
|
||||
constructExecutionMetaData: jest.fn().mockReturnValue([{ json: {} }]),
|
||||
},
|
||||
};
|
||||
|
||||
jest.spyOn(utilities, 'removeTrailingSlash');
|
||||
jest.mock('../../../../utils/utilities', () => ({
|
||||
...jest.requireActual('../../../../utils/utilities'),
|
||||
getFileSha: jest.fn().mockResolvedValue('mockedSHA'),
|
||||
}));
|
||||
});
|
||||
|
||||
it('should call remove trailing slash', async () => {
|
||||
mockExecutionContext.getNodeParameter.mockImplementation((parameterName: string) => {
|
||||
if (parameterName === 'operation') {
|
||||
return 'list';
|
||||
}
|
||||
if (parameterName === 'resource') {
|
||||
return 'file';
|
||||
}
|
||||
if (parameterName === 'filePath') {
|
||||
return 'path/to/file/';
|
||||
}
|
||||
if (parameterName === 'owner') {
|
||||
return 'me';
|
||||
}
|
||||
if (parameterName === 'repository') {
|
||||
return 'repo';
|
||||
}
|
||||
return '';
|
||||
});
|
||||
|
||||
await githubNode.execute.call(mockExecutionContext);
|
||||
|
||||
expect(utilities.removeTrailingSlash).toHaveBeenCalledWith('path/to/file/');
|
||||
expect(mockExecutionContext.helpers.requestWithAuthentication).toHaveBeenCalledWith(
|
||||
'githubOAuth2Api',
|
||||
{
|
||||
body: {},
|
||||
headers: { 'User-Agent': 'n8n' },
|
||||
json: true,
|
||||
method: 'GET',
|
||||
qs: {},
|
||||
uri: 'https://api.github.com/repos/me/repo/contents/path%2Fto%2Ffile',
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
const baseUrl = 'https://api.github.com';
|
||||
nock(baseUrl)
|
||||
.persist()
|
||||
.defaultReplyHeaders({ 'Content-Type': 'application/json' })
|
||||
.get('/search/users')
|
||||
.query(true)
|
||||
.reply(200, usersResponse)
|
||||
.get('/search/repositories')
|
||||
.query(true)
|
||||
.reply(200, repositoriesResponse)
|
||||
.get(`/repos/${owner}/${repository}/actions/workflows`)
|
||||
.reply(200, workflowsResponse)
|
||||
.post(`/repos/${owner}/${repository}/actions/workflows/${workflowId}/dispatches`, {
|
||||
ref: 'main',
|
||||
inputs: {},
|
||||
})
|
||||
.reply(200, {});
|
||||
});
|
||||
|
||||
new NodeTestHarness().setupTests({
|
||||
workflowFiles: ['GithubTestWorkflow.json'],
|
||||
});
|
||||
});
|
||||
|
||||
describe('Error Handling', () => {
|
||||
let githubNode: Github;
|
||||
let mockExecutionContext: any;
|
||||
|
||||
beforeEach(() => {
|
||||
githubNode = new Github();
|
||||
mockExecutionContext = {
|
||||
getNode: jest.fn().mockReturnValue({ name: 'Github' }),
|
||||
getNodeParameter: jest.fn(),
|
||||
getInputData: jest.fn().mockReturnValue([{ json: {} }]),
|
||||
continueOnFail: jest.fn().mockReturnValue(false),
|
||||
putExecutionToWait: jest.fn(),
|
||||
getCredentials: jest.fn().mockResolvedValue({
|
||||
server: 'https://api.github.com',
|
||||
user: 'test',
|
||||
accessToken: 'test',
|
||||
}),
|
||||
helpers: {
|
||||
returnJsonArray: jest.fn().mockReturnValue([{ json: {} }]),
|
||||
httpRequest: jest.fn(),
|
||||
httpRequestWithAuthentication: jest.fn(),
|
||||
requestWithAuthentication: jest
|
||||
.fn()
|
||||
.mockImplementation(async (_credentialType, options) => {
|
||||
if (options.uri.includes('dispatches') && options.method === 'POST') {
|
||||
const error: any = new Error('Not Found');
|
||||
error.statusCode = 404;
|
||||
error.message = 'Not Found';
|
||||
throw error;
|
||||
}
|
||||
return {};
|
||||
}),
|
||||
request: jest.fn(),
|
||||
constructExecutionMetaData: jest.fn().mockReturnValue([{ json: {} }]),
|
||||
assertBinaryData: jest.fn(),
|
||||
prepareBinaryData: jest.fn(),
|
||||
},
|
||||
getWorkflowDataProxy: jest.fn().mockReturnValue({
|
||||
$execution: {
|
||||
resumeUrl: 'https://example.com/webhook',
|
||||
},
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
it('should throw NodeOperationError for invalid JSON inputs', async () => {
|
||||
mockExecutionContext.getNodeParameter.mockImplementation((parameterName: string) => {
|
||||
if (parameterName === 'inputs') {
|
||||
return 'invalid json';
|
||||
}
|
||||
if (parameterName === 'resource') {
|
||||
return 'workflow';
|
||||
}
|
||||
if (parameterName === 'operation') {
|
||||
return 'dispatchAndWait';
|
||||
}
|
||||
if (parameterName === 'authentication') {
|
||||
return 'accessToken';
|
||||
}
|
||||
return '';
|
||||
});
|
||||
|
||||
await expect(async () => {
|
||||
await githubNode.execute.call(mockExecutionContext);
|
||||
}).rejects.toThrow(NodeOperationError);
|
||||
});
|
||||
|
||||
it('should throw NodeOperationError for 404 errors when dispatching a workflow', async () => {
|
||||
const owner = 'testOwner';
|
||||
const repository = 'testRepository';
|
||||
const workflowId = 147025216;
|
||||
|
||||
mockExecutionContext.helpers.requestWithAuthentication.mockRejectedValueOnce({
|
||||
statusCode: 404,
|
||||
message: 'Not Found',
|
||||
});
|
||||
|
||||
mockExecutionContext.getNodeParameter.mockImplementation((parameterName: string) => {
|
||||
if (parameterName === 'owner') {
|
||||
return owner;
|
||||
}
|
||||
if (parameterName === 'repository') {
|
||||
return repository;
|
||||
}
|
||||
if (parameterName === 'workflowId') {
|
||||
return workflowId;
|
||||
}
|
||||
if (parameterName === 'inputs') {
|
||||
return '{}';
|
||||
}
|
||||
if (parameterName === 'ref') {
|
||||
return 'main';
|
||||
}
|
||||
if (parameterName === 'resource') {
|
||||
return 'workflow';
|
||||
}
|
||||
if (parameterName === 'operation') {
|
||||
return 'dispatchAndWait';
|
||||
}
|
||||
if (parameterName === 'authentication') {
|
||||
return 'accessToken';
|
||||
}
|
||||
return '';
|
||||
});
|
||||
|
||||
await expect(async () => {
|
||||
await githubNode.execute.call(mockExecutionContext);
|
||||
}).rejects.toThrow(/The workflow to dispatch could not be found/);
|
||||
});
|
||||
|
||||
it('should throw NodeApiError for general API errors', async () => {
|
||||
const owner = 'testOwner';
|
||||
const repository = 'testRepository';
|
||||
const workflowId = 147025216;
|
||||
|
||||
mockExecutionContext.helpers.requestWithAuthentication.mockRejectedValueOnce({
|
||||
statusCode: 500,
|
||||
message: 'Internal Server Error',
|
||||
});
|
||||
|
||||
mockExecutionContext.getNodeParameter.mockImplementation((parameterName: string) => {
|
||||
if (parameterName === 'owner') {
|
||||
return owner;
|
||||
}
|
||||
if (parameterName === 'repository') {
|
||||
return repository;
|
||||
}
|
||||
if (parameterName === 'workflowId') {
|
||||
return workflowId;
|
||||
}
|
||||
if (parameterName === 'inputs') {
|
||||
return '{}';
|
||||
}
|
||||
if (parameterName === 'ref') {
|
||||
return 'main';
|
||||
}
|
||||
if (parameterName === 'resource') {
|
||||
return 'workflow';
|
||||
}
|
||||
if (parameterName === 'operation') {
|
||||
return 'dispatch';
|
||||
}
|
||||
if (parameterName === 'authentication') {
|
||||
return 'accessToken';
|
||||
}
|
||||
return '';
|
||||
});
|
||||
|
||||
await expect(async () => {
|
||||
await githubNode.execute.call(mockExecutionContext);
|
||||
}).rejects.toThrow();
|
||||
});
|
||||
|
||||
it('should throw NodeApiError for general API errors in dispatchAndWait operation', async () => {
|
||||
const owner = 'testOwner';
|
||||
const repository = 'testRepository';
|
||||
const workflowId = 147025216;
|
||||
|
||||
mockExecutionContext.getWorkflowDataProxy = jest.fn().mockReturnValue({
|
||||
$execution: {
|
||||
resumeUrl: 'https://example.com/webhook',
|
||||
},
|
||||
});
|
||||
|
||||
mockExecutionContext.helpers.requestWithAuthentication.mockRejectedValueOnce({
|
||||
statusCode: 500,
|
||||
message: 'Internal Server Error',
|
||||
});
|
||||
|
||||
mockExecutionContext.getNodeParameter.mockImplementation((parameterName: string) => {
|
||||
if (parameterName === 'owner') {
|
||||
return owner;
|
||||
}
|
||||
if (parameterName === 'repository') {
|
||||
return repository;
|
||||
}
|
||||
if (parameterName === 'workflowId') {
|
||||
return workflowId;
|
||||
}
|
||||
if (parameterName === 'inputs') {
|
||||
return '{}';
|
||||
}
|
||||
if (parameterName === 'ref') {
|
||||
return 'main';
|
||||
}
|
||||
if (parameterName === 'resource') {
|
||||
return 'workflow';
|
||||
}
|
||||
if (parameterName === 'operation') {
|
||||
return 'dispatchAndWait';
|
||||
}
|
||||
if (parameterName === 'authentication') {
|
||||
return 'accessToken';
|
||||
}
|
||||
return '';
|
||||
});
|
||||
|
||||
await expect(async () => {
|
||||
await githubNode.execute.call(mockExecutionContext);
|
||||
}).rejects.toThrow(NodeApiError);
|
||||
|
||||
expect(mockExecutionContext.helpers.requestWithAuthentication).toHaveBeenCalledWith(
|
||||
expect.any(String),
|
||||
expect.objectContaining({
|
||||
method: 'POST',
|
||||
uri: expect.stringContaining(
|
||||
`/repos/${owner}/${repository}/actions/workflows/${workflowId}/dispatches`,
|
||||
),
|
||||
body: expect.objectContaining({
|
||||
ref: 'main',
|
||||
inputs: expect.objectContaining({
|
||||
resumeUrl: 'https://example.com/webhook',
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Workflow Operations', () => {
|
||||
let githubNode: Github;
|
||||
let mockExecutionContext: any;
|
||||
|
||||
beforeEach(() => {
|
||||
githubNode = new Github();
|
||||
mockExecutionContext = {
|
||||
getNode: jest.fn().mockReturnValue({ name: 'Github' }),
|
||||
getNodeParameter: jest.fn(),
|
||||
getInputData: jest.fn().mockReturnValue([{ json: {} }]),
|
||||
continueOnFail: jest.fn().mockReturnValue(false),
|
||||
getCredentials: jest.fn().mockResolvedValue({
|
||||
server: 'https://api.github.com',
|
||||
user: 'test',
|
||||
accessToken: 'test',
|
||||
}),
|
||||
helpers: {
|
||||
returnJsonArray: jest.fn().mockReturnValue([{ json: {} }]),
|
||||
requestWithAuthentication: jest.fn().mockResolvedValue({}),
|
||||
constructExecutionMetaData: jest.fn().mockReturnValue([{ json: {} }]),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
it('should use extractValue for workflowId in disable operation', async () => {
|
||||
const owner = 'testOwner';
|
||||
const repository = 'testRepository';
|
||||
const workflowId = 147025216;
|
||||
|
||||
mockExecutionContext.getNodeParameter.mockImplementation(
|
||||
(parameterName: string, _itemIndex: number, defaultValue: string, options?: any) => {
|
||||
if (parameterName === 'owner') {
|
||||
return owner;
|
||||
}
|
||||
if (parameterName === 'repository') {
|
||||
return repository;
|
||||
}
|
||||
if (parameterName === 'workflowId') {
|
||||
expect(options).toBeDefined();
|
||||
expect(options.extractValue).toBe(true);
|
||||
return workflowId;
|
||||
}
|
||||
if (parameterName === 'resource') {
|
||||
return 'workflow';
|
||||
}
|
||||
if (parameterName === 'operation') {
|
||||
return 'disable';
|
||||
}
|
||||
if (parameterName === 'authentication') {
|
||||
return 'accessToken';
|
||||
}
|
||||
return defaultValue;
|
||||
},
|
||||
);
|
||||
|
||||
await githubNode.execute.call(mockExecutionContext);
|
||||
|
||||
expect(mockExecutionContext.helpers.requestWithAuthentication).toHaveBeenCalledWith(
|
||||
expect.any(String),
|
||||
expect.objectContaining({
|
||||
method: 'PUT',
|
||||
uri: `https://api.github.com/repos/${owner}/${repository}/actions/workflows/${workflowId}/disable`,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should use extractValue for workflowId in enable operation', async () => {
|
||||
const owner = 'testOwner';
|
||||
const repository = 'testRepository';
|
||||
const workflowId = 147025216;
|
||||
|
||||
mockExecutionContext.getNodeParameter.mockImplementation(
|
||||
(parameterName: string, _itemIndex: number, defaultValue: string, options?: any) => {
|
||||
if (parameterName === 'owner') {
|
||||
return owner;
|
||||
}
|
||||
if (parameterName === 'repository') {
|
||||
return repository;
|
||||
}
|
||||
if (parameterName === 'workflowId') {
|
||||
expect(options).toBeDefined();
|
||||
expect(options.extractValue).toBe(true);
|
||||
return workflowId;
|
||||
}
|
||||
if (parameterName === 'resource') {
|
||||
return 'workflow';
|
||||
}
|
||||
if (parameterName === 'operation') {
|
||||
return 'enable';
|
||||
}
|
||||
if (parameterName === 'authentication') {
|
||||
return 'accessToken';
|
||||
}
|
||||
return defaultValue;
|
||||
},
|
||||
);
|
||||
|
||||
await githubNode.execute.call(mockExecutionContext);
|
||||
|
||||
expect(mockExecutionContext.helpers.requestWithAuthentication).toHaveBeenCalledWith(
|
||||
expect.any(String),
|
||||
expect.objectContaining({
|
||||
method: 'PUT',
|
||||
uri: `https://api.github.com/repos/${owner}/${repository}/actions/workflows/${workflowId}/enable`,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should use extractValue for workflowId in get operation', async () => {
|
||||
const owner = 'testOwner';
|
||||
const repository = 'testRepository';
|
||||
const workflowId = 147025216;
|
||||
|
||||
mockExecutionContext.getNodeParameter.mockImplementation(
|
||||
(parameterName: string, _itemIndex: number, defaultValue: string, options?: any) => {
|
||||
if (parameterName === 'owner') {
|
||||
return owner;
|
||||
}
|
||||
if (parameterName === 'repository') {
|
||||
return repository;
|
||||
}
|
||||
if (parameterName === 'workflowId') {
|
||||
expect(options).toBeDefined();
|
||||
expect(options.extractValue).toBe(true);
|
||||
return workflowId;
|
||||
}
|
||||
if (parameterName === 'resource') {
|
||||
return 'workflow';
|
||||
}
|
||||
if (parameterName === 'operation') {
|
||||
return 'get';
|
||||
}
|
||||
if (parameterName === 'authentication') {
|
||||
return 'accessToken';
|
||||
}
|
||||
return defaultValue;
|
||||
},
|
||||
);
|
||||
|
||||
await githubNode.execute.call(mockExecutionContext);
|
||||
|
||||
expect(mockExecutionContext.helpers.requestWithAuthentication).toHaveBeenCalledWith(
|
||||
expect.any(String),
|
||||
expect.objectContaining({
|
||||
method: 'GET',
|
||||
uri: `https://api.github.com/repos/${owner}/${repository}/actions/workflows/${workflowId}`,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should use extractValue for workflowId in getUsage operation', async () => {
|
||||
const owner = 'testOwner';
|
||||
const repository = 'testRepository';
|
||||
const workflowId = 147025216;
|
||||
|
||||
mockExecutionContext.getNodeParameter.mockImplementation(
|
||||
(parameterName: string, _itemIndex: number, defaultValue: string, options?: any) => {
|
||||
if (parameterName === 'owner') {
|
||||
return owner;
|
||||
}
|
||||
if (parameterName === 'repository') {
|
||||
return repository;
|
||||
}
|
||||
if (parameterName === 'workflowId') {
|
||||
expect(options).toBeDefined();
|
||||
expect(options.extractValue).toBe(true);
|
||||
return workflowId;
|
||||
}
|
||||
if (parameterName === 'resource') {
|
||||
return 'workflow';
|
||||
}
|
||||
if (parameterName === 'operation') {
|
||||
return 'getUsage';
|
||||
}
|
||||
if (parameterName === 'authentication') {
|
||||
return 'accessToken';
|
||||
}
|
||||
return defaultValue;
|
||||
},
|
||||
);
|
||||
|
||||
await githubNode.execute.call(mockExecutionContext);
|
||||
|
||||
expect(mockExecutionContext.helpers.requestWithAuthentication).toHaveBeenCalledWith(
|
||||
expect.any(String),
|
||||
expect.objectContaining({
|
||||
method: 'GET',
|
||||
uri: `https://api.github.com/repos/${owner}/${repository}/actions/workflows/${workflowId}/timing`,
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Parameter Extraction', () => {
|
||||
it('should use extractValue for workflowId parameter', () => {
|
||||
const githubNode = new Github();
|
||||
const description = githubNode.description;
|
||||
|
||||
const workflowIdParam = description.properties.find((prop) => prop.name === 'workflowId');
|
||||
|
||||
expect(workflowIdParam).toBeDefined();
|
||||
expect(workflowIdParam?.type).toBe('resourceLocator');
|
||||
|
||||
const workflowOperations = description.properties.find(
|
||||
(prop) =>
|
||||
prop.name === 'operation' && prop.displayOptions?.show?.resource?.includes('workflow'),
|
||||
);
|
||||
|
||||
expect(workflowOperations).toBeDefined();
|
||||
expect(workflowOperations?.options).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({ value: 'disable' }),
|
||||
expect.objectContaining({ value: 'dispatch' }),
|
||||
expect.objectContaining({ value: 'enable' }),
|
||||
expect.objectContaining({ value: 'get' }),
|
||||
expect.objectContaining({ value: 'getUsage' }),
|
||||
]),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('User Operations', () => {
|
||||
let githubNode: Github;
|
||||
let mockExecutionContext: any;
|
||||
|
||||
beforeEach(() => {
|
||||
githubNode = new Github();
|
||||
mockExecutionContext = {
|
||||
getNode: jest.fn().mockReturnValue({ name: 'Github' }),
|
||||
getNodeParameter: jest.fn(),
|
||||
getInputData: jest.fn().mockReturnValue([{ json: {} }]),
|
||||
continueOnFail: jest.fn().mockReturnValue(false),
|
||||
getCredentials: jest.fn().mockResolvedValue({
|
||||
server: 'https://api.github.com',
|
||||
user: 'test',
|
||||
accessToken: 'test',
|
||||
}),
|
||||
helpers: {
|
||||
returnJsonArray: jest.fn().mockReturnValue([{ json: {} }]),
|
||||
requestWithAuthentication: jest.fn().mockResolvedValue({}),
|
||||
constructExecutionMetaData: jest.fn().mockReturnValue([{ json: {} }]),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
it('should fetch open issues by default (user:getIssues)', async () => {
|
||||
mockExecutionContext.getNodeParameter.mockImplementation((parameterName: string) => {
|
||||
if (parameterName === 'resource') return 'user';
|
||||
if (parameterName === 'operation') return 'getUserIssues';
|
||||
if (parameterName === 'getUserIssuesFilters') return {};
|
||||
if (parameterName === 'returnAll') return true;
|
||||
if (parameterName === 'authentication') return 'accessToken';
|
||||
return '';
|
||||
});
|
||||
mockExecutionContext.helpers.requestWithAuthentication.mockResolvedValue({
|
||||
body: [
|
||||
{ id: 1, title: 'Issue 1', state: 'open' },
|
||||
{ id: 2, title: 'Issue 2', state: 'open' },
|
||||
],
|
||||
headers: {},
|
||||
});
|
||||
|
||||
await githubNode.execute.call(mockExecutionContext);
|
||||
expect(mockExecutionContext.helpers.requestWithAuthentication).toHaveBeenCalledWith(
|
||||
expect.any(String),
|
||||
expect.objectContaining({
|
||||
method: 'GET',
|
||||
uri: 'https://api.github.com/issues',
|
||||
qs: expect.not.objectContaining({ state: 'closed' }),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should fetch closed issues when state filter is set to closed (user:getIssues)', async () => {
|
||||
mockExecutionContext.getNodeParameter.mockImplementation((parameterName: string) => {
|
||||
if (parameterName === 'resource') return 'user';
|
||||
if (parameterName === 'operation') return 'getUserIssues';
|
||||
if (parameterName === 'getUserIssuesFilters') return { state: 'closed' };
|
||||
if (parameterName === 'returnAll') return true;
|
||||
if (parameterName === 'authentication') return 'accessToken';
|
||||
return '';
|
||||
});
|
||||
|
||||
mockExecutionContext.helpers.requestWithAuthentication.mockResolvedValue({
|
||||
body: [{ id: 3, title: 'Issue 3', state: 'closed' }],
|
||||
headers: {},
|
||||
});
|
||||
|
||||
await githubNode.execute.call(mockExecutionContext);
|
||||
expect(mockExecutionContext.helpers.requestWithAuthentication).toHaveBeenCalledWith(
|
||||
expect.any(String),
|
||||
expect.objectContaining({
|
||||
method: 'GET',
|
||||
uri: 'https://api.github.com/issues',
|
||||
qs: expect.objectContaining({ state: 'closed' }),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should fetch issues with a specific label (user:getIssues)', async () => {
|
||||
mockExecutionContext.getNodeParameter.mockImplementation((parameterName: string) => {
|
||||
if (parameterName === 'resource') return 'user';
|
||||
if (parameterName === 'operation') return 'getUserIssues';
|
||||
if (parameterName === 'getUserIssuesFilters') return { labels: 'bug' };
|
||||
if (parameterName === 'returnAll') return true;
|
||||
if (parameterName === 'authentication') return 'accessToken';
|
||||
return '';
|
||||
});
|
||||
|
||||
mockExecutionContext.helpers.requestWithAuthentication.mockResolvedValue({
|
||||
body: [{ id: 4, title: 'Issue 4', state: 'open', labels: ['bug'] }],
|
||||
headers: {},
|
||||
});
|
||||
|
||||
await githubNode.execute.call(mockExecutionContext);
|
||||
expect(mockExecutionContext.helpers.requestWithAuthentication).toHaveBeenCalledWith(
|
||||
expect.any(String),
|
||||
expect.objectContaining({
|
||||
method: 'GET',
|
||||
uri: 'https://api.github.com/issues',
|
||||
qs: expect.objectContaining({ labels: 'bug' }),
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,64 @@
|
||||
import type { IWebhookFunctions } from 'n8n-workflow';
|
||||
|
||||
import { Github } from '../../Github.node';
|
||||
|
||||
describe('Github Node - Webhook Method', () => {
|
||||
let githubNode: Github;
|
||||
let mockWebhookFunctions: IWebhookFunctions;
|
||||
|
||||
beforeEach(() => {
|
||||
githubNode = new Github();
|
||||
|
||||
mockWebhookFunctions = {
|
||||
getRequestObject: jest.fn(),
|
||||
getResponseObject: jest.fn(),
|
||||
getNodeParameter: jest.fn(),
|
||||
getNode: jest.fn(),
|
||||
helpers: {
|
||||
returnJsonArray: jest.fn(),
|
||||
},
|
||||
} as unknown as IWebhookFunctions;
|
||||
});
|
||||
|
||||
it('should process webhook request and return workflowData', async () => {
|
||||
const sampleWebhookBody = {
|
||||
action: 'opened',
|
||||
issue: {
|
||||
number: 123,
|
||||
title: 'Test Issue',
|
||||
body: 'This is a test issue',
|
||||
user: {
|
||||
login: 'testuser',
|
||||
},
|
||||
},
|
||||
repository: {
|
||||
name: 'test-repo',
|
||||
owner: {
|
||||
login: 'test-owner',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const mockRequestObject = {
|
||||
body: sampleWebhookBody,
|
||||
headers: {
|
||||
'x-github-event': 'issues',
|
||||
'x-github-delivery': '72d3162e-cc78-11e3-81ab-4c9367dc0958',
|
||||
},
|
||||
};
|
||||
|
||||
(mockWebhookFunctions.getRequestObject as jest.Mock).mockReturnValue(mockRequestObject);
|
||||
(mockWebhookFunctions.helpers.returnJsonArray as jest.Mock).mockReturnValue([
|
||||
sampleWebhookBody,
|
||||
]);
|
||||
|
||||
const result = await githubNode.webhook.call(mockWebhookFunctions);
|
||||
|
||||
expect(result).toEqual({
|
||||
workflowData: [[sampleWebhookBody]],
|
||||
});
|
||||
|
||||
expect(mockWebhookFunctions.getRequestObject).toHaveBeenCalled();
|
||||
expect(mockWebhookFunctions.helpers.returnJsonArray).toHaveBeenCalledWith(sampleWebhookBody);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,76 @@
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {},
|
||||
"type": "n8n-nodes-base.manualTrigger",
|
||||
"typeVersion": 1,
|
||||
"position": [200, -360],
|
||||
"id": "0889ff06-41e2-4786-a0fe-ca330c3711e7",
|
||||
"name": "When clicking ‘Execute workflow’"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"resource": "workflow",
|
||||
"operation": "dispatchAndWait",
|
||||
"owner": {
|
||||
"__rl": true,
|
||||
"value": "Owner",
|
||||
"mode": "list",
|
||||
"cachedResultName": "Owner",
|
||||
"cachedResultUrl": "https://github.com/Owner"
|
||||
},
|
||||
"repository": {
|
||||
"__rl": true,
|
||||
"value": "test-github-actions",
|
||||
"mode": "list",
|
||||
"cachedResultName": "test-github-actions",
|
||||
"cachedResultUrl": "https://github.com/Owner/test-github-actions"
|
||||
},
|
||||
"workflowId": {
|
||||
"__rl": true,
|
||||
"value": 145370278,
|
||||
"mode": "list",
|
||||
"cachedResultName": "New Test Workflow"
|
||||
},
|
||||
"ref": {
|
||||
"__rl": true,
|
||||
"value": "test-branch",
|
||||
"mode": "list",
|
||||
"cachedResultName": "test-branch"
|
||||
}
|
||||
},
|
||||
"type": "n8n-nodes-base.github",
|
||||
"typeVersion": 1.1,
|
||||
"position": [220, 0],
|
||||
"id": "105cb5f0-bcc3-4397-ba06-bda8cf46c71b",
|
||||
"name": "Dispatch and Wait for Completion",
|
||||
"webhookId": "02bfeade-db6c-412a-8627-fe3a9952e8ee",
|
||||
"credentials": {
|
||||
"githubApi": {
|
||||
"id": "RtvkwCTqGZ2sLhB8",
|
||||
"name": "GitHub account 3"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": {
|
||||
"When clicking ‘Execute workflow’": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Dispatch and Wait for Completion",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"pinData": {
|
||||
"Dispatch and Wait for Completion": [
|
||||
{
|
||||
"json": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {},
|
||||
"type": "n8n-nodes-base.manualTrigger",
|
||||
"typeVersion": 1,
|
||||
"position": [-300, 260],
|
||||
"id": "b14bf20f-78b0-490a-bbc6-d02b1af4c03c",
|
||||
"name": "When clicking ‘Execute workflow’"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"resource": "workflow",
|
||||
"workflowId": {
|
||||
"__rl": true,
|
||||
"value": 147025216,
|
||||
"mode": "list",
|
||||
"cachedResultName": "CI"
|
||||
},
|
||||
"owner": {
|
||||
"__rl": true,
|
||||
"value": "testOwner",
|
||||
"mode": "name"
|
||||
},
|
||||
"repository": {
|
||||
"__rl": true,
|
||||
"value": "testRepository",
|
||||
"mode": "name"
|
||||
}
|
||||
},
|
||||
"type": "n8n-nodes-base.github",
|
||||
"typeVersion": 1,
|
||||
"position": [-80, 260],
|
||||
"id": "061752c9-507c-4b27-ba18-47b21d487aed",
|
||||
"name": "GitHub",
|
||||
"credentials": {
|
||||
"githubApi": {
|
||||
"id": "1",
|
||||
"name": "GitHub account"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {},
|
||||
"type": "n8n-nodes-base.noOp",
|
||||
"typeVersion": 1,
|
||||
"position": [120, 260],
|
||||
"id": "3bc54e8f-eeba-496d-a95f-bb8927eff671",
|
||||
"name": "No Operation, do nothing"
|
||||
}
|
||||
],
|
||||
"connections": {
|
||||
"When clicking ‘Execute workflow’": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "GitHub",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"GitHub": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "No Operation, do nothing",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"pinData": {
|
||||
"No Operation, do nothing": [
|
||||
{
|
||||
"json": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
import { GithubTrigger } from '../../GithubTrigger.node';
|
||||
import * as GenericFunctions from '../../GenericFunctions';
|
||||
import * as GithubTriggerHelpers from '../../GithubTriggerHelpers';
|
||||
import { NodeOperationError } from 'n8n-workflow';
|
||||
|
||||
describe('GithubTrigger Node', () => {
|
||||
describe('checkExists webhook method', () => {
|
||||
let webhookData: Record<string, any>;
|
||||
let mockThis: any;
|
||||
|
||||
beforeEach(() => {
|
||||
webhookData = {
|
||||
webhookId: '123456',
|
||||
webhookEvents: ['push'],
|
||||
};
|
||||
|
||||
mockThis = {
|
||||
getWorkflowStaticData: () => webhookData,
|
||||
getNodeParameter: jest.fn().mockImplementation((name: string) => {
|
||||
if (name === 'owner') return 'some-owner';
|
||||
if (name === 'repository') return 'some-repo';
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
it('should delete webhook data and return false when webhook is not found (404)', async () => {
|
||||
jest.spyOn(GenericFunctions, 'githubApiRequest').mockRejectedValue({ httpCode: '404' });
|
||||
|
||||
const trigger = new GithubTrigger();
|
||||
const result = await trigger.webhookMethods.default.checkExists.call(mockThis);
|
||||
|
||||
expect(result).toBe(false);
|
||||
expect(webhookData.webhookId).toBeUndefined();
|
||||
expect(webhookData.webhookEvents).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('create webhook method', () => {
|
||||
let mockThis: any;
|
||||
let webhookData: Record<string, any>;
|
||||
|
||||
beforeEach(() => {
|
||||
webhookData = {};
|
||||
mockThis = {
|
||||
getNodeWebhookUrl: () => 'https://example.com/webhook',
|
||||
getNodeParameter: jest.fn().mockImplementation((name: string) => {
|
||||
if (name === 'owner') return 'some-owner';
|
||||
if (name === 'repository') return 'some-repo';
|
||||
if (name === 'events') return ['push'];
|
||||
if (name === 'options') return { insecureSSL: false };
|
||||
}),
|
||||
getWorkflowStaticData: () => webhookData,
|
||||
getNode: () => ({}),
|
||||
};
|
||||
});
|
||||
|
||||
it('should return true and set webhookId and webhookSecret when creation succeeds', async () => {
|
||||
const createdWebhook = { id: '789', active: true };
|
||||
|
||||
jest.spyOn(GenericFunctions, 'githubApiRequest').mockResolvedValueOnce(createdWebhook);
|
||||
|
||||
const trigger = new GithubTrigger();
|
||||
const result = await trigger.webhookMethods.default.create.call(mockThis);
|
||||
|
||||
expect(result).toBe(true);
|
||||
expect(webhookData.webhookId).toBe('789');
|
||||
expect(webhookData.webhookSecret).toBeDefined();
|
||||
expect(typeof webhookData.webhookSecret).toBe('string');
|
||||
expect(webhookData.webhookSecret.length).toBe(64); // 32 bytes in hex
|
||||
});
|
||||
|
||||
it('should send the secret to GitHub API when creating webhook', async () => {
|
||||
const createdWebhook = { id: '789', active: true };
|
||||
|
||||
const apiRequestSpy = jest
|
||||
.spyOn(GenericFunctions, 'githubApiRequest')
|
||||
.mockResolvedValueOnce(createdWebhook);
|
||||
|
||||
const trigger = new GithubTrigger();
|
||||
await trigger.webhookMethods.default.create.call(mockThis);
|
||||
|
||||
expect(apiRequestSpy).toHaveBeenCalledWith(
|
||||
'POST',
|
||||
'/repos/some-owner/some-repo/hooks',
|
||||
expect.objectContaining({
|
||||
config: expect.objectContaining({
|
||||
secret: expect.any(String),
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle 422 by checking for existing matching webhook (no secret stored)', async () => {
|
||||
const existingWebhook = {
|
||||
id: '123',
|
||||
events: ['push'],
|
||||
config: { url: 'https://example.com/webhook' },
|
||||
};
|
||||
|
||||
jest
|
||||
.spyOn(GenericFunctions, 'githubApiRequest')
|
||||
.mockRejectedValueOnce({ httpCode: '422' }) // POST fails
|
||||
.mockResolvedValueOnce([existingWebhook]); // GET returns matching
|
||||
|
||||
const trigger = new GithubTrigger();
|
||||
const result = await trigger.webhookMethods.default.create.call(mockThis);
|
||||
|
||||
expect(result).toBe(true);
|
||||
expect(webhookData.webhookId).toBe('123');
|
||||
// Existing webhook won't have secret stored (backwards compatibility)
|
||||
expect(webhookData.webhookSecret).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should throw NodeOperationError if repo is not found (404)', async () => {
|
||||
jest.spyOn(GenericFunctions, 'githubApiRequest').mockRejectedValue({ httpCode: '404' });
|
||||
|
||||
const trigger = new GithubTrigger();
|
||||
|
||||
await expect(trigger.webhookMethods.default.create.call(mockThis)).rejects.toThrow(
|
||||
NodeOperationError,
|
||||
);
|
||||
|
||||
await expect(trigger.webhookMethods.default.create.call(mockThis)).rejects.toThrow(
|
||||
/Check that the repository exists/,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('delete webhook method', () => {
|
||||
let webhookData: Record<string, any>;
|
||||
let mockThis: any;
|
||||
|
||||
beforeEach(() => {
|
||||
webhookData = {
|
||||
webhookId: '123456',
|
||||
webhookEvents: ['push'],
|
||||
webhookSecret: 'test-secret',
|
||||
};
|
||||
|
||||
mockThis = {
|
||||
getWorkflowStaticData: () => webhookData,
|
||||
getNodeParameter: jest.fn().mockImplementation((name: string) => {
|
||||
if (name === 'owner') return 'some-owner';
|
||||
if (name === 'repository') return 'some-repo';
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
it('should delete webhook data including secret when deletion succeeds', async () => {
|
||||
jest.spyOn(GenericFunctions, 'githubApiRequest').mockResolvedValueOnce({});
|
||||
|
||||
const trigger = new GithubTrigger();
|
||||
const result = await trigger.webhookMethods.default.delete.call(mockThis);
|
||||
|
||||
expect(result).toBe(true);
|
||||
expect(webhookData.webhookId).toBeUndefined();
|
||||
expect(webhookData.webhookEvents).toBeUndefined();
|
||||
expect(webhookData.webhookSecret).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('webhook method', () => {
|
||||
let mockThis: any;
|
||||
let webhookData: Record<string, any>;
|
||||
|
||||
beforeEach(() => {
|
||||
webhookData = {
|
||||
webhookSecret: 'test-secret',
|
||||
};
|
||||
|
||||
mockThis = {
|
||||
getWorkflowStaticData: () => webhookData,
|
||||
getBodyData: jest.fn().mockReturnValue({ action: 'opened' }),
|
||||
getHeaderData: jest.fn().mockReturnValue({}),
|
||||
getQueryData: jest.fn().mockReturnValue({}),
|
||||
getResponseObject: jest.fn().mockReturnValue({
|
||||
status: jest.fn().mockReturnThis(),
|
||||
send: jest.fn().mockReturnThis(),
|
||||
end: jest.fn(),
|
||||
}),
|
||||
getRequestObject: jest.fn().mockReturnValue({
|
||||
header: jest.fn(),
|
||||
rawBody: '{}',
|
||||
}),
|
||||
helpers: {
|
||||
returnJsonArray: jest.fn().mockImplementation((data) => data),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
it('should reject with 401 when signature verification fails', async () => {
|
||||
jest.spyOn(GithubTriggerHelpers, 'verifySignature').mockReturnValueOnce(false);
|
||||
|
||||
const trigger = new GithubTrigger();
|
||||
const result = await trigger.webhook.call(mockThis);
|
||||
|
||||
expect(result).toEqual({ noWebhookResponse: true });
|
||||
expect(mockThis.getResponseObject).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should process webhook when signature verification succeeds', async () => {
|
||||
jest.spyOn(GithubTriggerHelpers, 'verifySignature').mockReturnValueOnce(true);
|
||||
|
||||
const trigger = new GithubTrigger();
|
||||
const result = await trigger.webhook.call(mockThis);
|
||||
|
||||
expect(result).toHaveProperty('workflowData');
|
||||
});
|
||||
|
||||
it('should return OK for ping events when signature verification succeeds', async () => {
|
||||
jest.spyOn(GithubTriggerHelpers, 'verifySignature').mockReturnValueOnce(true);
|
||||
mockThis.getBodyData.mockReturnValue({ hook_id: '123' });
|
||||
|
||||
const trigger = new GithubTrigger();
|
||||
const result = await trigger.webhook.call(mockThis);
|
||||
|
||||
expect(result).toEqual({ webhookResponse: 'OK' });
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user