mirror of
https://github.com/n8n-io/n8n.git
synced 2026-06-01 09:17:08 +02:00
711 lines
21 KiB
TypeScript
711 lines
21 KiB
TypeScript
import { mock } from 'jest-mock-extended';
|
|
import type { IWebhookFunctions, INodeType } from 'n8n-workflow';
|
|
|
|
import { SlackTrigger } from '../SlackTrigger.node';
|
|
|
|
// Mock the helper functions
|
|
jest.mock('../SlackTriggerHelpers', () => ({
|
|
verifySignature: jest.fn().mockResolvedValue(true),
|
|
getChannelInfo: jest.fn().mockResolvedValue({ id: 'C123', name: 'test-channel' }),
|
|
getUserInfo: jest.fn().mockResolvedValue({ id: 'U123', name: 'test-user' }),
|
|
downloadFile: jest.fn().mockResolvedValue(Buffer.from('test file content')),
|
|
}));
|
|
|
|
describe('SlackTrigger Node', () => {
|
|
let slackTrigger: INodeType;
|
|
let mockWebhookFunctions: ReturnType<typeof mock<IWebhookFunctions>>;
|
|
|
|
beforeEach(() => {
|
|
jest.clearAllMocks();
|
|
slackTrigger = new SlackTrigger();
|
|
mockWebhookFunctions = mock<IWebhookFunctions>();
|
|
|
|
// Mock helpers
|
|
mockWebhookFunctions.helpers = {
|
|
prepareBinaryData: jest.fn().mockResolvedValue({
|
|
data: 'binary-data',
|
|
mimeType: 'text/plain',
|
|
fileName: 'test.txt',
|
|
}),
|
|
} as any;
|
|
|
|
// Default mock setup
|
|
mockWebhookFunctions.getNodeParameter.mockImplementation(
|
|
(paramName: string, defaultValue?: any) => {
|
|
switch (paramName) {
|
|
case 'trigger':
|
|
return ['file_share'];
|
|
case 'watchWorkspace':
|
|
return false;
|
|
case 'channelId':
|
|
return 'C123';
|
|
case 'downloadFiles':
|
|
return false;
|
|
case 'options':
|
|
return {};
|
|
default:
|
|
return defaultValue;
|
|
}
|
|
},
|
|
);
|
|
|
|
mockWebhookFunctions.getResponseObject.mockReturnValue({
|
|
status: jest.fn().mockReturnThis(),
|
|
send: jest.fn().mockReturnThis(),
|
|
json: jest.fn().mockReturnThis(),
|
|
end: jest.fn(),
|
|
} as any);
|
|
});
|
|
|
|
describe('webhook method - eventChannel extraction', () => {
|
|
it('should extract eventChannel from req.body.event.channel when available', async () => {
|
|
const mockRequest = {
|
|
body: {
|
|
type: 'event_callback',
|
|
event: {
|
|
type: 'message',
|
|
channel: 'C123',
|
|
user: 'U456',
|
|
text: 'Hello world',
|
|
},
|
|
},
|
|
};
|
|
|
|
mockWebhookFunctions.getRequestObject.mockReturnValue(mockRequest as any);
|
|
|
|
const result = await slackTrigger.webhook!.call(mockWebhookFunctions);
|
|
|
|
expect(result.workflowData).toBeDefined();
|
|
expect(result.workflowData![0][0].json).toEqual(mockRequest.body.event);
|
|
});
|
|
|
|
it('should extract eventChannel from req.body.event.item.channel when event.channel is not available', async () => {
|
|
const mockRequest = {
|
|
body: {
|
|
type: 'event_callback',
|
|
event: {
|
|
type: 'reaction_added',
|
|
user: 'U456',
|
|
item: {
|
|
channel: 'C123',
|
|
ts: '1234567890.123456',
|
|
},
|
|
reaction: 'thumbsup',
|
|
},
|
|
},
|
|
};
|
|
|
|
mockWebhookFunctions.getRequestObject.mockReturnValue(mockRequest as any);
|
|
mockWebhookFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
switch (paramName) {
|
|
case 'trigger':
|
|
return ['reaction_added'];
|
|
case 'watchWorkspace':
|
|
return false;
|
|
case 'channelId':
|
|
return 'C123';
|
|
default:
|
|
return {};
|
|
}
|
|
});
|
|
|
|
const result = await slackTrigger.webhook!.call(mockWebhookFunctions);
|
|
|
|
expect(result.workflowData).toBeDefined();
|
|
expect(result.workflowData![0][0].json).toEqual(mockRequest.body.event);
|
|
});
|
|
|
|
it('should handle when req.body.event.item is undefined/null without throwing error', async () => {
|
|
const mockRequest = {
|
|
body: {
|
|
type: 'event_callback',
|
|
event: {
|
|
type: 'reaction_added',
|
|
user: 'U456',
|
|
item: null, // This could cause the original error
|
|
reaction: 'thumbsup',
|
|
channel_id: 'C123',
|
|
},
|
|
},
|
|
};
|
|
|
|
mockWebhookFunctions.getRequestObject.mockReturnValue(mockRequest as any);
|
|
mockWebhookFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
switch (paramName) {
|
|
case 'trigger':
|
|
return ['reaction_added'];
|
|
case 'watchWorkspace':
|
|
return false;
|
|
case 'channelId':
|
|
return 'C123';
|
|
default:
|
|
return {};
|
|
}
|
|
});
|
|
|
|
// This should not throw an error
|
|
const result = await slackTrigger.webhook!.call(mockWebhookFunctions);
|
|
|
|
expect(result.workflowData).toBeDefined();
|
|
expect(result.workflowData![0][0].json).toEqual(mockRequest.body.event);
|
|
});
|
|
|
|
it('should fallback to req.body.event.channel_id when channel and item.channel are not available', async () => {
|
|
const mockRequest = {
|
|
body: {
|
|
type: 'event_callback',
|
|
event: {
|
|
type: 'message',
|
|
user: 'U456',
|
|
text: 'Hello world',
|
|
channel_id: 'C123', // Fallback value
|
|
},
|
|
},
|
|
};
|
|
|
|
mockWebhookFunctions.getRequestObject.mockReturnValue(mockRequest as any);
|
|
|
|
const result = await slackTrigger.webhook!.call(mockWebhookFunctions);
|
|
|
|
expect(result.workflowData).toBeDefined();
|
|
expect(result.workflowData![0][0].json).toEqual(mockRequest.body.event);
|
|
});
|
|
|
|
it('should handle file_share event with undefined item gracefully', async () => {
|
|
const mockRequest = {
|
|
body: {
|
|
type: 'event_callback',
|
|
event: {
|
|
type: 'message',
|
|
subtype: 'file_share',
|
|
user: 'U456',
|
|
channel: 'C123',
|
|
files: [
|
|
{
|
|
id: 'F123',
|
|
name: 'test.txt',
|
|
url_private_download: 'https://files.slack.com/test.txt',
|
|
mimetype: 'text/plain',
|
|
},
|
|
],
|
|
},
|
|
},
|
|
};
|
|
|
|
mockWebhookFunctions.getRequestObject.mockReturnValue(mockRequest as any);
|
|
|
|
const result = await slackTrigger.webhook!.call(mockWebhookFunctions);
|
|
|
|
expect(result.workflowData).toBeDefined();
|
|
expect(result.workflowData![0][0].json).toEqual(mockRequest.body.event);
|
|
});
|
|
|
|
it('should handle complex event structure without throwing errors', async () => {
|
|
const mockRequest = {
|
|
body: {
|
|
type: 'event_callback',
|
|
event: {
|
|
type: 'app_mention',
|
|
user: 'U456',
|
|
text: '<@U123> hello there',
|
|
// No channel, item, or channel_id - edge case
|
|
},
|
|
},
|
|
};
|
|
|
|
mockWebhookFunctions.getRequestObject.mockReturnValue(mockRequest as any);
|
|
mockWebhookFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
switch (paramName) {
|
|
case 'trigger':
|
|
return ['app_mention'];
|
|
case 'watchWorkspace':
|
|
return true; // Watch whole workspace, so channel check should be skipped
|
|
default:
|
|
return {};
|
|
}
|
|
});
|
|
|
|
const result = await slackTrigger.webhook!.call(mockWebhookFunctions);
|
|
|
|
expect(result.workflowData).toBeDefined();
|
|
expect(result.workflowData![0][0].json).toEqual(mockRequest.body.event);
|
|
});
|
|
});
|
|
|
|
describe('webhook method - file_share event handling', () => {
|
|
it('should handle file_share event when item is undefined', async () => {
|
|
const mockRequest = {
|
|
body: {
|
|
type: 'event_callback',
|
|
event: {
|
|
type: 'message',
|
|
subtype: 'file_share',
|
|
user: 'U456',
|
|
channel: 'C123',
|
|
files: [
|
|
{
|
|
id: 'F123',
|
|
name: 'test.txt',
|
|
url_private_download: 'https://files.slack.com/test.txt',
|
|
mimetype: 'text/plain',
|
|
},
|
|
],
|
|
item: undefined, // This was causing the original error
|
|
},
|
|
},
|
|
};
|
|
|
|
mockWebhookFunctions.getRequestObject.mockReturnValue(mockRequest as any);
|
|
mockWebhookFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
switch (paramName) {
|
|
case 'trigger':
|
|
return ['file_share'];
|
|
case 'downloadFiles':
|
|
return true;
|
|
case 'watchWorkspace':
|
|
return false;
|
|
case 'channelId':
|
|
return 'C123';
|
|
default:
|
|
return {};
|
|
}
|
|
});
|
|
|
|
const result = await slackTrigger.webhook!.call(mockWebhookFunctions);
|
|
|
|
expect(result.workflowData).toBeDefined();
|
|
expect(result.workflowData![0][0].json).toEqual(mockRequest.body.event);
|
|
expect(result.workflowData![0][0].binary).toBeDefined();
|
|
});
|
|
|
|
it('should handle file_share event when item is null', async () => {
|
|
const mockRequest = {
|
|
body: {
|
|
type: 'event_callback',
|
|
event: {
|
|
type: 'message',
|
|
subtype: 'file_share',
|
|
user: 'U456',
|
|
channel: 'C123',
|
|
files: [
|
|
{
|
|
id: 'F123',
|
|
name: 'test.txt',
|
|
url_private_download: 'https://files.slack.com/test.txt',
|
|
mimetype: 'text/plain',
|
|
},
|
|
],
|
|
item: null, // Another potential error case
|
|
},
|
|
},
|
|
};
|
|
|
|
mockWebhookFunctions.getRequestObject.mockReturnValue(mockRequest as any);
|
|
mockWebhookFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
switch (paramName) {
|
|
case 'trigger':
|
|
return ['file_share'];
|
|
case 'downloadFiles':
|
|
return false;
|
|
case 'watchWorkspace':
|
|
return false;
|
|
case 'channelId':
|
|
return 'C123';
|
|
default:
|
|
return {};
|
|
}
|
|
});
|
|
|
|
const result = await slackTrigger.webhook!.call(mockWebhookFunctions);
|
|
|
|
expect(result.workflowData).toBeDefined();
|
|
expect(result.workflowData![0][0].json).toEqual(mockRequest.body.event);
|
|
});
|
|
|
|
it('should handle file_share event with valid item.channel', async () => {
|
|
const mockRequest = {
|
|
body: {
|
|
type: 'event_callback',
|
|
event: {
|
|
type: 'message',
|
|
subtype: 'file_share',
|
|
user: 'U456',
|
|
files: [
|
|
{
|
|
id: 'F123',
|
|
name: 'test.txt',
|
|
url_private_download: 'https://files.slack.com/test.txt',
|
|
mimetype: 'text/plain',
|
|
},
|
|
],
|
|
item: {
|
|
channel: 'C123',
|
|
ts: '1234567890.123456',
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
mockWebhookFunctions.getRequestObject.mockReturnValue(mockRequest as any);
|
|
mockWebhookFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
switch (paramName) {
|
|
case 'trigger':
|
|
return ['file_share'];
|
|
case 'downloadFiles':
|
|
return false;
|
|
case 'watchWorkspace':
|
|
return false;
|
|
case 'channelId':
|
|
return 'C123';
|
|
default:
|
|
return {};
|
|
}
|
|
});
|
|
|
|
const result = await slackTrigger.webhook!.call(mockWebhookFunctions);
|
|
|
|
expect(result.workflowData).toBeDefined();
|
|
expect(result.workflowData![0][0].json).toEqual(mockRequest.body.event);
|
|
});
|
|
});
|
|
|
|
describe('webhook method - user ignore list', () => {
|
|
const getMessageEvent = (overrides: Record<string, unknown> = {}) => ({
|
|
body: {
|
|
type: 'event_callback',
|
|
event: {
|
|
type: 'message',
|
|
channel: 'C123',
|
|
text: 'Hello world',
|
|
...overrides,
|
|
},
|
|
},
|
|
});
|
|
|
|
beforeEach(() => {
|
|
mockWebhookFunctions.getNodeParameter.mockImplementation(
|
|
(paramName: string, defaultValue?: any) => {
|
|
switch (paramName) {
|
|
case 'trigger':
|
|
return ['message'];
|
|
case 'watchWorkspace':
|
|
return false;
|
|
case 'channelId':
|
|
return 'C123';
|
|
case 'downloadFiles':
|
|
return false;
|
|
case 'options':
|
|
return { userIds: ['U_IGNORED'] };
|
|
default:
|
|
return defaultValue;
|
|
}
|
|
},
|
|
);
|
|
});
|
|
|
|
it('should ignore event when event.user matches an ignored user', async () => {
|
|
mockWebhookFunctions.getRequestObject.mockReturnValue(
|
|
getMessageEvent({ user: 'U_IGNORED' }) as any,
|
|
);
|
|
|
|
const result = await slackTrigger.webhook!.call(mockWebhookFunctions);
|
|
|
|
expect(result).toEqual({});
|
|
});
|
|
|
|
it('should ignore event when event.user is undefined but event.message.user matches an ignored user', async () => {
|
|
mockWebhookFunctions.getRequestObject.mockReturnValue(
|
|
getMessageEvent({ user: undefined, message: { user: 'U_IGNORED' } }) as any,
|
|
);
|
|
|
|
const result = await slackTrigger.webhook!.call(mockWebhookFunctions);
|
|
|
|
expect(result).toEqual({});
|
|
});
|
|
|
|
it('should not ignore event when event.user does not match any ignored user', async () => {
|
|
mockWebhookFunctions.getRequestObject.mockReturnValue(
|
|
getMessageEvent({ user: 'U_SOMEONE_ELSE' }) as any,
|
|
);
|
|
|
|
const result = await slackTrigger.webhook!.call(mockWebhookFunctions);
|
|
|
|
expect(result.workflowData).toBeDefined();
|
|
});
|
|
|
|
it('should not ignore event when both event.user and event.message.user are absent from the ignore list', async () => {
|
|
mockWebhookFunctions.getRequestObject.mockReturnValue(
|
|
getMessageEvent({ user: undefined, message: { user: 'U_SOMEONE_ELSE' } }) as any,
|
|
);
|
|
|
|
const result = await slackTrigger.webhook!.call(mockWebhookFunctions);
|
|
|
|
expect(result.workflowData).toBeDefined();
|
|
});
|
|
|
|
it('should not ignore event when neither event.user nor event.message.user exist', async () => {
|
|
mockWebhookFunctions.getRequestObject.mockReturnValue(
|
|
getMessageEvent({ user: undefined }) as any,
|
|
);
|
|
|
|
const result = await slackTrigger.webhook!.call(mockWebhookFunctions);
|
|
|
|
expect(result.workflowData).toBeDefined();
|
|
});
|
|
|
|
it('should use event.user over event.message.user when both are present', async () => {
|
|
mockWebhookFunctions.getRequestObject.mockReturnValue(
|
|
getMessageEvent({ user: 'U_SOMEONE_ELSE', message: { user: 'U_IGNORED' } }) as any,
|
|
);
|
|
|
|
const result = await slackTrigger.webhook!.call(mockWebhookFunctions);
|
|
|
|
expect(result.workflowData).toBeDefined();
|
|
});
|
|
});
|
|
|
|
describe('webhook method - reaction emoji filter', () => {
|
|
const reactionRequest = (reaction: string) => ({
|
|
body: {
|
|
type: 'event_callback',
|
|
event: {
|
|
type: 'reaction_added',
|
|
user: 'U456',
|
|
item: { channel: 'C123', ts: '1234567890.123456' },
|
|
reaction,
|
|
},
|
|
},
|
|
});
|
|
|
|
beforeEach(() => {
|
|
mockWebhookFunctions.getNodeParameter.mockImplementation(
|
|
(paramName: string, defaultValue?: any) => {
|
|
switch (paramName) {
|
|
case 'trigger':
|
|
return ['reaction_added'];
|
|
case 'watchWorkspace':
|
|
return false;
|
|
case 'channelId':
|
|
return 'C123';
|
|
case 'downloadFiles':
|
|
return false;
|
|
case 'options':
|
|
return {};
|
|
default:
|
|
return defaultValue;
|
|
}
|
|
},
|
|
);
|
|
});
|
|
|
|
it('should trigger when no emoji filter is set', async () => {
|
|
mockWebhookFunctions.getRequestObject.mockReturnValue(reactionRequest('thumbsup') as any);
|
|
|
|
const result = await slackTrigger.webhook!.call(mockWebhookFunctions);
|
|
|
|
expect(result.workflowData).toBeDefined();
|
|
});
|
|
|
|
it('should trigger when reaction matches the filter', async () => {
|
|
mockWebhookFunctions.getRequestObject.mockReturnValue(reactionRequest('thumbsup') as any);
|
|
mockWebhookFunctions.getNodeParameter.mockImplementation(
|
|
(paramName: string, defaultValue?: any) => {
|
|
if (paramName === 'options') return { reactionEmojis: 'thumbsup' };
|
|
if (paramName === 'trigger') return ['reaction_added'];
|
|
if (paramName === 'watchWorkspace') return false;
|
|
if (paramName === 'channelId') return 'C123';
|
|
return defaultValue;
|
|
},
|
|
);
|
|
|
|
const result = await slackTrigger.webhook!.call(mockWebhookFunctions);
|
|
|
|
expect(result.workflowData).toBeDefined();
|
|
});
|
|
|
|
it('should not trigger when reaction does not match the filter', async () => {
|
|
mockWebhookFunctions.getRequestObject.mockReturnValue(reactionRequest('eyes') as any);
|
|
mockWebhookFunctions.getNodeParameter.mockImplementation(
|
|
(paramName: string, defaultValue?: any) => {
|
|
if (paramName === 'options') return { reactionEmojis: 'thumbsup' };
|
|
if (paramName === 'trigger') return ['reaction_added'];
|
|
if (paramName === 'watchWorkspace') return false;
|
|
if (paramName === 'channelId') return 'C123';
|
|
return defaultValue;
|
|
},
|
|
);
|
|
|
|
const result = await slackTrigger.webhook!.call(mockWebhookFunctions);
|
|
|
|
expect(result).toEqual({});
|
|
});
|
|
|
|
it('should support multiple comma-separated emoji names', async () => {
|
|
mockWebhookFunctions.getRequestObject.mockReturnValue(reactionRequest('eyes') as any);
|
|
mockWebhookFunctions.getNodeParameter.mockImplementation(
|
|
(paramName: string, defaultValue?: any) => {
|
|
if (paramName === 'options') return { reactionEmojis: 'thumbsup, eyes' };
|
|
if (paramName === 'trigger') return ['reaction_added'];
|
|
if (paramName === 'watchWorkspace') return false;
|
|
if (paramName === 'channelId') return 'C123';
|
|
return defaultValue;
|
|
},
|
|
);
|
|
|
|
const result = await slackTrigger.webhook!.call(mockWebhookFunctions);
|
|
|
|
expect(result.workflowData).toBeDefined();
|
|
});
|
|
|
|
it('should match emoji names case-insensitively', async () => {
|
|
mockWebhookFunctions.getRequestObject.mockReturnValue(reactionRequest('thumbsup') as any);
|
|
mockWebhookFunctions.getNodeParameter.mockImplementation(
|
|
(paramName: string, defaultValue?: any) => {
|
|
if (paramName === 'options') return { reactionEmojis: 'ThumbsUp' };
|
|
if (paramName === 'trigger') return ['reaction_added'];
|
|
if (paramName === 'watchWorkspace') return false;
|
|
if (paramName === 'channelId') return 'C123';
|
|
return defaultValue;
|
|
},
|
|
);
|
|
|
|
const result = await slackTrigger.webhook!.call(mockWebhookFunctions);
|
|
|
|
expect(result.workflowData).toBeDefined();
|
|
});
|
|
|
|
it('should trim whitespace around emoji names', async () => {
|
|
mockWebhookFunctions.getRequestObject.mockReturnValue(reactionRequest('thumbsup') as any);
|
|
mockWebhookFunctions.getNodeParameter.mockImplementation(
|
|
(paramName: string, defaultValue?: any) => {
|
|
if (paramName === 'options') return { reactionEmojis: ' thumbsup , eyes ' };
|
|
if (paramName === 'trigger') return ['reaction_added'];
|
|
if (paramName === 'watchWorkspace') return false;
|
|
if (paramName === 'channelId') return 'C123';
|
|
return defaultValue;
|
|
},
|
|
);
|
|
|
|
const result = await slackTrigger.webhook!.call(mockWebhookFunctions);
|
|
|
|
expect(result.workflowData).toBeDefined();
|
|
});
|
|
|
|
it('should not trigger when filter has entries but reaction is an empty string', async () => {
|
|
mockWebhookFunctions.getRequestObject.mockReturnValue(reactionRequest('') as any);
|
|
mockWebhookFunctions.getNodeParameter.mockImplementation(
|
|
(paramName: string, defaultValue?: any) => {
|
|
if (paramName === 'options') return { reactionEmojis: 'thumbsup' };
|
|
if (paramName === 'trigger') return ['reaction_added'];
|
|
if (paramName === 'watchWorkspace') return false;
|
|
if (paramName === 'channelId') return 'C123';
|
|
return defaultValue;
|
|
},
|
|
);
|
|
|
|
const result = await slackTrigger.webhook!.call(mockWebhookFunctions);
|
|
|
|
expect(result).toEqual({});
|
|
});
|
|
});
|
|
|
|
describe('webhook method - other event scenarios', () => {
|
|
it('should handle team_join event (no channel extraction needed)', async () => {
|
|
const mockRequest = {
|
|
body: {
|
|
type: 'event_callback',
|
|
event: {
|
|
type: 'team_join',
|
|
user: {
|
|
id: 'U789',
|
|
name: 'newuser',
|
|
real_name: 'New User',
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
mockWebhookFunctions.getRequestObject.mockReturnValue(mockRequest as any);
|
|
|
|
let resolveIds = false;
|
|
mockWebhookFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
|
switch (paramName) {
|
|
case 'trigger':
|
|
return ['team_join'];
|
|
case 'options':
|
|
return resolveIds ? { resolveIds: true } : {};
|
|
default:
|
|
return {};
|
|
}
|
|
});
|
|
|
|
resolveIds = false;
|
|
const resultNoResolve = await slackTrigger.webhook!.call(mockWebhookFunctions);
|
|
expect(resultNoResolve.workflowData).toBeDefined();
|
|
expect(resultNoResolve.workflowData![0][0].json).toEqual(mockRequest.body.event);
|
|
|
|
resolveIds = true;
|
|
const resultResolve = await slackTrigger.webhook!.call(mockWebhookFunctions);
|
|
expect(resultResolve.workflowData).toBeDefined();
|
|
const out = resultResolve.workflowData![0][0].json as { user_resolved?: string };
|
|
expect(out.user_resolved).toBe(mockRequest.body.event.user.name);
|
|
});
|
|
|
|
it('should trigger on app_home_opened event without channel validation', async () => {
|
|
mockWebhookFunctions.getNodeParameter.mockImplementation(
|
|
(paramName: string, defaultValue?: any) => {
|
|
switch (paramName) {
|
|
case 'trigger':
|
|
return ['app_home_opened'];
|
|
case 'watchWorkspace':
|
|
return false;
|
|
case 'options':
|
|
return {};
|
|
default:
|
|
return defaultValue;
|
|
}
|
|
},
|
|
);
|
|
|
|
const mockRequest = {
|
|
body: {
|
|
type: 'event_callback',
|
|
event: {
|
|
type: 'app_home_opened',
|
|
user: 'U061F7AUR',
|
|
channel: 'D0LAN2Q65',
|
|
tab: 'home',
|
|
event_ts: '1515449522000016',
|
|
},
|
|
},
|
|
};
|
|
|
|
mockWebhookFunctions.getRequestObject.mockReturnValue(mockRequest as any);
|
|
|
|
const result = await slackTrigger.webhook!.call(mockWebhookFunctions);
|
|
|
|
expect(result.workflowData).toBeDefined();
|
|
expect(result.workflowData![0][0].json).toEqual(mockRequest.body.event);
|
|
});
|
|
|
|
it('should handle url_verification challenge', async () => {
|
|
const mockRequest = {
|
|
body: {
|
|
type: 'url_verification',
|
|
challenge: 'test_challenge_123',
|
|
},
|
|
};
|
|
|
|
mockWebhookFunctions.getRequestObject.mockReturnValue(mockRequest as any);
|
|
|
|
const result = await slackTrigger.webhook!.call(mockWebhookFunctions);
|
|
|
|
expect(result.noWebhookResponse).toBe(true);
|
|
expect(mockWebhookFunctions.getResponseObject().status).toHaveBeenCalledWith(200);
|
|
expect(mockWebhookFunctions.getResponseObject().json).toHaveBeenCalledWith({
|
|
challenge: 'test_challenge_123',
|
|
});
|
|
});
|
|
});
|
|
});
|