2023-07-18 09:12:15 +02:00
|
|
|
import { IEvent, FEATURE_ENVIRONMENT_ENABLED } from '../types/events';
|
|
|
|
import SlackAppAddon from './slack-app';
|
2023-07-20 14:37:06 +02:00
|
|
|
import { ChatPostMessageArguments, ErrorCode } from '@slack/web-api';
|
2023-07-18 09:12:15 +02:00
|
|
|
|
|
|
|
const slackApiCalls: ChatPostMessageArguments[] = [];
|
2023-08-15 13:12:04 +02:00
|
|
|
|
2023-09-14 09:19:38 +02:00
|
|
|
let postMessage = jest.fn().mockImplementation((options) => {
|
2023-07-20 14:37:06 +02:00
|
|
|
slackApiCalls.push(options);
|
|
|
|
return Promise.resolve();
|
|
|
|
});
|
|
|
|
|
2023-07-18 09:12:15 +02:00
|
|
|
jest.mock('@slack/web-api', () => ({
|
|
|
|
WebClient: jest.fn().mockImplementation(() => ({
|
|
|
|
chat: {
|
2023-09-14 09:19:38 +02:00
|
|
|
postMessage,
|
2023-07-18 09:12:15 +02:00
|
|
|
},
|
2023-07-20 14:37:06 +02:00
|
|
|
on: jest.fn(),
|
2023-07-18 09:12:15 +02:00
|
|
|
})),
|
2023-07-20 14:37:06 +02:00
|
|
|
ErrorCode: {
|
|
|
|
PlatformError: 'slack_webapi_platform_error',
|
|
|
|
},
|
|
|
|
WebClientEvent: {
|
|
|
|
RATE_LIMITED: 'rate_limited',
|
|
|
|
},
|
2023-07-18 09:12:15 +02:00
|
|
|
}));
|
|
|
|
|
2023-07-20 14:37:06 +02:00
|
|
|
describe('SlackAppAddon', () => {
|
|
|
|
let addon;
|
|
|
|
const accessToken = 'test-access-token';
|
|
|
|
const loggerMock = {
|
|
|
|
debug: jest.fn(),
|
|
|
|
info: jest.fn(),
|
|
|
|
warn: jest.fn(),
|
|
|
|
error: jest.fn(),
|
|
|
|
fatal: jest.fn(),
|
|
|
|
};
|
|
|
|
const getLogger = jest.fn(() => loggerMock);
|
|
|
|
const mockError = {
|
|
|
|
code: ErrorCode.PlatformError,
|
|
|
|
data: 'Platform error message',
|
|
|
|
};
|
2023-07-18 09:12:15 +02:00
|
|
|
|
|
|
|
const event: IEvent = {
|
|
|
|
id: 1,
|
|
|
|
createdAt: new Date(),
|
|
|
|
type: FEATURE_ENVIRONMENT_ENABLED,
|
|
|
|
createdBy: 'some@user.com',
|
|
|
|
project: 'default',
|
|
|
|
featureName: 'some-toggle',
|
|
|
|
environment: 'development',
|
|
|
|
data: {
|
|
|
|
name: 'some-toggle',
|
|
|
|
enabled: false,
|
|
|
|
type: 'release',
|
|
|
|
strategies: [{ name: 'default' }],
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2023-07-20 14:37:06 +02:00
|
|
|
beforeEach(() => {
|
|
|
|
jest.useFakeTimers();
|
|
|
|
slackApiCalls.length = 0;
|
2023-09-14 09:19:38 +02:00
|
|
|
postMessage.mockClear();
|
2023-07-20 14:37:06 +02:00
|
|
|
addon = new SlackAppAddon({
|
|
|
|
getLogger,
|
|
|
|
unleashUrl: 'http://some-url.com',
|
|
|
|
});
|
|
|
|
});
|
2023-07-18 09:12:15 +02:00
|
|
|
|
2023-07-20 14:37:06 +02:00
|
|
|
afterEach(() => {
|
|
|
|
jest.useRealTimers();
|
2023-07-18 09:12:15 +02:00
|
|
|
});
|
|
|
|
|
2023-07-20 14:37:06 +02:00
|
|
|
it('should post message when feature is toggled', async () => {
|
2023-09-18 09:32:37 +02:00
|
|
|
await addon.handleEvent(event, {
|
|
|
|
accessToken,
|
|
|
|
defaultChannels: 'general',
|
|
|
|
});
|
2023-07-18 09:12:15 +02:00
|
|
|
|
2023-07-20 14:37:06 +02:00
|
|
|
expect(slackApiCalls.length).toBe(1);
|
2023-08-15 13:12:04 +02:00
|
|
|
expect(slackApiCalls[0].channel).toBe('general');
|
2023-07-18 09:12:15 +02:00
|
|
|
});
|
|
|
|
|
2023-09-18 09:32:37 +02:00
|
|
|
it('should post to all channels in defaultChannels', async () => {
|
|
|
|
await addon.handleEvent(event, {
|
|
|
|
accessToken,
|
|
|
|
defaultChannels: 'general, another-channel-1',
|
|
|
|
});
|
|
|
|
|
|
|
|
expect(slackApiCalls.length).toBe(2);
|
|
|
|
expect(slackApiCalls[0].channel).toBe('general');
|
|
|
|
expect(slackApiCalls[1].channel).toBe('another-channel-1');
|
|
|
|
});
|
|
|
|
|
2023-07-20 14:37:06 +02:00
|
|
|
it('should post to all channels in tags', async () => {
|
|
|
|
const eventWith2Tags: IEvent = {
|
|
|
|
...event,
|
|
|
|
tags: [
|
|
|
|
{ type: 'slack', value: 'general' },
|
|
|
|
{ type: 'slack', value: 'another-channel-1' },
|
|
|
|
],
|
|
|
|
};
|
|
|
|
|
|
|
|
await addon.handleEvent(eventWith2Tags, { accessToken });
|
|
|
|
|
|
|
|
expect(slackApiCalls.length).toBe(2);
|
2023-08-15 13:12:04 +02:00
|
|
|
expect(slackApiCalls[0].channel).toBe('general');
|
|
|
|
expect(slackApiCalls[1].channel).toBe('another-channel-1');
|
2023-07-20 14:37:06 +02:00
|
|
|
});
|
|
|
|
|
2023-09-18 09:32:37 +02:00
|
|
|
it('should concatenate defaultChannels and channels in tags to post to all unique channels found', async () => {
|
|
|
|
const eventWith2Tags: IEvent = {
|
2023-07-21 15:15:43 +02:00
|
|
|
...event,
|
2023-09-18 09:32:37 +02:00
|
|
|
tags: [
|
|
|
|
{ type: 'slack', value: 'general' },
|
|
|
|
{ type: 'slack', value: 'another-channel-1' },
|
|
|
|
],
|
2023-07-21 15:15:43 +02:00
|
|
|
};
|
|
|
|
|
2023-09-18 09:32:37 +02:00
|
|
|
await addon.handleEvent(eventWith2Tags, {
|
2023-07-21 15:15:43 +02:00
|
|
|
accessToken,
|
2023-09-18 09:32:37 +02:00
|
|
|
defaultChannels: 'another-channel-1, another-channel-2',
|
2023-07-21 15:15:43 +02:00
|
|
|
});
|
|
|
|
|
2023-09-18 09:32:37 +02:00
|
|
|
expect(slackApiCalls.length).toBe(3);
|
|
|
|
expect(slackApiCalls[0].channel).toBe('general');
|
|
|
|
expect(slackApiCalls[1].channel).toBe('another-channel-1');
|
|
|
|
expect(slackApiCalls[2].channel).toBe('another-channel-2');
|
2023-07-21 15:15:43 +02:00
|
|
|
});
|
|
|
|
|
2023-09-18 09:32:37 +02:00
|
|
|
it('should not post a message if there are no tagged channels and no defaultChannels', async () => {
|
|
|
|
await addon.handleEvent(event, {
|
2023-07-21 15:15:43 +02:00
|
|
|
accessToken,
|
|
|
|
});
|
|
|
|
|
2023-09-18 09:32:37 +02:00
|
|
|
expect(slackApiCalls.length).toBe(0);
|
2023-07-21 15:15:43 +02:00
|
|
|
});
|
|
|
|
|
2023-07-20 14:37:06 +02:00
|
|
|
it('should log error when an API call fails', async () => {
|
2023-09-14 09:19:38 +02:00
|
|
|
postMessage = jest.fn().mockRejectedValue(mockError);
|
2023-07-20 14:37:06 +02:00
|
|
|
|
2023-09-18 09:32:37 +02:00
|
|
|
await addon.handleEvent(event, {
|
|
|
|
accessToken,
|
|
|
|
defaultChannels: 'general',
|
|
|
|
});
|
2023-07-20 14:37:06 +02:00
|
|
|
|
|
|
|
expect(loggerMock.warn).toHaveBeenCalledWith(
|
|
|
|
`Error handling event ${event.type}. A platform error occurred: Platform error message`,
|
|
|
|
expect.any(Object),
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2023-09-14 09:19:38 +02:00
|
|
|
it('should handle rejections in chat.postMessage', async () => {
|
2023-07-20 14:37:06 +02:00
|
|
|
const eventWith3Tags: IEvent = {
|
|
|
|
...event,
|
|
|
|
tags: [
|
|
|
|
{ type: 'slack', value: 'general' },
|
|
|
|
{ type: 'slack', value: 'another-channel-1' },
|
|
|
|
{ type: 'slack', value: 'another-channel-2' },
|
|
|
|
],
|
|
|
|
};
|
|
|
|
|
2023-09-14 09:19:38 +02:00
|
|
|
postMessage = jest
|
2023-07-20 14:37:06 +02:00
|
|
|
.fn()
|
|
|
|
.mockResolvedValueOnce({ ok: true })
|
|
|
|
.mockResolvedValueOnce({ ok: true })
|
|
|
|
.mockRejectedValueOnce(mockError);
|
|
|
|
|
|
|
|
await addon.handleEvent(eventWith3Tags, { accessToken });
|
|
|
|
|
2023-09-14 09:19:38 +02:00
|
|
|
expect(postMessage).toHaveBeenCalledTimes(3);
|
2023-07-20 14:37:06 +02:00
|
|
|
expect(loggerMock.warn).toHaveBeenCalledWith(
|
|
|
|
`Error handling event ${FEATURE_ENVIRONMENT_ENABLED}. A platform error occurred: Platform error message`,
|
|
|
|
expect.any(Object),
|
|
|
|
);
|
|
|
|
expect(loggerMock.info).toHaveBeenCalledWith(
|
|
|
|
`Handled event ${FEATURE_ENVIRONMENT_ENABLED} dispatching 2 out of 3 messages successfully.`,
|
|
|
|
);
|
|
|
|
});
|
2023-07-18 09:12:15 +02:00
|
|
|
});
|