/*! * @license * Copyright Squiz Australia Pty Ltd. All Rights Reserved. */ import { faker } from '@faker-js/faker/locale/en'; import { SlackClient } from './SlackClient'; import { SLACK_ALERT_LEVEL_ERROR, SLACK_ALERT_LEVEL_INFO, SLACK_ALERT_LEVEL_SUCCESS, SLACK_ALERT_LEVEL_WARNING, SlackAlertLevel, } from './types/SlackClient.types'; describe('SlackClient singleton methods', () => { let mockRegion: string; let mockEnvironment: string; let mockWebhookUrl: string; let mockApplication: string; let slackClient: SlackClient; beforeEach(() => { mockRegion = 'us'; mockEnvironment = 'dev'; mockWebhookUrl = 'https://example.com'; mockApplication = 'Job Runner'; SlackClient.initialize(mockEnvironment, mockRegion, mockWebhookUrl, mockApplication); slackClient = SlackClient.getClient(); }); describe('initialize', () => { it('should throw an error if environment, region, webhook URL or application are undefined', () => { expect(() => SlackClient.initialize(undefined, mockRegion, mockWebhookUrl, mockApplication)).toThrowError( new Error('Failed to initialize SlackClient, environment vars not set'), ); expect(() => SlackClient.initialize(mockEnvironment, undefined, mockWebhookUrl, mockApplication)).toThrowError( new Error('Failed to initialize SlackClient, environment vars not set'), ); expect(() => SlackClient.initialize(mockEnvironment, mockRegion, undefined, mockApplication)).toThrowError( new Error('Failed to initialize SlackClient, environment vars not set'), ); expect(() => SlackClient.initialize(mockEnvironment, mockRegion, mockWebhookUrl, undefined)).toThrowError( new Error('Failed to initialize SlackClient, environment vars not set'), ); expect(() => SlackClient.initialize()).toThrowError( new Error('Failed to initialize SlackClient, environment vars not set'), ); }); it('should not throw an error if environment, region, webhook URL and application are defined/valid', () => { expect(() => SlackClient.initialize(mockEnvironment, mockRegion, mockWebhookUrl, mockApplication), ).not.toThrowError(); }); }); describe('getClient', () => { it('should return the existing instance of SlackClient', () => { const localSlackClient = SlackClient.getClient(); expect(localSlackClient).toBe(slackClient); }); }); describe('getIcon', () => { it('should return an icon matching the alert level', () => { const errorIcon = SlackClient.getIcon(SLACK_ALERT_LEVEL_ERROR); expect(errorIcon).toBe(':alert:'); const warningIcon = SlackClient.getIcon(SLACK_ALERT_LEVEL_WARNING); expect(warningIcon).toBe('⚠️'); const infoIcon = SlackClient.getIcon(SLACK_ALERT_LEVEL_INFO); expect(infoIcon).toBe('ℹ️'); const successIcon = SlackClient.getIcon(SLACK_ALERT_LEVEL_SUCCESS); expect(successIcon).toBe('✅'); }); it('should return an "INFO" icon by default', () => { const icon = SlackClient.getIcon(); expect(icon).toBe('ℹ️'); }); it('should return "null" for unknown alert level', () => { const badIcon = SlackClient.getIcon('unknown' as SlackAlertLevel); expect(badIcon).toBe(null); }); }); describe('getRequestBody', () => { it('should generate request body for Slack based on message and alert level', () => { const mockMessage = faker.lorem.sentence(); const mockLevel: SlackAlertLevel = faker.helpers.arrayElement([ SLACK_ALERT_LEVEL_ERROR, SLACK_ALERT_LEVEL_WARNING, SLACK_ALERT_LEVEL_INFO, SLACK_ALERT_LEVEL_SUCCESS, ]); const mockIcon = SlackClient.getIcon(mockLevel); const requestBody = SlackClient.getRequestBody(mockMessage, mockLevel); expect(requestBody.text).toContain(mockIcon); expect(requestBody.text).toContain(mockMessage); expect(requestBody.text).toContain(`${mockEnvironment[0].toUpperCase()}${mockEnvironment.slice(1)}`); expect(requestBody.text).toContain(mockRegion.toUpperCase()); expect(requestBody.text).toContain(mockApplication); }); it('should generate request body for an INFO alert if level not provided', () => { const mockMessage = faker.lorem.sentence(); const mockInfoIcon = SlackClient.getIcon(); const requestBody = SlackClient.getRequestBody(mockMessage); expect(requestBody.text).toContain(mockInfoIcon); }); }); describe('sendAlert', () => { const fetchSpy = jest.spyOn(global, 'fetch'); let mockMessage: string; beforeEach(() => { mockMessage = faker.lorem.sentence(); }); it('should make a POST request to the Slack webhook URL', async () => { fetchSpy.mockImplementation( jest.fn(() => Promise.resolve({ status: 200, json: () => Promise.resolve({}), }), ) as jest.Mock, ); expect(async () => await slackClient.sendAlert(mockMessage)).not.toThrowError(); expect(fetchSpy).toHaveBeenCalled(); }); it('should throw an error if request fails', async () => { fetchSpy.mockImplementation( jest.fn(() => Promise.resolve({ status: 401, headers: new Headers({ 'Content-Type': 'application/json' }), json: () => Promise.resolve({ message: 'Unauthorized' }), text: () => Promise.resolve('Unauthorized'), }), ) as jest.Mock, ); const consoleLogSpy = jest.spyOn(console, 'log'); const mockMessage = 'Test Alert Message'; await slackClient.sendAlert(mockMessage); expect(consoleLogSpy).toBeCalledTimes(1); expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('SlackClient failed with 401 status')); }); }); });