3 * Copyright (C) 2009-2024 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 userEvent from '@testing-library/user-event';
21 import React from 'react';
22 import selectEvent from 'react-select-event';
23 import { byRole, byText } from '~sonar-aligned/helpers/testSelector';
24 import AlmSettingsServiceMock from '../../../../../api/mocks/AlmSettingsServiceMock';
25 import CurrentUserContextProvider from '../../../../../app/components/current-user/CurrentUserContextProvider';
26 import { mockComponent } from '../../../../../helpers/mocks/component';
27 import { mockCurrentUser } from '../../../../../helpers/testMocks';
28 import { renderComponent } from '../../../../../helpers/testReactTestingUtils';
31 ProjectAlmBindingConfigurationErrorScope,
32 } from '../../../../../types/alm-settings';
33 import { Component } from '../../../../../types/types';
34 import { CurrentUser } from '../../../../../types/users';
35 import PRDecorationBinding from '../PRDecorationBinding';
37 let almSettings: AlmSettingsServiceMock;
40 almSettings = new AlmSettingsServiceMock();
48 [AlmKeys.GitLab]: { 'gitlab.repository': 'Repository', monorepo: false },
50 'github.repository': 'Repository',
51 'github.summary_comment_setting': false,
55 'azure.repository': 'Repository',
56 'azure.project': 'Project',
59 [AlmKeys.BitbucketCloud]: { 'bitbucketcloud.repository': 'Repository', monorepo: false },
60 [AlmKeys.BitbucketServer]: {
61 'bitbucket.repository': 'Repository',
62 'bitbucket.slug': 'Slug',
81 key: 'conf-bitbucketcloud-1',
82 alm: AlmKeys.BitbucketCloud,
85 key: 'conf-bitbucketserver-1',
86 alm: AlmKeys.BitbucketServer,
89 'should get, set, delete and validate binding for $alm',
90 async ({ key, alm }: { alm: AlmKeys; key: string }) => {
91 const { ui, user } = getPageObjects();
92 almSettings.setProjectBindingConfigurationErrors({
93 scope: ProjectAlmBindingConfigurationErrorScope.Global,
94 errors: [{ msg: 'cute error' }],
96 const { rerender } = renderPRDecorationBinding();
97 expect(await ui.mainTitle.find()).toBeInTheDocument();
100 await selectEvent.select(ui.input('name', 'combobox').get(), (content) =>
101 content.includes(key),
104 const list = inputsList[alm];
105 for (const [inputId, value] of Object.entries(list)) {
106 // eslint-disable-next-line no-await-in-loop
107 await ui.setInput(inputId, value);
109 // Save form and check for errors
110 await user.click(ui.saveButton.get());
111 expect(await ui.validationMsg('cute error').find()).toBeInTheDocument();
113 // Check validation with errors
114 await user.click(ui.validateButton.get());
115 expect(ui.validationMsg('cute error').get()).toBeInTheDocument();
117 // Save form and check for errors
118 almSettings.setProjectBindingConfigurationErrors(undefined);
120 Object.keys(list).find((key) => key.endsWith('.repository')) as string,
123 await user.click(ui.saveButton.get());
125 await ui.validationMsg('settings.pr_decoration.binding.check_configuration.success').find(),
126 ).toBeInTheDocument();
128 await user.click(ui.validateButton.get());
130 ui.validationMsg('settings.pr_decoration.binding.check_configuration.success').get(),
131 ).toBeInTheDocument();
133 // Rerender and verify that validation is done for binding
135 <MockedPRDecorationBinding component={mockComponent()} currentUser={mockCurrentUser()} />,
138 await ui.validationMsg('settings.pr_decoration.binding.check_configuration.success').find(),
139 ).toBeInTheDocument();
140 expect(ui.saveButton.query()).not.toBeInTheDocument();
143 await user.click(ui.resetButton.get());
144 expect(ui.input('', 'textbox').query()).not.toBeInTheDocument();
145 expect(ui.input('', 'switch').query()).not.toBeInTheDocument();
149 function getPageObjects() {
150 const user = userEvent.setup();
152 async function setInput(inputId: string, value: string | boolean) {
153 if (typeof value === 'boolean') {
155 await user.click(ui.input(inputId, 'switch').get());
158 const input = ui.input(inputId, 'textbox').get();
159 await user.clear(input);
160 await user.type(input, value);
165 mainTitle: byRole('heading', { name: 'settings.pr_decoration.binding.title' }),
166 input: (id: string, role: 'combobox' | 'switch' | 'textbox') =>
167 byRole(role, { name: new RegExp(`settings.pr_decoration.binding.form.${id}`) }),
168 saveButton: byRole('button', { name: 'save' }),
169 resetButton: byRole('button', { name: 'reset_verb' }),
170 validateButton: byRole('button', {
171 name: 'settings.pr_decoration.binding.check_configuration',
173 validationMsg: (text: string) => byText(text),
183 function MockedPRDecorationBinding({
187 component: Component;
188 currentUser: CurrentUser;
191 <CurrentUserContextProvider currentUser={currentUser}>
192 <PRDecorationBinding component={component} />
193 </CurrentUserContextProvider>
197 function renderPRDecorationBinding(
198 component: Component = mockComponent(),
199 currentUser: CurrentUser = mockCurrentUser(),
201 return renderComponent(
202 <MockedPRDecorationBinding component={component} currentUser={currentUser} />,