Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add microsoft teams support #44

Merged
merged 8 commits into from
Aug 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .cypress/fixtures/test_microsoft_teams_channel.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"config": {
"name": "Test microsoft teams channel",
"description": "A test microsoft teams channel",
"config_type": "microsoft_teams",
"is_enabled": true,
"microsoft_teams": {
"url": "https://testdomain.webhook.office.com/123"
}
}
}
25 changes: 23 additions & 2 deletions .cypress/integration/channels.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import { delay } from '../utils/constants';
import testSlackChannel from '../fixtures/test_slack_channel';
import testChimeChannel from '../fixtures/test_chime_channel';
import testMicrosoftTeamsChannel from '../fixtures/test_microsoft_teams_channel.json';
import testWebhookChannel from '../fixtures/test_webhook_channel.json';
import testTlsSmtpSender from '../fixtures/test_tls_smtp_sender';

Expand Down Expand Up @@ -69,6 +70,25 @@ describe('Test create channels', () => {
cy.contains('successfully created.').should('exist');
});

it('creates a microsoft teams channel and send test message', () => {
cy.get('[placeholder="Enter channel name"]').type('Test microsoft teams channel');

cy.get('.euiSuperSelectControl').contains('Slack').click({ force: true });
cy.wait(delay);
cy.get('.euiContextMenuItem__text')
.contains('Microsoft Teams')
.click({ force: true });
cy.wait(delay);

cy.get('[data-test-subj="create-channel-microsoftTeams-webhook-input"]').type(
'https://testdomain.webhook.office.com/123'
);
cy.wait(delay);

cy.get('[data-test-subj="create-channel-create-button"]').click();
cy.contains('successfully created.').should('exist');
});

