From 767576d5ad4827cca851b2bda21a7ff122a93b5f Mon Sep 17 00:00:00 2001 From: Shireen Missi <94372015+ShireenMissi@users.noreply.github.com> Date: Tue, 27 May 2025 09:43:20 +0100 Subject: [PATCH] test(Slack Node): Add tests for SlackV1 node (no-changelog) (#15699) --- .../Slack/test/v1/GenericFunctions.test.ts | 161 ++++++++++++++++++ .../Slack/test/v1/node/channel/create.test.ts | 53 ++++++ .../test/v1/node/channel/create.workflow.json | 111 ++++++++++++ .../Slack/test/v1/node/message/post.test.ts | 50 ++++++ .../test/v1/node/message/post.workflow.json | 110 ++++++++++++ 5 files changed, 485 insertions(+) create mode 100644 packages/nodes-base/nodes/Slack/test/v1/GenericFunctions.test.ts create mode 100644 packages/nodes-base/nodes/Slack/test/v1/node/channel/create.test.ts create mode 100644 packages/nodes-base/nodes/Slack/test/v1/node/channel/create.workflow.json create mode 100644 packages/nodes-base/nodes/Slack/test/v1/node/message/post.test.ts create mode 100644 packages/nodes-base/nodes/Slack/test/v1/node/message/post.workflow.json diff --git a/packages/nodes-base/nodes/Slack/test/v1/GenericFunctions.test.ts b/packages/nodes-base/nodes/Slack/test/v1/GenericFunctions.test.ts new file mode 100644 index 0000000000..7ab20958b8 --- /dev/null +++ b/packages/nodes-base/nodes/Slack/test/v1/GenericFunctions.test.ts @@ -0,0 +1,161 @@ +import type { IExecuteFunctions } from 'n8n-workflow'; + +import { slackApiRequest, slackApiRequestAllItems, validateJSON } from '../../V1/GenericFunctions'; + +jest.mock('n8n-workflow', () => ({ + ...jest.requireActual('n8n-workflow'), + NodeApiError: jest.fn(), +})); + +describe('Slack V1 > GenericFunctions', () => { + let mockExecuteFunctions: IExecuteFunctions; + + beforeEach(() => { + jest.clearAllMocks(); + mockExecuteFunctions = { + helpers: { + requestWithAuthentication: jest.fn(), + }, + getNode: jest.fn().mockReturnValue({ type: 'n8n-nodes-base.slack', typeVersion: 1 }), + getNodeParameter: jest.fn().mockReturnValue('accessToken'), + } as unknown as IExecuteFunctions; + }); + + describe('slackApiRequest', () => { + it('should handle successful response', async () => { + const mockResponse = { ok: true, data: 'testData' }; + mockExecuteFunctions.helpers.requestWithAuthentication = jest + .fn() + .mockResolvedValue(mockResponse); + + const result = await slackApiRequest.call(mockExecuteFunctions, 'GET', '/test'); + expect(result).toEqual(mockResponse); + }); + + it('should use OAuth2 credentials when authentication is oAuth2', async () => { + mockExecuteFunctions.getNodeParameter = jest.fn().mockReturnValue('oAuth2'); + const mockResponse = { ok: true }; + mockExecuteFunctions.helpers.requestWithAuthentication = jest + .fn() + .mockResolvedValue(mockResponse); + + await slackApiRequest.call(mockExecuteFunctions, 'GET', '/test'); + + expect(mockExecuteFunctions.helpers.requestWithAuthentication).toHaveBeenCalledWith( + 'slackOAuth2Api', + expect.any(Object), + expect.objectContaining({ + oauth2: expect.any(Object), + }), + ); + }); + }); + + describe('slackApiRequestAllItems', () => { + it('should use default limit of 100 when no limit is provided', async () => { + const mockResponse = { + ok: true, + channels: [{ id: 'ch1' }], + response_metadata: { next_cursor: undefined }, + }; + + mockExecuteFunctions.helpers.requestWithAuthentication = jest + .fn() + .mockResolvedValue(mockResponse); + + await slackApiRequestAllItems.bind(mockExecuteFunctions)( + 'channels', + 'GET', + 'conversations.list', + ); + + expect(mockExecuteFunctions.helpers.requestWithAuthentication).toHaveBeenCalledWith( + 'slackApi', + expect.objectContaining({ + headers: expect.any(Object), + qs: { + limit: 100, + page: 2, + cursor: undefined, + }, + json: true, + method: 'GET', + uri: expect.any(String), + }), + expect.any(Object), + ); + }); + + it('should use count instead of limit for files.list endpoint', async () => { + const mockResponse = { + ok: true, + files: [{ id: 'file1' }], + response_metadata: { next_cursor: undefined }, + }; + + mockExecuteFunctions.helpers.requestWithAuthentication = jest + .fn() + .mockResolvedValue(mockResponse); + + await slackApiRequestAllItems.call(mockExecuteFunctions, 'files', 'GET', 'files.list'); + + expect(mockExecuteFunctions.helpers.requestWithAuthentication).toHaveBeenCalledWith( + 'slackApi', + expect.objectContaining({ + headers: expect.any(Object), + qs: { + count: 100, + page: 2, + cursor: undefined, + }, + json: true, + method: 'GET', + uri: expect.any(String), + }), + expect.any(Object), + ); + }); + + it('should handle pagination with response_metadata next_cursor', async () => { + const responses = [ + { + ok: true, + channels: [{ id: '1' }], + response_metadata: { next_cursor: 'cursor1' }, + }, + { + ok: true, + channels: [{ id: '2' }], + response_metadata: { next_cursor: '' }, + }, + ]; + + mockExecuteFunctions.helpers.requestWithAuthentication = jest + .fn() + .mockImplementationOnce(() => responses[0]) + .mockImplementationOnce(() => responses[1]); + + const result = await slackApiRequestAllItems.call( + mockExecuteFunctions, + 'channels', + 'GET', + 'conversations.list', + ); + + expect(result).toEqual([{ id: '1' }, { id: '2' }]); + expect(mockExecuteFunctions.helpers.requestWithAuthentication).toHaveBeenCalledTimes(2); + }); + }); + + describe('validateJSON', () => { + it('should return undefined for invalid JSON', () => { + const result = validateJSON('{invalid:json}'); + expect(result).toBeUndefined(); + }); + + it('should return parsed object for valid JSON', () => { + const result = validateJSON('{"key":"value"}'); + expect(result).toEqual({ key: 'value' }); + }); + }); +}); diff --git a/packages/nodes-base/nodes/Slack/test/v1/node/channel/create.test.ts b/packages/nodes-base/nodes/Slack/test/v1/node/channel/create.test.ts new file mode 100644 index 0000000000..46d404cc58 --- /dev/null +++ b/packages/nodes-base/nodes/Slack/test/v1/node/channel/create.test.ts @@ -0,0 +1,53 @@ +import { NodeTestHarness } from '@nodes-testing/node-test-harness'; +import nock from 'nock'; + +const API_RESPONSE = { + ok: true, + channel: { + id: 'C085WNEHP4Y', + name: 'test-channel', + is_channel: true, + is_group: false, + is_im: false, + is_mpim: false, + is_private: false, + created: 1734325731, + is_archived: false, + is_general: false, + unlinked: 0, + name_normalized: 'test-channel', + is_shared: false, + is_org_shared: false, + is_pending_ext_shared: false, + pending_shared: [], + context_team_id: 'T0364MSFHV2', + creator: 'U0362BXQYJW', + is_ext_shared: false, + shared_team_ids: ['T0364MSFHV2'], + pending_connected_team_ids: [], + is_member: true, + topic: { + value: '', + creator: '', + last_set: 0, + }, + purpose: { + value: '', + creator: '', + last_set: 0, + }, + }, +}; + +describe('Test SlackV1, channel => create', () => { + const slackNock = nock('https://slack.com') + .post('/api/conversations.create', { + name: 'test-channel', + }) + .reply(200, API_RESPONSE); + + afterAll(() => slackNock.done()); + new NodeTestHarness().setupTests({ + workflowFiles: ['create.workflow.json'], + }); +}); diff --git a/packages/nodes-base/nodes/Slack/test/v1/node/channel/create.workflow.json b/packages/nodes-base/nodes/Slack/test/v1/node/channel/create.workflow.json new file mode 100644 index 0000000000..7c4a71ba01 --- /dev/null +++ b/packages/nodes-base/nodes/Slack/test/v1/node/channel/create.workflow.json @@ -0,0 +1,111 @@ +{ + "name": "slack tests", + "nodes": [ + { + "parameters": {}, + "id": "e679c883-1839-47dc-9511-8f7dc370e6b0", + "name": "When clicking 'Test workflow'", + "type": "n8n-nodes-base.manualTrigger", + "typeVersion": 1, + "position": [820, 360] + }, + { + "parameters": { + "authentication": "accessToken", + "resource": "channel", + "operation": "create", + "channelId": "test-channel", + "additionalFields": { + "isPrivate": false + } + }, + "id": "2e1937a6-4c8f-4cd1-ae42-11b2bd12cc4c", + "name": "Slack", + "type": "n8n-nodes-base.slack", + "typeVersion": 1, + "position": [1040, 360], + "credentials": { + "slackApi": { + "id": "Bg0bWXf8apAimCqJ", + "name": "Slack account 2" + } + } + }, + { + "parameters": {}, + "id": "06652908-6b8e-443a-9508-ab229b011b73", + "name": "No Operation, do nothing", + "type": "n8n-nodes-base.noOp", + "typeVersion": 1, + "position": [1260, 360] + } + ], + "pinData": { + "No Operation, do nothing": [ + { + "json": { + "id": "C085WNEHP4Y", + "name": "test-channel", + "is_channel": true, + "is_group": false, + "is_im": false, + "is_mpim": false, + "is_private": false, + "created": 1734325731, + "is_archived": false, + "is_general": false, + "unlinked": 0, + "name_normalized": "test-channel", + "is_shared": false, + "is_org_shared": false, + "is_pending_ext_shared": false, + "pending_shared": [], + "context_team_id": "T0364MSFHV2", + "creator": "U0362BXQYJW", + "is_ext_shared": false, + "shared_team_ids": ["T0364MSFHV2"], + "pending_connected_team_ids": [], + "is_member": true, + "topic": { + "value": "", + "creator": "", + "last_set": 0 + }, + "purpose": { + "value": "", + "creator": "", + "last_set": 0 + } + } + } + ] + }, + "connections": { + "When clicking 'Test workflow'": { + "main": [ + [ + { + "node": "Slack", + "type": "main", + "index": 0 + } + ] + ] + }, + "Slack": { + "main": [ + [ + { + "node": "No Operation, do nothing", + "type": "main", + "index": 0 + } + ] + ] + } + }, + "active": false, + "settings": { + "executionOrder": "v1" + } +} diff --git a/packages/nodes-base/nodes/Slack/test/v1/node/message/post.test.ts b/packages/nodes-base/nodes/Slack/test/v1/node/message/post.test.ts new file mode 100644 index 0000000000..d0a9339829 --- /dev/null +++ b/packages/nodes-base/nodes/Slack/test/v1/node/message/post.test.ts @@ -0,0 +1,50 @@ +import { NodeTestHarness } from '@nodes-testing/node-test-harness'; +import nock from 'nock'; + +const API_RESPONSE = { + ok: true, + channel: 'C08514ZPKB8', + message: { + user: 'U0362BXQYJW', + type: 'message', + ts: '1734322671.726339', + bot_id: 'B0382SHFM46', + app_id: 'A037UTP0Z39', + text: 'test message', + team: 'T0364MSFHV2', + bot_profile: { + id: 'B0382SHFM46', + app_id: 'A037UTP0Z39', + name: 'blocks-test', + icons: { + image_36: 'https://a.slack-edge.com/80588/img/plugins/app/bot_36.png', + image_48: 'https://a.slack-edge.com/80588/img/plugins/app/bot_48.png', + image_72: 'https://a.slack-edge.com/80588/img/plugins/app/service_72.png', + }, + deleted: false, + updated: 1648028754, + team_id: 'T0364MSFHV2', + }, + }, + message_timestamp: '1734322671.726339', +}; + +describe('Test SlackV1, message => post', () => { + const slackNock = nock('https://slack.com') + .post('/api/chat.postMessage', { + channel: 'C08514ZPKB8', + text: 'test message', + attachments: [], + icon_emoji: '😁', + link_names: true, + mrkdwn: true, + unfurl_links: true, + unfurl_media: true, + }) + .reply(200, API_RESPONSE); + + afterAll(() => slackNock.done()); + new NodeTestHarness().setupTests({ + workflowFiles: ['post.workflow.json'], + }); +}); diff --git a/packages/nodes-base/nodes/Slack/test/v1/node/message/post.workflow.json b/packages/nodes-base/nodes/Slack/test/v1/node/message/post.workflow.json new file mode 100644 index 0000000000..f3e54c86ec --- /dev/null +++ b/packages/nodes-base/nodes/Slack/test/v1/node/message/post.workflow.json @@ -0,0 +1,110 @@ +{ + "name": "slack tests", + "nodes": [ + { + "parameters": {}, + "id": "e679c883-1839-47dc-9511-8f7dc370e6b0", + "name": "When clicking 'Test workflow'", + "type": "n8n-nodes-base.manualTrigger", + "typeVersion": 1, + "position": [820, 360] + }, + { + "parameters": { + "authentication": "accessToken", + "resource": "message", + "operation": "post", + "channel": "C08514ZPKB8", + "text": "test message", + "otherOptions": { + "icon_emoji": "😁", + "link_names": true, + "mrkdwn": true, + "unfurl_links": true, + "unfurl_media": true + }, + "jsonParameters": false + }, + "id": "2e1937a6-4c8f-4cd1-ae42-11b2bd12cc4c", + "name": "Slack", + "type": "n8n-nodes-base.slack", + "typeVersion": 1, + "position": [1040, 360], + "credentials": { + "slackApi": { + "id": "Bg0bWXf8apAimCqJ", + "name": "Slack account 2" + } + } + }, + { + "parameters": {}, + "id": "06652908-6b8e-443a-9508-ab229b011b73", + "name": "No Operation, do nothing", + "type": "n8n-nodes-base.noOp", + "typeVersion": 1, + "position": [1260, 360] + } + ], + "pinData": { + "No Operation, do nothing": [ + { + "json": { + "ok": true, + "channel": "C08514ZPKB8", + "message": { + "user": "U0362BXQYJW", + "type": "message", + "ts": "1734322671.726339", + "bot_id": "B0382SHFM46", + "app_id": "A037UTP0Z39", + "text": "test message", + "team": "T0364MSFHV2", + "bot_profile": { + "id": "B0382SHFM46", + "app_id": "A037UTP0Z39", + "name": "blocks-test", + "icons": { + "image_36": "https://a.slack-edge.com/80588/img/plugins/app/bot_36.png", + "image_48": "https://a.slack-edge.com/80588/img/plugins/app/bot_48.png", + "image_72": "https://a.slack-edge.com/80588/img/plugins/app/service_72.png" + }, + "deleted": false, + "updated": 1648028754, + "team_id": "T0364MSFHV2" + } + }, + "message_timestamp": "1734322671.726339" + } + } + ] + }, + "connections": { + "When clicking 'Test workflow'": { + "main": [ + [ + { + "node": "Slack", + "type": "main", + "index": 0 + } + ] + ] + }, + "Slack": { + "main": [ + [ + { + "node": "No Operation, do nothing", + "type": "main", + "index": 0 + } + ] + ] + } + }, + "active": false, + "settings": { + "executionOrder": "v1" + } +}