From 6379ce53a93626dd728573eaa3db6614caf0484c Mon Sep 17 00:00:00 2001 From: lukyn76 Date: Fri, 29 Aug 2025 06:55:07 +0200 Subject: [PATCH] fix(GithubTrigger Node): Correctly access httpCode from error object (#17697) Co-authored-by: Your Name --- .../nodes/Github/GithubTrigger.node.ts | 6 +- .../__tests__/node/GithubTrigger.node.test.ts | 101 ++++++++++++++++++ 2 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 packages/nodes-base/nodes/Github/__tests__/node/GithubTrigger.node.test.ts diff --git a/packages/nodes-base/nodes/Github/GithubTrigger.node.ts b/packages/nodes-base/nodes/Github/GithubTrigger.node.ts index 4aebf11361..9e63ed859c 100644 --- a/packages/nodes-base/nodes/Github/GithubTrigger.node.ts +++ b/packages/nodes-base/nodes/Github/GithubTrigger.node.ts @@ -474,7 +474,7 @@ export class GithubTrigger implements INodeType { try { await githubApiRequest.call(this, 'GET', endpoint, {}); } catch (error) { - if (error.cause.httpCode === '404') { + if (error.httpCode === '404') { // Webhook does not exist delete webhookData.webhookId; delete webhookData.webhookEvents; @@ -524,7 +524,7 @@ export class GithubTrigger implements INodeType { try { responseData = await githubApiRequest.call(this, 'POST', endpoint, body); } catch (error) { - if (error.cause.httpCode === '422') { + if (error.httpCode === '422') { // Webhook exists already // Get the data of the already registered webhook @@ -550,7 +550,7 @@ export class GithubTrigger implements INodeType { ); } - if (error.cause.httpCode === '404') { + if (error.httpCode === '404') { throw new NodeOperationError( this.getNode(), 'Check that the repository exists and that you have permission to create the webhooks this node requires', diff --git a/packages/nodes-base/nodes/Github/__tests__/node/GithubTrigger.node.test.ts b/packages/nodes-base/nodes/Github/__tests__/node/GithubTrigger.node.test.ts new file mode 100644 index 0000000000..cf66676963 --- /dev/null +++ b/packages/nodes-base/nodes/Github/__tests__/node/GithubTrigger.node.test.ts @@ -0,0 +1,101 @@ +import { GithubTrigger } from '../../GithubTrigger.node'; +import * as GenericFunctions from '../../GenericFunctions'; +import { NodeOperationError } from 'n8n-workflow'; + +describe('GithubTrigger Node', () => { + describe('checkExists webhook method', () => { + let webhookData: Record; + 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; + + 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 when creation succeeds', async () => { + const createdWebhook = { id: '789', active: true }; + + jest.spyOn(GenericFunctions, 'githubApiRequest').mockResolvedValueOnce(createdWebhook); // Simulate successful POST + + const trigger = new GithubTrigger(); + const result = await trigger.webhookMethods.default.create.call(mockThis); + + expect(result).toBe(true); + expect(webhookData.webhookId).toBe('789'); + }); + + it('should handle 422 by checking for existing matching webhook', 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'); + }); + + 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/, + ); + }); + }); +});