AlmSettingsBindingDefinitions,
AlmSettingsInstance,
AzureBindingDefinition,
+ AzureProjectAlmBindingParams,
BitbucketCloudBindingDefinition,
+ BitbucketCloudProjectAlmBindingParams,
+ BitbucketProjectAlmBindingParams,
BitbucketServerBindingDefinition,
GithubBindingDefinition,
+ GithubProjectAlmBindingParams,
GitlabBindingDefinition,
+ GitlabProjectAlmBindingParams,
+ ProjectAlmBindingConfigurationErrors,
+ ProjectAlmBindingParams,
+ ProjectAlmBindingResponse,
} from '../../types/alm-settings';
import {
countBoundProjects,
createGithubConfiguration,
createGitlabConfiguration,
deleteConfiguration,
+ deleteProjectAlmBinding,
getAlmDefinitions,
getAlmSettings,
+ getProjectAlmBinding,
+ setProjectAzureBinding,
+ setProjectBitbucketBinding,
+ setProjectBitbucketCloudBinding,
+ setProjectGithubBinding,
+ setProjectGitlabBinding,
updateAzureConfiguration,
updateBitbucketCloudConfiguration,
updateBitbucketServerConfiguration,
updateGithubConfiguration,
updateGitlabConfiguration,
validateAlmSettings,
+ validateProjectAlmBinding,
} from '../alm-settings';
const defaultAlmDefinitions = {
}),
];
+interface EnhancedProjectAlmBindingParam extends ProjectAlmBindingParams {
+ projectName?: string;
+ repositoryName?: string;
+ repository?: string;
+ slug?: string;
+ summaryCommentEnabled?: boolean;
+}
+
export default class AlmSettingsServiceMock {
#almDefinitions: AlmSettingsBindingDefinitions;
#almSettings: AlmSettingsInstance[];
#definitionError = '';
+ #projectsBindings: { [key: string]: ProjectAlmBindingResponse | undefined } = {};
+ #projectBindingConfigurationErrors: ProjectAlmBindingConfigurationErrors | undefined = undefined;
constructor() {
this.#almSettings = cloneDeep(defaultAlmSettings);
jest
.mocked(updateBitbucketCloudConfiguration)
.mockImplementation(this.handleUpdateBitbucketCloudConfiguration);
+ jest.mocked(getProjectAlmBinding).mockImplementation(this.handleGetProjectBinding);
+ jest.mocked(deleteProjectAlmBinding).mockImplementation(this.handleDeleteProjectAlmBinding);
+ jest.mocked(setProjectAzureBinding).mockImplementation(this.handleSetProjectAzureBinding);
+ jest
+ .mocked(setProjectBitbucketBinding)
+ .mockImplementation(this.handleSetProjectBitbucketBinding);
+ jest
+ .mocked(setProjectBitbucketCloudBinding)
+ .mockImplementation(this.handleSetProjectBitbucketCloudBinding);
+ jest.mocked(setProjectGithubBinding).mockImplementation(this.handleSetProjectGithubBinding);
+ jest.mocked(setProjectGitlabBinding).mockImplementation(this.handleSetProjectGitlabBinding);
+ jest.mocked(validateProjectAlmBinding).mockImplementation(this.handleValidateProjectAlmBinding);
}
handleGetAlmDefinitions = () => {
return this.reply(undefined);
};
+ handleGetProjectBinding = (project: string) => {
+ const projectBinding = this.#projectsBindings[project];
+
+ if (projectBinding === undefined) {
+ return Promise.reject(
+ new Response('', {
+ status: 404,
+ })
+ );
+ }
+
+ return this.reply(projectBinding);
+ };
+
+ handleSetProjectBinding = (alm: AlmKeys, data: EnhancedProjectAlmBindingParam) => {
+ this.#projectsBindings[data.project] = {
+ alm,
+ key: data.almSetting,
+ repository: data.repositoryName ?? (data.repository as string),
+ monorepo: data.monorepo,
+ slug: data.projectName ?? data.slug,
+ summaryCommentEnabled: data.summaryCommentEnabled ?? false,
+ url: 'https://company.com/project',
+ };
+ return this.reply(undefined);
+ };
+
+ handleSetProjectAzureBinding = (data: AzureProjectAlmBindingParams) => {
+ return this.handleSetProjectBinding(AlmKeys.Azure, data);
+ };
+
+ handleSetProjectBitbucketBinding = (data: BitbucketProjectAlmBindingParams) => {
+ return this.handleSetProjectBinding(AlmKeys.BitbucketServer, data);
+ };
+
+ handleSetProjectBitbucketCloudBinding = (data: BitbucketCloudProjectAlmBindingParams) => {
+ return this.handleSetProjectBinding(AlmKeys.BitbucketCloud, data);
+ };
+
+ handleSetProjectGithubBinding = (data: GithubProjectAlmBindingParams) => {
+ return this.handleSetProjectBinding(AlmKeys.GitHub, data);
+ };
+
+ handleSetProjectGitlabBinding = (data: GitlabProjectAlmBindingParams) => {
+ return this.handleSetProjectBinding(AlmKeys.GitLab, data);
+ };
+
+ handleValidateProjectAlmBinding = () => {
+ return this.reply(this.#projectBindingConfigurationErrors);
+ };
+
+ setProjectBindingConfigurationErrors = (errors?: ProjectAlmBindingConfigurationErrors) => {
+ this.#projectBindingConfigurationErrors = errors;
+ };
+
+ handleDeleteProjectAlmBinding = (project: string) => {
+ this.#projectsBindings[project] = undefined;
+ return this.reply(undefined);
+ };
+
reset = () => {
this.#almSettings = cloneDeep(defaultAlmSettings);
this.#almDefinitions = cloneDeep(defaultAlmDefinitions);
+ this.#projectsBindings = {};
+ this.#projectBindingConfigurationErrors = undefined;
this.setDefinitionErrorMessage('');
};
import { screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import * as React from 'react';
+import { mockProjectAlmBindingResponse } from '../../../../../helpers/mocks/alm-settings';
import {
mockMainBranch,
mockPullRequest,
renderHeader(
{
currentUser: mockLoggedInUser(),
- projectBinding: { alm: AlmKeys.GitLab, key: 'key', monorepo: true },
+ projectBinding: mockProjectAlmBindingResponse({
+ alm: AlmKeys.GitLab,
+ key: 'key',
+ monorepo: true,
+ }),
},
[]
);
almSettings.reset();
});
-const ui = {
- almHeading: byRole('heading', { name: 'settings.almintegration.title' }),
- emptyIntro: (almKey: AlmKeys) => byText(`settings.almintegration.empty.${almKey}`),
- createConfigurationButton: byRole('button', { name: 'settings.almintegration.create' }),
- tab: (almKey: AlmKeys) =>
- byRole('tab', { name: `${almKey} settings.almintegration.tab.${almKey}` }),
- bitbucketConfiguration: (almKey: AlmKeys.BitbucketCloud | AlmKeys.BitbucketServer) =>
- byRole('button', { name: `alm.${almKey}.long` }),
- configurationInput: (id: string) =>
- byRole('textbox', { name: `settings.almintegration.form.${id}` }),
- updateSecretValueButton: (key: string) =>
- byRole('button', {
- name: `settings.almintegration.form.secret.update_field_x.settings.almintegration.form.${key}`,
- }),
- saveConfigurationButton: byRole('button', { name: 'settings.almintegration.form.save' }),
- editConfigurationButton: (key: string) =>
- byRole('button', { name: `settings.almintegration.edit_configuration.${key}` }),
- deleteConfigurationButton: (key: string) =>
- byRole('button', { name: `settings.almintegration.delete_configuration.${key}` }),
- cancelButton: byRole('button', { name: 'cancel' }),
- confirmDelete: byRole('button', { name: 'delete' }),
- checkConfigurationButton: (key: string) =>
- byRole('button', { name: `settings.almintegration.check_configuration_x.${key}` }),
- validationErrorMessage: byRole('alert'),
- validationSuccessMessage: byRole('status'),
-};
-
describe('github tab', () => {
it('can create/edit/delete new configuration', async () => {
+ const { ui } = getPageObjects();
const { rerender } = renderAlmIntegration();
expect(await ui.almHeading.find()).toBeInTheDocument();
expect(ui.emptyIntro(AlmKeys.GitHub).get()).toBeInTheDocument();
// Create new configuration
- await createConfiguration('Name', {
+ await ui.createConfiguration('Name', {
'name.github': 'Name',
'url.github': 'https://api.github.com',
app_id: 'Github App ID',
private_key: 'Key',
});
- await editConfiguration('New Name', 'Name', 'client_secret.github', AlmKeys.GitHub);
+ await ui.editConfiguration('New Name', 'Name', 'client_secret.github', AlmKeys.GitHub);
- await checkConfiguration('New Name');
+ await ui.checkConfiguration('New Name');
rerender(<AlmIntegration />);
expect(await screen.findByRole('heading', { name: 'New Name' })).toBeInTheDocument();
- await deleteConfiguration('New Name');
+ await ui.deleteConfiguration('New Name');
expect(ui.emptyIntro(AlmKeys.GitHub).get()).toBeInTheDocument();
});
});
'%s tab',
(almKey: AlmKeys.Azure | AlmKeys.GitLab) => {
it('can create/edit/delete new configuration', async () => {
+ const { ui } = getPageObjects();
+
renderAlmIntegration();
expect(await ui.almHeading.find()).toBeInTheDocument();
expect(ui.emptyIntro(almKey).get()).toBeInTheDocument();
// Create new configuration
- await createConfiguration('Name', {
+ await ui.createConfiguration('Name', {
[`name.${almKey}`]: 'Name',
[`url.${almKey}`]: 'https://api.alm.com',
personal_access_token: 'Access Token',
// Cannot create another configuration without Multiple Alm feature
expect(ui.createConfigurationButton.get()).toBeDisabled();
- await editConfiguration('New Name', 'Name', 'personal_access_token', almKey);
+ await ui.editConfiguration('New Name', 'Name', 'personal_access_token', almKey);
- await checkConfiguration('New Name');
+ await ui.checkConfiguration('New Name');
- await deleteConfiguration('New Name');
+ await ui.deleteConfiguration('New Name');
expect(ui.emptyIntro(almKey).get()).toBeInTheDocument();
});
}
describe('bitbucket tab', () => {
it('can create/edit/delete new configuration', async () => {
+ const { ui } = getPageObjects();
renderAlmIntegration([Feature.MultipleAlm]);
expect(await ui.almHeading.find()).toBeInTheDocument();
expect(ui.emptyIntro(AlmKeys.BitbucketServer).get()).toBeInTheDocument();
// Create new Bitbucket Server configuration
- await createConfiguration(
+ await ui.createConfiguration(
'Name',
{
'name.bitbucket': 'Name',
);
// Create new Bitbucket Cloud configuration
- await createConfiguration(
+ await ui.createConfiguration(
'Name Cloud',
{
'name.bitbucket': 'Name Cloud',
);
// Edit, check delete Bitbucket Server configuration
- await editConfiguration('New Name', 'Name', 'personal_access_token', AlmKeys.BitbucketServer);
+ await ui.editConfiguration(
+ 'New Name',
+ 'Name',
+ 'personal_access_token',
+ AlmKeys.BitbucketServer
+ );
- await checkConfiguration('New Name');
+ await ui.checkConfiguration('New Name');
- await deleteConfiguration('New Name');
+ await ui.deleteConfiguration('New Name');
// Cloud configuration still exists
expect(screen.getByRole('heading', { name: 'Name Cloud' })).toBeInTheDocument();
});
});
-async function createConfiguration(
- name: string,
- params: { [key: string]: string },
- almKey?: AlmKeys.BitbucketCloud | AlmKeys.BitbucketServer
-) {
- await userEvent.click(ui.createConfigurationButton.get());
- expect(ui.saveConfigurationButton.get()).toBeDisabled();
-
- if (almKey) {
- await userEvent.click(ui.bitbucketConfiguration(almKey).get());
+function getPageObjects() {
+ const user = userEvent.setup();
+
+ const ui = {
+ almHeading: byRole('heading', { name: 'settings.almintegration.title' }),
+ emptyIntro: (almKey: AlmKeys) => byText(`settings.almintegration.empty.${almKey}`),
+ createConfigurationButton: byRole('button', { name: 'settings.almintegration.create' }),
+ tab: (almKey: AlmKeys) =>
+ byRole('tab', { name: `${almKey} settings.almintegration.tab.${almKey}` }),
+ bitbucketConfiguration: (almKey: AlmKeys.BitbucketCloud | AlmKeys.BitbucketServer) =>
+ byRole('button', { name: `alm.${almKey}.long` }),
+ configurationInput: (id: string) =>
+ byRole('textbox', { name: `settings.almintegration.form.${id}` }),
+ updateSecretValueButton: (key: string) =>
+ byRole('button', {
+ name: `settings.almintegration.form.secret.update_field_x.settings.almintegration.form.${key}`,
+ }),
+ saveConfigurationButton: byRole('button', { name: 'settings.almintegration.form.save' }),
+ editConfigurationButton: (key: string) =>
+ byRole('button', { name: `settings.almintegration.edit_configuration.${key}` }),
+ deleteConfigurationButton: (key: string) =>
+ byRole('button', { name: `settings.almintegration.delete_configuration.${key}` }),
+ cancelButton: byRole('button', { name: 'cancel' }),
+ confirmDelete: byRole('button', { name: 'delete' }),
+ checkConfigurationButton: (key: string) =>
+ byRole('button', { name: `settings.almintegration.check_configuration_x.${key}` }),
+ validationErrorMessage: byRole('alert'),
+ validationSuccessMessage: byRole('status'),
+ };
+
+ async function createConfiguration(
+ name: string,
+ params: { [key: string]: string },
+ almKey?: AlmKeys.BitbucketCloud | AlmKeys.BitbucketServer
+ ) {
+ await userEvent.click(ui.createConfigurationButton.get());
+ expect(ui.saveConfigurationButton.get()).toBeDisabled();
+
+ if (almKey) {
+ await userEvent.click(ui.bitbucketConfiguration(almKey).get());
+ }
+
+ for (const [key, value] of Object.entries(params)) {
+ // eslint-disable-next-line no-await-in-loop
+ await userEvent.type(ui.configurationInput(key).get(), value);
+ }
+ expect(ui.saveConfigurationButton.get()).toBeEnabled();
+ await userEvent.click(ui.saveConfigurationButton.get());
+
+ // New configuration is created
+ expect(screen.getByRole('heading', { name })).toBeInTheDocument();
}
- for (const [key, value] of Object.entries(params)) {
- // eslint-disable-next-line no-await-in-loop
- await userEvent.type(ui.configurationInput(key).get(), value);
+ async function editConfiguration(
+ newName: string,
+ currentName: string,
+ secretId: string,
+ almKey: AlmKeys
+ ) {
+ almSettings.setDefinitionErrorMessage('Something is wrong');
+ await userEvent.click(ui.editConfigurationButton(currentName).get());
+ expect(ui.configurationInput(secretId).query()).not.toBeInTheDocument();
+ await userEvent.click(ui.updateSecretValueButton(secretId).get());
+ await userEvent.type(ui.configurationInput(secretId).get(), 'New Secret Value');
+ await userEvent.clear(ui.configurationInput(`name.${almKey}`).get());
+ await userEvent.type(ui.configurationInput(`name.${almKey}`).get(), newName);
+ await userEvent.click(ui.saveConfigurationButton.get());
+
+ // Existing configuration is edited
+ expect(screen.queryByRole('heading', { name: currentName })).not.toBeInTheDocument();
+ expect(screen.getByRole('heading', { name: newName })).toBeInTheDocument();
+ expect(ui.validationErrorMessage.get()).toHaveTextContent('Something is wrong');
}
- expect(ui.saveConfigurationButton.get()).toBeEnabled();
- await userEvent.click(ui.saveConfigurationButton.get());
-
- // New configuration is created
- expect(screen.getByRole('heading', { name })).toBeInTheDocument();
-}
-async function editConfiguration(
- newName: string,
- currentName: string,
- secretId: string,
- almKey: AlmKeys
-) {
- almSettings.setDefinitionErrorMessage('Something is wrong');
- await userEvent.click(ui.editConfigurationButton(currentName).get());
- expect(ui.configurationInput(secretId).query()).not.toBeInTheDocument();
- await userEvent.click(ui.updateSecretValueButton(secretId).get());
- await userEvent.type(ui.configurationInput(secretId).get(), 'New Secret Value');
- await userEvent.clear(ui.configurationInput(`name.${almKey}`).get());
- await userEvent.type(ui.configurationInput(`name.${almKey}`).get(), newName);
- await userEvent.click(ui.saveConfigurationButton.get());
-
- // Existing configuration is edited
- expect(screen.queryByRole('heading', { name: currentName })).not.toBeInTheDocument();
- expect(screen.getByRole('heading', { name: newName })).toBeInTheDocument();
- expect(ui.validationErrorMessage.get()).toHaveTextContent('Something is wrong');
-}
+ async function checkConfiguration(name: string) {
+ almSettings.setDefinitionErrorMessage('');
+ await userEvent.click(ui.checkConfigurationButton(name).get());
+ expect(ui.validationSuccessMessage.getAll()[0]).toHaveTextContent(
+ 'alert.tooltip.successsettings.almintegration.configuration_valid'
+ );
+ }
-async function checkConfiguration(name: string) {
- almSettings.setDefinitionErrorMessage('');
- await userEvent.click(ui.checkConfigurationButton(name).get());
- expect(ui.validationSuccessMessage.getAll()[0]).toHaveTextContent(
- 'alert.tooltip.successsettings.almintegration.configuration_valid'
- );
-}
+ async function deleteConfiguration(name: string) {
+ await userEvent.click(ui.deleteConfigurationButton(name).get());
+ await userEvent.click(ui.cancelButton.get());
+ expect(screen.getByRole('heading', { name })).toBeInTheDocument();
-async function deleteConfiguration(name: string) {
- await userEvent.click(ui.deleteConfigurationButton(name).get());
- await userEvent.click(ui.cancelButton.get());
- expect(screen.getByRole('heading', { name })).toBeInTheDocument();
+ await userEvent.click(ui.deleteConfigurationButton(name).get());
+ await userEvent.click(ui.confirmDelete.get());
+ expect(screen.queryByRole('heading', { name })).not.toBeInTheDocument();
+ }
- await userEvent.click(ui.deleteConfigurationButton(name).get());
- await userEvent.click(ui.confirmDelete.get());
- expect(screen.queryByRole('heading', { name })).not.toBeInTheDocument();
+ return {
+ ui: {
+ ...ui,
+ createConfiguration,
+ editConfiguration,
+ deleteConfiguration,
+ checkConfiguration,
+ },
+ user,
+ };
}
function renderAlmIntegration(features: Feature[] = []) {
);
}
-function renderHelp({ help, helpExample, helpParams, id }: CommonFieldProps) {
+function renderHelp({ help, helpExample, helpParams = {}, id }: CommonFieldProps) {
return (
help && (
<>
renderLabel({ ...props, optional: true }),
<div className="display-flex-center big-spacer-top">
<div className="display-inline-block text-top">
- <Toggle name={id} onChange={(v) => onFieldChange(propKey, v)} value={value} />
+ <Toggle id={id} name={id} onChange={(v) => onFieldChange(propKey, v)} value={value} />
{value == null && <span className="spacer-left note">{translate('settings.not_set')}</span>}
</div>
{inputExtra}
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { cloneDeep } from 'lodash';
import * as React from 'react';
import {
deleteProjectAlmBinding,
[AlmKeys.GitLab]: ['repository'],
};
+const INITIAL_FORM_DATA = { key: '', repository: '', monorepo: false };
+
export class PRDecorationBinding extends React.PureComponent<Props, State> {
mounted = false;
state: State = {
- formData: { key: '', monorepo: false },
+ formData: cloneDeep(INITIAL_FORM_DATA),
instances: [],
isChanged: false,
isConfigured: false,
submitProjectAlmBinding(
alm: AlmKeys,
key: string,
- almSpecificFields?: Omit<FormData, 'key'>
+ almSpecificFields: Omit<FormData, 'key'>
): Promise<void> {
const almSetting = key;
+ const { repository, slug = '', monorepo = false } = almSpecificFields;
const project = this.props.component.key;
- const repository = almSpecificFields?.repository;
- const slug = almSpecificFields?.slug;
- const monorepo = almSpecificFields?.monorepo ?? false;
-
- if (!repository) {
- return Promise.reject();
- }
switch (alm) {
case AlmKeys.Azure: {
- if (!slug) {
- return Promise.reject();
- }
return setProjectAzureBinding({
almSetting,
project,
});
}
case AlmKeys.BitbucketServer: {
- if (!slug) {
- return Promise.reject();
- }
return setProjectBitbucketBinding({
almSetting,
project,
return {
formData: newFormData,
isValid: this.validateForm(newFormData),
- isChanged: !this.isDataSame(newFormData, originalData || { key: '', monorepo: false }),
+ isChanged: !this.isDataSame(newFormData, originalData || cloneDeep(INITIAL_FORM_DATA)),
successfullyUpdated: false,
};
});
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { mockAlmSettingsInstance } from '../../../../../helpers/mocks/alm-settings';
-import { AlmKeys, AlmSettingsInstance } from '../../../../../types/alm-settings';
-import { AlmSpecificForm, AlmSpecificFormProps } from '../AlmSpecificForm';
-
-it.each([
- [AlmKeys.Azure],
- [AlmKeys.BitbucketServer],
- [AlmKeys.BitbucketCloud],
- [AlmKeys.GitHub],
- [AlmKeys.GitLab],
-])('should render correctly for %s', (alm) => {
- expect(shallowRender(alm)).toMatchSnapshot();
-});
-
-it.each([
- [
- AlmKeys.BitbucketServer,
- [mockAlmSettingsInstance({ alm: AlmKeys.BitbucketServer, url: 'http://bbs.example.com' })],
- ],
- [AlmKeys.GitHub, [mockAlmSettingsInstance({ url: 'http://example.com/api/v3' })]],
- [AlmKeys.GitHub, [mockAlmSettingsInstance({ url: 'http://api.github.com' })]],
-])(
- 'should render correctly for %s if an instance URL is provided',
- (alm: AlmKeys, instances: AlmSettingsInstance[]) => {
- expect(shallowRender(alm, { instances })).toMatchSnapshot();
- }
-);
-
-it('should render the monorepo field when the feature is supported', () => {
- expect(shallowRender(AlmKeys.Azure, { hasFeature: jest.fn(() => true) })).toMatchSnapshot();
-});
-
-function shallowRender(alm: AlmKeys, props: Partial<AlmSpecificFormProps> = {}) {
- return shallow(
- <AlmSpecificForm
- alm={alm}
- instances={[]}
- formData={{
- key: '',
- repository: '',
- slug: '',
- monorepo: false,
- }}
- onFieldChange={jest.fn()}
- hasFeature={jest.fn()}
- {...props}
- />
- );
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import userEvent from '@testing-library/user-event';
+import React from 'react';
+import selectEvent from 'react-select-event';
+import { byRole } from 'testing-library-selector';
+import AlmSettingsServiceMock from '../../../../../api/mocks/AlmSettingsServiceMock';
+import CurrentUserContextProvider from '../../../../../app/components/current-user/CurrentUserContextProvider';
+import { mockComponent } from '../../../../../helpers/mocks/component';
+import { mockCurrentUser } from '../../../../../helpers/testMocks';
+import { renderComponent } from '../../../../../helpers/testReactTestingUtils';
+import {
+ AlmKeys,
+ ProjectAlmBindingConfigurationErrorScope,
+} from '../../../../../types/alm-settings';
+import { Component } from '../../../../../types/types';
+import { CurrentUser } from '../../../../../types/users';
+import PRDecorationBinding from '../PRDecorationBinding';
+
+jest.mock('../../../../../api/alm-settings');
+
+let almSettings: AlmSettingsServiceMock;
+
+beforeAll(() => {
+ almSettings = new AlmSettingsServiceMock();
+});
+
+afterEach(() => {
+ almSettings.reset();
+});
+
+const inputsList = {
+ [AlmKeys.GitLab]: { 'gitlab.repository': 'Repository', monorepo: false },
+ [AlmKeys.GitHub]: {
+ 'github.repository': 'Repository',
+ 'github.summary_comment_setting': false,
+ monorepo: false,
+ },
+ [AlmKeys.Azure]: {
+ 'azure.repository': 'Repository',
+ 'azure.project': 'Project',
+ monorepo: false,
+ },
+ [AlmKeys.BitbucketCloud]: { 'bitbucketcloud.repository': 'Repository', monorepo: false },
+ [AlmKeys.BitbucketServer]: {
+ 'bitbucket.repository': 'Repository',
+ 'bitbucket.slug': 'Slug',
+ monorepo: false,
+ },
+};
+
+it.each([
+ {
+ key: 'conf-final-1',
+ alm: AlmKeys.GitLab,
+ },
+ {
+ key: 'conf-github-1',
+ alm: AlmKeys.GitHub,
+ },
+ {
+ key: 'conf-azure-1',
+ alm: AlmKeys.Azure,
+ },
+ {
+ key: 'conf-bitbucketcloud-1',
+ alm: AlmKeys.BitbucketCloud,
+ },
+ {
+ key: 'conf-bitbucketserver-1',
+ alm: AlmKeys.BitbucketServer,
+ },
+])(
+ 'should get, set, delete and validate binding for $alm',
+ async ({ key, alm }: { key: string; alm: AlmKeys }) => {
+ const { ui, user } = getPageObjects();
+ almSettings.setProjectBindingConfigurationErrors({
+ scope: ProjectAlmBindingConfigurationErrorScope.Global,
+ errors: [{ msg: 'cute error' }],
+ });
+ const { rerender } = renderPRDecorationBinding();
+ expect(await ui.mainTitle.find()).toBeInTheDocument();
+
+ // Set form data
+ await selectEvent.select(ui.input('name', 'combobox').get(), (content) =>
+ content.includes(key)
+ );
+
+ const list = inputsList[alm];
+ for (const [inputId, value] of Object.entries(list)) {
+ // eslint-disable-next-line no-await-in-loop
+ await ui.setInput(inputId, value);
+ }
+ // Save form and check for errors
+ await user.click(ui.saveButton.get());
+ expect(ui.validationErrorMsg.get()).toHaveTextContent('cute error');
+
+ // Check validation with errors
+ await user.click(ui.validateButton.get());
+ expect(ui.validationErrorMsg.get()).toHaveTextContent('cute error');
+
+ // Save form and check for errors
+ almSettings.setProjectBindingConfigurationErrors(undefined);
+ await ui.setInput(
+ Object.keys(list).find((key) => key.endsWith('.repository')) as string,
+ 'Anything'
+ );
+ await user.click(ui.saveButton.get());
+ expect(await ui.validationSuccessMsg.find()).toHaveTextContent(
+ 'settings.pr_decoration.binding.check_configuration.success'
+ );
+
+ await user.click(ui.validateButton.get());
+ expect(ui.validationSuccessMsg.get()).toHaveTextContent(
+ 'settings.pr_decoration.binding.check_configuration.success'
+ );
+
+ // Rerender and verify that validation is done for binding
+ rerender(
+ <MockedPRDecorationBinding component={mockComponent()} currentUser={mockCurrentUser()} />
+ );
+ expect(await ui.validationSuccessMsg.find()).toHaveTextContent(
+ 'settings.pr_decoration.binding.check_configuration.success'
+ );
+ expect(ui.saveButton.query()).not.toBeInTheDocument();
+
+ // Reset binding
+ await user.click(ui.resetButton.get());
+ expect(ui.input('', 'textbox').query()).not.toBeInTheDocument();
+ expect(ui.input('', 'switch').query()).not.toBeInTheDocument();
+ }
+);
+
+function getPageObjects() {
+ const user = userEvent.setup();
+
+ async function setInput(inputId: string, value: string | boolean) {
+ if (typeof value === 'boolean') {
+ if (value) {
+ await user.click(ui.input(inputId, 'switch').get());
+ }
+ } else {
+ const input = ui.input(inputId, 'textbox').get();
+ await user.clear(input);
+ await user.type(input, value);
+ }
+ }
+
+ const ui = {
+ mainTitle: byRole('heading', { name: 'settings.pr_decoration.binding.title' }),
+ input: (id: string, role: 'combobox' | 'switch' | 'textbox') =>
+ byRole(role, { name: new RegExp(`settings.pr_decoration.binding.form.${id}`) }),
+ saveButton: byRole('button', { name: 'save' }),
+ resetButton: byRole('button', { name: 'reset_verb' }),
+ validateButton: byRole('button', {
+ name: 'settings.pr_decoration.binding.check_configuration',
+ }),
+ validationErrorMsg: byRole('alert'),
+ validationSuccessMsg: byRole('status'),
+ setInput,
+ };
+
+ return {
+ ui,
+ user,
+ };
+}
+
+function MockedPRDecorationBinding({
+ component,
+ currentUser,
+}: {
+ component: Component;
+ currentUser: CurrentUser;
+}) {
+ return (
+ <CurrentUserContextProvider currentUser={currentUser}>
+ <PRDecorationBinding component={component} />
+ </CurrentUserContextProvider>
+ );
+}
+
+function renderPRDecorationBinding(
+ component: Component = mockComponent(),
+ currentUser: CurrentUser = mockCurrentUser()
+) {
+ return renderComponent(
+ <MockedPRDecorationBinding component={component} currentUser={currentUser} />
+ );
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import {
- deleteProjectAlmBinding,
- getAlmSettings,
- getProjectAlmBinding,
- setProjectAzureBinding,
- setProjectBitbucketBinding,
- setProjectBitbucketCloudBinding,
- setProjectGithubBinding,
- setProjectGitlabBinding,
- validateProjectAlmBinding,
-} from '../../../../../api/alm-settings';
-import {
- mockAlmSettingsInstance,
- mockProjectAlmBindingConfigurationErrors,
- mockProjectAlmBindingResponse,
-} from '../../../../../helpers/mocks/alm-settings';
-import { mockComponent } from '../../../../../helpers/mocks/component';
-import { mockCurrentUser } from '../../../../../helpers/testMocks';
-import { waitAndUpdate } from '../../../../../helpers/testUtils';
-import { AlmKeys, AlmSettingsInstance } from '../../../../../types/alm-settings';
-import { PRDecorationBinding } from '../PRDecorationBinding';
-import PRDecorationBindingRenderer from '../PRDecorationBindingRenderer';
-
-jest.mock('../../../../../api/alm-settings', () => ({
- getAlmSettings: jest.fn().mockResolvedValue([]),
- getProjectAlmBinding: jest.fn().mockResolvedValue(undefined),
- setProjectAzureBinding: jest.fn().mockResolvedValue(undefined),
- setProjectBitbucketBinding: jest.fn().mockResolvedValue(undefined),
- setProjectGithubBinding: jest.fn().mockResolvedValue(undefined),
- setProjectGitlabBinding: jest.fn().mockResolvedValue(undefined),
- setProjectBitbucketCloudBinding: jest.fn().mockResolvedValue(undefined),
- deleteProjectAlmBinding: jest.fn().mockResolvedValue(undefined),
- validateProjectAlmBinding: jest.fn().mockResolvedValue(undefined),
-}));
-
-const PROJECT_KEY = 'project-key';
-
-beforeEach(() => {
- jest.clearAllMocks();
-});
-
-it('should render correctly', () => {
- expect(shallowRender()).toMatchSnapshot();
-});
-
-it('should fill selects and fill formdata', async () => {
- const url = 'github.com';
- const instances = [{ key: 'instance1', url, alm: AlmKeys.GitHub }];
- const formdata = {
- key: 'instance1',
- repository: 'account/repo',
- };
- (getAlmSettings as jest.Mock).mockResolvedValueOnce(instances);
- (getProjectAlmBinding as jest.Mock).mockResolvedValueOnce(formdata);
-
- const wrapper = shallowRender();
- await waitAndUpdate(wrapper);
-
- expect(wrapper.state().loading).toBe(false);
- expect(wrapper.state().formData).toEqual(formdata);
- expect(wrapper.state().isChanged).toBe(false);
-});
-
-it('should handle reset', async () => {
- const wrapper = shallowRender();
- await waitAndUpdate(wrapper);
- wrapper.setState({
- formData: {
- key: 'whatever',
- repository: 'something/else',
- monorepo: false,
- },
- });
-
- wrapper.instance().handleReset();
- await waitAndUpdate(wrapper);
-
- expect(deleteProjectAlmBinding).toHaveBeenCalledWith(PROJECT_KEY);
- expect(wrapper.state().formData).toEqual({ key: '', repository: '', slug: '', monorepo: false });
- expect(wrapper.state().isChanged).toBe(false);
-});
-
-describe('handleSubmit', () => {
- const instances: AlmSettingsInstance[] = [
- { key: 'github', alm: AlmKeys.GitHub },
- { key: 'azure', alm: AlmKeys.Azure },
- { key: 'bitbucket', alm: AlmKeys.BitbucketServer },
- { key: 'gitlab', alm: AlmKeys.GitLab },
- { key: 'bitbucketcloud', alm: AlmKeys.BitbucketCloud },
- ];
-
- it('should work for github', async () => {
- const wrapper = shallowRender();
- await waitAndUpdate(wrapper);
- const githubKey = 'github';
- const repository = 'repo/path';
- const summaryCommentEnabled = true;
- const monorepo = true;
- wrapper.setState({
- formData: { key: githubKey, repository, summaryCommentEnabled, monorepo },
- instances,
- });
- wrapper.instance().handleSubmit();
- await waitAndUpdate(wrapper);
-
- expect(setProjectGithubBinding).toHaveBeenCalledWith({
- almSetting: githubKey,
- project: PROJECT_KEY,
- repository,
- summaryCommentEnabled,
- monorepo,
- });
- expect(wrapper.state().successfullyUpdated).toBe(true);
- });
-
- it('should work for azure', async () => {
- const wrapper = shallowRender();
- await waitAndUpdate(wrapper);
- const azureKey = 'azure';
- const repository = 'az-rep';
- const slug = 'az-project';
- const monorepo = true;
- wrapper.setState({
- formData: { key: azureKey, repository, slug, monorepo },
- instances,
- });
- wrapper.instance().handleSubmit();
- await waitAndUpdate(wrapper);
-
- expect(setProjectAzureBinding).toHaveBeenCalledWith({
- almSetting: azureKey,
- project: PROJECT_KEY,
- projectName: slug,
- repositoryName: repository,
- monorepo,
- });
- expect(wrapper.state().successfullyUpdated).toBe(true);
- });
-
- it('should work for bitbucket', async () => {
- const wrapper = shallowRender();
- await waitAndUpdate(wrapper);
- const bitbucketKey = 'bitbucket';
- const repository = 'repoKey';
- const slug = 'repoSlug';
- const monorepo = true;
- wrapper.setState({ formData: { key: bitbucketKey, repository, slug, monorepo }, instances });
- wrapper.instance().handleSubmit();
- await waitAndUpdate(wrapper);
-
- expect(setProjectBitbucketBinding).toHaveBeenCalledWith({
- almSetting: bitbucketKey,
- project: PROJECT_KEY,
- repository,
- slug,
- monorepo,
- });
- expect(wrapper.state().successfullyUpdated).toBe(true);
- });
-
- it('should work for gitlab', async () => {
- const wrapper = shallowRender();
- await waitAndUpdate(wrapper);
- const gitlabKey = 'gitlab';
- const repository = 'repo';
- const monorepo = true;
- wrapper.setState({
- formData: { key: gitlabKey, repository, monorepo },
- instances,
- });
- wrapper.instance().handleSubmit();
- await waitAndUpdate(wrapper);
-
- expect(setProjectGitlabBinding).toHaveBeenCalledWith({
- almSetting: gitlabKey,
- project: PROJECT_KEY,
- repository,
- monorepo,
- });
- expect(wrapper.state().successfullyUpdated).toBe(true);
- });
-
- it('should work for bitbucket cloud', async () => {
- const wrapper = shallowRender();
- await waitAndUpdate(wrapper);
- const bitbucketKey = 'bitbucketcloud';
- const repository = 'repoKey';
- const monorepo = true;
- wrapper.setState({ formData: { key: bitbucketKey, repository, monorepo }, instances: [] });
- wrapper.instance().handleSubmit();
- await waitAndUpdate(wrapper);
- expect(setProjectBitbucketCloudBinding).not.toHaveBeenCalled();
-
- wrapper.setState({ formData: { key: bitbucketKey, repository, monorepo }, instances });
- wrapper.instance().handleSubmit();
- await waitAndUpdate(wrapper);
-
- expect(setProjectBitbucketCloudBinding).toHaveBeenCalledWith({
- almSetting: bitbucketKey,
- project: PROJECT_KEY,
- repository,
- monorepo,
- });
- expect(wrapper.state().successfullyUpdated).toBe(true);
- });
-});
-
-describe.each([[500], [404]])('For status %i', (status) => {
- it('should handle failures gracefully', async () => {
- const newFormData = {
- key: 'whatever',
- repository: 'something/else',
- monorepo: false,
- };
-
- (getProjectAlmBinding as jest.Mock).mockRejectedValueOnce({ status });
- (setProjectGithubBinding as jest.Mock).mockRejectedValueOnce({ status });
- (deleteProjectAlmBinding as jest.Mock).mockRejectedValueOnce({ status });
-
- const wrapper = shallowRender();
- await waitAndUpdate(wrapper);
- wrapper.setState({
- formData: newFormData,
- originalData: undefined,
- });
-
- wrapper.instance().handleSubmit();
- await waitAndUpdate(wrapper);
- expect(wrapper.instance().state.originalData).toBeUndefined();
- wrapper.instance().handleReset();
- await waitAndUpdate(wrapper);
- expect(wrapper.instance().state.formData).toEqual(newFormData);
- });
-});
-
-it('should handle field changes', async () => {
- const url = 'git.enterprise.com';
- const repository = 'my/repo';
- const instances: AlmSettingsInstance[] = [
- { key: 'instance1', url, alm: AlmKeys.GitHub },
- { key: 'instance2', url, alm: AlmKeys.GitHub },
- { key: 'instance3', url: 'otherurl', alm: AlmKeys.GitHub },
- ];
- (getAlmSettings as jest.Mock).mockResolvedValueOnce(instances);
- const wrapper = shallowRender();
- await waitAndUpdate(wrapper);
-
- wrapper.instance().handleFieldChange('key', 'instance2');
- await waitAndUpdate(wrapper);
- expect(wrapper.state().formData).toEqual({
- key: 'instance2',
- monorepo: false,
- });
-
- wrapper.instance().handleFieldChange('repository', repository);
- await waitAndUpdate(wrapper);
- expect(wrapper.state().formData).toEqual({
- key: 'instance2',
- repository,
- monorepo: false,
- });
-
- wrapper.instance().handleFieldChange('summaryCommentEnabled', true);
- await waitAndUpdate(wrapper);
- expect(wrapper.state().formData).toEqual({
- key: 'instance2',
- monorepo: false,
- repository,
- summaryCommentEnabled: true,
- });
-
- wrapper.instance().handleFieldChange('monorepo', true);
- await waitAndUpdate(wrapper);
- expect(wrapper.state().formData).toEqual({
- key: 'instance2',
- repository,
- summaryCommentEnabled: true,
- monorepo: true,
- });
-});
-
-it.each([
- [AlmKeys.Azure, { monorepo: false }],
- [AlmKeys.Azure, { slug: 'test', monorepo: false }],
- [AlmKeys.Azure, { repository: 'test', monorepo: false }],
- [AlmKeys.BitbucketServer, { monorepo: false }],
- [AlmKeys.BitbucketServer, { slug: 'test', monorepo: false }],
- [AlmKeys.BitbucketServer, { repository: 'test', monorepo: false }],
- [AlmKeys.BitbucketCloud, { monorepo: false }],
- [AlmKeys.GitHub, { monorepo: false }],
- [AlmKeys.GitLab, { monorepo: false }],
-])(
- 'should properly reject promise for %s & %s',
- async (almKey: AlmKeys, params: { monorepo: boolean }) => {
- const wrapper = shallowRender();
-
- expect.assertions(1);
- await expect(
- wrapper.instance().submitProjectAlmBinding(almKey, 'binding', params)
- ).rejects.toBeUndefined();
- }
-);
-
-it('should validate form', async () => {
- const wrapper = shallowRender();
- await waitAndUpdate(wrapper);
-
- const validateMethod = wrapper.instance().validateForm;
-
- expect(validateMethod({ key: '', repository: '', monorepo: false })).toBe(false);
- expect(validateMethod({ key: '', repository: 'c', monorepo: false })).toBe(false);
-
- wrapper.setState({
- instances: [
- { key: 'azure', alm: AlmKeys.Azure },
- { key: 'bitbucket', alm: AlmKeys.BitbucketServer },
- { key: 'bitbucketcloud', alm: AlmKeys.BitbucketCloud },
- { key: 'github', alm: AlmKeys.GitHub },
- { key: 'gitlab', alm: AlmKeys.GitLab },
- ],
- });
-
- [
- { values: { key: 'azure', monorepo: false, repository: 'rep' }, result: false },
- { values: { key: 'azure', monorepo: false, slug: 'project' }, result: false },
- {
- values: { key: 'azure', monorepo: false, repository: 'repo', slug: 'project' },
- result: true,
- },
- { values: { key: 'github', monorepo: false, repository: '' }, result: false },
- { values: { key: 'github', monorepo: false, repository: 'asdf' }, result: true },
- { values: { key: 'bitbucket', monorepo: false, repository: 'key' }, result: false },
- {
- values: { key: 'bitbucket', monorepo: false, repository: 'key', slug: 'slug' },
- result: true,
- },
- { values: { key: 'bitbucketcloud', monorepo: false, repository: '' }, result: false },
- { values: { key: 'bitbucketcloud', monorepo: false, repository: 'key' }, result: true },
- { values: { key: 'gitlab', monorepo: false }, result: false },
- { values: { key: 'gitlab', monorepo: false, repository: 'key' }, result: true },
- ].forEach(({ values, result }) => {
- expect(validateMethod(values)).toBe(result);
- });
-});
-
-it('should call the validation WS and store errors', async () => {
- (getAlmSettings as jest.Mock).mockResolvedValueOnce(mockAlmSettingsInstance());
- (getProjectAlmBinding as jest.Mock).mockResolvedValueOnce(
- mockProjectAlmBindingResponse({ key: 'key' })
- );
-
- const errors = mockProjectAlmBindingConfigurationErrors();
- (validateProjectAlmBinding as jest.Mock).mockRejectedValueOnce(errors);
-
- const wrapper = shallowRender();
-
- wrapper.find(PRDecorationBindingRenderer).props().onCheckConfiguration();
-
- await waitAndUpdate(wrapper);
-
- expect(validateProjectAlmBinding).toHaveBeenCalledWith(PROJECT_KEY);
- expect(wrapper.state().configurationErrors).toBe(errors);
-});
-
-it('should call the validation WS after loading', async () => {
- (getAlmSettings as jest.Mock).mockResolvedValueOnce([mockAlmSettingsInstance()]);
- (getProjectAlmBinding as jest.Mock).mockResolvedValueOnce(
- mockProjectAlmBindingResponse({ key: 'key ' })
- );
-
- const wrapper = shallowRender();
-
- await waitAndUpdate(wrapper);
-
- expect(validateProjectAlmBinding).toHaveBeenCalled();
-});
-
-it('should call the validation WS upon saving', async () => {
- (getAlmSettings as jest.Mock).mockResolvedValueOnce([mockAlmSettingsInstance()]);
- (getProjectAlmBinding as jest.Mock).mockResolvedValueOnce(
- mockProjectAlmBindingResponse({ key: 'key ' })
- );
-
- const wrapper = shallowRender();
-
- wrapper.instance().handleFieldChange('key', 'key');
- wrapper.instance().handleSubmit();
-
- await waitAndUpdate(wrapper);
-
- expect(validateProjectAlmBinding).toHaveBeenCalled();
-});
-
-function shallowRender(props: Partial<PRDecorationBinding['props']> = {}) {
- return shallow<PRDecorationBinding>(
- <PRDecorationBinding
- currentUser={mockCurrentUser()}
- component={mockComponent({ key: PROJECT_KEY })}
- {...props}
- />
- );
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import {
- AlmKeys,
- AlmSettingsInstance,
- ProjectAlmBindingConfigurationErrors,
- ProjectAlmBindingConfigurationErrorScope,
-} from '../../../../../types/alm-settings';
-import PRDecorationBindingRenderer, {
- PRDecorationBindingRendererProps,
-} from '../PRDecorationBindingRenderer';
-
-const urls = ['http://github.enterprise.com', 'http://bbs.enterprise.com'];
-const instances: AlmSettingsInstance[] = [
- {
- alm: AlmKeys.GitHub,
- key: 'i1',
- url: urls[0],
- },
- {
- alm: AlmKeys.GitHub,
- key: 'i2',
- url: urls[0],
- },
- {
- alm: AlmKeys.BitbucketServer,
- key: 'i3',
- url: urls[1],
- },
- {
- alm: AlmKeys.Azure,
- key: 'i4',
- },
-];
-const configurationErrors: ProjectAlmBindingConfigurationErrors = {
- scope: ProjectAlmBindingConfigurationErrorScope.Global,
- errors: [{ msg: 'Test' }, { msg: 'tesT' }],
-};
-
-it.each([
- ['when loading', { loading: true }],
- ['with no ALM instances (admin user)', { isSysAdmin: true }],
- ['with no ALM instances (non-admin user)', {}],
- ['with a single ALM instance', { instances: [instances[0]] }],
- ['with an empty form', { instances }],
- [
- 'with a valid and saved form',
- {
- formData: {
- key: 'i1',
- repository: 'account/repo',
- monorepo: false,
- },
- isChanged: false,
- isConfigured: true,
- instances,
- },
- ],
- [
- 'when there are configuration errors (non-admin user)',
- { instances, isConfigured: true, configurationErrors },
- ],
- [
- 'when there are configuration errors (admin user)',
- {
- formData: {
- key: 'i1',
- repository: 'account/repo',
- monorepo: false,
- },
- instances,
- isConfigured: true,
- configurationErrors,
- isSysAdmin: true,
- },
- ],
- [
- 'when there are configuration errors (admin user) and error are at PROJECT level',
- {
- instances,
- isConfigured: true,
- configurationErrors: {
- ...configurationErrors,
- scope: ProjectAlmBindingConfigurationErrorScope.Project,
- },
- isSysAdmin: true,
- },
- ],
-])('should render correctly', (name: string, props: PRDecorationBindingRendererProps) => {
- expect(shallowRender(props)).toMatchSnapshot(name);
-});
-
-it.each([
- ['updating', { updating: true }],
- ['update is successfull', { successfullyUpdated: true }],
- ['form is valid', { isValid: true }],
- ['configuration is saved', { isConfigured: true }],
- ['configuration check is in progress', { isConfigured: true, checkingConfiguration: true }],
-])(
- 'should display action section correctly when',
- (name: string, props: PRDecorationBindingRendererProps) => {
- expect(shallowRender({ ...props, instances }).find('.action-section')).toMatchSnapshot(name);
- }
-);
-
-function shallowRender(props: Partial<PRDecorationBindingRendererProps> = {}) {
- return shallow(
- <PRDecorationBindingRenderer
- formData={{
- key: '',
- repository: '',
- monorepo: false,
- }}
- instances={[]}
- isChanged={false}
- isConfigured={false}
- isValid={false}
- loading={false}
- onFieldChange={jest.fn()}
- onReset={jest.fn()}
- onSubmit={jest.fn()}
- updating={false}
- successfullyUpdated={false}
- checkingConfiguration={false}
- onCheckConfiguration={jest.fn()}
- isSysAdmin={false}
- {...props}
- />
- );
-}
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly for azure 1`] = `
-<Fragment>
- <div
- className="settings-definition"
- >
- <div
- className="settings-definition-left"
- >
- <label
- className="h3"
- htmlFor="azure.project"
- >
- settings.pr_decoration.binding.form.azure.project
- <MandatoryFieldMarker />
- </label>
- <div
- className="markdown small spacer-top"
- >
- <FormattedMessage
- defaultMessage="settings.pr_decoration.binding.form.azure.project.help"
- id="settings.pr_decoration.binding.form.azure.project.help"
- />
- <div
- className="spacer-top nowrap"
- >
- example
- :
- <em>
- <strong>
- My Project
- </strong>
- </em>
- </div>
- </div>
- </div>
- <div
- className="settings-definition-right padded-top"
- >
- <input
- className="input-super-large big-spacer-top"
- id="azure.project"
- maxLength={256}
- name="azure.project"
- onChange={[Function]}
- type="text"
- value=""
- />
- </div>
- </div>
- <div
- className="settings-definition"
- >
- <div
- className="settings-definition-left"
- >
- <label
- className="h3"
- htmlFor="azure.repository"
- >
- settings.pr_decoration.binding.form.azure.repository
- <MandatoryFieldMarker />
- </label>
- <div
- className="markdown small spacer-top"
- >
- <FormattedMessage
- defaultMessage="settings.pr_decoration.binding.form.azure.repository.help"
- id="settings.pr_decoration.binding.form.azure.repository.help"
- />
- <div
- className="spacer-top nowrap"
- >
- example
- :
- <em>
- <strong>
- My Repository
- </strong>
- </em>
- </div>
- </div>
- </div>
- <div
- className="settings-definition-right padded-top"
- >
- <input
- className="input-super-large big-spacer-top"
- id="azure.repository"
- maxLength={256}
- name="azure.repository"
- onChange={[Function]}
- type="text"
- value=""
- />
- </div>
- </div>
-</Fragment>
-`;
-
-exports[`should render correctly for bitbucket 1`] = `
-<Fragment>
- <div
- className="settings-definition"
- >
- <div
- className="settings-definition-left"
- >
- <label
- className="h3"
- htmlFor="bitbucket.repository"
- >
- settings.pr_decoration.binding.form.bitbucket.repository
- <MandatoryFieldMarker />
- </label>
- <div
- className="markdown small spacer-top"
- >
- <FormattedMessage
- defaultMessage="settings.pr_decoration.binding.form.bitbucket.repository.help"
- id="settings.pr_decoration.binding.form.bitbucket.repository.help"
- />
- <div
- className="spacer-top nowrap"
- >
- example
- :
- <em>
- https://bb.company.com/projects/
- <strong>
- MY_PROJECT_KEY
- </strong>
- /repos/my-repository-slug/browse
- </em>
- </div>
- </div>
- </div>
- <div
- className="settings-definition-right padded-top"
- >
- <input
- className="input-super-large big-spacer-top"
- id="bitbucket.repository"
- maxLength={256}
- name="bitbucket.repository"
- onChange={[Function]}
- type="text"
- value=""
- />
- </div>
- </div>
- <div
- className="settings-definition"
- >
- <div
- className="settings-definition-left"
- >
- <label
- className="h3"
- htmlFor="bitbucket.slug"
- >
- settings.pr_decoration.binding.form.bitbucket.slug
- <MandatoryFieldMarker />
- </label>
- <div
- className="markdown small spacer-top"
- >
- <FormattedMessage
- defaultMessage="settings.pr_decoration.binding.form.bitbucket.slug.help"
- id="settings.pr_decoration.binding.form.bitbucket.slug.help"
- />
- <div
- className="spacer-top nowrap"
- >
- example
- :
- <em>
- https://bb.company.com/projects/MY_PROJECT_KEY/repos/
- <strong>
- my-repository-slug
- </strong>
- /browse
- </em>
- </div>
- </div>
- </div>
- <div
- className="settings-definition-right padded-top"
- >
- <input
- className="input-super-large big-spacer-top"
- id="bitbucket.slug"
- maxLength={256}
- name="bitbucket.slug"
- onChange={[Function]}
- type="text"
- value=""
- />
- </div>
- </div>
-</Fragment>
-`;
-
-exports[`should render correctly for bitbucket if an instance URL is provided 1`] = `
-<Fragment>
- <div
- className="settings-definition"
- >
- <div
- className="settings-definition-left"
- >
- <label
- className="h3"
- htmlFor="bitbucket.repository"
- >
- settings.pr_decoration.binding.form.bitbucket.repository
- <MandatoryFieldMarker />
- </label>
- <div
- className="markdown small spacer-top"
- >
- <FormattedMessage
- defaultMessage="settings.pr_decoration.binding.form.bitbucket.repository.help"
- id="settings.pr_decoration.binding.form.bitbucket.repository.help"
- />
- <div
- className="spacer-top nowrap"
- >
- example
- :
- <em>
- http://bbs.example.com/projects/
- <strong>
- MY_PROJECT_KEY
- </strong>
- /repos/my-repository-slug/browse
- </em>
- </div>
- </div>
- </div>
- <div
- className="settings-definition-right padded-top"
- >
- <input
- className="input-super-large big-spacer-top"
- id="bitbucket.repository"
- maxLength={256}
- name="bitbucket.repository"
- onChange={[Function]}
- type="text"
- value=""
- />
- </div>
- </div>
- <div
- className="settings-definition"
- >
- <div
- className="settings-definition-left"
- >
- <label
- className="h3"
- htmlFor="bitbucket.slug"
- >
- settings.pr_decoration.binding.form.bitbucket.slug
- <MandatoryFieldMarker />
- </label>
- <div
- className="markdown small spacer-top"
- >
- <FormattedMessage
- defaultMessage="settings.pr_decoration.binding.form.bitbucket.slug.help"
- id="settings.pr_decoration.binding.form.bitbucket.slug.help"
- />
- <div
- className="spacer-top nowrap"
- >
- example
- :
- <em>
- http://bbs.example.com/projects/MY_PROJECT_KEY/repos/
- <strong>
- my-repository-slug
- </strong>
- /browse
- </em>
- </div>
- </div>
- </div>
- <div
- className="settings-definition-right padded-top"
- >
- <input
- className="input-super-large big-spacer-top"
- id="bitbucket.slug"
- maxLength={256}
- name="bitbucket.slug"
- onChange={[Function]}
- type="text"
- value=""
- />
- </div>
- </div>
-</Fragment>
-`;
-
-exports[`should render correctly for bitbucketcloud 1`] = `
-<Fragment>
- <div
- className="settings-definition"
- >
- <div
- className="settings-definition-left"
- >
- <label
- className="h3"
- htmlFor="bitbucketcloud.repository"
- >
- settings.pr_decoration.binding.form.bitbucketcloud.repository
- <MandatoryFieldMarker />
- </label>
- <div
- className="markdown small spacer-top"
- >
- <FormattedMessage
- defaultMessage="settings.pr_decoration.binding.form.bitbucketcloud.repository.help"
- id="settings.pr_decoration.binding.form.bitbucketcloud.repository.help"
- />
- <div
- className="spacer-top nowrap"
- >
- example
- :
- <em>
- https://bitbucket.org/my-workspace/
- <strong>
- my-repository-slug
- </strong>
- </em>
- </div>
- </div>
- </div>
- <div
- className="settings-definition-right padded-top"
- >
- <input
- className="input-super-large big-spacer-top"
- id="bitbucketcloud.repository"
- maxLength={256}
- name="bitbucketcloud.repository"
- onChange={[Function]}
- type="text"
- value=""
- />
- </div>
- </div>
-</Fragment>
-`;
-
-exports[`should render correctly for github 1`] = `
-<Fragment>
- <div
- className="settings-definition"
- >
- <div
- className="settings-definition-left"
- >
- <label
- className="h3"
- htmlFor="github.repository"
- >
- settings.pr_decoration.binding.form.github.repository
- <MandatoryFieldMarker />
- </label>
- <div
- className="markdown small spacer-top"
- >
- <FormattedMessage
- defaultMessage="settings.pr_decoration.binding.form.github.repository.help"
- id="settings.pr_decoration.binding.form.github.repository.help"
- />
- <div
- className="spacer-top nowrap"
- >
- example
- :
- <em>
- https://github.com/
- <strong>
- sonarsource/sonarqube
- </strong>
- </em>
- </div>
- </div>
- </div>
- <div
- className="settings-definition-right padded-top"
- >
- <input
- className="input-super-large big-spacer-top"
- id="github.repository"
- maxLength={256}
- name="github.repository"
- onChange={[Function]}
- type="text"
- value=""
- />
- </div>
- </div>
- <div
- className="settings-definition"
- >
- <div
- className="settings-definition-left"
- >
- <label
- className="h3"
- htmlFor="github.summary_comment_setting"
- >
- settings.pr_decoration.binding.form.github.summary_comment_setting
- </label>
- <div
- className="markdown small spacer-top"
- >
- <FormattedMessage
- defaultMessage="settings.pr_decoration.binding.form.github.summary_comment_setting.help"
- id="settings.pr_decoration.binding.form.github.summary_comment_setting.help"
- />
- </div>
- </div>
- <div
- className="settings-definition-right padded-top"
- >
- <div
- className="display-flex-center big-spacer-top"
- >
- <div
- className="display-inline-block text-top"
- >
- <Toggle
- name="github.summary_comment_setting"
- onChange={[Function]}
- value={true}
- />
- </div>
- </div>
- </div>
- </div>
-</Fragment>
-`;
-
-exports[`should render correctly for github if an instance URL is provided 1`] = `
-<Fragment>
- <div
- className="settings-definition"
- >
- <div
- className="settings-definition-left"
- >
- <label
- className="h3"
- htmlFor="github.repository"
- >
- settings.pr_decoration.binding.form.github.repository
- <MandatoryFieldMarker />
- </label>
- <div
- className="markdown small spacer-top"
- >
- <FormattedMessage
- defaultMessage="settings.pr_decoration.binding.form.github.repository.help"
- id="settings.pr_decoration.binding.form.github.repository.help"
- />
- <div
- className="spacer-top nowrap"
- >
- example
- :
- <em>
- http://example.com/
- <strong>
- sonarsource/sonarqube
- </strong>
- </em>
- </div>
- </div>
- </div>
- <div
- className="settings-definition-right padded-top"
- >
- <input
- className="input-super-large big-spacer-top"
- id="github.repository"
- maxLength={256}
- name="github.repository"
- onChange={[Function]}
- type="text"
- value=""
- />
- </div>
- </div>
- <div
- className="settings-definition"
- >
- <div
- className="settings-definition-left"
- >
- <label
- className="h3"
- htmlFor="github.summary_comment_setting"
- >
- settings.pr_decoration.binding.form.github.summary_comment_setting
- </label>
- <div
- className="markdown small spacer-top"
- >
- <FormattedMessage
- defaultMessage="settings.pr_decoration.binding.form.github.summary_comment_setting.help"
- id="settings.pr_decoration.binding.form.github.summary_comment_setting.help"
- />
- </div>
- </div>
- <div
- className="settings-definition-right padded-top"
- >
- <div
- className="display-flex-center big-spacer-top"
- >
- <div
- className="display-inline-block text-top"
- >
- <Toggle
- name="github.summary_comment_setting"
- onChange={[Function]}
- value={true}
- />
- </div>
- </div>
- </div>
- </div>
-</Fragment>
-`;
-
-exports[`should render correctly for github if an instance URL is provided 2`] = `
-<Fragment>
- <div
- className="settings-definition"
- >
- <div
- className="settings-definition-left"
- >
- <label
- className="h3"
- htmlFor="github.repository"
- >
- settings.pr_decoration.binding.form.github.repository
- <MandatoryFieldMarker />
- </label>
- <div
- className="markdown small spacer-top"
- >
- <FormattedMessage
- defaultMessage="settings.pr_decoration.binding.form.github.repository.help"
- id="settings.pr_decoration.binding.form.github.repository.help"
- />
- <div
- className="spacer-top nowrap"
- >
- example
- :
- <em>
- https://github.com/
- <strong>
- sonarsource/sonarqube
- </strong>
- </em>
- </div>
- </div>
- </div>
- <div
- className="settings-definition-right padded-top"
- >
- <input
- className="input-super-large big-spacer-top"
- id="github.repository"
- maxLength={256}
- name="github.repository"
- onChange={[Function]}
- type="text"
- value=""
- />
- </div>
- </div>
- <div
- className="settings-definition"
- >
- <div
- className="settings-definition-left"
- >
- <label
- className="h3"
- htmlFor="github.summary_comment_setting"
- >
- settings.pr_decoration.binding.form.github.summary_comment_setting
- </label>
- <div
- className="markdown small spacer-top"
- >
- <FormattedMessage
- defaultMessage="settings.pr_decoration.binding.form.github.summary_comment_setting.help"
- id="settings.pr_decoration.binding.form.github.summary_comment_setting.help"
- />
- </div>
- </div>
- <div
- className="settings-definition-right padded-top"
- >
- <div
- className="display-flex-center big-spacer-top"
- >
- <div
- className="display-inline-block text-top"
- >
- <Toggle
- name="github.summary_comment_setting"
- onChange={[Function]}
- value={true}
- />
- </div>
- </div>
- </div>
- </div>
-</Fragment>
-`;
-
-exports[`should render correctly for gitlab 1`] = `
-<Fragment>
- <div
- className="settings-definition"
- >
- <div
- className="settings-definition-left"
- >
- <label
- className="h3"
- htmlFor="gitlab.repository"
- >
- settings.pr_decoration.binding.form.gitlab.repository
- <MandatoryFieldMarker />
- </label>
- <div
- className="markdown small spacer-top"
- >
- <FormattedMessage
- defaultMessage="settings.pr_decoration.binding.form.gitlab.repository.help"
- id="settings.pr_decoration.binding.form.gitlab.repository.help"
- />
- <div
- className="spacer-top nowrap"
- >
- example
- :
- <em>
- <strong>
- 123456
- </strong>
- </em>
- </div>
- </div>
- </div>
- <div
- className="settings-definition-right padded-top"
- >
- <input
- className="input-super-large big-spacer-top"
- id="gitlab.repository"
- maxLength={256}
- name="gitlab.repository"
- onChange={[Function]}
- type="text"
- value=""
- />
- </div>
- </div>
-</Fragment>
-`;
-
-exports[`should render the monorepo field when the feature is supported 1`] = `
-<Fragment>
- <div
- className="settings-definition"
- >
- <div
- className="settings-definition-left"
- >
- <label
- className="h3"
- htmlFor="azure.project"
- >
- settings.pr_decoration.binding.form.azure.project
- <MandatoryFieldMarker />
- </label>
- <div
- className="markdown small spacer-top"
- >
- <FormattedMessage
- defaultMessage="settings.pr_decoration.binding.form.azure.project.help"
- id="settings.pr_decoration.binding.form.azure.project.help"
- />
- <div
- className="spacer-top nowrap"
- >
- example
- :
- <em>
- <strong>
- My Project
- </strong>
- </em>
- </div>
- </div>
- </div>
- <div
- className="settings-definition-right padded-top"
- >
- <input
- className="input-super-large big-spacer-top"
- id="azure.project"
- maxLength={256}
- name="azure.project"
- onChange={[Function]}
- type="text"
- value=""
- />
- </div>
- </div>
- <div
- className="settings-definition"
- >
- <div
- className="settings-definition-left"
- >
- <label
- className="h3"
- htmlFor="azure.repository"
- >
- settings.pr_decoration.binding.form.azure.repository
- <MandatoryFieldMarker />
- </label>
- <div
- className="markdown small spacer-top"
- >
- <FormattedMessage
- defaultMessage="settings.pr_decoration.binding.form.azure.repository.help"
- id="settings.pr_decoration.binding.form.azure.repository.help"
- />
- <div
- className="spacer-top nowrap"
- >
- example
- :
- <em>
- <strong>
- My Repository
- </strong>
- </em>
- </div>
- </div>
- </div>
- <div
- className="settings-definition-right padded-top"
- >
- <input
- className="input-super-large big-spacer-top"
- id="azure.repository"
- maxLength={256}
- name="azure.repository"
- onChange={[Function]}
- type="text"
- value=""
- />
- </div>
- </div>
- <div
- className="settings-definition"
- >
- <div
- className="settings-definition-left"
- >
- <label
- className="h3"
- htmlFor="monorepo"
- >
- settings.pr_decoration.binding.form.monorepo
- </label>
- <div
- className="markdown small spacer-top"
- >
- <FormattedMessage
- defaultMessage="settings.pr_decoration.binding.form.monorepo.help"
- id="settings.pr_decoration.binding.form.monorepo.help"
- values={
- {
- "doc_link": <withAppStateContext(DocLink)
- to="/devops-platform-integration/azure-devops-integration/"
- >
- learn_more
- </withAppStateContext(DocLink)>,
- }
- }
- />
- </div>
- </div>
- <div
- className="settings-definition-right padded-top"
- >
- <div
- className="display-flex-center big-spacer-top"
- >
- <div
- className="display-inline-block text-top"
- >
- <Toggle
- name="monorepo"
- onChange={[Function]}
- value={false}
- />
- </div>
- </div>
- </div>
- </div>
-</Fragment>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<PRDecorationBindingRenderer
- checkingConfiguration={false}
- formData={
- {
- "key": "",
- "monorepo": false,
- }
- }
- instances={[]}
- isChanged={false}
- isConfigured={false}
- isSysAdmin={false}
- isValid={false}
- loading={true}
- onCheckConfiguration={[Function]}
- onFieldChange={[Function]}
- onReset={[Function]}
- onSubmit={[Function]}
- successfullyUpdated={false}
- updating={false}
-/>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should display action section correctly when: configuration check is in progress 1`] = `
-<div
- className="display-flex-center big-spacer-top action-section"
->
- <Button
- className="spacer-right"
- onClick={[MockFunction]}
- >
- <span
- data-test="project-settings__alm-reset"
- >
- reset_verb
- </span>
- </Button>
- <Button
- disabled={true}
- onClick={[MockFunction]}
- >
- settings.pr_decoration.binding.check_configuration
- <DeferredSpinner
- className="spacer-left"
- loading={true}
- />
- </Button>
-</div>
-`;
-
-exports[`should display action section correctly when: configuration is saved 1`] = `
-<div
- className="display-flex-center big-spacer-top action-section"
->
- <Button
- className="spacer-right"
- onClick={[MockFunction]}
- >
- <span
- data-test="project-settings__alm-reset"
- >
- reset_verb
- </span>
- </Button>
- <Button
- disabled={false}
- onClick={[MockFunction]}
- >
- settings.pr_decoration.binding.check_configuration
- <DeferredSpinner
- className="spacer-left"
- loading={false}
- />
- </Button>
-</div>
-`;
-
-exports[`should display action section correctly when: form is valid 1`] = `
-<div
- className="display-flex-center big-spacer-top action-section"
-/>
-`;
-
-exports[`should display action section correctly when: update is successfull 1`] = `
-<div
- className="display-flex-center big-spacer-top action-section"
->
- <span
- className="text-success spacer-right"
- >
- <AlertSuccessIcon
- className="spacer-right"
- />
- settings.state.saved
- </span>
-</div>
-`;
-
-exports[`should display action section correctly when: updating 1`] = `
-<div
- className="display-flex-center big-spacer-top action-section"
-/>
-`;
-
-exports[`should render correctly: when loading 1`] = `<DeferredSpinner />`;
-
-exports[`should render correctly: when there are configuration errors (admin user) 1`] = `
-<div>
- <header
- className="page-header"
- >
- <h1
- className="page-title"
- >
- settings.pr_decoration.binding.title
- </h1>
- </header>
- <div
- className="markdown small spacer-top big-spacer-bottom"
- >
- settings.pr_decoration.binding.description
- </div>
- <form
- onSubmit={[Function]}
- >
- <MandatoryFieldsExplanation
- className="form-field"
- />
- <div
- className="settings-definition big-spacer-bottom"
- >
- <div
- className="settings-definition-left"
- >
- <label
- className="h3"
- htmlFor="name"
- >
- settings.pr_decoration.binding.form.name
- <MandatoryFieldMarker
- className="spacer-right"
- />
- </label>
- <div
- className="markdown small spacer-top"
- >
- settings.pr_decoration.binding.form.name.help
- </div>
- </div>
- <div
- className="settings-definition-right"
- >
- <AlmSettingsInstanceSelector
- classNames="abs-width-400 big-spacer-top it__configuration-name-select"
- initialValue="i1"
- inputId="name"
- instances={
- [
- {
- "alm": "github",
- "key": "i1",
- "url": "http://github.enterprise.com",
- },
- {
- "alm": "github",
- "key": "i2",
- "url": "http://github.enterprise.com",
- },
- {
- "alm": "bitbucket",
- "key": "i3",
- "url": "http://bbs.enterprise.com",
- },
- {
- "alm": "azure",
- "key": "i4",
- },
- ]
- }
- onChange={[Function]}
- />
- </div>
- </div>
- <withAvailableFeaturesContext(AlmSpecificForm)
- alm="github"
- formData={
- {
- "key": "i1",
- "monorepo": false,
- "repository": "account/repo",
- }
- }
- instances={
- [
- {
- "alm": "github",
- "key": "i1",
- "url": "http://github.enterprise.com",
- },
- {
- "alm": "github",
- "key": "i2",
- "url": "http://github.enterprise.com",
- },
- {
- "alm": "bitbucket",
- "key": "i3",
- "url": "http://bbs.enterprise.com",
- },
- {
- "alm": "azure",
- "key": "i4",
- },
- ]
- }
- onFieldChange={[MockFunction]}
- />
- <div
- className="display-flex-center big-spacer-top action-section"
- >
- <Button
- className="spacer-right"
- onClick={[MockFunction]}
- >
- <span
- data-test="project-settings__alm-reset"
- >
- reset_verb
- </span>
- </Button>
- <Button
- disabled={false}
- onClick={[MockFunction]}
- >
- settings.pr_decoration.binding.check_configuration
- <DeferredSpinner
- className="spacer-left"
- loading={false}
- />
- </Button>
- </div>
- <Alert
- className="big-spacer-top"
- display="inline"
- variant="error"
- >
- <p
- className="spacer-bottom"
- >
- settings.pr_decoration.binding.check_configuration.failure
- </p>
- <ul
- className="list-styled"
- >
- <li
- key="0"
- >
- Test
- </li>
- <li
- key="1"
- >
- tesT
- </li>
- </ul>
- <p>
- <FormattedMessage
- defaultMessage="settings.pr_decoration.binding.check_configuration.failure.check_global_settings"
- id="settings.pr_decoration.binding.check_configuration.failure.check_global_settings"
- values={
- {
- "link": <ForwardRef(Link)
- to={
- {
- "pathname": "/admin/settings",
- "search": "?category=almintegration&alm=github",
- }
- }
- >
- settings.pr_decoration.binding.check_configuration.failure.check_global_settings.link
- </ForwardRef(Link)>,
- }
- }
- />
- </p>
- </Alert>
- </form>
-</div>
-`;
-
-exports[`should render correctly: when there are configuration errors (admin user) and error are at PROJECT level 1`] = `
-<div>
- <header
- className="page-header"
- >
- <h1
- className="page-title"
- >
- settings.pr_decoration.binding.title
- </h1>
- </header>
- <div
- className="markdown small spacer-top big-spacer-bottom"
- >
- settings.pr_decoration.binding.description
- </div>
- <form
- onSubmit={[Function]}
- >
- <MandatoryFieldsExplanation
- className="form-field"
- />
- <div
- className="settings-definition big-spacer-bottom"
- >
- <div
- className="settings-definition-left"
- >
- <label
- className="h3"
- htmlFor="name"
- >
- settings.pr_decoration.binding.form.name
- <MandatoryFieldMarker
- className="spacer-right"
- />
- </label>
- <div
- className="markdown small spacer-top"
- >
- settings.pr_decoration.binding.form.name.help
- </div>
- </div>
- <div
- className="settings-definition-right"
- >
- <AlmSettingsInstanceSelector
- classNames="abs-width-400 big-spacer-top it__configuration-name-select"
- initialValue=""
- inputId="name"
- instances={
- [
- {
- "alm": "github",
- "key": "i1",
- "url": "http://github.enterprise.com",
- },
- {
- "alm": "github",
- "key": "i2",
- "url": "http://github.enterprise.com",
- },
- {
- "alm": "bitbucket",
- "key": "i3",
- "url": "http://bbs.enterprise.com",
- },
- {
- "alm": "azure",
- "key": "i4",
- },
- ]
- }
- onChange={[Function]}
- />
- </div>
- </div>
- <div
- className="display-flex-center big-spacer-top action-section"
- >
- <Button
- className="spacer-right"
- onClick={[MockFunction]}
- >
- <span
- data-test="project-settings__alm-reset"
- >
- reset_verb
- </span>
- </Button>
- <Button
- disabled={false}
- onClick={[MockFunction]}
- >
- settings.pr_decoration.binding.check_configuration
- <DeferredSpinner
- className="spacer-left"
- loading={false}
- />
- </Button>
- </div>
- <Alert
- className="big-spacer-top"
- display="inline"
- variant="error"
- >
- <p
- className="spacer-bottom"
- >
- settings.pr_decoration.binding.check_configuration.failure
- </p>
- <ul
- className="list-styled"
- >
- <li
- key="0"
- >
- Test
- </li>
- <li
- key="1"
- >
- tesT
- </li>
- </ul>
- </Alert>
- </form>
-</div>
-`;
-
-exports[`should render correctly: when there are configuration errors (non-admin user) 1`] = `
-<div>
- <header
- className="page-header"
- >
- <h1
- className="page-title"
- >
- settings.pr_decoration.binding.title
- </h1>
- </header>
- <div
- className="markdown small spacer-top big-spacer-bottom"
- >
- settings.pr_decoration.binding.description
- </div>
- <form
- onSubmit={[Function]}
- >
- <MandatoryFieldsExplanation
- className="form-field"
- />
- <div
- className="settings-definition big-spacer-bottom"
- >
- <div
- className="settings-definition-left"
- >
- <label
- className="h3"
- htmlFor="name"
- >
- settings.pr_decoration.binding.form.name
- <MandatoryFieldMarker
- className="spacer-right"
- />
- </label>
- <div
- className="markdown small spacer-top"
- >
- settings.pr_decoration.binding.form.name.help
- </div>
- </div>
- <div
- className="settings-definition-right"
- >
- <AlmSettingsInstanceSelector
- classNames="abs-width-400 big-spacer-top it__configuration-name-select"
- initialValue=""
- inputId="name"
- instances={
- [
- {
- "alm": "github",
- "key": "i1",
- "url": "http://github.enterprise.com",
- },
- {
- "alm": "github",
- "key": "i2",
- "url": "http://github.enterprise.com",
- },
- {
- "alm": "bitbucket",
- "key": "i3",
- "url": "http://bbs.enterprise.com",
- },
- {
- "alm": "azure",
- "key": "i4",
- },
- ]
- }
- onChange={[Function]}
- />
- </div>
- </div>
- <div
- className="display-flex-center big-spacer-top action-section"
- >
- <Button
- className="spacer-right"
- onClick={[MockFunction]}
- >
- <span
- data-test="project-settings__alm-reset"
- >
- reset_verb
- </span>
- </Button>
- <Button
- disabled={false}
- onClick={[MockFunction]}
- >
- settings.pr_decoration.binding.check_configuration
- <DeferredSpinner
- className="spacer-left"
- loading={false}
- />
- </Button>
- </div>
- <Alert
- className="big-spacer-top"
- display="inline"
- variant="error"
- >
- <p
- className="spacer-bottom"
- >
- settings.pr_decoration.binding.check_configuration.failure
- </p>
- <ul
- className="list-styled"
- >
- <li
- key="0"
- >
- Test
- </li>
- <li
- key="1"
- >
- tesT
- </li>
- </ul>
- <p>
- settings.pr_decoration.binding.check_configuration.contact_admin
- </p>
- </Alert>
- </form>
-</div>
-`;
-
-exports[`should render correctly: with a single ALM instance 1`] = `
-<div>
- <header
- className="page-header"
- >
- <h1
- className="page-title"
- >
- settings.pr_decoration.binding.title
- </h1>
- </header>
- <div
- className="markdown small spacer-top big-spacer-bottom"
- >
- settings.pr_decoration.binding.description
- </div>
- <form
- onSubmit={[Function]}
- >
- <MandatoryFieldsExplanation
- className="form-field"
- />
- <div
- className="settings-definition big-spacer-bottom"
- >
- <div
- className="settings-definition-left"
- >
- <label
- className="h3"
- htmlFor="name"
- >
- settings.pr_decoration.binding.form.name
- <MandatoryFieldMarker
- className="spacer-right"
- />
- </label>
- <div
- className="markdown small spacer-top"
- >
- settings.pr_decoration.binding.form.name.help
- </div>
- </div>
- <div
- className="settings-definition-right"
- >
- <AlmSettingsInstanceSelector
- classNames="abs-width-400 big-spacer-top it__configuration-name-select"
- initialValue=""
- inputId="name"
- instances={
- [
- {
- "alm": "github",
- "key": "i1",
- "url": "http://github.enterprise.com",
- },
- ]
- }
- onChange={[Function]}
- />
- </div>
- </div>
- <div
- className="display-flex-center big-spacer-top action-section"
- />
- </form>
-</div>
-`;
-
-exports[`should render correctly: with a valid and saved form 1`] = `
-<div>
- <header
- className="page-header"
- >
- <h1
- className="page-title"
- >
- settings.pr_decoration.binding.title
- </h1>
- </header>
- <div
- className="markdown small spacer-top big-spacer-bottom"
- >
- settings.pr_decoration.binding.description
- </div>
- <form
- onSubmit={[Function]}
- >
- <MandatoryFieldsExplanation
- className="form-field"
- />
- <div
- className="settings-definition big-spacer-bottom"
- >
- <div
- className="settings-definition-left"
- >
- <label
- className="h3"
- htmlFor="name"
- >
- settings.pr_decoration.binding.form.name
- <MandatoryFieldMarker
- className="spacer-right"
- />
- </label>
- <div
- className="markdown small spacer-top"
- >
- settings.pr_decoration.binding.form.name.help
- </div>
- </div>
- <div
- className="settings-definition-right"
- >
- <AlmSettingsInstanceSelector
- classNames="abs-width-400 big-spacer-top it__configuration-name-select"
- initialValue="i1"
- inputId="name"
- instances={
- [
- {
- "alm": "github",
- "key": "i1",
- "url": "http://github.enterprise.com",
- },
- {
- "alm": "github",
- "key": "i2",
- "url": "http://github.enterprise.com",
- },
- {
- "alm": "bitbucket",
- "key": "i3",
- "url": "http://bbs.enterprise.com",
- },
- {
- "alm": "azure",
- "key": "i4",
- },
- ]
- }
- onChange={[Function]}
- />
- </div>
- </div>
- <withAvailableFeaturesContext(AlmSpecificForm)
- alm="github"
- formData={
- {
- "key": "i1",
- "monorepo": false,
- "repository": "account/repo",
- }
- }
- instances={
- [
- {
- "alm": "github",
- "key": "i1",
- "url": "http://github.enterprise.com",
- },
- {
- "alm": "github",
- "key": "i2",
- "url": "http://github.enterprise.com",
- },
- {
- "alm": "bitbucket",
- "key": "i3",
- "url": "http://bbs.enterprise.com",
- },
- {
- "alm": "azure",
- "key": "i4",
- },
- ]
- }
- onFieldChange={[MockFunction]}
- />
- <div
- className="display-flex-center big-spacer-top action-section"
- >
- <Button
- className="spacer-right"
- onClick={[MockFunction]}
- >
- <span
- data-test="project-settings__alm-reset"
- >
- reset_verb
- </span>
- </Button>
- <Button
- disabled={false}
- onClick={[MockFunction]}
- >
- settings.pr_decoration.binding.check_configuration
- <DeferredSpinner
- className="spacer-left"
- loading={false}
- />
- </Button>
- </div>
- <Alert
- className="big-spacer-top"
- display="inline"
- variant="success"
- >
- settings.pr_decoration.binding.check_configuration.success
- </Alert>
- </form>
-</div>
-`;
-
-exports[`should render correctly: with an empty form 1`] = `
-<div>
- <header
- className="page-header"
- >
- <h1
- className="page-title"
- >
- settings.pr_decoration.binding.title
- </h1>
- </header>
- <div
- className="markdown small spacer-top big-spacer-bottom"
- >
- settings.pr_decoration.binding.description
- </div>
- <form
- onSubmit={[Function]}
- >
- <MandatoryFieldsExplanation
- className="form-field"
- />
- <div
- className="settings-definition big-spacer-bottom"
- >
- <div
- className="settings-definition-left"
- >
- <label
- className="h3"
- htmlFor="name"
- >
- settings.pr_decoration.binding.form.name
- <MandatoryFieldMarker
- className="spacer-right"
- />
- </label>
- <div
- className="markdown small spacer-top"
- >
- settings.pr_decoration.binding.form.name.help
- </div>
- </div>
- <div
- className="settings-definition-right"
- >
- <AlmSettingsInstanceSelector
- classNames="abs-width-400 big-spacer-top it__configuration-name-select"
- initialValue=""
- inputId="name"
- instances={
- [
- {
- "alm": "github",
- "key": "i1",
- "url": "http://github.enterprise.com",
- },
- {
- "alm": "github",
- "key": "i2",
- "url": "http://github.enterprise.com",
- },
- {
- "alm": "bitbucket",
- "key": "i3",
- "url": "http://bbs.enterprise.com",
- },
- {
- "alm": "azure",
- "key": "i4",
- },
- ]
- }
- onChange={[Function]}
- />
- </div>
- </div>
- <div
- className="display-flex-center big-spacer-top action-section"
- />
- </form>
-</div>
-`;
-
-exports[`should render correctly: with no ALM instances (admin user) 1`] = `
-<div>
- <Alert
- className="spacer-top huge-spacer-bottom"
- variant="info"
- >
- <FormattedMessage
- defaultMessage="settings.pr_decoration.binding.no_bindings.admin"
- id="settings.pr_decoration.binding.no_bindings.admin"
- values={
- {
- "link": <ForwardRef(Link)
- to={
- {
- "pathname": "/admin/settings",
- "search": "?category=almintegration",
- }
- }
- >
- settings.pr_decoration.binding.no_bindings.link
- </ForwardRef(Link)>,
- }
- }
- />
- </Alert>
-</div>
-`;
-
-exports[`should render correctly: with no ALM instances (non-admin user) 1`] = `
-<div>
- <Alert
- className="spacer-top huge-spacer-bottom"
- variant="info"
- >
- settings.pr_decoration.binding.no_bindings
- </Alert>
-</div>
-`;
};
it('should be able to generate new key', async () => {
+ const user = userEvent.setup();
renderEncryptionApp();
expect(await ui.appHeading.find()).toBeInTheDocument();
- await userEvent.click(ui.generateSecretButton.get());
+ await user.click(ui.generateSecretButton.get());
expect(ui.copyToClipboard.get()).toHaveAttribute('data-clipboard-text', 'secretKey');
});
it('should be able to encrypt property value when secret is registered', async () => {
+ const user = userEvent.setup();
settingsMock.setSecretKeyAvailable(true);
renderEncryptionApp();
expect(await ui.appHeading.find()).toBeInTheDocument();
- await userEvent.type(ui.encryptTextarea.get(), 'sonar.announcement.message');
- await userEvent.click(ui.encryptButton.get());
+ await user.type(ui.encryptTextarea.get(), 'sonar.announcement.message');
+ await user.click(ui.encryptButton.get());
expect(ui.copyToClipboard.get()).toHaveAttribute('data-clipboard-text', 'encryptedValue');
// can generate new secret in view
- await userEvent.click(ui.generateNewSecretButton.get());
+ await user.click(ui.generateNewSecretButton.get());
expect(ui.copyToClipboard.get()).toHaveAttribute('data-clipboard-text', 'secretKey');
});
import './Toggle.css';
interface Props {
+ id?: string;
ariaLabel?: string;
disabled?: boolean;
name?: string;
};
render() {
- const { ariaLabel, disabled, name } = this.props;
+ const { ariaLabel, disabled, name, id } = this.props;
const value = this.getValue();
const className = classNames('boolean-toggle', { 'boolean-toggle-on': value });
return (
<Button
+ id={id}
className={className}
disabled={disabled}
aria-label={ariaLabel}
}}
placeholder={translate('alm.configuration.selector.placeholder')}
getOptionValue={(opt) => opt.key}
- value={instances.find((inst) => inst.key === initialValue)}
+ value={instances.find((inst) => inst.key === initialValue) ?? null}
/>
);
}
return {
alm: AlmKeys.GitHub,
key: 'foo',
+ repository: 'repo',
monorepo: false,
...overrides,
};
export interface ProjectAlmBindingResponse {
alm: AlmKeys;
key: string;
- repository?: string;
+ repository: string;
slug?: string;
+ url?: string;
summaryCommentEnabled?: boolean;
monorepo: boolean;
}
export interface ProjectAzureBindingResponse extends ProjectAlmBindingResponse {
alm: AlmKeys.Azure;
- repository: string;
slug: string;
url: string;
}
export interface ProjectBitbucketBindingResponse extends ProjectAlmBindingResponse {
alm: AlmKeys.BitbucketServer;
- repository: string;
slug: string;
}
export interface ProjectBitbucketCloudBindingResponse extends ProjectAlmBindingResponse {
alm: AlmKeys.BitbucketCloud;
- repository: string;
}
export interface ProjectGitHubBindingResponse extends ProjectAlmBindingResponse {
alm: AlmKeys.GitHub;
- repository: string;
}
export interface ProjectGitLabBindingResponse extends ProjectAlmBindingResponse {
alm: AlmKeys.GitLab;
- repository: string;
url: string;
}