it('creates an email channel', () => {
cy.get('[placeholder="Enter channel name"]').type('Test email channel');

Expand Down Expand Up @@ -114,7 +134,7 @@ describe('Test create channels', () => {
.contains('Email')
.click({ force: true });
cy.wait(delay);

cy.get('input.euiRadio__input#ses_account').click({ force: true });
cy.wait(delay);

Expand Down Expand Up @@ -195,6 +215,7 @@ describe('Test channels table', () => {
// Create test channels
cy.createConfig(testSlackChannel);
cy.createConfig(testChimeChannel);
cy.createConfig(testMicrosoftTeamsChannel);
cy.createConfig(testWebhookChannel);
cy.createTestEmailChannel();
});
Expand Down Expand Up @@ -292,7 +313,7 @@ describe('Test channel details', () => {
cy.contains('successfully unmuted.').should('exist');
cy.contains('Active').should('exist');
});

it('edits channels', () => {
cy.contains('Actions').click({ force: true });
cy.contains('Edit').click({ force: true });
Expand Down
1 change: 1 addition & 0 deletions cypress.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"requestTimeout": 60000,
"responseTimeout": 60000,
"defaultCommandTimeout": 60000,
"pageLoadTimeout":90000,
"retries": {
"runMode": 2,
"openMode": 2
Expand Down
3 changes: 3 additions & 0 deletions models/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ export interface ChannelItemType extends ConfigType {
chime?: {
url: string;
};
microsoft_teams?: {
url: string;
};
webhook?: {
url: string;
header_params: object;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,11 @@ describe('<ChannelSettingsDetails /> spec', () => {
);
expect(utils.container.firstChild).toMatchSnapshot();
});

it('renders Teams channel', () => {
const utils = render(
<ChannelSettingsDetails channel={MOCK_DATA.microsoftTeams} />
);
expect(utils.container.firstChild).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,62 @@ exports[`<ChannelSettingsDetails /> spec renders Slack channel 1`] = `
</div>
`;

exports[`<ChannelSettingsDetails /> spec renders Teams channel 1`] = `
<div>
<div
class="euiSpacer euiSpacer--s"
/>
<div
class="euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--directionRow euiFlexGroup--responsive"
>
<div
class="euiFlexItem"
>
<dl
class="euiDescriptionList euiDescriptionList--row"
style="word-break: break-word; white-space: pre-line;"
>
<dt
class="euiDescriptionList__title"
>
Channel type
</dt>
<dd
class="euiDescriptionList__description"
>
Microsoft Teams
</dd>
</dl>
</div>
<div
class="euiFlexItem"
>
<dl
class="euiDescriptionList euiDescriptionList--row"
style="word-break: break-word; white-space: pre-line;"
>
<dt
class="euiDescriptionList__title"
>
Webhook URL
</dt>
<dd
class="euiDescriptionList__description"
>
https://chimehook
</dd>
</dl>
</div>
<div
class="euiFlexItem"
/>
</div>
<div
class="euiSpacer euiSpacer--m"
/>
</div>
`;

exports[`<ChannelSettingsDetails /> spec renders Webhook channel 1`] = `
<div>
<div
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,19 @@ export function ChannelSettingsDetails(props: ChannelSettingsDetailsProps) {
},
]
);
} else if (type === BACKEND_CHANNEL_TYPE.MICROSOFT_TEAMS) {
settingsList.push(
...[
{
title: 'Channel type',
description: CHANNEL_TYPE.microsoft_teams,
},
{
title: 'Webhook URL',
description: props.channel.microsoft_teams!.url || '-',
},
]
);
} else if (type === BACKEND_CHANNEL_TYPE.EMAIL) {
const emailObject = deconstructEmailObject(props.channel.email!);
const recipientsDescription = getModalComponent(
Expand Down
17 changes: 16 additions & 1 deletion public/pages/CreateChannel/CreateChannel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { HeaderItemType, WebhookHttpType, WebhookMethodType } from '../Channels/
import { MainContext } from '../Main/Main';
import { ChannelNamePanel } from './components/ChannelNamePanel';
import { ChimeSettings } from './components/ChimeSettings';
import { MicrosoftTeamsSettings } from './components/MicrosoftTeamsSettings';
import { CustomWebhookSettings } from './components/CustomWebhookSettings';
import { EmailSettings } from './components/EmailSettings';
import { SlackSettings } from './components/SlackSettings';
Expand Down Expand Up @@ -96,6 +97,7 @@ export function CreateChannel(props: CreateChannelsProps) {

const [slackWebhook, setSlackWebhook] = useState('');
const [chimeWebhook, setChimeWebhook] = useState('');
const [microsoftTeamsWebhook, setMicrosoftTeamsWebhook] = useState('');

const [senderType, setSenderType] = useState<SenderType>('smtp_account');
const [selectedSmtpSenderOptions, setSelectedSmtpSenderOptions] = useState<
Expand Down Expand Up @@ -130,6 +132,7 @@ export function CreateChannel(props: CreateChannelsProps) {
name: [],
slackWebhook: [],
chimeWebhook: [],
microsoftTeamsWebhook: [],
smtpSender: [],
sesSender: [],
recipients: [],
Expand Down Expand Up @@ -184,6 +187,8 @@ export function CreateChannel(props: CreateChannelsProps) {
setSlackWebhook(response.slack?.url || '');
} else if (type === BACKEND_CHANNEL_TYPE.CHIME) {
setChimeWebhook(response.chime?.url || '');
} else if (type === BACKEND_CHANNEL_TYPE.MICROSOFT_TEAMS) {
setMicrosoftTeamsWebhook(response.microsoft_teams?.url || '');
} else if (type === BACKEND_CHANNEL_TYPE.EMAIL) {
const emailObject = deconstructEmailObject(response.email!);
setSenderType(emailObject.senderType);
Expand Down Expand Up @@ -220,6 +225,7 @@ export function CreateChannel(props: CreateChannelsProps) {
name: validateChannelName(name),
slackWebhook: [],
chimeWebhook: [],
microsoftTeamsWebhook: [],
smtpSender: [],
sesSender: [],
recipients: [],
Expand All @@ -233,6 +239,8 @@ export function CreateChannel(props: CreateChannelsProps) {
errors.slackWebhook = validateWebhookURL(slackWebhook);
} else if (channelType === BACKEND_CHANNEL_TYPE.CHIME) {
errors.chimeWebhook = validateWebhookURL(chimeWebhook);
} else if (channelType === BACKEND_CHANNEL_TYPE.MICROSOFT_TEAMS) {
errors.microsoftTeamsWebhook = validateWebhookURL(microsoftTeamsWebhook);
} else if (channelType === BACKEND_CHANNEL_TYPE.EMAIL) {
if (senderType === 'smtp_account') {
errors.smtpSender = validateEmailSender(selectedSmtpSenderOptions);
Expand Down Expand Up @@ -270,6 +278,8 @@ export function CreateChannel(props: CreateChannelsProps) {
config.slack = { url: slackWebhook };
} else if (channelType === BACKEND_CHANNEL_TYPE.CHIME) {
config.chime = { url: chimeWebhook };
} else if (channelType === BACKEND_CHANNEL_TYPE.MICROSOFT_TEAMS) {
config.microsoft_teams = { url: microsoftTeamsWebhook };
} else if (channelType === BACKEND_CHANNEL_TYPE.CUSTOM_WEBHOOK) {
config.webhook = constructWebhookObject(
webhookTypeIdSelected,
Expand Down Expand Up @@ -401,7 +411,12 @@ export function CreateChannel(props: CreateChannelsProps) {
chimeWebhook={chimeWebhook}
setChimeWebhook={setChimeWebhook}
/>
) : channelType === BACKEND_CHANNEL_TYPE.EMAIL ? (
) : channelType === BACKEND_CHANNEL_TYPE.MICROSOFT_TEAMS ? (
<MicrosoftTeamsSettings
microsoftTeamsWebhook={microsoftTeamsWebhook}
setMicrosoftTeamsWebhook={setMicrosoftTeamsWebhook}
/>
): channelType === BACKEND_CHANNEL_TYPE.EMAIL ? (
<EmailSettings
senderType={senderType}
setSenderType={setSenderType}
Expand Down
37 changes: 37 additions & 0 deletions public/pages/CreateChannel/__tests__/CreateChannel.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ describe('<CreateChannel/> spec', () => {
availableConfigTypes: [
'slack',
'chime',
'microsoft_teams',
'webhook',
'email',
'sns',
Expand Down Expand Up @@ -161,6 +162,42 @@ describe('<CreateChannel/> spec', () => {
});
});

it('renders the component for editing microsoft teams', async () => {
const notificationServiceMockMicrosoftTeams = jest.fn() as any;
const getMicrosoftTeamsChannel = jest.fn(
async (queryObject: object) => MOCK_DATA.microsoftTeams
);
notificationServiceMockMicrosoftTeams.notificationService = {
getChannel: getMicrosoftTeamsChannel,
updateConfig: updateConfigFailure,
};
const props = {
location: { search: '' },
match: { params: { id: 'test' } },
};
const utilsMicrosoftTeams = render(
<MainContext.Provider value={mainStateMock}>
<ServicesContext.Provider value={notificationServiceMockMicrosoftTeams}>
<CoreServicesContext.Provider value={coreServicesMock}>
<CreateChannel
{...(props as RouteComponentProps<{ id: string }>)}
edit={true}
/>
</CoreServicesContext.Provider>
</ServicesContext.Provider>
</MainContext.Provider>
);

await waitFor(() => {
expect(getMicrosoftTeamsChannel).toBeCalled();
});

utilsMicrosoftTeams.getByTestId('create-channel-create-button').click();
await waitFor(() => {
expect(updateConfigFailure).toBeCalled();
});
});

it('renders the component for editing email', async () => {
const notificationServiceMockEmail = jest.fn() as any;
const getEmailChannel = jest.fn(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { fireEvent, render } from '@testing-library/react';
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import React from 'react';
import { MicrosoftTeamsSettings } from '../components/MicrosoftTeamsSettings';
import { CreateChannelContext } from '../CreateChannel';

describe('<MicrosoftTeamsSettings /> spec', () => {
configure({ adapter: new Adapter() });

it('renders the component', () => {
const setMicrosoftTeamsWebhook = jest.fn();
const utils = render(
<CreateChannelContext.Provider
value={{
edit: false,
inputErrors: { microsoftTeamsWebhook: [] },
setInputErrors: jest.fn(),
}}
>
<MicrosoftTeamsSettings
microsoftTeamsWebhook="test webhook"
setMicrosoftTeamsWebhook={setMicrosoftTeamsWebhook}
/>
</CreateChannelContext.Provider>
);
expect(utils.container.firstChild).toMatchSnapshot();
});

it('renders the component with error', () => {
const setMicrosoftTeamsWebhook = jest.fn();
const utils = render(
<CreateChannelContext.Provider
value={{
edit: false,
inputErrors: { microsoftTeamsWebhook: ['test error'] },
setInputErrors: jest.fn(),
}}
>
<MicrosoftTeamsSettings
microsoftTeamsWebhook="test webhook"
setMicrosoftTeamsWebhook={setMicrosoftTeamsWebhook}
/>
</CreateChannelContext.Provider>
);
expect(utils.container.firstChild).toMatchSnapshot();
});

it('changes input', () => {
const setMicrosoftTeamsWebhook = jest.fn();
const setInputErrors = jest.fn();
const utils = render(
<CreateChannelContext.Provider
value={{
edit: false,
inputErrors: { microsoftTeamsWebhook: [] },
setInputErrors,
}}
>
<MicrosoftTeamsSettings
microsoftTeamsWebhook="test webhook"
setMicrosoftTeamsWebhook={setMicrosoftTeamsWebhook}
/>
</CreateChannelContext.Provider>
);
const input = utils.getByLabelText('Webhook URL');
fireEvent.change(input, { target: { value: 'https://test-microsoftTeams-url' } });
fireEvent.blur(input);
expect(setMicrosoftTeamsWebhook).toBeCalledWith('https://test-microsoftTeams-url');
expect(setInputErrors).toBeCalled();
});
});
Loading