Skip to content

Commit

Permalink
add microsoft teams support (#44)
Browse files Browse the repository at this point in the history
* add microsoft teams support

Signed-off-by: zhichao-aws <zhichaog@amazon.com>

* microsoft teams unit test

Signed-off-by: yuye-aws <yuyezhu@amazon.com>

* microsoft teams cypress test

Signed-off-by: yuye-aws <yuyezhu@amazon.com>

* add snapshot for microsoft teams unit test

Signed-off-by: yuye-aws <yuyezhu@amazon.com>

* add mockdata for microsoft teams unit test

Signed-off-by: yuye-aws <yuyezhu@amazon.com>

* fix cypress mock teams url

Signed-off-by: zhichao-aws <zhichaog@amazon.com>

* extend pageload timeout for cy.visit

Signed-off-by: zhichao-aws <zhichaog@amazon.com>

---------

Signed-off-by: zhichao-aws <zhichaog@amazon.com>
Signed-off-by: yuye-aws <yuyezhu@amazon.com>
Co-authored-by: yuye-aws <yuyezhu@amazon.com>
  • Loading branch information
zhichao-aws and yuye-aws authored Aug 28, 2023
1 parent a108290 commit 5903c27
Show file tree
Hide file tree
Showing 16 changed files with 399 additions and 4 deletions.
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

0 comments on commit 5903c27

Please sign in to comment.