3 * Copyright (C) 2009-2023 SonarSource SA
4 * mailto:info AT sonarsource DOT com
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 import { screen } from '@testing-library/react';
21 import userEvent from '@testing-library/user-event';
22 import React from 'react';
23 import { byRole, byText } from 'testing-library-selector';
24 import AlmSettingsServiceMock from '../../../../../api/mocks/AlmSettingsServiceMock';
25 import { AvailableFeaturesContext } from '../../../../../app/components/available-features/AvailableFeaturesContext';
26 import { renderComponent } from '../../../../../helpers/testReactTestingUtils';
27 import { AlmKeys } from '../../../../../types/alm-settings';
28 import { Feature } from '../../../../../types/features';
29 import AlmIntegration from '../AlmIntegration';
31 jest.mock('../../../../../api/alm-settings');
33 let almSettings: AlmSettingsServiceMock;
36 almSettings = new AlmSettingsServiceMock();
43 describe('github tab', () => {
44 it('can create/edit/delete new configuration', async () => {
45 const { ui } = getPageObjects();
46 const { rerender } = renderAlmIntegration();
47 expect(await ui.almHeading.find()).toBeInTheDocument();
48 expect(ui.emptyIntro(AlmKeys.GitHub).get()).toBeInTheDocument();
50 // Create new configuration
51 await ui.createConfiguration('Name', {
52 'name.github': 'Name',
53 'url.github': 'https://api.github.com',
54 app_id: 'Github App ID',
55 'client_id.github': 'Github Client ID',
56 'client_secret.github': 'Client Secret',
60 await ui.editConfiguration('New Name', 'Name', 'client_secret.github', AlmKeys.GitHub);
62 await ui.checkConfiguration('New Name');
64 rerender(<AlmIntegration />);
65 expect(await screen.findByRole('heading', { name: 'New Name' })).toBeInTheDocument();
67 await ui.deleteConfiguration('New Name');
68 expect(ui.emptyIntro(AlmKeys.GitHub).get()).toBeInTheDocument();
72 describe.each([AlmKeys.GitLab, AlmKeys.Azure])(
74 (almKey: AlmKeys.Azure | AlmKeys.GitLab) => {
75 it('can create/edit/delete new configuration', async () => {
76 const { ui } = getPageObjects();
78 renderAlmIntegration();
79 expect(await ui.almHeading.find()).toBeInTheDocument();
81 await userEvent.click(ui.tab(almKey).get());
82 expect(ui.emptyIntro(almKey).get()).toBeInTheDocument();
84 // Create new configuration
85 await ui.createConfiguration('Name', {
86 [`name.${almKey}`]: 'Name',
87 [`url.${almKey}`]: 'https://api.alm.com',
88 personal_access_token: 'Access Token',
91 // Cannot create another configuration without Multiple Alm feature
92 expect(ui.createConfigurationButton.get()).toBeDisabled();
94 await ui.editConfiguration('New Name', 'Name', 'personal_access_token', almKey);
96 await ui.checkConfiguration('New Name');
98 await ui.deleteConfiguration('New Name');
99 expect(ui.emptyIntro(almKey).get()).toBeInTheDocument();
104 describe('bitbucket tab', () => {
105 it('can create/edit/delete new configuration', async () => {
106 const { ui } = getPageObjects();
107 renderAlmIntegration([Feature.MultipleAlm]);
108 expect(await ui.almHeading.find()).toBeInTheDocument();
110 await userEvent.click(ui.tab(AlmKeys.BitbucketServer).get());
111 expect(ui.emptyIntro(AlmKeys.BitbucketServer).get()).toBeInTheDocument();
113 // Create new Bitbucket Server configuration
114 await ui.createConfiguration(
117 'name.bitbucket': 'Name',
118 'url.bitbucket': 'https://api.bitbucket.com',
119 personal_access_token: 'Access Token',
121 AlmKeys.BitbucketServer
124 // Create new Bitbucket Cloud configuration
125 await ui.createConfiguration(
128 'name.bitbucket': 'Name Cloud',
129 'workspace.bitbucketcloud': 'workspace',
130 'client_id.bitbucketcloud': 'Client ID',
131 'client_secret.bitbucketcloud': 'Client Secret',
133 AlmKeys.BitbucketCloud
136 // Edit, check delete Bitbucket Server configuration
137 await ui.editConfiguration(
140 'personal_access_token',
141 AlmKeys.BitbucketServer
144 await ui.checkConfiguration('New Name');
146 await ui.deleteConfiguration('New Name');
148 // Cloud configuration still exists
149 expect(screen.getByRole('heading', { name: 'Name Cloud' })).toBeInTheDocument();
153 function getPageObjects() {
154 const user = userEvent.setup();
157 almHeading: byRole('heading', { name: 'settings.almintegration.title' }),
158 emptyIntro: (almKey: AlmKeys) => byText(`settings.almintegration.empty.${almKey}`),
159 createConfigurationButton: byRole('button', { name: 'settings.almintegration.create' }),
160 tab: (almKey: AlmKeys) =>
161 byRole('tab', { name: `${almKey} settings.almintegration.tab.${almKey}` }),
162 bitbucketConfiguration: (almKey: AlmKeys.BitbucketCloud | AlmKeys.BitbucketServer) =>
163 byRole('button', { name: `alm.${almKey}.long` }),
164 configurationInput: (id: string) =>
165 byRole('textbox', { name: `settings.almintegration.form.${id}` }),
166 updateSecretValueButton: (key: string) =>
168 name: `settings.almintegration.form.secret.update_field_x.settings.almintegration.form.${key}`,
170 saveConfigurationButton: byRole('button', { name: 'settings.almintegration.form.save' }),
171 editConfigurationButton: (key: string) =>
172 byRole('button', { name: `settings.almintegration.edit_configuration.${key}` }),
173 deleteConfigurationButton: (key: string) =>
174 byRole('button', { name: `settings.almintegration.delete_configuration.${key}` }),
175 cancelButton: byRole('button', { name: 'cancel' }),
176 confirmDelete: byRole('button', { name: 'delete' }),
177 checkConfigurationButton: (key: string) =>
178 byRole('button', { name: `settings.almintegration.check_configuration_x.${key}` }),
179 validationErrorMessage: byRole('alert'),
180 validationSuccessMessage: byRole('status'),
183 async function createConfiguration(
185 params: { [key: string]: string },
186 almKey?: AlmKeys.BitbucketCloud | AlmKeys.BitbucketServer
188 await userEvent.click(ui.createConfigurationButton.get());
189 expect(ui.saveConfigurationButton.get()).toBeDisabled();
192 await userEvent.click(ui.bitbucketConfiguration(almKey).get());
195 for (const [key, value] of Object.entries(params)) {
196 // eslint-disable-next-line no-await-in-loop
197 await userEvent.type(ui.configurationInput(key).get(), value);
199 expect(ui.saveConfigurationButton.get()).toBeEnabled();
200 await userEvent.click(ui.saveConfigurationButton.get());
202 // New configuration is created
203 expect(screen.getByRole('heading', { name })).toBeInTheDocument();
206 async function editConfiguration(
212 almSettings.setDefinitionErrorMessage('Something is wrong');
213 await userEvent.click(ui.editConfigurationButton(currentName).get());
214 expect(ui.configurationInput(secretId).query()).not.toBeInTheDocument();
215 await userEvent.click(ui.updateSecretValueButton(secretId).get());
216 await userEvent.type(ui.configurationInput(secretId).get(), 'New Secret Value');
217 await userEvent.clear(ui.configurationInput(`name.${almKey}`).get());
218 await userEvent.type(ui.configurationInput(`name.${almKey}`).get(), newName);
219 await userEvent.click(ui.saveConfigurationButton.get());
221 // Existing configuration is edited
222 expect(screen.queryByRole('heading', { name: currentName })).not.toBeInTheDocument();
223 expect(screen.getByRole('heading', { name: newName })).toBeInTheDocument();
224 expect(ui.validationErrorMessage.get()).toHaveTextContent('Something is wrong');
227 async function checkConfiguration(name: string) {
228 almSettings.setDefinitionErrorMessage('');
229 await userEvent.click(ui.checkConfigurationButton(name).get());
230 expect(ui.validationSuccessMessage.getAll()[0]).toHaveTextContent(
231 'alert.tooltip.successsettings.almintegration.configuration_valid'
235 async function deleteConfiguration(name: string) {
236 await userEvent.click(ui.deleteConfigurationButton(name).get());
237 await userEvent.click(ui.cancelButton.get());
238 expect(screen.getByRole('heading', { name })).toBeInTheDocument();
240 await userEvent.click(ui.deleteConfigurationButton(name).get());
241 await userEvent.click(ui.confirmDelete.get());
242 expect(screen.queryByRole('heading', { name })).not.toBeInTheDocument();
257 function renderAlmIntegration(features: Feature[] = []) {
258 return renderComponent(
259 <AvailableFeaturesContext.Provider value={features}>
261 </AvailableFeaturesContext.Provider>