aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--server/sonar-web/src/main/js/api/mocks/NewCodePeriodsServiceMock.ts60
-rw-r--r--server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts37
-rw-r--r--server/sonar-web/src/main/js/apps/account/__tests__/Account-it.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/components/LeakPeriodLegend.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/MeasuresPanelNoNewCode.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/ProjectLeakPeriodInfo.tsx8
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/ProjectLeakPeriodInfo-test.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/LeakPeriodLegend.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/components/BaselineSettingAnalysis.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/components/BaselineSettingDays.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/components/BaselineSettingPreviousVersion.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/components/BaselineSettingReferenceBranch.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/components/BranchBaselineSettingModal.tsx17
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/components/BranchList.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/components/BranchListRow.tsx14
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/components/ProjectBaselineApp.tsx (renamed from server/sonar-web/src/main/js/apps/projectBaseline/components/App.tsx)36
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/components/ProjectBaselineSelector.tsx20
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BaselineSettingAnalysis-test.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BaselineSettingDays-test.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BaselineSettingPreviousVersion-test.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BaselineSettingReferenceBranch-test.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BranchBaselineSettingModal-test.tsx10
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BranchList-test.tsx11
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BranchListRow-test.tsx25
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/ProjectBaselineApp-test.tsx (renamed from server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/App-test.tsx)15
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/ProjectBaselineSelector-test.tsx28
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/__snapshots__/ProjectBaselineApp-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/__snapshots__/App-test.tsx.snap)0
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/utils-test.ts51
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/constants.ts (renamed from server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForNumber-test.tsx)26
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/routes.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/utils.ts22
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/Definition.tsx14
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/NewCodePeriod.tsx68
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/__tests__/AnalysisScope-test.tsx49
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/__tests__/Definition-it.tsx448
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/__tests__/NewCodePeriod-it.tsx158
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/NewCodePeriod-it.tsx.snap57
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/authentication/__tests__/Authentication-it.tsx6
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/inputs/InputForBoolean.tsx16
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/inputs/InputForFormattedText.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/inputs/InputForJSON.tsx9
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/inputs/InputForSecured.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/inputs/InputForSingleSelectList.tsx5
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/inputs/InputForText.tsx8
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/inputs/MultiValueInput.tsx1
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/inputs/PropertySetInput.tsx7
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/Input-test.tsx80
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForBoolean-test.tsx70
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForFormattedText-test.tsx86
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForJSON-test.tsx80
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForPassword-test.tsx42
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForSecured-test.tsx96
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForSingleSelectList-test.tsx63
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForText-test.tsx57
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/MultiValueInput-test.tsx96
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/PrimitiveInput-test.tsx46
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/SimpleInput-test.tsx86
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/__snapshots__/InputForJSON-test.tsx.snap51
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/__snapshots__/PrimitiveInput-test.tsx.snap349
-rw-r--r--server/sonar-web/src/main/js/components/controls/Toggle.tsx22
-rw-r--r--server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Toggle-test.tsx.snap9
-rw-r--r--server/sonar-web/src/main/js/components/controls/buttons.tsx1
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/periods-test.ts23
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/new-code-period.ts (renamed from server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForString-test.tsx)30
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/settings.ts7
-rw-r--r--server/sonar-web/src/main/js/helpers/periods.ts6
-rw-r--r--server/sonar-web/src/main/js/types/settings.ts1
-rw-r--r--server/sonar-web/src/main/js/types/types.ts11
-rw-r--r--sonar-core/src/main/resources/org/sonar/l10n/core.properties4
69 files changed, 859 insertions, 1733 deletions
diff --git a/server/sonar-web/src/main/js/api/mocks/NewCodePeriodsServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/NewCodePeriodsServiceMock.ts
new file mode 100644
index 00000000000..df8b3b6ba57
--- /dev/null
+++ b/server/sonar-web/src/main/js/api/mocks/NewCodePeriodsServiceMock.ts
@@ -0,0 +1,60 @@
+/*
+ * 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 { cloneDeep } from 'lodash';
+import { mockNewCodePeriod } from '../../helpers/mocks/new-code-period';
+import { NewCodePeriod, NewCodePeriodSettingType } from '../../types/types';
+import { getNewCodePeriod, setNewCodePeriod } from '../newCodePeriod';
+
+jest.mock('../newCodePeriod');
+
+const defaultNewCodePeriod = mockNewCodePeriod();
+
+export default class NewCodePeriodsServiceMock {
+ #newCodePeriod: NewCodePeriod;
+
+ constructor() {
+ this.#newCodePeriod = cloneDeep(defaultNewCodePeriod);
+ jest.mocked(getNewCodePeriod).mockImplementation(this.handleGetNewCodePeriod);
+ jest.mocked(setNewCodePeriod).mockImplementation(this.handleSetNewCodePeriod);
+ }
+
+ handleGetNewCodePeriod = () => {
+ return this.reply(this.#newCodePeriod);
+ };
+
+ handleSetNewCodePeriod = (data: {
+ project?: string;
+ branch?: string;
+ type: NewCodePeriodSettingType;
+ value?: string;
+ }) => {
+ const { type, value } = data;
+ this.#newCodePeriod = mockNewCodePeriod({ type, value });
+ return this.reply(undefined);
+ };
+
+ reset = () => {
+ this.#newCodePeriod = cloneDeep(defaultNewCodePeriod);
+ };
+
+ reply<T>(response: T): Promise<T> {
+ return Promise.resolve(cloneDeep(response));
+ }
+}
diff --git a/server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts
index abfd964dcb8..b22051af84a 100644
--- a/server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts
+++ b/server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts
@@ -17,9 +17,9 @@
* 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 { cloneDeep, isArray, isObject, isString } from 'lodash';
import { HousekeepingPolicy } from '../../apps/audit-logs/utils';
-import { mockDefinition } from '../../helpers/mocks/settings';
+import { mockDefinition, mockSettingFieldDefinition } from '../../helpers/mocks/settings';
import { BranchParameters } from '../../types/branch-like';
import {
ExtendedSettingDefinition,
@@ -37,7 +37,8 @@ import {
setSettingValue,
} from '../settings';
-const isEmptyString = (i: string) => i.trim() === '';
+const isEmptyField = (o: any) => isObject(o) && Object.values(o).some(isEmptyString);
+const isEmptyString = (i: any) => isString(i) && i.trim() === '';
export const DEFAULT_DEFINITIONS_MOCK = [
mockDefinition({
@@ -46,7 +47,6 @@ export const DEFAULT_DEFINITIONS_MOCK = [
subCategory: 'Announcement',
name: 'Announcement message',
description: 'Enter message',
- defaultValue: '.js,.jsx,.cjs,.vue,.mjs',
type: SettingType.TEXT,
}),
mockDefinition({
@@ -55,7 +55,6 @@ export const DEFAULT_DEFINITIONS_MOCK = [
subCategory: 'Compute Engine',
name: 'Run analysis in paralel',
description: 'Enter message',
- defaultValue: '.js,.jsx,.cjs,.vue,.mjs',
type: SettingType.TEXT,
}),
mockDefinition({
@@ -84,6 +83,18 @@ export const DEFAULT_DEFINITIONS_MOCK = [
description: 'Paths to xml files',
multiValues: true,
}),
+ mockDefinition({
+ category: 'COBOL',
+ key: 'sonar.cobol.compilationConstants',
+ subCategory: 'Preprocessor',
+ name: 'Compilation Constants',
+ description: 'Lets do it',
+ type: SettingType.PROPERTY_SET,
+ fields: [
+ mockSettingFieldDefinition(),
+ mockSettingFieldDefinition({ key: 'value', name: 'Value' }),
+ ],
+ }),
];
export default class SettingsServiceMock {
@@ -131,8 +142,9 @@ export default class SettingsServiceMock {
handleSetSettingValue = (definition: SettingDefinition, value: any): Promise<void> => {
if (
- (typeof value === 'string' && isEmptyString(value)) ||
- (value instanceof Array && value.some(isEmptyString))
+ isEmptyString(value) ||
+ (isArray(value) && value.some(isEmptyString)) ||
+ isEmptyField(value)
) {
throw new ResponseError('validation error', {
errors: [{ msg: 'A non empty value must be provided' }],
@@ -149,7 +161,9 @@ export default class SettingsServiceMock {
const definition = this.#definitions.find(
(d) => d.key === data.keys
) as ExtendedSettingDefinition;
- if (definition.multiValues === true) {
+ if (definition.type === SettingType.PROPERTY_SET) {
+ setting.fieldValues = [];
+ } else if (definition.multiValues === true) {
setting.values = definition.defaultValue?.split(',') ?? [];
} else {
setting.value = definition.defaultValue ?? '';
@@ -168,12 +182,17 @@ export default class SettingsServiceMock {
if (setting) {
setting.value = value;
setting.values = value;
+ setting.fieldValues = value;
} else {
- this.#settingValues.push({ key, value });
+ this.#settingValues.push({ key, value, values: value, fieldValues: value });
}
return this;
};
+ setDefinition = (definition: ExtendedSettingDefinition) => {
+ this.#definitions.push(definition);
+ };
+
reset = () => {
this.#settingValues = cloneDeep(this.#defaultValues);
this.#definitions = cloneDeep(DEFAULT_DEFINITIONS_MOCK);
diff --git a/server/sonar-web/src/main/js/apps/account/__tests__/Account-it.tsx b/server/sonar-web/src/main/js/apps/account/__tests__/Account-it.tsx
index 02ec79d5a74..a740d347879 100644
--- a/server/sonar-web/src/main/js/apps/account/__tests__/Account-it.tsx
+++ b/server/sonar-web/src/main/js/apps/account/__tests__/Account-it.tsx
@@ -236,7 +236,7 @@ describe('profile page', () => {
const user = userEvent.setup();
renderAccountApp(mockLoggedInUser());
- const toggle = screen.getByRole('button', {
+ const toggle = screen.getByRole('switch', {
name: 'my_account.preferences.keyboard_shortcuts.enabled',
});
expect(toggle).toBeInTheDocument();
diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/LeakPeriodLegend.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/LeakPeriodLegend.tsx
index 812d7f22130..f6f5acb46a5 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/components/LeakPeriodLegend.tsx
+++ b/server/sonar-web/src/main/js/apps/component-measures/components/LeakPeriodLegend.tsx
@@ -27,7 +27,7 @@ import DateFromNow from '../../../components/intl/DateFromNow';
import DateTimeFormatter, { formatterOption } from '../../../components/intl/DateTimeFormatter';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { getPeriodDate, getPeriodLabel } from '../../../helpers/periods';
-import { ComponentMeasure, Period } from '../../../types/types';
+import { ComponentMeasure, NewCodePeriodSettingType, Period } from '../../../types/types';
interface Props {
className?: string;
@@ -65,7 +65,7 @@ export class LeakPeriodLegend extends React.PureComponent<Props & WrappedCompone
</div>
);
- if (period.mode === 'days' || period.mode === 'NUMBER_OF_DAYS') {
+ if (period.mode === 'days' || period.mode === NewCodePeriodSettingType.NUMBER_OF_DAYS) {
return label;
}
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/MeasuresPanelNoNewCode.tsx b/server/sonar-web/src/main/js/apps/overview/branches/MeasuresPanelNoNewCode.tsx
index e75f4fe0a6a..37d8c2ac37f 100644
--- a/server/sonar-web/src/main/js/apps/overview/branches/MeasuresPanelNoNewCode.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/branches/MeasuresPanelNoNewCode.tsx
@@ -27,7 +27,7 @@ import { getBaseUrl } from '../../../helpers/system';
import { queryToSearch } from '../../../helpers/urls';
import { Branch } from '../../../types/branch-like';
import { ComponentQualifier } from '../../../types/component';
-import { Component, Period } from '../../../types/types';
+import { Component, NewCodePeriodSettingType, Period } from '../../../types/types';
export interface MeasuresPanelNoNewCodeProps {
branch?: Branch;
@@ -41,7 +41,7 @@ export default function MeasuresPanelNoNewCode(props: MeasuresPanelNoNewCodeProp
const isApp = component.qualifier === ComponentQualifier.Application;
const hasBadReferenceBranch =
- !isApp && !!period && !period.date && period.mode === 'REFERENCE_BRANCH';
+ !isApp && !!period && !period.date && period.mode === NewCodePeriodSettingType.REFERENCE_BRANCH;
/*
* If the period is "reference branch"-based, and if there's no date, it means
* that we're not lacking a second analysis, but that we'll never have new code because the
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/ProjectLeakPeriodInfo.tsx b/server/sonar-web/src/main/js/apps/overview/branches/ProjectLeakPeriodInfo.tsx
index 51eadd8dc84..ec76ddfafde 100644
--- a/server/sonar-web/src/main/js/apps/overview/branches/ProjectLeakPeriodInfo.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/branches/ProjectLeakPeriodInfo.tsx
@@ -24,7 +24,7 @@ import DateFromNow from '../../../components/intl/DateFromNow';
import { formatterOption } from '../../../components/intl/DateTimeFormatter';
import { translateWithParameters } from '../../../helpers/l10n';
import { getPeriodDate, getPeriodLabel } from '../../../helpers/periods';
-import { Period } from '../../../types/types';
+import { NewCodePeriodSettingType, Period } from '../../../types/types';
export interface ProjectLeakPeriodInfoProps extends WrappedComponentProps {
leakPeriod: Period;
@@ -38,7 +38,7 @@ export function ProjectLeakPeriodInfo(props: ProjectLeakPeriodInfoProps) {
const leakPeriodLabel = getPeriodLabel(
leakPeriod,
- ['manual_baseline', 'SPECIFIC_ANALYSIS'].includes(leakPeriod.mode)
+ ['manual_baseline', NewCodePeriodSettingType.SPECIFIC_ANALYSIS].includes(leakPeriod.mode)
? (date: string) => formatTime(date, formatterOption)
: (date: string) => formatDate(date, longFormatterOption)
);
@@ -49,8 +49,8 @@ export function ProjectLeakPeriodInfo(props: ProjectLeakPeriodInfoProps) {
if (
leakPeriod.mode === 'days' ||
- leakPeriod.mode === 'NUMBER_OF_DAYS' ||
- leakPeriod.mode === 'REFERENCE_BRANCH'
+ leakPeriod.mode === NewCodePeriodSettingType.NUMBER_OF_DAYS ||
+ leakPeriod.mode === NewCodePeriodSettingType.REFERENCE_BRANCH
) {
return <div className="note spacer-top">{leakPeriodLabel} </div>;
}
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/ProjectLeakPeriodInfo-test.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/ProjectLeakPeriodInfo-test.tsx
index fe635fe2114..516922ab183 100644
--- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/ProjectLeakPeriodInfo-test.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/ProjectLeakPeriodInfo-test.tsx
@@ -23,7 +23,7 @@ import * as React from 'react';
import { IntlShape } from 'react-intl';
import { mockPeriod } from '../../../../helpers/testMocks';
import { renderComponent } from '../../../../helpers/testReactTestingUtils';
-import { Period } from '../../../../types/types';
+import { NewCodePeriodSettingType, Period } from '../../../../types/types';
import { ProjectLeakPeriodInfo } from '../ProjectLeakPeriodInfo';
jest.mock('date-fns', () => {
@@ -62,7 +62,7 @@ it('should render correctly for "previous_analysis"', async () => {
it('should render correctly for "REFERENCE_BRANCH"', async () => {
renderProjectLeakPeriodInfo({
- mode: 'REFERENCE_BRANCH',
+ mode: NewCodePeriodSettingType.REFERENCE_BRANCH,
parameter: 'master',
});
expect(await screen.findByText('overview.period.reference_branch.master')).toBeInTheDocument();
diff --git a/server/sonar-web/src/main/js/apps/overview/components/LeakPeriodLegend.tsx b/server/sonar-web/src/main/js/apps/overview/components/LeakPeriodLegend.tsx
index 86c20c726a5..43fe036e6be 100644
--- a/server/sonar-web/src/main/js/apps/overview/components/LeakPeriodLegend.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/components/LeakPeriodLegend.tsx
@@ -26,7 +26,7 @@ import DateFromNow from '../../../components/intl/DateFromNow';
import DateTimeFormatter, { formatterOption } from '../../../components/intl/DateTimeFormatter';
import { translateWithParameters } from '../../../helpers/l10n';
import { getPeriodDate, getPeriodLabel } from '../../../helpers/periods';
-import { Dict, Period } from '../../../types/types';
+import { Dict, NewCodePeriodSettingType, Period } from '../../../types/types';
interface Props {
period: Period;
@@ -56,7 +56,7 @@ export class LeakPeriodLegend extends React.PureComponent<Props & WrappedCompone
return null;
}
- if (period.mode === 'days' || period.mode === 'NUMBER_OF_DAYS') {
+ if (period.mode === 'days' || period.mode === NewCodePeriodSettingType.NUMBER_OF_DAYS) {
return (
<div className="overview-legend overview-legend-spaced-line">
{translateWithParameters('overview.new_code_period_x', leakPeriodLabel)}
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/components/BaselineSettingAnalysis.tsx b/server/sonar-web/src/main/js/apps/projectBaseline/components/BaselineSettingAnalysis.tsx
index f31cd308728..0528174c70c 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/components/BaselineSettingAnalysis.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/components/BaselineSettingAnalysis.tsx
@@ -32,7 +32,7 @@ export default function BaselineSettingAnalysis({ disabled, onSelect, selected }
return (
<RadioCard
disabled={disabled}
- onClick={() => onSelect('SPECIFIC_ANALYSIS')}
+ onClick={() => onSelect(NewCodePeriodSettingType.SPECIFIC_ANALYSIS)}
selected={selected}
title={translate('baseline.specific_analysis')}
>
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/components/BaselineSettingDays.tsx b/server/sonar-web/src/main/js/apps/projectBaseline/components/BaselineSettingDays.tsx
index 0f356bfd880..ef42354448d 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/components/BaselineSettingDays.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/components/BaselineSettingDays.tsx
@@ -41,7 +41,7 @@ export default function BaselineSettingDays(props: Props) {
<RadioCard
className={className}
disabled={disabled}
- onClick={() => onSelect('NUMBER_OF_DAYS')}
+ onClick={() => onSelect(NewCodePeriodSettingType.NUMBER_OF_DAYS)}
selected={selected}
title={translate('baseline.number_days')}
>
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/components/BaselineSettingPreviousVersion.tsx b/server/sonar-web/src/main/js/apps/projectBaseline/components/BaselineSettingPreviousVersion.tsx
index 5084aa5a124..e0ccc8487f9 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/components/BaselineSettingPreviousVersion.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/components/BaselineSettingPreviousVersion.tsx
@@ -34,7 +34,7 @@ export default function BaselineSettingPreviousVersion(props: Props) {
return (
<RadioCard
disabled={disabled}
- onClick={() => onSelect('PREVIOUS_VERSION')}
+ onClick={() => onSelect(NewCodePeriodSettingType.PREVIOUS_VERSION)}
selected={selected}
title={
translate('baseline.previous_version') + (isDefault ? ` (${translate('default')})` : '')
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/components/BaselineSettingReferenceBranch.tsx b/server/sonar-web/src/main/js/apps/projectBaseline/components/BaselineSettingReferenceBranch.tsx
index 35600e31718..6604d1e39da 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/components/BaselineSettingReferenceBranch.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/components/BaselineSettingReferenceBranch.tsx
@@ -98,7 +98,7 @@ export default function BaselineSettingReferenceBranch(props: BaselineSettingRef
<RadioCard
className={className}
disabled={disabled}
- onClick={() => props.onSelect('REFERENCE_BRANCH')}
+ onClick={() => props.onSelect(NewCodePeriodSettingType.REFERENCE_BRANCH)}
selected={selected}
title={translate('baseline.reference_branch')}
>
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/components/BranchBaselineSettingModal.tsx b/server/sonar-web/src/main/js/apps/projectBaseline/components/BranchBaselineSettingModal.tsx
index a9236fe447e..0a3ec852329 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/components/BranchBaselineSettingModal.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/components/BranchBaselineSettingModal.tsx
@@ -60,9 +60,10 @@ export default class BranchBaselineSettingModal extends React.PureComponent<Prop
const defaultBranch = otherBranches.length > 0 ? otherBranches[0].name : '';
this.state = {
- analysis: this.getValueFromProps('SPECIFIC_ANALYSIS') || '',
- days: this.getValueFromProps('NUMBER_OF_DAYS') || '30',
- referenceBranch: this.getValueFromProps('REFERENCE_BRANCH') || defaultBranch,
+ analysis: this.getValueFromProps(NewCodePeriodSettingType.SPECIFIC_ANALYSIS) || '',
+ days: this.getValueFromProps(NewCodePeriodSettingType.NUMBER_OF_DAYS) || '30',
+ referenceBranch:
+ this.getValueFromProps(NewCodePeriodSettingType.REFERENCE_BRANCH) || defaultBranch,
saving: false,
selected: this.props.branch.newCodePeriod && this.props.branch.newCodePeriod.type,
};
@@ -164,7 +165,7 @@ export default class BranchBaselineSettingModal extends React.PureComponent<Prop
<BaselineSettingPreviousVersion
isDefault={false}
onSelect={this.handleSelectSetting}
- selected={selected === 'PREVIOUS_VERSION'}
+ selected={selected === NewCodePeriodSettingType.PREVIOUS_VERSION}
/>
<BaselineSettingDays
days={days}
@@ -172,22 +173,22 @@ export default class BranchBaselineSettingModal extends React.PureComponent<Prop
isValid={isValid}
onChangeDays={this.handleSelectDays}
onSelect={this.handleSelectSetting}
- selected={selected === 'NUMBER_OF_DAYS'}
+ selected={selected === NewCodePeriodSettingType.NUMBER_OF_DAYS}
/>
<BaselineSettingAnalysis
onSelect={this.handleSelectSetting}
- selected={selected === 'SPECIFIC_ANALYSIS'}
+ selected={selected === NewCodePeriodSettingType.SPECIFIC_ANALYSIS}
/>
<BaselineSettingReferenceBranch
branchList={branchList.map(this.branchToOption)}
onChangeReferenceBranch={this.handleSelectReferenceBranch}
onSelect={this.handleSelectSetting}
referenceBranch={referenceBranch}
- selected={selected === 'REFERENCE_BRANCH'}
+ selected={selected === NewCodePeriodSettingType.REFERENCE_BRANCH}
settingLevel="branch"
/>
</div>
- {selected === 'SPECIFIC_ANALYSIS' && (
+ {selected === NewCodePeriodSettingType.SPECIFIC_ANALYSIS && (
<BranchAnalysisList
analysis={analysis}
branch={branch.name}
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/components/BranchList.tsx b/server/sonar-web/src/main/js/apps/projectBaseline/components/BranchList.tsx
index a3a5bf7f2dc..7d9943686e5 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/components/BranchList.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/components/BranchList.tsx
@@ -24,6 +24,7 @@ import { isBranch, sortBranches } from '../../../helpers/branch-like';
import { translate } from '../../../helpers/l10n';
import { Branch, BranchLike, BranchWithNewCodePeriod } from '../../../types/branch-like';
import { Component, NewCodePeriod } from '../../../types/types';
+import { DEFAULT_GENERAL_SETTING_TYPE } from '../constants';
import BranchBaselineSettingModal from './BranchBaselineSettingModal';
import BranchListRow from './BranchListRow';
@@ -74,7 +75,7 @@ export default class BranchList extends React.PureComponent<Props, State> {
if (!newCodePeriod) {
return b;
}
- const { type = 'PREVIOUS_VERSION', value, effectiveValue } = newCodePeriod;
+ const { type = DEFAULT_GENERAL_SETTING_TYPE, value, effectiveValue } = newCodePeriod;
return {
...b,
newCodePeriod: { type, value, effectiveValue },
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/components/BranchListRow.tsx b/server/sonar-web/src/main/js/apps/projectBaseline/components/BranchListRow.tsx
index 9ed131753c9..ff07fee94dd 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/components/BranchListRow.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/components/BranchListRow.tsx
@@ -25,7 +25,7 @@ import WarningIcon from '../../../components/icons/WarningIcon';
import DateTimeFormatter from '../../../components/intl/DateTimeFormatter';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { BranchWithNewCodePeriod } from '../../../types/branch-like';
-import { NewCodePeriod } from '../../../types/types';
+import { NewCodePeriod, NewCodePeriodSettingType } from '../../../types/types';
export interface BranchListRowProps {
branch: BranchWithNewCodePeriod;
@@ -37,7 +37,7 @@ export interface BranchListRowProps {
function renderNewCodePeriodSetting(newCodePeriod: NewCodePeriod) {
switch (newCodePeriod.type) {
- case 'SPECIFIC_ANALYSIS':
+ case NewCodePeriodSettingType.SPECIFIC_ANALYSIS:
return (
<>
{`${translate('baseline.specific_analysis')}: `}
@@ -48,11 +48,11 @@ function renderNewCodePeriodSetting(newCodePeriod: NewCodePeriod) {
)}
</>
);
- case 'NUMBER_OF_DAYS':
+ case NewCodePeriodSettingType.NUMBER_OF_DAYS:
return `${translate('baseline.number_days')}: ${newCodePeriod.value}`;
- case 'PREVIOUS_VERSION':
+ case NewCodePeriodSettingType.PREVIOUS_VERSION:
return translate('baseline.previous_version');
- case 'REFERENCE_BRANCH':
+ case NewCodePeriodSettingType.REFERENCE_BRANCH:
return `${translate('baseline.reference_branch')}: ${newCodePeriod.value}`;
default:
return newCodePeriod.type;
@@ -65,7 +65,7 @@ function branchInheritsItselfAsReference(
) {
return (
!branch.newCodePeriod &&
- inheritedSetting.type === 'REFERENCE_BRANCH' &&
+ inheritedSetting.type === NewCodePeriodSettingType.REFERENCE_BRANCH &&
branch.name === inheritedSetting.value
);
}
@@ -77,7 +77,7 @@ function referenceBranchDoesNotExist(
return (
branch.newCodePeriod &&
branch.newCodePeriod.value &&
- branch.newCodePeriod.type === 'REFERENCE_BRANCH' &&
+ branch.newCodePeriod.type === NewCodePeriodSettingType.REFERENCE_BRANCH &&
!existingBranches.includes(branch.newCodePeriod.value)
);
}
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/components/App.tsx b/server/sonar-web/src/main/js/apps/projectBaseline/components/ProjectBaselineApp.tsx
index 80dbcf8f0eb..025cc21974e 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/components/App.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/components/ProjectBaselineApp.tsx
@@ -36,6 +36,7 @@ import { Branch, BranchLike } from '../../../types/branch-like';
import { Feature } from '../../../types/features';
import { ParsedAnalysis } from '../../../types/project-activity';
import { Component, NewCodePeriod, NewCodePeriodSettingType } from '../../../types/types';
+import { DEFAULT_GENERAL_SETTING_TYPE } from '../constants';
import '../styles.css';
import { getSettingValue } from '../utils';
import AppHeader from './AppHeader';
@@ -66,11 +67,7 @@ interface State {
const DEFAULT_NUMBER_OF_DAYS = '30';
-const DEFAULT_GENERAL_SETTING: { type: NewCodePeriodSettingType } = {
- type: 'PREVIOUS_VERSION',
-};
-
-export class App extends React.PureComponent<Props, State> {
+export class ProjectBaselineApp extends React.PureComponent<Props, State> {
mounted = false;
state: State = {
branchList: [],
@@ -107,7 +104,8 @@ export class App extends React.PureComponent<Props, State> {
const { referenceBranch } = this.state;
const defaultDays =
- (generalSetting.type === 'NUMBER_OF_DAYS' && generalSetting.value) || DEFAULT_NUMBER_OF_DAYS;
+ (generalSetting.type === NewCodePeriodSettingType.NUMBER_OF_DAYS && generalSetting.value) ||
+ DEFAULT_NUMBER_OF_DAYS;
return {
loading: false,
@@ -116,10 +114,15 @@ export class App extends React.PureComponent<Props, State> {
generalSetting,
selected: currentSetting || generalSetting.type,
overrideGeneralSetting: Boolean(currentSetting),
- days: (currentSetting === 'NUMBER_OF_DAYS' && currentSettingValue) || defaultDays,
- analysis: (currentSetting === 'SPECIFIC_ANALYSIS' && currentSettingValue) || '',
+ days:
+ (currentSetting === NewCodePeriodSettingType.NUMBER_OF_DAYS && currentSettingValue) ||
+ defaultDays,
+ analysis:
+ (currentSetting === NewCodePeriodSettingType.SPECIFIC_ANALYSIS && currentSettingValue) ||
+ '',
referenceBranch:
- (currentSetting === 'REFERENCE_BRANCH' && currentSettingValue) || referenceBranch,
+ (currentSetting === NewCodePeriodSettingType.REFERENCE_BRANCH && currentSettingValue) ||
+ referenceBranch,
};
}
@@ -143,10 +146,12 @@ export class App extends React.PureComponent<Props, State> {
([generalSetting, setting]) => {
if (this.mounted) {
if (!generalSetting.type) {
- generalSetting = DEFAULT_GENERAL_SETTING;
+ generalSetting = { type: DEFAULT_GENERAL_SETTING_TYPE };
}
const currentSettingValue = setting.value;
- const currentSetting = setting.inherited ? undefined : setting.type || 'PREVIOUS_VERSION';
+ const currentSetting = setting.inherited
+ ? undefined
+ : setting.type || DEFAULT_GENERAL_SETTING_TYPE;
this.setState(
this.getUpdatedState({
@@ -191,8 +196,11 @@ export class App extends React.PureComponent<Props, State> {
handleCancel = () =>
this.setState(
- ({ generalSetting = DEFAULT_GENERAL_SETTING, currentSetting, currentSettingValue }) =>
- this.getUpdatedState({ generalSetting, currentSetting, currentSettingValue })
+ ({
+ generalSetting = { type: DEFAULT_GENERAL_SETTING_TYPE },
+ currentSetting,
+ currentSettingValue,
+ }) => this.getUpdatedState({ generalSetting, currentSetting, currentSettingValue })
);
handleSelectSetting = (selected?: NewCodePeriodSettingType) => this.setState({ selected });
@@ -322,4 +330,4 @@ export class App extends React.PureComponent<Props, State> {
}
}
-export default withComponentContext(withAvailableFeatures(withAppStateContext(App)));
+export default withComponentContext(withAvailableFeatures(withAppStateContext(ProjectBaselineApp)));
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/components/ProjectBaselineSelector.tsx b/server/sonar-web/src/main/js/apps/projectBaseline/components/ProjectBaselineSelector.tsx
index 76aa0647165..ac0eb18dbef 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/components/ProjectBaselineSelector.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/components/ProjectBaselineSelector.tsx
@@ -60,7 +60,7 @@ export interface ProjectBaselineSelectorProps {
function renderGeneralSetting(generalSetting: NewCodePeriod) {
let setting: string;
let description: string;
- if (generalSetting.type === 'NUMBER_OF_DAYS') {
+ if (generalSetting.type === NewCodePeriodSettingType.NUMBER_OF_DAYS) {
setting = `${translate('baseline.number_days')} (${translateWithParameters(
'duration.days',
generalSetting.value || '?'
@@ -137,7 +137,9 @@ export default function ProjectBaselineSelector(props: ProjectBaselineSelectorPr
<BaselineSettingPreviousVersion
disabled={!overrideGeneralSetting}
onSelect={props.onSelectSetting}
- selected={overrideGeneralSetting && selected === 'PREVIOUS_VERSION'}
+ selected={
+ overrideGeneralSetting && selected === NewCodePeriodSettingType.PREVIOUS_VERSION
+ }
/>
<BaselineSettingDays
days={days}
@@ -146,7 +148,9 @@ export default function ProjectBaselineSelector(props: ProjectBaselineSelectorPr
isValid={isValid}
onChangeDays={props.onSelectDays}
onSelect={props.onSelectSetting}
- selected={overrideGeneralSetting && selected === 'NUMBER_OF_DAYS'}
+ selected={
+ overrideGeneralSetting && selected === NewCodePeriodSettingType.NUMBER_OF_DAYS
+ }
/>
{branchesEnabled ? (
<BaselineSettingReferenceBranch
@@ -155,18 +159,22 @@ export default function ProjectBaselineSelector(props: ProjectBaselineSelectorPr
onChangeReferenceBranch={props.onSelectReferenceBranch}
onSelect={props.onSelectSetting}
referenceBranch={referenceBranch || ''}
- selected={overrideGeneralSetting && selected === 'REFERENCE_BRANCH'}
+ selected={
+ overrideGeneralSetting && selected === NewCodePeriodSettingType.REFERENCE_BRANCH
+ }
settingLevel="project"
/>
) : (
<BaselineSettingAnalysis
disabled={!overrideGeneralSetting}
onSelect={props.onSelectSetting}
- selected={overrideGeneralSetting && selected === 'SPECIFIC_ANALYSIS'}
+ selected={
+ overrideGeneralSetting && selected === NewCodePeriodSettingType.SPECIFIC_ANALYSIS
+ }
/>
)}
</div>
- {selected === 'SPECIFIC_ANALYSIS' && (
+ {selected === NewCodePeriodSettingType.SPECIFIC_ANALYSIS && (
<BranchAnalysisList
analysis={analysis || ''}
branch={branch.name}
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BaselineSettingAnalysis-test.tsx b/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BaselineSettingAnalysis-test.tsx
index c4b9ec1718b..f6960dbe0fb 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BaselineSettingAnalysis-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BaselineSettingAnalysis-test.tsx
@@ -19,6 +19,7 @@
*/
import { shallow } from 'enzyme';
import * as React from 'react';
+import { NewCodePeriodSettingType } from '../../../../types/types';
import BaselineSettingAnalysis, { Props } from '../BaselineSettingAnalysis';
it('should render correctly', () => {
@@ -30,7 +31,7 @@ it('should callback when clicked', () => {
const wrapper = shallowRender({ onSelect, selected: false });
wrapper.find('RadioCard').first().simulate('click');
- expect(onSelect).toHaveBeenCalledWith('SPECIFIC_ANALYSIS');
+ expect(onSelect).toHaveBeenCalledWith(NewCodePeriodSettingType.SPECIFIC_ANALYSIS);
});
function shallowRender(props: Partial<Props> = {}) {
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BaselineSettingDays-test.tsx b/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BaselineSettingDays-test.tsx
index 95fcbe423d4..a7aa306c6c6 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BaselineSettingDays-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BaselineSettingDays-test.tsx
@@ -19,6 +19,7 @@
*/
import { shallow } from 'enzyme';
import * as React from 'react';
+import { NewCodePeriodSettingType } from '../../../../types/types';
import BaselineSettingDays, { Props } from '../BaselineSettingDays';
it('should render correctly', () => {
@@ -37,7 +38,7 @@ it('should callback when clicked', () => {
const wrapper = shallowRender({ onSelect, selected: false });
wrapper.find('RadioCard').first().simulate('click');
- expect(onSelect).toHaveBeenCalledWith('NUMBER_OF_DAYS');
+ expect(onSelect).toHaveBeenCalledWith(NewCodePeriodSettingType.NUMBER_OF_DAYS);
});
it('should callback when changing days', () => {
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BaselineSettingPreviousVersion-test.tsx b/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BaselineSettingPreviousVersion-test.tsx
index b680fb9cb88..9072f671c8d 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BaselineSettingPreviousVersion-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BaselineSettingPreviousVersion-test.tsx
@@ -19,6 +19,7 @@
*/
import { shallow } from 'enzyme';
import * as React from 'react';
+import { NewCodePeriodSettingType } from '../../../../types/types';
import BaselineSettingPreviousVersion, { Props } from '../BaselineSettingPreviousVersion';
it('should render correctly', () => {
@@ -31,7 +32,7 @@ it('should callback when clicked', () => {
const wrapper = shallowRender({ onSelect, selected: false });
wrapper.find('RadioCard').first().simulate('click');
- expect(onSelect).toHaveBeenCalledWith('PREVIOUS_VERSION');
+ expect(onSelect).toHaveBeenCalledWith(NewCodePeriodSettingType.PREVIOUS_VERSION);
});
function shallowRender(props: Partial<Props> = {}) {
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BaselineSettingReferenceBranch-test.tsx b/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BaselineSettingReferenceBranch-test.tsx
index c240643795d..dd9f28b5a76 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BaselineSettingReferenceBranch-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BaselineSettingReferenceBranch-test.tsx
@@ -22,6 +22,7 @@ import * as React from 'react';
import { OptionProps, Props as ReactSelectProps } from 'react-select';
import RadioCard from '../../../../components/controls/RadioCard';
import Select from '../../../../components/controls/Select';
+import { NewCodePeriodSettingType } from '../../../../types/types';
import BaselineSettingReferenceBranch, {
BaselineSettingReferenceBranchProps,
BranchOption,
@@ -49,7 +50,7 @@ it('should callback when clicked', () => {
const wrapper = shallowRender({ onSelect, selected: false });
wrapper.find(RadioCard).first().simulate('click');
- expect(onSelect).toHaveBeenCalledWith('REFERENCE_BRANCH');
+ expect(onSelect).toHaveBeenCalledWith(NewCodePeriodSettingType.REFERENCE_BRANCH);
});
it('should callback when changing selection', () => {
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BranchBaselineSettingModal-test.tsx b/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BranchBaselineSettingModal-test.tsx
index 06f71f16c33..8a0e83b8e50 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BranchBaselineSettingModal-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BranchBaselineSettingModal-test.tsx
@@ -22,6 +22,7 @@ import * as React from 'react';
import { setNewCodePeriod } from '../../../../api/newCodePeriod';
import { mockBranch, mockMainBranch } from '../../../../helpers/mocks/branch-like';
import { mockEvent, waitAndUpdate } from '../../../../helpers/testUtils';
+import { NewCodePeriodSettingType } from '../../../../types/types';
import BranchBaselineSettingModal from '../BranchBaselineSettingModal';
jest.mock('../../../../api/newCodePeriod', () => ({
@@ -38,7 +39,7 @@ it('should render correctly', () => {
it('should display the branch analysis list when necessary', () => {
const wrapper = shallowRender();
- wrapper.setState({ selected: 'SPECIFIC_ANALYSIS' });
+ wrapper.setState({ selected: NewCodePeriodSettingType.SPECIFIC_ANALYSIS });
expect(wrapper.find('BranchAnalysisList')).toHaveLength(1);
});
@@ -51,7 +52,10 @@ it('should save correctly', async () => {
component,
});
- wrapper.setState({ analysis: 'analysis572893', selected: 'SPECIFIC_ANALYSIS' });
+ wrapper.setState({
+ analysis: 'analysis572893',
+ selected: NewCodePeriodSettingType.SPECIFIC_ANALYSIS,
+ });
await waitAndUpdate(wrapper);
wrapper.instance().handleSubmit(mockEvent());
@@ -59,7 +63,7 @@ it('should save correctly', async () => {
expect(setNewCodePeriod).toHaveBeenCalledWith({
project: component,
- type: 'SPECIFIC_ANALYSIS',
+ type: NewCodePeriodSettingType.SPECIFIC_ANALYSIS,
value: 'analysis572893',
branch: 'branchname',
});
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BranchList-test.tsx b/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BranchList-test.tsx
index df935426e90..3fab1ff976f 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BranchList-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BranchList-test.tsx
@@ -23,6 +23,7 @@ import { listBranchesNewCodePeriod, resetNewCodePeriod } from '../../../../api/n
import { mockBranch, mockMainBranch } from '../../../../helpers/mocks/branch-like';
import { mockComponent } from '../../../../helpers/mocks/component';
import { waitAndUpdate } from '../../../../helpers/testUtils';
+import { NewCodePeriodSettingType } from '../../../../types/types';
import BranchBaselineSettingModal from '../BranchBaselineSettingModal';
import BranchList from '../BranchList';
@@ -35,7 +36,7 @@ const newCodePeriods = [
{
projectKey: '',
branchKey: 'master',
- type: 'NUMBER_OF_DAYS',
+ type: NewCodePeriodSettingType.NUMBER_OF_DAYS,
value: '27',
},
];
@@ -73,7 +74,9 @@ it('should toggle popup', async () => {
expect(nodes).toHaveLength(1);
expect(nodes.first().props().branch).toEqual(mockMainBranch());
- wrapper.instance().closeEditModal('master', { type: 'NUMBER_OF_DAYS', value: '23' });
+ wrapper
+ .instance()
+ .closeEditModal('master', { type: NewCodePeriodSettingType.NUMBER_OF_DAYS, value: '23' });
expect(wrapper.find('BranchBaselineSettingModal')).toHaveLength(0);
expect(wrapper.state().branches.find((b) => b.name === 'master')).toEqual({
@@ -82,7 +85,7 @@ it('should toggle popup', async () => {
isMain: true,
name: 'master',
newCodePeriod: {
- type: 'NUMBER_OF_DAYS',
+ type: NewCodePeriodSettingType.NUMBER_OF_DAYS,
value: '23',
},
});
@@ -93,7 +96,7 @@ function shallowRender(props: Partial<BranchList['props']> = {}) {
<BranchList
branchList={[]}
component={mockComponent()}
- inheritedSetting={{ type: 'PREVIOUS_VERSION' }}
+ inheritedSetting={{ type: NewCodePeriodSettingType.PREVIOUS_VERSION }}
{...props}
/>
);
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BranchListRow-test.tsx b/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BranchListRow-test.tsx
index 66f6593bb16..12f2bb83be1 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BranchListRow-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/BranchListRow-test.tsx
@@ -21,6 +21,7 @@ import { shallow } from 'enzyme';
import * as React from 'react';
import { ActionsDropdownItem } from '../../../../components/controls/ActionsDropdown';
import { mockBranch, mockMainBranch } from '../../../../helpers/mocks/branch-like';
+import { NewCodePeriodSettingType } from '../../../../types/types';
import BranchListRow, { BranchListRowProps } from '../BranchListRow';
it('should render correctly', () => {
@@ -28,17 +29,23 @@ it('should render correctly', () => {
expect(
shallowRender({
branch: mockBranch({ name: 'branch-7.3' }),
- inheritedSetting: { type: 'REFERENCE_BRANCH', value: 'branch-7.3' },
+ inheritedSetting: { type: NewCodePeriodSettingType.REFERENCE_BRANCH, value: 'branch-7.3' },
})
).toMatchSnapshot('faulty branch');
expect(
shallowRender({
- branch: { ...mockBranch(), newCodePeriod: { type: 'NUMBER_OF_DAYS', value: '21' } },
+ branch: {
+ ...mockBranch(),
+ newCodePeriod: { type: NewCodePeriodSettingType.NUMBER_OF_DAYS, value: '21' },
+ },
})
).toMatchSnapshot('branch with number of days');
expect(
shallowRender({
- branch: { ...mockBranch(), newCodePeriod: { type: 'PREVIOUS_VERSION' } },
+ branch: {
+ ...mockBranch(),
+ newCodePeriod: { type: NewCodePeriodSettingType.PREVIOUS_VERSION },
+ },
})
).toMatchSnapshot('branch with previous version');
expect(
@@ -46,7 +53,7 @@ it('should render correctly', () => {
branch: {
...mockBranch(),
newCodePeriod: {
- type: 'SPECIFIC_ANALYSIS',
+ type: NewCodePeriodSettingType.SPECIFIC_ANALYSIS,
value: 'A85835',
effectiveValue: '2018-12-02T13:01:12',
},
@@ -55,7 +62,10 @@ it('should render correctly', () => {
).toMatchSnapshot('branch with specific analysis');
expect(
shallowRender({
- branch: { ...mockBranch(), newCodePeriod: { type: 'REFERENCE_BRANCH', value: 'master' } },
+ branch: {
+ ...mockBranch(),
+ newCodePeriod: { type: NewCodePeriodSettingType.REFERENCE_BRANCH, value: 'master' },
+ },
})
).toMatchSnapshot('branch with reference branch');
});
@@ -74,7 +84,10 @@ it('should callback to reset when clicked', () => {
const resetToDefault = jest.fn();
const branchName = 'branch-6.5';
const wrapper = shallowRender({
- branch: { ...mockBranch({ name: branchName }), newCodePeriod: { type: 'REFERENCE_BRANCH' } },
+ branch: {
+ ...mockBranch({ name: branchName }),
+ newCodePeriod: { type: NewCodePeriodSettingType.REFERENCE_BRANCH },
+ },
onResetToDefault: resetToDefault,
});
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/App-test.tsx b/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/ProjectBaselineApp-test.tsx
index aaa7056fe0d..1f368a4060e 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/App-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/ProjectBaselineApp-test.tsx
@@ -28,7 +28,8 @@ import { mockBranch, mockMainBranch, mockPullRequest } from '../../../../helpers
import { mockComponent } from '../../../../helpers/mocks/component';
import { mockAppState } from '../../../../helpers/testMocks';
import { mockEvent, waitAndUpdate } from '../../../../helpers/testUtils';
-import { App } from '../App';
+import { NewCodePeriodSettingType } from '../../../../types/types';
+import { ProjectBaselineApp } from '../ProjectBaselineApp';
jest.mock('../../../../api/newCodePeriod', () => ({
getNewCodePeriod: jest.fn().mockResolvedValue({}),
@@ -75,12 +76,12 @@ it('should save correctly', async () => {
const component = mockComponent();
const wrapper = shallowRender({ component });
await waitAndUpdate(wrapper);
- wrapper.setState({ selected: 'NUMBER_OF_DAYS', days: '23' });
+ wrapper.setState({ selected: NewCodePeriodSettingType.NUMBER_OF_DAYS, days: '23' });
wrapper.instance().handleSubmit(mockEvent());
await waitAndUpdate(wrapper);
expect(setNewCodePeriod).toHaveBeenCalledWith({
project: component.key,
- type: 'NUMBER_OF_DAYS',
+ type: NewCodePeriodSettingType.NUMBER_OF_DAYS,
value: '23',
});
expect(wrapper.state('currentSetting')).toEqual(wrapper.state('selected'));
@@ -92,7 +93,7 @@ it('should handle errors gracefully', async () => {
(resetNewCodePeriod as jest.Mock).mockRejectedValue('error');
const wrapper = shallowRender();
- wrapper.setState({ selected: 'PREVIOUS_VERSION' });
+ wrapper.setState({ selected: NewCodePeriodSettingType.PREVIOUS_VERSION });
await waitAndUpdate(wrapper);
expect(wrapper.state('loading')).toBe(false);
@@ -104,9 +105,9 @@ it('should handle errors gracefully', async () => {
expect(wrapper.state('saving')).toBe(false);
});
-function shallowRender(props: Partial<App['props']> = {}) {
- return shallow<App>(
- <App
+function shallowRender(props: Partial<ProjectBaselineApp['props']> = {}) {
+ return shallow<ProjectBaselineApp>(
+ <ProjectBaselineApp
branchLike={mockBranch()}
branchLikes={[mockMainBranch()]}
appState={mockAppState({ canAdmin: true })}
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/ProjectBaselineSelector-test.tsx b/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/ProjectBaselineSelector-test.tsx
index 09b2ecdfe1d..740f830be9c 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/ProjectBaselineSelector-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/ProjectBaselineSelector-test.tsx
@@ -20,6 +20,7 @@
import { shallow } from 'enzyme';
import * as React from 'react';
import { mockBranch, mockMainBranch } from '../../../../helpers/mocks/branch-like';
+import { NewCodePeriodSettingType } from '../../../../types/types';
import ProjectBaselineSelector, { ProjectBaselineSelectorProps } from '../ProjectBaselineSelector';
it('should render correctly', () => {
@@ -27,18 +28,21 @@ it('should render correctly', () => {
expect(
shallowRender({
branchesEnabled: false,
- generalSetting: { type: 'NUMBER_OF_DAYS', value: '23' },
+ generalSetting: { type: NewCodePeriodSettingType.NUMBER_OF_DAYS, value: '23' },
})
).toMatchSnapshot();
expect(
- shallowRender({ branchesEnabled: false, generalSetting: { type: 'NUMBER_OF_DAYS', value: '' } })
+ shallowRender({
+ branchesEnabled: false,
+ generalSetting: { type: NewCodePeriodSettingType.NUMBER_OF_DAYS, value: '' },
+ })
).toMatchSnapshot();
});
it('should not show save button when unchanged', () => {
const wrapper = shallowRender({
- currentSetting: 'PREVIOUS_VERSION',
- selected: 'PREVIOUS_VERSION',
+ currentSetting: NewCodePeriodSettingType.PREVIOUS_VERSION,
+ selected: NewCodePeriodSettingType.PREVIOUS_VERSION,
overrideGeneralSetting: true,
});
expect(wrapper.find('SubmitButton').parent().hasClass('invisible')).toBe(true);
@@ -46,8 +50,8 @@ it('should not show save button when unchanged', () => {
it('should show save button when changed', () => {
const wrapper = shallowRender({
- currentSetting: 'PREVIOUS_VERSION',
- selected: 'NUMBER_OF_DAYS',
+ currentSetting: NewCodePeriodSettingType.PREVIOUS_VERSION,
+ selected: NewCodePeriodSettingType.NUMBER_OF_DAYS,
overrideGeneralSetting: true,
});
expect(wrapper.find('SubmitButton')).toHaveLength(1);
@@ -55,10 +59,10 @@ it('should show save button when changed', () => {
it('should show save button when value changed', () => {
const wrapper = shallowRender({
- currentSetting: 'NUMBER_OF_DAYS',
+ currentSetting: NewCodePeriodSettingType.NUMBER_OF_DAYS,
currentSettingValue: '23',
days: '25',
- selected: 'NUMBER_OF_DAYS',
+ selected: NewCodePeriodSettingType.NUMBER_OF_DAYS,
overrideGeneralSetting: true,
});
expect(wrapper.find('SubmitButton')).toHaveLength(1);
@@ -66,10 +70,10 @@ it('should show save button when value changed', () => {
it('should disable the save button when saving', () => {
const wrapper = shallowRender({
- currentSetting: 'NUMBER_OF_DAYS',
+ currentSetting: NewCodePeriodSettingType.NUMBER_OF_DAYS,
currentSettingValue: '25',
saving: true,
- selected: 'PREVIOUS_VERSION',
+ selected: NewCodePeriodSettingType.PREVIOUS_VERSION,
overrideGeneralSetting: true,
});
@@ -78,9 +82,9 @@ it('should disable the save button when saving', () => {
it('should disable the save button when date is invalid', () => {
const wrapper = shallowRender({
- currentSetting: 'PREVIOUS_VERSION',
+ currentSetting: NewCodePeriodSettingType.PREVIOUS_VERSION,
days: 'hello',
- selected: 'NUMBER_OF_DAYS',
+ selected: NewCodePeriodSettingType.NUMBER_OF_DAYS,
overrideGeneralSetting: true,
});
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/__snapshots__/App-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/__snapshots__/ProjectBaselineApp-test.tsx.snap
index 847b62f98de..847b62f98de 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/__snapshots__/App-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/__snapshots__/ProjectBaselineApp-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/utils-test.ts b/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/utils-test.ts
index 044e63b9da6..2d53227ef9f 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/utils-test.ts
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/utils-test.ts
@@ -17,6 +17,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { NewCodePeriodSettingType } from '../../../../types/types';
import { getSettingValue, validateSetting } from '../../utils';
describe('getSettingValue', () => {
@@ -27,19 +28,27 @@ describe('getSettingValue', () => {
};
it('should work for Days', () => {
- expect(getSettingValue({ ...state, type: 'NUMBER_OF_DAYS' })).toBe(state.days);
+ expect(getSettingValue({ ...state, type: NewCodePeriodSettingType.NUMBER_OF_DAYS })).toBe(
+ state.days
+ );
});
it('should work for Analysis', () => {
- expect(getSettingValue({ ...state, type: 'SPECIFIC_ANALYSIS' })).toBe(state.analysis);
+ expect(getSettingValue({ ...state, type: NewCodePeriodSettingType.SPECIFIC_ANALYSIS })).toBe(
+ state.analysis
+ );
});
it('should work for Previous version', () => {
- expect(getSettingValue({ ...state, type: 'PREVIOUS_VERSION' })).toBeUndefined();
+ expect(
+ getSettingValue({ ...state, type: NewCodePeriodSettingType.PREVIOUS_VERSION })
+ ).toBeUndefined();
});
it('should work for Reference branch', () => {
- expect(getSettingValue({ ...state, type: 'REFERENCE_BRANCH' })).toBe(state.referenceBranch);
+ expect(getSettingValue({ ...state, type: NewCodePeriodSettingType.REFERENCE_BRANCH })).toBe(
+ state.referenceBranch
+ );
});
});
@@ -48,68 +57,68 @@ describe('validateSettings', () => {
expect(validateSetting({ days: '' })).toEqual({ isChanged: false, isValid: false });
expect(
validateSetting({
- currentSetting: 'PREVIOUS_VERSION',
+ currentSetting: NewCodePeriodSettingType.PREVIOUS_VERSION,
days: '12',
- selected: 'NUMBER_OF_DAYS',
+ selected: NewCodePeriodSettingType.NUMBER_OF_DAYS,
})
).toEqual({ isChanged: true, isValid: true });
expect(
validateSetting({
- currentSetting: 'PREVIOUS_VERSION',
+ currentSetting: NewCodePeriodSettingType.PREVIOUS_VERSION,
days: 'nope',
- selected: 'NUMBER_OF_DAYS',
+ selected: NewCodePeriodSettingType.NUMBER_OF_DAYS,
})
).toEqual({ isChanged: true, isValid: false });
expect(
validateSetting({
- currentSetting: 'NUMBER_OF_DAYS',
+ currentSetting: NewCodePeriodSettingType.NUMBER_OF_DAYS,
currentSettingValue: '15',
days: '15',
- selected: 'NUMBER_OF_DAYS',
+ selected: NewCodePeriodSettingType.NUMBER_OF_DAYS,
})
).toEqual({ isChanged: false, isValid: true });
expect(
validateSetting({
- currentSetting: 'NUMBER_OF_DAYS',
+ currentSetting: NewCodePeriodSettingType.NUMBER_OF_DAYS,
currentSettingValue: '15',
days: '13',
- selected: 'NUMBER_OF_DAYS',
+ selected: NewCodePeriodSettingType.NUMBER_OF_DAYS,
})
).toEqual({ isChanged: true, isValid: true });
expect(
validateSetting({
analysis: 'analysis1',
- currentSetting: 'SPECIFIC_ANALYSIS',
+ currentSetting: NewCodePeriodSettingType.SPECIFIC_ANALYSIS,
currentSettingValue: 'analysis1',
days: '',
- selected: 'SPECIFIC_ANALYSIS',
+ selected: NewCodePeriodSettingType.SPECIFIC_ANALYSIS,
})
).toEqual({ isChanged: false, isValid: true });
expect(
validateSetting({
analysis: 'analysis2',
- currentSetting: 'SPECIFIC_ANALYSIS',
+ currentSetting: NewCodePeriodSettingType.SPECIFIC_ANALYSIS,
currentSettingValue: 'analysis1',
days: '',
- selected: 'SPECIFIC_ANALYSIS',
+ selected: NewCodePeriodSettingType.SPECIFIC_ANALYSIS,
})
).toEqual({ isChanged: true, isValid: true });
expect(
validateSetting({
- currentSetting: 'REFERENCE_BRANCH',
+ currentSetting: NewCodePeriodSettingType.REFERENCE_BRANCH,
currentSettingValue: 'master',
days: '',
referenceBranch: 'master',
- selected: 'REFERENCE_BRANCH',
+ selected: NewCodePeriodSettingType.REFERENCE_BRANCH,
})
).toEqual({ isChanged: false, isValid: true });
expect(
validateSetting({
- currentSetting: 'REFERENCE_BRANCH',
+ currentSetting: NewCodePeriodSettingType.REFERENCE_BRANCH,
currentSettingValue: 'master',
days: '',
referenceBranch: '',
- selected: 'REFERENCE_BRANCH',
+ selected: NewCodePeriodSettingType.REFERENCE_BRANCH,
})
).toEqual({ isChanged: true, isValid: false });
});
@@ -125,7 +134,7 @@ describe('validateSettings', () => {
});
expect(
validateSetting({
- currentSetting: 'PREVIOUS_VERSION',
+ currentSetting: NewCodePeriodSettingType.PREVIOUS_VERSION,
days: '',
overrideGeneralSetting: false,
})
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForNumber-test.tsx b/server/sonar-web/src/main/js/apps/projectBaseline/constants.ts
index e22ba04f8c9..00c2c82e24b 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForNumber-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/constants.ts
@@ -17,26 +17,8 @@
* 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 { mockSetting } from '../../../../../helpers/mocks/settings';
-import InputForNumber from '../InputForNumber';
-import SimpleInput from '../SimpleInput';
-it('should render SimpleInput', () => {
- const onChange = jest.fn();
- const simpleInput = shallow(
- <InputForNumber
- isDefault={false}
- name="foo"
- onChange={onChange}
- setting={mockSetting()}
- value={17}
- />
- ).find(SimpleInput);
- expect(simpleInput.length).toBe(1);
- expect(simpleInput.prop('name')).toBe('foo');
- expect(simpleInput.prop('value')).toBe(17);
- expect(simpleInput.prop('type')).toBe('text');
- expect(simpleInput.prop('onChange')).toBeDefined();
-});
+import { NewCodePeriodSettingType } from '../../types/types';
+
+export const DEFAULT_GENERAL_SETTING_TYPE: NewCodePeriodSettingType =
+ NewCodePeriodSettingType.PREVIOUS_VERSION;
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/routes.tsx b/server/sonar-web/src/main/js/apps/projectBaseline/routes.tsx
index 5397eae9553..2235fe7aabf 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/routes.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/routes.tsx
@@ -19,8 +19,8 @@
*/
import React from 'react';
import { Route } from 'react-router-dom';
-import App from './components/App';
+import ProjectBaselineApp from './components/ProjectBaselineApp';
-const routes = () => <Route path="baseline" element={<App />} />;
+const routes = () => <Route path="baseline" element={<ProjectBaselineApp />} />;
export default routes;
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/utils.ts b/server/sonar-web/src/main/js/apps/projectBaseline/utils.ts
index 3f249e2fd77..2ca20b85b1e 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/utils.ts
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/utils.ts
@@ -37,11 +37,11 @@ export function getSettingValue({
type?: NewCodePeriodSettingType;
}) {
switch (type) {
- case 'NUMBER_OF_DAYS':
+ case NewCodePeriodSettingType.NUMBER_OF_DAYS:
return days;
- case 'REFERENCE_BRANCH':
+ case NewCodePeriodSettingType.REFERENCE_BRANCH:
return referenceBranch;
- case 'SPECIFIC_ANALYSIS':
+ case NewCodePeriodSettingType.SPECIFIC_ANALYSIS:
return analysis;
default:
return undefined;
@@ -74,17 +74,19 @@ export function validateSetting(state: {
isChanged =
overrideGeneralSetting === false ||
selected !== currentSetting ||
- (selected === 'NUMBER_OF_DAYS' && days !== currentSettingValue) ||
- (selected === 'SPECIFIC_ANALYSIS' && analysis !== currentSettingValue) ||
- (selected === 'REFERENCE_BRANCH' && referenceBranch !== currentSettingValue);
+ (selected === NewCodePeriodSettingType.NUMBER_OF_DAYS && days !== currentSettingValue) ||
+ (selected === NewCodePeriodSettingType.SPECIFIC_ANALYSIS &&
+ analysis !== currentSettingValue) ||
+ (selected === NewCodePeriodSettingType.REFERENCE_BRANCH &&
+ referenceBranch !== currentSettingValue);
}
const isValid =
overrideGeneralSetting === false ||
- selected === 'PREVIOUS_VERSION' ||
- (selected === 'SPECIFIC_ANALYSIS' && analysis.length > 0) ||
- (selected === 'NUMBER_OF_DAYS' && validateDays(days)) ||
- (selected === 'REFERENCE_BRANCH' && referenceBranch.length > 0);
+ selected === NewCodePeriodSettingType.PREVIOUS_VERSION ||
+ (selected === NewCodePeriodSettingType.SPECIFIC_ANALYSIS && analysis.length > 0) ||
+ (selected === NewCodePeriodSettingType.NUMBER_OF_DAYS && validateDays(days)) ||
+ (selected === NewCodePeriodSettingType.REFERENCE_BRANCH && referenceBranch.length > 0);
return { isChanged, isValid };
}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/Definition.tsx b/server/sonar-web/src/main/js/apps/settings/components/Definition.tsx
index c0167864efc..ca7d3221869 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/Definition.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/Definition.tsx
@@ -90,10 +90,9 @@ export default class Definition extends React.PureComponent<Props, State> {
settingValue,
});
- this.timeout = window.setTimeout(
- () => this.setState({ success: false }),
- SAFE_SET_STATE_DELAY
- );
+ this.timeout = window.setTimeout(() => {
+ this.setState({ success: false });
+ }, SAFE_SET_STATE_DELAY);
} catch (e) {
const validationMessage = await parseError(e as Response);
this.setState({ loading: false, validationMessage });
@@ -179,10 +178,9 @@ export default class Definition extends React.PureComponent<Props, State> {
settingValue,
});
- this.timeout = window.setTimeout(
- () => this.setState({ success: false }),
- SAFE_SET_STATE_DELAY
- );
+ this.timeout = window.setTimeout(() => {
+ this.setState({ success: false });
+ }, SAFE_SET_STATE_DELAY);
} catch (e) {
const validationMessage = await parseError(e as Response);
this.setState({ loading: false, validationMessage });
diff --git a/server/sonar-web/src/main/js/apps/settings/components/NewCodePeriod.tsx b/server/sonar-web/src/main/js/apps/settings/components/NewCodePeriod.tsx
index d6c260352c6..d59c3bf8775 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/NewCodePeriod.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/NewCodePeriod.tsx
@@ -40,8 +40,6 @@ interface State {
success: boolean;
}
-const DEFAULT_SETTING = 'PREVIOUS_VERSION';
-
export default class NewCodePeriod extends React.PureComponent<{}, State> {
mounted = false;
state: State = {
@@ -63,14 +61,12 @@ export default class NewCodePeriod extends React.PureComponent<{}, State> {
fetchNewCodePeriodSetting() {
getNewCodePeriod()
.then(({ type, value }) => {
- const currentSetting = type || DEFAULT_SETTING;
-
this.setState(({ days }) => ({
- currentSetting,
- days: currentSetting === 'NUMBER_OF_DAYS' ? String(value) : days,
+ currentSetting: type,
+ days: type === NewCodePeriodSettingType.NUMBER_OF_DAYS ? String(value) : days,
loading: false,
currentSettingValue: value,
- selected: currentSetting,
+ selected: type,
}));
})
.catch(() => {
@@ -89,7 +85,10 @@ export default class NewCodePeriod extends React.PureComponent<{}, State> {
onCancel = () => {
this.setState(({ currentSetting, currentSettingValue, days }) => ({
selected: currentSetting,
- days: currentSetting === 'NUMBER_OF_DAYS' ? String(currentSettingValue) : days,
+ days:
+ currentSetting === NewCodePeriodSettingType.NUMBER_OF_DAYS
+ ? String(currentSettingValue)
+ : days,
}));
};
@@ -99,29 +98,27 @@ export default class NewCodePeriod extends React.PureComponent<{}, State> {
const { days, selected } = this.state;
const type = selected;
- const value = type === 'NUMBER_OF_DAYS' ? days : undefined;
-
- if (type) {
- this.setState({ saving: true, success: false });
- setNewCodePeriod({
- type,
- value,
- }).then(
- () => {
- this.setState({
- saving: false,
- currentSetting: type,
- currentSettingValue: value || undefined,
- success: true,
- });
- },
- () => {
- this.setState({
- saving: false,
- });
- }
- );
- }
+ const value = type === NewCodePeriodSettingType.NUMBER_OF_DAYS ? days : undefined;
+
+ this.setState({ saving: true, success: false });
+ setNewCodePeriod({
+ type: type as NewCodePeriodSettingType,
+ value,
+ }).then(
+ () => {
+ this.setState({
+ saving: false,
+ currentSetting: type,
+ currentSettingValue: value || undefined,
+ success: true,
+ });
+ },
+ () => {
+ this.setState({
+ saving: false,
+ });
+ }
+ );
};
render() {
@@ -130,9 +127,10 @@ export default class NewCodePeriod extends React.PureComponent<{}, State> {
const isChanged =
selected !== currentSetting ||
- (selected === 'NUMBER_OF_DAYS' && String(days) !== currentSettingValue);
+ (selected === NewCodePeriodSettingType.NUMBER_OF_DAYS &&
+ String(days) !== currentSettingValue);
- const isValid = selected !== 'NUMBER_OF_DAYS' || validateDays(days);
+ const isValid = selected !== NewCodePeriodSettingType.NUMBER_OF_DAYS || validateDays(days);
return (
<ul className="settings-sub-categories-list">
@@ -174,7 +172,7 @@ export default class NewCodePeriod extends React.PureComponent<{}, State> {
<BaselineSettingPreviousVersion
isDefault={true}
onSelect={this.onSelectSetting}
- selected={selected === 'PREVIOUS_VERSION'}
+ selected={selected === NewCodePeriodSettingType.PREVIOUS_VERSION}
/>
<BaselineSettingDays
className="spacer-top"
@@ -183,7 +181,7 @@ export default class NewCodePeriod extends React.PureComponent<{}, State> {
isValid={isValid}
onChangeDays={this.onSelectDays}
onSelect={this.onSelectSetting}
- selected={selected === 'NUMBER_OF_DAYS'}
+ selected={selected === NewCodePeriodSettingType.NUMBER_OF_DAYS}
/>
{isChanged && (
<div className="big-spacer-top">
diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/AnalysisScope-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/__tests__/AnalysisScope-test.tsx
new file mode 100644
index 00000000000..a6df6000d50
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/settings/components/__tests__/AnalysisScope-test.tsx
@@ -0,0 +1,49 @@
+/*
+ * 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 { uniq } from 'lodash';
+import * as React from 'react';
+import { byRole, byText } from 'testing-library-selector';
+import { DEFAULT_DEFINITIONS_MOCK } from '../../../../api/mocks/SettingsServiceMock';
+import { mockComponent } from '../../../../helpers/mocks/component';
+import { renderComponent } from '../../../../helpers/testReactTestingUtils';
+import { AdditionalCategoryComponentProps, ADDITIONAL_CATEGORIES } from '../AdditionalCategories';
+
+const ui = {
+ introduction: byText('settings.analysis_scope.wildcards.introduction'),
+ docLink: byRole('link', { name: /learn_more/ }),
+};
+
+it('renders correctly', async () => {
+ renderAnalysisScope();
+
+ expect(await ui.introduction.find()).toBeInTheDocument();
+ expect(ui.docLink.get()).toBeInTheDocument();
+});
+
+function renderAnalysisScope(overrides: Partial<AdditionalCategoryComponentProps> = {}) {
+ const props = {
+ definitions: DEFAULT_DEFINITIONS_MOCK,
+ categories: uniq(DEFAULT_DEFINITIONS_MOCK.map((d) => d.category)),
+ selectedCategory: 'general',
+ component: mockComponent(),
+ ...overrides,
+ };
+ return renderComponent(<>{ADDITIONAL_CATEGORIES[2].renderComponent(props)}</>);
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/Definition-it.tsx b/server/sonar-web/src/main/js/apps/settings/components/__tests__/Definition-it.tsx
index 40869c50470..98d85ea341e 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/Definition-it.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/__tests__/Definition-it.tsx
@@ -17,156 +17,378 @@
* 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 { getValue, resetSettingValue, setSettingValue } from '../../../../api/settings';
-import { mockDefinition, mockSettingValue } from '../../../../helpers/mocks/settings';
-import { waitAndUpdate } from '../../../../helpers/testUtils';
-import { SettingType } from '../../../../types/settings';
+import { screen } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import { last } from 'lodash';
+import React from 'react';
+import selectEvent from 'react-select-event';
+import { byLabelText, byRole, byText } from 'testing-library-selector';
+import SettingsServiceMock, {
+ DEFAULT_DEFINITIONS_MOCK,
+} from '../../../../api/mocks/SettingsServiceMock';
+import { mockComponent } from '../../../../helpers/mocks/component';
+import { mockDefinition } from '../../../../helpers/mocks/settings';
+import { renderComponent } from '../../../../helpers/testReactTestingUtils';
+import { ExtendedSettingDefinition, SettingType, SettingValue } from '../../../../types/settings';
+import { Component } from '../../../../types/types';
import Definition from '../Definition';
-jest.mock('../../../../api/settings', () => ({
- getValue: jest.fn().mockResolvedValue({}),
- resetSettingValue: jest.fn().mockResolvedValue(undefined),
- setSettingValue: jest.fn().mockResolvedValue(undefined),
-}));
+jest.mock('../../../../api/settings');
+
+let settingsMock: SettingsServiceMock;
beforeAll(() => {
- jest.useFakeTimers();
+ settingsMock = new SettingsServiceMock();
});
-afterAll(() => {
- jest.runOnlyPendingTimers();
- jest.useRealTimers();
+afterEach(() => {
+ settingsMock.reset();
});
-beforeEach(() => {
- jest.clearAllMocks();
+beforeEach(jest.clearAllMocks);
+
+const ui = {
+ nameHeading: (name: string) => byRole('heading', { name }),
+ announcementInput: byLabelText('property.sonar.announcement.message.name'),
+ securedInput: byRole('textbox', { name: 'property.sonar.announcement.message.secured.name' }),
+ multiValuesInput: byRole('textbox', { name: 'property.sonar.javascript.globals.name' }),
+ urlKindInput: byRole('textbox', { name: /sonar.auth.gitlab.url/ }),
+ fieldsInput: (name: string) => byRole('textbox', { name: `property.${name}.name` }),
+ savedMsg: byText('settings.state.saved'),
+ validationMsg: byText(/settings.state.validation_failed/),
+ jsonFormatStatus: byRole('status', { name: 'alert.tooltip.info' }),
+ jsonFormatButton: byRole('button', { name: 'settings.json.format' }),
+ toggleButton: byRole('switch'),
+ selectOption: (value: string) => byText(value),
+ saveButton: byRole('button', { name: 'save' }),
+ cancelButton: byRole('button', { name: 'cancel' }),
+ changeButton: byRole('button', { name: 'change_verb' }),
+ resetButton: (name: string | RegExp = 'reset_verb') => byRole('button', { name }),
+ deleteValueButton: byRole('button', {
+ name: /settings.definition.delete_value/,
+ }),
+ deleteFieldsButton: byRole('button', {
+ name: /settings.definitions.delete_fields/,
+ }),
+};
+
+it.each([
+ SettingType.TEXT,
+ SettingType.STRING,
+ SettingType.PASSWORD,
+ SettingType.INTEGER,
+ SettingType.LONG,
+ SettingType.FLOAT,
+ 'uknown type',
+])(
+ 'renders definition for SettingType = %s and can do operations',
+ async (settingType: SettingType) => {
+ const user = userEvent.setup();
+ renderDefinition({ type: settingType });
+
+ expect(
+ await ui.nameHeading('property.sonar.announcement.message.name').find()
+ ).toBeInTheDocument();
+
+ // Should see no empty validation message
+ await user.type(ui.announcementInput.get(), ' ');
+ await user.click(ui.saveButton.get());
+ expect(await ui.validationMsg.find()).toBeInTheDocument();
+
+ // Should save variable
+ await user.type(ui.announcementInput.get(), 'Testing');
+ await user.click(await ui.saveButton.find());
+ expect(ui.validationMsg.query()).not.toBeInTheDocument();
+ expect(ui.announcementInput.get()).toHaveValue(' Testing');
+ expect(ui.savedMsg.get()).toBeInTheDocument();
+
+ // Validation message when clearing input to empty
+ await user.clear(ui.announcementInput.get());
+ expect(ui.validationMsg.get()).toBeInTheDocument();
+
+ // Should reset to previous state on clicking cancel
+ await user.type(ui.announcementInput.get(), 'Testing2');
+ await user.click(ui.cancelButton.get());
+ expect(ui.announcementInput.get()).toHaveValue(' Testing');
+
+ // Clicking reset opens dialog and reset to default on confirm
+ await user.click(
+ ui.resetButton('settings.definition.reset.property.sonar.announcement.message.name').get()
+ );
+ await user.click(ui.resetButton().get());
+ expect(ui.announcementInput.get()).toHaveValue('');
+ }
+);
+
+it('renders definition for SettingType = JSON and can do operations', async () => {
+ const user = userEvent.setup();
+ renderDefinition({ type: SettingType.JSON });
+
+ expect(
+ await ui.nameHeading('property.sonar.announcement.message.name').find()
+ ).toBeInTheDocument();
+
+ // Should show error message if JSON format is not valid
+ await user.type(ui.announcementInput.get(), 'invalid format');
+ expect(ui.validationMsg.get()).toBeInTheDocument();
+ await user.click(ui.jsonFormatButton.get());
+ expect(ui.jsonFormatStatus.get()).toBeInTheDocument();
+
+ // Can save valid json and format it
+ await user.clear(ui.announcementInput.get());
+ await user.type(ui.announcementInput.get(), '1');
+ await user.click(ui.jsonFormatButton.get());
+ expect(ui.jsonFormatStatus.query()).not.toBeInTheDocument();
+
+ await user.click(ui.saveButton.get());
+ expect(ui.savedMsg.get()).toBeInTheDocument();
});
-describe('Handle change (and check)', () => {
- it.each([
- ['empty, no default', mockDefinition(), '', 'settings.state.value_cant_be_empty_no_default'],
- [
- 'empty, default',
- mockDefinition({ defaultValue: 'dflt' }),
- '',
- 'settings.state.value_cant_be_empty',
- ],
- [
- 'invalid url',
- mockDefinition({ key: 'sonar.core.serverBaseURL' }),
- '%invalid',
- 'settings.state.url_not_valid.%invalid',
- ],
- [
- 'valid url',
- mockDefinition({ key: 'sonar.core.serverBaseURL' }),
- 'http://www.sonarqube.org',
- undefined,
- ],
- [
- 'invalid JSON',
- mockDefinition({ type: SettingType.JSON }),
- '{{broken: "json}',
- 'Unexpected token { in JSON at position 1',
- ],
- ['valid JSON', mockDefinition({ type: SettingType.JSON }), '{"validJson": true}', undefined],
- ])(
- 'should handle change (and check value): %s',
- (_caseName, definition, changedValue, expectedValidationMessage) => {
- const wrapper = shallowRender({ definition });
-
- wrapper.instance().handleChange(changedValue);
-
- expect(wrapper.state().changedValue).toBe(changedValue);
- expect(wrapper.state().success).toBe(false);
- expect(wrapper.state().validationMessage).toBe(expectedValidationMessage);
- }
+it('renders definition for SettingType = BOOLEAN and can do operations', async () => {
+ const user = userEvent.setup();
+ renderDefinition({
+ type: SettingType.BOOLEAN,
+ });
+
+ expect(
+ await ui.nameHeading('property.sonar.announcement.message.name').find()
+ ).toBeInTheDocument();
+
+ // Can toggle
+ await user.click(ui.toggleButton.get());
+ expect(ui.toggleButton.get()).toBeChecked();
+
+ // Can cancel toggle
+ await user.click(ui.cancelButton.get());
+ expect(ui.toggleButton.get()).not.toBeChecked();
+
+ // Can save toggle
+ await user.click(ui.toggleButton.get());
+ await user.click(ui.saveButton.get());
+ expect(ui.toggleButton.get()).toBeChecked();
+ expect(ui.savedMsg.get()).toBeInTheDocument();
+
+ // Can reset toggle
+ await user.click(
+ ui.resetButton('settings.definition.reset.property.sonar.announcement.message.name').get()
);
+ await user.click(ui.resetButton().get());
+ expect(ui.toggleButton.get()).not.toBeChecked();
});
-it('should handle cancel', () => {
- const wrapper = shallowRender();
- wrapper.setState({ changedValue: 'whatever', validationMessage: 'something wrong' });
+it('renders definition for SettingType = SINGLE_SELECT_LIST and can do operations', async () => {
+ const user = userEvent.setup();
+ renderDefinition({
+ type: SettingType.SINGLE_SELECT_LIST,
+ options: ['first', 'second'],
+ });
- wrapper.instance().handleCancel();
+ expect(
+ await ui.nameHeading('property.sonar.announcement.message.name').find()
+ ).toBeInTheDocument();
- expect(wrapper.state().changedValue).toBeUndefined();
- expect(wrapper.state().validationMessage).toBeUndefined();
-});
+ // Can select option
+ expect(ui.selectOption('Select...').get()).toBeInTheDocument();
+ await selectEvent.select(ui.announcementInput.get(), 'first');
+ expect(ui.selectOption('first').get()).toBeInTheDocument();
-describe('handleSave', () => {
- it('should ignore when value unchanged', () => {
- const wrapper = shallowRender();
+ // Can cancel action
+ await user.click(ui.cancelButton.get());
+ expect(ui.selectOption('Select...').get()).toBeInTheDocument();
- wrapper.instance().handleSave();
+ // Can save
+ await selectEvent.select(ui.announcementInput.get(), 'second');
+ await user.click(ui.saveButton.get());
+ expect(ui.savedMsg.get()).toBeInTheDocument();
+
+ // Can reset
+ await user.click(
+ ui.resetButton('settings.definition.reset.property.sonar.announcement.message.name').get()
+ );
+ await user.click(ui.resetButton().get());
+ expect(ui.selectOption('Select...').get()).toBeInTheDocument();
+});
- expect(wrapper.state().loading).toBe(false);
- expect(setSettingValue).not.toHaveBeenCalled();
+it('renders definition for SettingType = FORMATTED_TEXT and can do operations', async () => {
+ const user = userEvent.setup();
+ renderDefinition({
+ type: SettingType.FORMATTED_TEXT,
});
- it('should handle an empty value', () => {
- const wrapper = shallowRender();
+ expect(
+ await ui.nameHeading('property.sonar.announcement.message.name').find()
+ ).toBeInTheDocument();
- wrapper.setState({ changedValue: '' });
+ // Should see no empty validation message
+ await user.type(ui.announcementInput.get(), ' ');
+ await user.click(ui.saveButton.get());
+ expect(await ui.validationMsg.find()).toBeInTheDocument();
- wrapper.instance().handleSave();
+ // Can cancel message
+ await user.clear(ui.announcementInput.get());
+ await user.type(ui.announcementInput.get(), 'msg');
+ await user.click(ui.cancelButton.get());
+ expect(ui.announcementInput.get()).toHaveValue('');
- expect(wrapper.state().loading).toBe(false);
- expect(wrapper.state().validationMessage).toBe('settings.state.value_cant_be_empty');
- expect(setSettingValue).not.toHaveBeenCalled();
- });
+ // Can save formatted message
+ await user.type(ui.announcementInput.get(), 'https://ok.com');
+ await user.click(ui.saveButton.get());
+ expect(ui.savedMsg.get()).toBeInTheDocument();
+ expect(ui.announcementInput.query()).not.toBeInTheDocument();
+});
- it('should save and update setting value', async () => {
- const settingValue = mockSettingValue();
- (getValue as jest.Mock).mockResolvedValueOnce(settingValue);
- const definition = mockDefinition();
- const wrapper = shallowRender({ definition });
+it('renders definition for multiValues type and can do operations', async () => {
+ const user = userEvent.setup();
+ renderDefinition(
+ DEFAULT_DEFINITIONS_MOCK[2],
+ {
+ key: DEFAULT_DEFINITIONS_MOCK[2].key,
+ values: DEFAULT_DEFINITIONS_MOCK[2].defaultValue?.split(','),
+ },
+ mockComponent()
+ );
- wrapper.setState({ changedValue: 'new value' });
+ expect(await ui.nameHeading('property.sonar.javascript.globals.name').find()).toBeInTheDocument();
+ expect(ui.multiValuesInput.getAll()).toHaveLength(4);
- wrapper.instance().handleSave();
+ // Should show validation message if no values
+ await user.click(ui.deleteValueButton.getAll()[0]);
+ await user.click(ui.deleteValueButton.getAll()[0]);
+ await user.click(ui.deleteValueButton.getAll()[0]);
- expect(wrapper.state().loading).toBe(true);
+ expect(await ui.multiValuesInput.findAll()).toHaveLength(1);
+ expect(ui.validationMsg.get()).toBeInTheDocument();
- await waitAndUpdate(wrapper);
+ // Can cancel and return to previous
+ await user.click(ui.cancelButton.get());
+ expect(ui.multiValuesInput.getAll()).toHaveLength(4);
- expect(setSettingValue).toHaveBeenCalledWith(definition, 'new value', undefined);
- expect(getValue).toHaveBeenCalledWith({ key: definition.key, component: undefined });
- expect(wrapper.state().changedValue).toBeUndefined();
- expect(wrapper.state().loading).toBe(false);
- expect(wrapper.state().success).toBe(true);
- expect(wrapper.state().settingValue).toBe(settingValue);
+ // Can update values and save
+ await user.type(last(ui.multiValuesInput.getAll()) as HTMLElement, 'new value');
+ await user.click(ui.saveButton.get());
+ expect(ui.savedMsg.get()).toBeInTheDocument();
+ expect(ui.multiValuesInput.getAll()).toHaveLength(5);
- jest.runAllTimers();
- expect(wrapper.state().success).toBe(false);
- });
+ // Can reset to default
+ await user.click(
+ ui.resetButton('settings.definition.reset.property.sonar.javascript.globals.name').get()
+ );
+ await user.click(ui.resetButton().get());
+ expect(ui.multiValuesInput.getAll()).toHaveLength(4);
});
-it('should reset and update setting value', async () => {
- const settingValue = mockSettingValue();
- (getValue as jest.Mock).mockResolvedValueOnce(settingValue);
- const definition = mockDefinition();
- const wrapper = shallowRender({ definition });
+it('renders definition for SettingType = PROPERTY_SET and can do operations', async () => {
+ const user = userEvent.setup();
+ renderDefinition(DEFAULT_DEFINITIONS_MOCK[5]);
+
+ expect(
+ await ui.nameHeading('property.sonar.cobol.compilationConstants.name').find()
+ ).toBeInTheDocument();
+ expect(screen.getByRole('columnheader', { name: 'Name' })).toBeInTheDocument();
+ expect(screen.getByRole('columnheader', { name: 'Value' })).toBeInTheDocument();
+
+ // Should type new values
+ await user.type(ui.fieldsInput('name').get(), 'any name');
+ expect(ui.fieldsInput('name').getAll()).toHaveLength(2);
- wrapper.instance().handleReset();
+ // Can cancel changes
+ await user.click(ui.cancelButton.get());
+ expect(ui.fieldsInput('name').getAll()).toHaveLength(1);
+ expect(ui.fieldsInput('name').get()).toHaveValue('');
- expect(wrapper.state().loading).toBe(true);
+ // Can save new values
+ await user.type(ui.fieldsInput('name').get(), 'any name');
+ await user.type(ui.fieldsInput('value').getAll()[0], 'any value');
+ await user.click(ui.saveButton.get());
- await waitAndUpdate(wrapper);
+ expect(ui.savedMsg.get()).toBeInTheDocument();
+ expect(ui.fieldsInput('name').getAll()[0]).toHaveValue('any name');
+ expect(ui.fieldsInput('value').getAll()[0]).toHaveValue('any value');
- expect(resetSettingValue).toHaveBeenCalledWith({ keys: definition.key, component: undefined });
- expect(getValue).toHaveBeenCalledWith({ key: definition.key, component: undefined });
- expect(wrapper.state().changedValue).toBeUndefined();
- expect(wrapper.state().loading).toBe(false);
- expect(wrapper.state().success).toBe(true);
- expect(wrapper.state().settingValue).toBe(settingValue);
+ // Deleting previous value show validation message
+ await user.click(ui.deleteFieldsButton.get());
+ expect(ui.validationMsg.get()).toBeInTheDocument();
- jest.runAllTimers();
- expect(wrapper.state().success).toBe(false);
+ // Can reset to default
+ await user.click(ui.resetButton(/settings.definition.reset/).get());
+ await user.click(ui.resetButton().get());
+
+ expect(ui.savedMsg.get()).toBeInTheDocument();
+ expect(ui.fieldsInput('name').get()).toHaveValue('');
+ expect(ui.fieldsInput('value').get()).toHaveValue('');
});
-function shallowRender(props: Partial<Definition['props']> = {}) {
- return shallow<Definition>(<Definition definition={mockDefinition()} {...props} />);
+it('renders secured definition and can do operations', async () => {
+ const user = userEvent.setup();
+ const key = `${DEFAULT_DEFINITIONS_MOCK[0].key}.secured`;
+ settingsMock.setDefinition(
+ mockDefinition({
+ ...DEFAULT_DEFINITIONS_MOCK[0],
+ key,
+ })
+ );
+ renderDefinition({
+ key,
+ });
+
+ expect(
+ await ui.nameHeading('property.sonar.announcement.message.secured.name').find()
+ ).toBeInTheDocument();
+
+ // Can type new value and cancel change
+ await user.type(ui.securedInput.get(), 'Anything');
+ expect(ui.securedInput.get()).toHaveValue('Anything');
+
+ // Can see validation message
+ await user.clear(ui.securedInput.get());
+ expect(ui.validationMsg.get()).toBeInTheDocument();
+
+ // Can cancel change
+ await user.click(ui.cancelButton.get());
+ expect(ui.securedInput.get()).toHaveValue('');
+
+ // Can save new value
+ await user.type(ui.securedInput.get(), 'Anything');
+ await user.click(ui.saveButton.get());
+ expect(ui.savedMsg.get()).toBeInTheDocument();
+ expect(ui.securedInput.query()).not.toBeInTheDocument();
+
+ // Can change value by unlocking input
+ await user.click(ui.changeButton.get());
+ expect(ui.securedInput.get()).toBeInTheDocument();
+
+ // Cam reset to default
+ await user.click(ui.resetButton(/settings.definition.reset/).get());
+ await user.click(ui.resetButton().get());
+
+ expect(ui.savedMsg.get()).toBeInTheDocument();
+});
+
+it('renders correctly for URL kind definition', async () => {
+ const user = userEvent.setup();
+ renderDefinition({ key: 'sonar.auth.gitlab.url' });
+
+ // Show validation message
+ await user.type(ui.urlKindInput.get(), 'wrongurl');
+ expect(ui.validationMsg.get()).toBeInTheDocument();
+ expect(ui.saveButton.get()).toBeDisabled();
+
+ // Hides validation msg with correct url
+ await user.type(ui.urlKindInput.get(), 'http://hi.there');
+ expect(ui.validationMsg.query()).not.toBeInTheDocument();
+ expect(ui.saveButton.get()).toBeEnabled();
+});
+
+function renderDefinition(
+ definition: Partial<ExtendedSettingDefinition> = {},
+ initialSetting?: SettingValue,
+ component?: Component
+) {
+ return renderComponent(
+ <Definition
+ definition={{ ...DEFAULT_DEFINITIONS_MOCK[0], ...definition }}
+ initialSettingValue={initialSetting}
+ component={component}
+ />
+ );
}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/NewCodePeriod-it.tsx b/server/sonar-web/src/main/js/apps/settings/components/__tests__/NewCodePeriod-it.tsx
index c95f2e18bb8..8d355a23ccf 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/NewCodePeriod-it.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/__tests__/NewCodePeriod-it.tsx
@@ -17,110 +17,76 @@
* 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 userEvent from '@testing-library/user-event';
import * as React from 'react';
-import { getNewCodePeriod, setNewCodePeriod } from '../../../../api/newCodePeriod';
-import { waitAndUpdate } from '../../../../helpers/testUtils';
+import { byRole, byText } from 'testing-library-selector';
+import NewCodePeriodsServiceMock from '../../../../api/mocks/NewCodePeriodsServiceMock';
+import { renderComponent } from '../../../../helpers/testReactTestingUtils';
import NewCodePeriod from '../NewCodePeriod';
-jest.mock('../../../../api/newCodePeriod', () => ({
- getNewCodePeriod: jest.fn().mockResolvedValue({}),
- setNewCodePeriod: jest.fn(() => Promise.resolve()),
-}));
+let newCodeMock: NewCodePeriodsServiceMock;
-beforeEach(() => {
- jest.clearAllMocks();
+beforeAll(() => {
+ newCodeMock = new NewCodePeriodsServiceMock();
});
-it('should render correctly', () => {
- expect(shallowRender()).toMatchSnapshot();
+afterEach(() => {
+ newCodeMock.reset();
});
-it('should load the current new code period on mount', async () => {
- const wrapper = shallowRender();
- await waitAndUpdate(wrapper);
- expect(getNewCodePeriod).toHaveBeenCalledTimes(1);
- expect(wrapper.state('currentSetting')).toBe('PREVIOUS_VERSION');
+const ui = {
+ newCodeTitle: byRole('heading', { name: 'settings.new_code_period.title' }),
+ savedMsg: byText('settings.state.saved'),
+ prevVersionRadio: byRole('radio', { name: /baseline.previous_version/ }),
+ daysNumberRadio: byRole('radio', { name: /baseline.number_days/ }),
+ daysInput: byRole('textbox'),
+ saveButton: byRole('button', { name: 'save' }),
+ cancelButton: byRole('button', { name: 'cancel' }),
+};
+
+it('renders and behaves as expected', async () => {
+ const user = userEvent.setup();
+ renderNewCodePeriod();
+
+ expect(await ui.newCodeTitle.find()).toBeInTheDocument();
+ // Previous version should be checked by default
+ expect(ui.prevVersionRadio.get()).toBeChecked();
+
+ // Can select number of days
+ await user.click(ui.daysNumberRadio.get());
+ expect(ui.daysNumberRadio.get()).toBeChecked();
+
+ // Save should be disabled for zero or NaN
+ expect(ui.daysInput.get()).toHaveValue('30');
+ await user.clear(ui.daysInput.get());
+ await user.type(ui.daysInput.get(), '0');
+ expect(await ui.saveButton.find()).toBeDisabled();
+ await user.clear(ui.daysInput.get());
+ await user.type(ui.daysInput.get(), 'asdas');
+ expect(ui.saveButton.get()).toBeDisabled();
+ await user.clear(ui.daysInput.get());
+
+ // Save enabled for valid days number
+ await user.type(ui.daysInput.get(), '10');
+ expect(ui.saveButton.get()).toBeEnabled();
+
+ // Can cancel action
+ await user.click(ui.cancelButton.get());
+ expect(ui.prevVersionRadio.get()).toBeChecked();
+
+ // Can save change
+ await user.click(ui.daysNumberRadio.get());
+ await user.type(ui.daysInput.get(), '10');
+ await user.click(ui.saveButton.get());
+ expect(ui.savedMsg.get()).toBeInTheDocument();
+
+ await user.click(ui.prevVersionRadio.get());
+ await user.click(ui.cancelButton.get());
+ await user.click(ui.prevVersionRadio.get());
+ await user.click(ui.saveButton.get());
+ expect(ui.savedMsg.get()).toBeInTheDocument();
});
-it('should load the current new code period with value on mount', async () => {
- (getNewCodePeriod as jest.Mock).mockResolvedValue({ type: 'NUMBER_OF_DAYS', value: '42' });
-
- const wrapper = shallowRender();
- await waitAndUpdate(wrapper);
- expect(getNewCodePeriod).toHaveBeenCalledTimes(1);
- expect(wrapper.state('currentSetting')).toBe('NUMBER_OF_DAYS');
- expect(wrapper.state('days')).toBe('42');
-});
-
-it('should only show the save button after changing the setting', async () => {
- (getNewCodePeriod as jest.Mock).mockResolvedValue({ type: 'PREVIOUS_VERSION' });
-
- const wrapper = shallowRender();
- await waitAndUpdate(wrapper);
-
- expect(wrapper.state('selected')).toBe('PREVIOUS_VERSION');
- expect(wrapper.find('SubmitButton')).toHaveLength(0);
-
- wrapper.instance().onSelectSetting('NUMBER_OF_DAYS');
- await waitAndUpdate(wrapper);
-
- expect(wrapper.find('SubmitButton')).toHaveLength(1);
-});
-
-it('should disable the button if the days are invalid', async () => {
- (getNewCodePeriod as jest.Mock).mockResolvedValue({ type: 'NUMBER_OF_DAYS', value: '42' });
-
- const wrapper = shallowRender();
- await waitAndUpdate(wrapper);
-
- wrapper.instance().onSelectDays('asd');
- await waitAndUpdate(wrapper);
-
- expect(wrapper.find('SubmitButton').first().prop('disabled')).toBe(true);
-
- wrapper.instance().onSelectDays('23');
- await waitAndUpdate(wrapper);
-
- expect(wrapper.find('SubmitButton').first().prop('disabled')).toBe(false);
-});
-
-it('should submit correctly', async () => {
- (getNewCodePeriod as jest.Mock).mockResolvedValue({ type: 'NUMBER_OF_DAYS', value: '42' });
-
- const preventDefault = jest.fn();
-
- const wrapper = shallowRender();
- await waitAndUpdate(wrapper);
- wrapper.instance().onSelectSetting('PREVIOUS_VERSION');
- await waitAndUpdate(wrapper);
-
- wrapper.find('form').simulate('submit', { preventDefault });
-
- expect(preventDefault).toHaveBeenCalledTimes(1);
- expect(setNewCodePeriod).toHaveBeenCalledWith({ type: 'PREVIOUS_VERSION', value: undefined });
- await waitAndUpdate(wrapper);
- expect(wrapper.state('currentSetting')).toEqual(wrapper.state('selected'));
-});
-
-it('should submit correctly with days', async () => {
- (getNewCodePeriod as jest.Mock).mockResolvedValue({ type: 'NUMBER_OF_DAYS', value: '42' });
-
- const preventDefault = jest.fn();
-
- const wrapper = shallowRender();
- await waitAndUpdate(wrapper);
- wrapper.instance().onSelectDays('66');
- await waitAndUpdate(wrapper);
-
- wrapper.find('form').simulate('submit', { preventDefault });
-
- expect(preventDefault).toHaveBeenCalledTimes(1);
- expect(setNewCodePeriod).toHaveBeenCalledWith({ type: 'NUMBER_OF_DAYS', value: '66' });
- await waitAndUpdate(wrapper);
- expect(wrapper.state('currentSetting')).toEqual(wrapper.state('selected'));
-});
-
-function shallowRender() {
- return shallow<NewCodePeriod>(<NewCodePeriod />);
+function renderNewCodePeriod() {
+ return renderComponent(<NewCodePeriod />);
}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/NewCodePeriod-it.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/NewCodePeriod-it.tsx.snap
deleted file mode 100644
index 24a811bedac..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/NewCodePeriod-it.tsx.snap
+++ /dev/null
@@ -1,57 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<ul
- className="settings-sub-categories-list"
->
- <li>
- <ul
- className="settings-definitions-list"
- >
- <li>
- <div
- className="settings-definition"
- >
- <div
- className="settings-definition-left"
- >
- <h3
- className="settings-definition-name"
- title="settings.new_code_period.title"
- >
- settings.new_code_period.title
- </h3>
- <div
- className="small big-spacer-top"
- >
- <FormattedMessage
- defaultMessage="settings.new_code_period.description"
- id="settings.new_code_period.description"
- values={
- {
- "link": <withAppStateContext(DocLink)
- to="/project-administration/defining-new-code/"
- >
- learn_more
- </withAppStateContext(DocLink)>,
- }
- }
- />
- <p
- className="spacer-top"
- >
- settings.new_code_period.description2
- </p>
- </div>
- </div>
- <div
- className="settings-definition-right"
- >
- <DeferredSpinner />
- </div>
- </div>
- </li>
- </ul>
- </li>
-</ul>
-`;
diff --git a/server/sonar-web/src/main/js/apps/settings/components/authentication/__tests__/Authentication-it.tsx b/server/sonar-web/src/main/js/apps/settings/components/authentication/__tests__/Authentication-it.tsx
index 1070420b649..463e2b9666d 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/authentication/__tests__/Authentication-it.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/authentication/__tests__/Authentication-it.tsx
@@ -75,7 +75,7 @@ afterEach(() => handler.resetValues());
const ui = {
saveButton: byRole('button', { name: 'settings.authentication.saml.form.save' }),
customMessageInformation: byText('settings.authentication.custom_message_information'),
- enabledToggle: byRole('button', { name: 'off' }),
+ enabledToggle: byRole('switch'),
testButton: byText('settings.authentication.saml.form.test'),
textbox1: byRole('textbox', { name: 'test1' }),
textbox2: byRole('textbox', { name: 'test2' }),
@@ -172,7 +172,7 @@ describe('SAML tab', () => {
await user.keyboard('new certificate');
// enable the configuration
await user.click(ui.enabledToggle.get());
- expect(screen.getByRole('button', { name: 'on' })).toBeInTheDocument();
+ expect(ui.enabledToggle.get()).toBeChecked();
await user.click(ui.saveButton.get());
expect(screen.getByText('settings.authentication.saml.form.save_success')).toBeInTheDocument();
@@ -180,7 +180,7 @@ describe('SAML tab', () => {
await user.click(screen.getByRole('tab', { name: 'github GitHub' }));
await user.click(screen.getByRole('tab', { name: 'SAML' }));
- expect(screen.getByRole('button', { name: 'on' })).toBeInTheDocument();
+ expect(ui.enabledToggle.get()).toBeChecked();
});
it('should handle and show errors to the user', async () => {
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForBoolean.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForBoolean.tsx
index d752a6d397b..1c1643fcc00 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForBoolean.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForBoolean.tsx
@@ -18,19 +18,25 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import Toggle from '../../../../components/controls/Toggle';
+import Toggle, { getToggleValue } from '../../../../components/controls/Toggle';
import { translate } from '../../../../helpers/l10n';
-import { DefaultSpecializedInputProps } from '../../utils';
+import { DefaultSpecializedInputProps, getPropertyName } from '../../utils';
interface Props extends DefaultSpecializedInputProps {
value: string | boolean | undefined;
}
-export default function InputForBoolean({ onChange, name, value }: Props) {
- const displayedValue = value != null ? value : false;
+export default function InputForBoolean({ onChange, name, value, setting }: Props) {
+ const toggleValue = getToggleValue(value != null ? value : false);
+
return (
<div className="display-inline-block text-top">
- <Toggle name={name} onChange={onChange} value={displayedValue} />
+ <Toggle
+ name={name}
+ onChange={onChange}
+ value={toggleValue}
+ ariaLabel={getPropertyName(setting.definition)}
+ />
{value == null && <span className="spacer-left note">{translate('settings.not_set')}</span>}
</div>
);
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForFormattedText.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForFormattedText.tsx
index d2c57097c43..a1ef8a82097 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForFormattedText.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForFormattedText.tsx
@@ -23,7 +23,7 @@ import { Button } from '../../../../components/controls/buttons';
import EditIcon from '../../../../components/icons/EditIcon';
import { translate } from '../../../../helpers/l10n';
import { sanitizeUserInput } from '../../../../helpers/sanitize';
-import { DefaultSpecializedInputProps } from '../../utils';
+import { DefaultSpecializedInputProps, getPropertyName } from '../../utils';
export default function InputForFormattedText(props: DefaultSpecializedInputProps) {
const { isEditing, setting, name, value } = props;
@@ -41,6 +41,7 @@ export default function InputForFormattedText(props: DefaultSpecializedInputProp
{editMode ? (
<div className="display-flex-row">
<textarea
+ aria-label={getPropertyName(setting.definition)}
className="settings-large-input text-top spacer-right"
name={name}
onChange={handleInputChange}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForJSON.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForJSON.tsx
index 9cccb2c1d6f..15d45a9a159 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForJSON.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForJSON.tsx
@@ -21,7 +21,7 @@ import * as React from 'react';
import { Button } from '../../../../components/controls/buttons';
import { Alert } from '../../../../components/ui/Alert';
import { translate } from '../../../../helpers/l10n';
-import { DefaultSpecializedInputProps } from '../../utils';
+import { DefaultSpecializedInputProps, getPropertyName } from '../../utils';
const JSON_SPACE_SIZE = 4;
@@ -49,15 +49,18 @@ export default class InputForJSON extends React.PureComponent<DefaultSpecialized
};
render() {
+ const { value, name, setting } = this.props;
const { formatError } = this.state;
+
return (
<div className="display-flex-end">
<textarea
className="settings-large-input text-top monospaced spacer-right"
- name={this.props.name}
+ name={name}
onChange={this.handleInputChange}
rows={5}
- value={this.props.value || ''}
+ value={value || ''}
+ aria-label={getPropertyName(setting.definition)}
/>
<div>
{formatError && <Alert variant="info">{translate('settings.json.format_error')} </Alert>}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForSecured.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForSecured.tsx
index 6923d8f063e..558e0f93ba5 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForSecured.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForSecured.tsx
@@ -25,6 +25,7 @@ import { translate } from '../../../../helpers/l10n';
import {
DefaultInputProps,
DefaultSpecializedInputProps,
+ getPropertyName,
getUniqueName,
isDefaultOrInherited,
} from '../../utils';
@@ -73,6 +74,7 @@ export default class InputForSecured extends React.PureComponent<Props, State> {
<>
<input className="hidden" type="password" />
<Input
+ aria-label={getPropertyName(setting.definition)}
autoComplete="off"
className="js-setting-input settings-large-input"
isDefault={isDefaultOrInherited(setting)}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForSingleSelectList.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForSingleSelectList.tsx
index c3e41c1bf8b..ec677d8d9da 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForSingleSelectList.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForSingleSelectList.tsx
@@ -20,7 +20,7 @@
import * as React from 'react';
import Select from '../../../../components/controls/Select';
import { ExtendedSettingDefinition } from '../../../../types/settings';
-import { DefaultSpecializedInputProps } from '../../utils';
+import { DefaultSpecializedInputProps, getPropertyName } from '../../utils';
type Props = DefaultSpecializedInputProps & Pick<ExtendedSettingDefinition, 'options'>;
@@ -30,7 +30,7 @@ export default class InputForSingleSelectList extends React.PureComponent<Props>
};
render() {
- const { options: opts, name, value } = this.props;
+ const { options: opts, name, value, setting } = this.props;
const options = opts.map((option) => ({
label: option,
@@ -42,6 +42,7 @@ export default class InputForSingleSelectList extends React.PureComponent<Props>
className="settings-large-input"
name={name}
onChange={this.handleInputChange}
+ aria-label={getPropertyName(setting.definition)}
options={options}
value={options.find((option) => option.value === value)}
/>
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForText.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForText.tsx
index 0d4bb30b33d..cc81005adeb 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForText.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForText.tsx
@@ -18,7 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import { DefaultSpecializedInputProps } from '../../utils';
+import { DefaultSpecializedInputProps, getPropertyName } from '../../utils';
export default class InputForText extends React.PureComponent<DefaultSpecializedInputProps> {
handleInputChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
@@ -26,13 +26,15 @@ export default class InputForText extends React.PureComponent<DefaultSpecialized
};
render() {
+ const { setting, name, value } = this.props;
return (
<textarea
className="settings-large-input text-top"
- name={this.props.name}
+ name={name}
onChange={this.handleInputChange}
rows={5}
- value={this.props.value || ''}
+ value={value || ''}
+ aria-label={getPropertyName(setting.definition)}
/>
);
}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/MultiValueInput.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/MultiValueInput.tsx
index 80cb2eb7fd5..2fdffa0ebb9 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/inputs/MultiValueInput.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/inputs/MultiValueInput.tsx
@@ -72,6 +72,7 @@ export default class MultiValueInput extends React.PureComponent<DefaultSpeciali
render() {
const displayedValue = [...this.ensureValue(), ...getEmptyValue(this.props.setting.definition)];
+
return (
<div>
<ul>
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/PropertySetInput.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/PropertySetInput.tsx
index 0ebffee9f5d..39977561d40 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/inputs/PropertySetInput.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/inputs/PropertySetInput.tsx
@@ -19,9 +19,11 @@
*/
import * as React from 'react';
import { DeleteButton } from '../../../../components/controls/buttons';
+import { translateWithParameters } from '../../../../helpers/l10n';
import {
DefaultSpecializedInputProps,
getEmptyValue,
+ getPropertyName,
getUniqueName,
isCategoryDefinition,
} from '../../utils';
@@ -75,6 +77,11 @@ export default class PropertySetInput extends React.PureComponent<DefaultSpecial
<td className="thin nowrap text-middle">
{!isLast && (
<DeleteButton
+ aria-label={translateWithParameters(
+ 'settings.definitions.delete_fields',
+ getPropertyName(setting.definition),
+ index
+ )}
className="js-remove-value"
onClick={() => this.handleDeleteValue(index)}
/>
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/Input-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/Input-test.tsx
deleted file mode 100644
index e575d170eb2..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/Input-test.tsx
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * 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 { mockDefinition, mockSetting } from '../../../../../helpers/mocks/settings';
-import { Setting, SettingType } from '../../../../../types/settings';
-import { DefaultInputProps } from '../../../utils';
-import Input from '../Input';
-import InputForSecured from '../InputForSecured';
-import MultiValueInput from '../MultiValueInput';
-import PrimitiveInput from '../PrimitiveInput';
-import PropertySetInput from '../PropertySetInput';
-
-it('should render PrimitiveInput', () => {
- const onChange = jest.fn();
- const input = shallowRender({ onChange }).find(PrimitiveInput);
- expect(input.length).toBe(1);
- expect(input.prop('value')).toBe('foo');
- expect(input.prop('onChange')).toBe(onChange);
-});
-
-it('should render Secured input', () => {
- const setting: Setting = mockSetting({
- key: 'foo.secured',
- definition: mockDefinition({ key: 'foo.secured', type: SettingType.PROPERTY_SET }),
- });
- const onChange = jest.fn();
- const input = shallowRender({ onChange, setting }).find(InputForSecured);
- expect(input.length).toBe(1);
- expect(input.prop('value')).toBe('foo');
- expect(input.prop('onChange')).toBe(onChange);
-});
-
-it('should render MultiValueInput', () => {
- const setting = mockSetting({
- definition: mockDefinition({ multiValues: true }),
- });
- const onChange = jest.fn();
- const value = ['foo', 'bar'];
- const input = shallowRender({ onChange, setting, value }).find(MultiValueInput);
- expect(input.length).toBe(1);
- expect(input.prop('setting')).toBe(setting);
- expect(input.prop('value')).toBe(value);
- expect(input.prop('onChange')).toBe(onChange);
-});
-
-it('should render PropertySetInput', () => {
- const setting: Setting = mockSetting({
- definition: mockDefinition({ type: SettingType.PROPERTY_SET }),
- });
-
- const onChange = jest.fn();
- const value = [{ foo: 'bar' }];
- const input = shallowRender({ onChange, setting, value }).find(PropertySetInput);
- expect(input.length).toBe(1);
- expect(input.prop('setting')).toBe(setting);
- expect(input.prop('value')).toBe(value);
- expect(input.prop('onChange')).toBe(onChange);
-});
-
-function shallowRender(props: Partial<DefaultInputProps> = {}) {
- return shallow(<Input onChange={jest.fn()} setting={mockSetting()} value="foo" {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForBoolean-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForBoolean-test.tsx
deleted file mode 100644
index f8f3aa5bb86..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForBoolean-test.tsx
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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 { mockSetting } from '../../../../../helpers/mocks/settings';
-import { DefaultSpecializedInputProps } from '../../../utils';
-import InputForBoolean from '../InputForBoolean';
-
-it('should render Toggle', () => {
- const onChange = jest.fn();
- const toggle = shallowRender({ onChange }).find('Toggle');
- expect(toggle.length).toBe(1);
- expect(toggle.prop('name')).toBe('foo');
- expect(toggle.prop('value')).toBe(true);
- expect(toggle.prop('onChange')).toBeDefined();
-});
-
-it('should render Toggle without value', () => {
- const onChange = jest.fn();
- const input = shallowRender({ onChange, value: undefined });
- const toggle = input.find('Toggle');
- expect(toggle.length).toBe(1);
- expect(toggle.prop('name')).toBe('foo');
- expect(toggle.prop('value')).toBe(false);
- expect(toggle.prop('onChange')).toBeDefined();
- expect(input.find('.note').length).toBe(1);
-});
-
-it('should call onChange', () => {
- const onChange = jest.fn();
-
- const input = shallowRender({ onChange, value: true });
- const toggle = input.find('Toggle');
- expect(toggle.length).toBe(1);
- expect(toggle.prop('onChange')).toBeDefined();
-
- toggle.prop<Function>('onChange')(false);
-
- expect(onChange).toHaveBeenCalledWith(false);
-});
-
-function shallowRender(props: Partial<DefaultSpecializedInputProps> = {}) {
- return shallow(
- <InputForBoolean
- isDefault={false}
- name="foo"
- onChange={jest.fn()}
- setting={mockSetting()}
- value={true}
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForFormattedText-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForFormattedText-test.tsx
deleted file mode 100644
index 7412bb5479f..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForFormattedText-test.tsx
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * 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 { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import * as React from 'react';
-import { mockSetting } from '../../../../../helpers/mocks/settings';
-import { renderComponent } from '../../../../../helpers/testReactTestingUtils';
-import { DefaultSpecializedInputProps } from '../../../utils';
-import InputForFormattedText from '../InputForFormattedText';
-
-it('should render correctly with no value for login message', () => {
- renderInputForFormattedText();
- expect(screen.getByRole('textbox')).toBeInTheDocument();
-});
-
-it('should render correctly with a value for login message', () => {
- renderInputForFormattedText({
- setting: mockSetting({ values: ['*text*', 'text'], hasValue: true }),
- });
- expect(screen.getByRole('button', { name: 'edit' })).toBeInTheDocument();
- expect(screen.getByText('text')).toBeInTheDocument();
-});
-
-it('should render correctly with a value for login message if hasValue is set', () => {
- renderInputForFormattedText({
- setting: mockSetting({ hasValue: true }),
- });
- expect(screen.getByRole('button', { name: 'edit' })).toBeInTheDocument();
-});
-
-it('should render editMode when value is empty', () => {
- renderInputForFormattedText({
- value: '',
- });
- expect(screen.getByRole('textbox')).toBeInTheDocument();
- expect(screen.queryByRole('button', { name: 'edit' })).not.toBeInTheDocument();
-});
-
-it('should render correctly if in editMode', async () => {
- const user = userEvent.setup();
- const onChange = jest.fn();
-
- renderInputForFormattedText({
- setting: mockSetting({ values: ['*text*', 'text'], hasValue: true }),
- isEditing: true,
- onChange,
- });
- expect(screen.getByRole('textbox')).toBeInTheDocument();
- expect(screen.queryByRole('button', { name: 'edit' })).not.toBeInTheDocument();
-
- await user.click(screen.getByRole('textbox'));
- await user.keyboard('N');
- expect(onChange).toHaveBeenCalledTimes(1);
-});
-
-function renderInputForFormattedText(props: Partial<DefaultSpecializedInputProps> = {}) {
- renderComponent(
- <InputForFormattedText
- onEditing={jest.fn()}
- isEditing={false}
- isDefault={true}
- name="name"
- onChange={jest.fn()}
- setting={mockSetting({ value: undefined, hasValue: false })}
- value="*text*"
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForJSON-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForJSON-test.tsx
deleted file mode 100644
index d6a1c26e329..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForJSON-test.tsx
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * 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 { mockSetting } from '../../../../../helpers/mocks/settings';
-import { change } from '../../../../../helpers/testUtils';
-import { DefaultSpecializedInputProps } from '../../../utils';
-import InputForJSON from '../InputForJSON';
-
-it('should render correctly', () => {
- expect(shallowRender()).toMatchSnapshot();
-});
-
-it('should call onChange', () => {
- const onChange = jest.fn();
- const wrapper = shallowRender({ onChange });
-
- change(wrapper.find('textarea'), '{"a": 1}');
- expect(onChange).toHaveBeenCalledWith('{"a": 1}');
-});
-
-it('should handle formatting for invalid JSON', () => {
- const onChange = jest.fn();
- const wrapper = shallowRender({ onChange, value: '{"a": 1b}' });
- wrapper.instance().format();
- expect(onChange).not.toHaveBeenCalled();
-
- expect(wrapper.state().formatError).toBe(true);
- expect(wrapper).toMatchSnapshot();
-});
-
-it('should handle formatting for valid JSON', () => {
- const onChange = jest.fn();
- const wrapper = shallowRender({ onChange, value: '{"a": 1}' });
- wrapper.instance().format();
- expect(onChange).toHaveBeenCalledWith(`{
- "a": 1
-}`);
-
- expect(wrapper.state().formatError).toBe(false);
-});
-
-it('should handle ignore formatting if empty', () => {
- const onChange = jest.fn();
- const wrapper = shallowRender({ onChange, value: '' });
- wrapper.instance().format();
- expect(onChange).not.toHaveBeenCalled();
-
- expect(wrapper.state().formatError).toBe(false);
-});
-
-function shallowRender(props: Partial<DefaultSpecializedInputProps> = {}) {
- return shallow<InputForJSON>(
- <InputForJSON
- isDefault={false}
- name="foo"
- onChange={jest.fn()}
- setting={mockSetting()}
- value=""
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForPassword-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForPassword-test.tsx
deleted file mode 100644
index eba4748fe2a..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForPassword-test.tsx
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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 { mockSetting } from '../../../../../helpers/mocks/settings';
-import InputForPassword from '../InputForPassword';
-import SimpleInput from '../SimpleInput';
-
-it('should render SimpleInput', () => {
- const onChange = jest.fn();
- const simpleInput = shallow(
- <InputForPassword
- isDefault={false}
- name="foo"
- onChange={onChange}
- setting={mockSetting()}
- value="bar"
- />
- ).find(SimpleInput);
- expect(simpleInput.length).toBe(1);
- expect(simpleInput.prop('name')).toBe('foo');
- expect(simpleInput.prop('value')).toBe('bar');
- expect(simpleInput.prop('type')).toBe('password');
- expect(simpleInput.prop('onChange')).toBeDefined();
-});
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForSecured-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForSecured-test.tsx
deleted file mode 100644
index a659d8cc9d0..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForSecured-test.tsx
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * 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 { mockSetting } from '../../../../../helpers/mocks/settings';
-import { change, click } from '../../../../../helpers/testUtils';
-import InputForSecured from '../InputForSecured';
-import InputForString from '../InputForString';
-
-it('should render lock icon, but no form', () => {
- const onChange = jest.fn();
- const input = shallowRender({ onChange });
-
- expect(input.find('LockIcon').length).toBe(1);
- expect(input.find('input').length).toBe(0);
-});
-
-it('should open form', () => {
- const onChange = jest.fn();
- const input = shallowRender({ onChange });
- const button = input.find('Button');
- expect(button.length).toBe(1);
-
- click(button);
- expect(input.find('input').length).toBe(1);
-});
-
-it('should set value', () => {
- const onChange = jest.fn(() => Promise.resolve());
- const input = shallowRender({ onChange });
-
- click(input.find('Button'));
- change(input.find(InputForString), 'secret');
- expect(onChange).toHaveBeenCalledWith('secret');
-});
-
-it('should show input when empty, and enable handle typing', () => {
- const input = shallowRender({ setting: mockSetting({ hasValue: false }) });
- const onChange = (value: string) => input.setProps({ hasValueChanged: true, value });
- input.setProps({ onChange });
-
- expect(input.find('input').length).toBe(1);
- change(input.find(InputForString), 'hello');
- expect(input.find('input').length).toBe(1);
- expect(input.find(InputForString).prop('value')).toBe('hello');
-});
-
-it('should handle value reset', () => {
- const input = shallowRender({ hasValueChanged: true, value: 'whatever' });
- input.setState({ changing: true });
-
- // reset
- input.setProps({ hasValueChanged: false, value: 'original' });
-
- expect(input.state('changing')).toBe(false);
-});
-
-it('should handle value reset to empty', () => {
- const input = shallowRender({ hasValueChanged: true, value: 'whatever' });
- input.setState({ changing: true });
-
- // outside change
- input.setProps({ hasValueChanged: false, setting: mockSetting({ hasValue: false }) });
-
- expect(input.state('changing')).toBe(true);
-});
-
-function shallowRender(props: Partial<InputForSecured['props']> = {}) {
- return shallow<InputForSecured>(
- <InputForSecured
- input={InputForString}
- hasValueChanged={false}
- onChange={jest.fn()}
- setting={mockSetting()}
- value="bar"
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForSingleSelectList-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForSingleSelectList-test.tsx
deleted file mode 100644
index 0af1e4ee087..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForSingleSelectList-test.tsx
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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 Select from '../../../../../components/controls/Select';
-import { mockSetting } from '../../../../../helpers/mocks/settings';
-import { DefaultSpecializedInputProps } from '../../../utils';
-import InputForSingleSelectList from '../InputForSingleSelectList';
-
-it('should render Select', () => {
- const onChange = jest.fn();
- const select = shallowRender({ onChange }).find(Select);
- expect(select.length).toBe(1);
- expect(select.prop('name')).toBe('foo');
- expect(select.prop('value')).toEqual({ label: 'bar', value: 'bar' });
- expect(select.prop('options')).toEqual([
- { value: 'foo', label: 'foo' },
- { value: 'bar', label: 'bar' },
- { value: 'baz', label: 'baz' },
- ]);
- expect(select.prop('onChange')).toBeDefined();
-});
-
-it('should call onChange', () => {
- const onChange = jest.fn();
- const select = shallowRender({ onChange }).find(Select);
- expect(select.length).toBe(1);
- expect(select.prop('onChange')).toBeDefined();
-
- select.prop<Function>('onChange')({ value: 'baz', label: 'baz' });
- expect(onChange).toHaveBeenCalledWith('baz');
-});
-
-function shallowRender(props: Partial<DefaultSpecializedInputProps> = {}) {
- return shallow(
- <InputForSingleSelectList
- isDefault={false}
- name="foo"
- onChange={jest.fn()}
- options={['foo', 'bar', 'baz']}
- setting={mockSetting()}
- value="bar"
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForText-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForText-test.tsx
deleted file mode 100644
index f9f2d2970cc..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForText-test.tsx
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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 { mockSetting } from '../../../../../helpers/mocks/settings';
-import { change } from '../../../../../helpers/testUtils';
-import { DefaultSpecializedInputProps } from '../../../utils';
-import InputForText from '../InputForText';
-
-it('should render textarea', () => {
- const onChange = jest.fn();
- const textarea = shallowRender({ onChange }).find('textarea');
- expect(textarea.length).toBe(1);
- expect(textarea.prop('name')).toBe('foo');
- expect(textarea.prop('value')).toBe('bar');
- expect(textarea.prop('onChange')).toBeDefined();
-});
-
-it('should call onChange', () => {
- const onChange = jest.fn();
- const textarea = shallowRender({ onChange }).find('textarea');
- expect(textarea.length).toBe(1);
- expect(textarea.prop('onChange')).toBeDefined();
-
- change(textarea, 'qux');
- expect(onChange).toHaveBeenCalledWith('qux');
-});
-
-function shallowRender(props: Partial<DefaultSpecializedInputProps> = {}) {
- return shallow(
- <InputForText
- isDefault={false}
- name="foo"
- onChange={jest.fn()}
- value="bar"
- {...props}
- setting={mockSetting()}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/MultiValueInput-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/MultiValueInput-test.tsx
deleted file mode 100644
index 86d02a8a988..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/MultiValueInput-test.tsx
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * 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, ShallowWrapper } from 'enzyme';
-import * as React from 'react';
-import { click } from '../../../../../helpers/testUtils';
-import { ExtendedSettingDefinition, SettingType } from '../../../../../types/settings';
-import { DefaultSpecializedInputProps } from '../../../utils';
-import MultiValueInput from '../MultiValueInput';
-import PrimitiveInput from '../PrimitiveInput';
-
-const settingValue = {
- key: 'example',
- hasValue: true,
-};
-
-const settingDefinition: ExtendedSettingDefinition = {
- category: 'general',
- fields: [],
- key: 'example',
- multiValues: true,
- options: [],
- subCategory: 'Branches',
- type: SettingType.STRING,
-};
-
-const assertValues = (inputs: ShallowWrapper<any>, values: string[]) => {
- values.forEach((value, index) => {
- const input = inputs.at(index);
- expect(input.prop('value')).toBe(value);
- });
-};
-
-it('should render one value', () => {
- const multiValueInput = shallowRender();
- const stringInputs = multiValueInput.find(PrimitiveInput);
- expect(stringInputs.length).toBe(1 + 1);
- assertValues(stringInputs, ['foo', '']);
-});
-
-it('should render several values', () => {
- const multiValueInput = shallowRender({ value: ['foo', 'bar', 'baz'] });
- const stringInputs = multiValueInput.find(PrimitiveInput);
- expect(stringInputs.length).toBe(3 + 1);
- assertValues(stringInputs, ['foo', 'bar', 'baz', '']);
-});
-
-it('should remove value', () => {
- const onChange = jest.fn();
- const multiValueInput = shallowRender({ onChange, value: ['foo', 'bar', 'baz'] });
- click(multiValueInput.find('.js-remove-value').at(1));
- expect(onChange).toHaveBeenCalledWith(['foo', 'baz']);
-});
-
-it('should change existing value', () => {
- const onChange = jest.fn();
- const multiValueInput = shallowRender({ onChange, value: ['foo', 'bar', 'baz'] });
- multiValueInput.find(PrimitiveInput).at(1).prop('onChange')('qux');
- expect(onChange).toHaveBeenCalledWith(['foo', 'qux', 'baz']);
-});
-
-it('should add new value', () => {
- const onChange = jest.fn();
- const multiValueInput = shallowRender({ onChange });
- multiValueInput.find(PrimitiveInput).at(1).prop('onChange')('bar');
- expect(onChange).toHaveBeenCalledWith(['foo', 'bar']);
-});
-
-function shallowRender(props: Partial<DefaultSpecializedInputProps> = {}) {
- return shallow(
- <MultiValueInput
- isDefault={true}
- name="bar"
- onChange={jest.fn()}
- setting={{ ...settingValue, definition: settingDefinition }}
- value={['foo']}
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/PrimitiveInput-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/PrimitiveInput-test.tsx
deleted file mode 100644
index df337a9d136..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/PrimitiveInput-test.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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 { mockDefinition, mockSetting } from '../../../../../helpers/mocks/settings';
-import { SettingType } from '../../../../../types/settings';
-import { DefaultSpecializedInputProps } from '../../../utils';
-import PrimitiveInput from '../PrimitiveInput';
-
-it.each(Object.values(SettingType).map(Array.of))(
- 'should render correctly for %s',
- (type: SettingType) => {
- const setting = mockSetting({ definition: mockDefinition({ type }) });
- expect(shallowRender({ setting })).toMatchSnapshot();
- }
-);
-
-function shallowRender(props: Partial<DefaultSpecializedInputProps> = {}) {
- return shallow(
- <PrimitiveInput
- isDefault={true}
- name="name"
- onChange={jest.fn()}
- setting={mockSetting()}
- value={['foo']}
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/SimpleInput-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/SimpleInput-test.tsx
deleted file mode 100644
index 577e0d439ab..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/SimpleInput-test.tsx
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * 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 { KeyboardKeys } from '../../../../../helpers/keycodes';
-import { mockSetting } from '../../../../../helpers/mocks/settings';
-import { change, mockEvent } from '../../../../../helpers/testUtils';
-import SimpleInput, { SimpleInputProps } from '../SimpleInput';
-
-it('should render input', () => {
- const input = shallowRender().find('input');
- expect(input.length).toBe(1);
- expect(input.prop('type')).toBe('text');
- expect(input.prop('className')).toContain('input-large');
- expect(input.prop('name')).toBe('foo');
- expect(input.prop('value')).toBe('bar');
- expect(input.prop('onChange')).toBeDefined();
-});
-
-it('should call onChange', () => {
- const onChange = jest.fn();
- const input = shallowRender({ onChange }).find('input');
- expect(input.length).toBe(1);
- expect(input.prop('onChange')).toBeDefined();
-
- change(input, 'qux');
- expect(onChange).toHaveBeenCalledWith('qux');
-});
-
-it('should handle enter', () => {
- const onSave = jest.fn();
- shallowRender({ onSave })
- .instance()
- .handleKeyDown(mockEvent({ nativeEvent: { key: KeyboardKeys.Enter } }));
- expect(onSave).toHaveBeenCalled();
-});
-
-it('should handle esc', () => {
- const onCancel = jest.fn();
- shallowRender({ onCancel })
- .instance()
- .handleKeyDown(mockEvent({ nativeEvent: { key: KeyboardKeys.Escape } }));
- expect(onCancel).toHaveBeenCalled();
-});
-
-it('should ignore other keys', () => {
- const onSave = jest.fn();
- const onCancel = jest.fn();
- shallowRender({ onCancel, onSave })
- .instance()
- .handleKeyDown(mockEvent({ nativeEvent: { key: KeyboardKeys.LeftArrow } }));
- expect(onSave).not.toHaveBeenCalled();
- expect(onCancel).not.toHaveBeenCalled();
-});
-
-function shallowRender(overrides: Partial<SimpleInputProps> = {}) {
- return shallow<SimpleInput>(
- <SimpleInput
- className="input-large"
- isDefault={false}
- name="foo"
- onChange={jest.fn()}
- type="text"
- setting={mockSetting()}
- value="bar"
- {...overrides}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/__snapshots__/InputForJSON-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/__snapshots__/InputForJSON-test.tsx.snap
deleted file mode 100644
index 3353ed9aa59..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/__snapshots__/InputForJSON-test.tsx.snap
+++ /dev/null
@@ -1,51 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should handle formatting for invalid JSON 1`] = `
-<div
- className="display-flex-end"
->
- <textarea
- className="settings-large-input text-top monospaced spacer-right"
- name="foo"
- onChange={[Function]}
- rows={5}
- value="{"a": 1b}"
- />
- <div>
- <Alert
- variant="info"
- >
- settings.json.format_error
-
- </Alert>
- <Button
- className="spacer-top"
- onClick={[Function]}
- >
- settings.json.format
- </Button>
- </div>
-</div>
-`;
-
-exports[`should render correctly 1`] = `
-<div
- className="display-flex-end"
->
- <textarea
- className="settings-large-input text-top monospaced spacer-right"
- name="foo"
- onChange={[Function]}
- rows={5}
- value=""
- />
- <div>
- <Button
- className="spacer-top"
- onClick={[Function]}
- >
- settings.json.format
- </Button>
- </div>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/__snapshots__/PrimitiveInput-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/__snapshots__/PrimitiveInput-test.tsx.snap
deleted file mode 100644
index ddfa45a802d..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/__snapshots__/PrimitiveInput-test.tsx.snap
+++ /dev/null
@@ -1,349 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly for BOOLEAN 1`] = `
-<InputForBoolean
- isDefault={true}
- name="name"
- onChange={[MockFunction]}
- setting={
- {
- "definition": {
- "category": "foo category",
- "fields": [],
- "key": "foo",
- "options": [],
- "subCategory": "foo subCat",
- "type": "BOOLEAN",
- },
- "hasValue": true,
- "inherited": true,
- "key": "foo",
- "value": "42",
- }
- }
- value={
- [
- "foo",
- ]
- }
-/>
-`;
-
-exports[`should render correctly for FLOAT 1`] = `
-<InputForNumber
- isDefault={true}
- name="name"
- onChange={[MockFunction]}
- setting={
- {
- "definition": {
- "category": "foo category",
- "fields": [],
- "key": "foo",
- "options": [],
- "subCategory": "foo subCat",
- "type": "FLOAT",
- },
- "hasValue": true,
- "inherited": true,
- "key": "foo",
- "value": "42",
- }
- }
- value={
- [
- "foo",
- ]
- }
-/>
-`;
-
-exports[`should render correctly for FORMATTED_TEXT 1`] = `
-<InputForFormattedText
- isDefault={true}
- name="name"
- onChange={[MockFunction]}
- setting={
- {
- "definition": {
- "category": "foo category",
- "fields": [],
- "key": "foo",
- "options": [],
- "subCategory": "foo subCat",
- "type": "FORMATTED_TEXT",
- },
- "hasValue": true,
- "inherited": true,
- "key": "foo",
- "value": "42",
- }
- }
- value={
- [
- "foo",
- ]
- }
-/>
-`;
-
-exports[`should render correctly for INTEGER 1`] = `
-<InputForNumber
- isDefault={true}
- name="name"
- onChange={[MockFunction]}
- setting={
- {
- "definition": {
- "category": "foo category",
- "fields": [],
- "key": "foo",
- "options": [],
- "subCategory": "foo subCat",
- "type": "INTEGER",
- },
- "hasValue": true,
- "inherited": true,
- "key": "foo",
- "value": "42",
- }
- }
- value={
- [
- "foo",
- ]
- }
-/>
-`;
-
-exports[`should render correctly for JSON 1`] = `
-<InputForJSON
- isDefault={true}
- name="name"
- onChange={[MockFunction]}
- setting={
- {
- "definition": {
- "category": "foo category",
- "fields": [],
- "key": "foo",
- "options": [],
- "subCategory": "foo subCat",
- "type": "JSON",
- },
- "hasValue": true,
- "inherited": true,
- "key": "foo",
- "value": "42",
- }
- }
- value={
- [
- "foo",
- ]
- }
-/>
-`;
-
-exports[`should render correctly for LICENSE 1`] = `
-<InputForString
- isDefault={true}
- name="name"
- onChange={[MockFunction]}
- setting={
- {
- "definition": {
- "category": "foo category",
- "fields": [],
- "key": "foo",
- "options": [],
- "subCategory": "foo subCat",
- "type": "LICENSE",
- },
- "hasValue": true,
- "inherited": true,
- "key": "foo",
- "value": "42",
- }
- }
- value={
- [
- "foo",
- ]
- }
-/>
-`;
-
-exports[`should render correctly for LONG 1`] = `
-<InputForNumber
- isDefault={true}
- name="name"
- onChange={[MockFunction]}
- setting={
- {
- "definition": {
- "category": "foo category",
- "fields": [],
- "key": "foo",
- "options": [],
- "subCategory": "foo subCat",
- "type": "LONG",
- },
- "hasValue": true,
- "inherited": true,
- "key": "foo",
- "value": "42",
- }
- }
- value={
- [
- "foo",
- ]
- }
-/>
-`;
-
-exports[`should render correctly for PASSWORD 1`] = `
-<InputForPassword
- isDefault={true}
- name="name"
- onChange={[MockFunction]}
- setting={
- {
- "definition": {
- "category": "foo category",
- "fields": [],
- "key": "foo",
- "options": [],
- "subCategory": "foo subCat",
- "type": "PASSWORD",
- },
- "hasValue": true,
- "inherited": true,
- "key": "foo",
- "value": "42",
- }
- }
- value={
- [
- "foo",
- ]
- }
-/>
-`;
-
-exports[`should render correctly for PROPERTY_SET 1`] = `
-<InputForString
- isDefault={true}
- name="name"
- onChange={[MockFunction]}
- setting={
- {
- "definition": {
- "category": "foo category",
- "fields": [],
- "key": "foo",
- "options": [],
- "subCategory": "foo subCat",
- "type": "PROPERTY_SET",
- },
- "hasValue": true,
- "inherited": true,
- "key": "foo",
- "value": "42",
- }
- }
- value={
- [
- "foo",
- ]
- }
-/>
-`;
-
-exports[`should render correctly for SINGLE_SELECT_LIST 1`] = `
-<Wrapped
- isDefault={true}
- name="name"
- onChange={[MockFunction]}
- setting={
- {
- "definition": {
- "category": "foo category",
- "fields": [],
- "key": "foo",
- "options": [],
- "subCategory": "foo subCat",
- "type": "SINGLE_SELECT_LIST",
- },
- "hasValue": true,
- "inherited": true,
- "key": "foo",
- "value": "42",
- }
- }
- value={
- [
- "foo",
- ]
- }
-/>
-`;
-
-exports[`should render correctly for STRING 1`] = `
-<InputForString
- isDefault={true}
- name="name"
- onChange={[MockFunction]}
- setting={
- {
- "definition": {
- "category": "foo category",
- "fields": [],
- "key": "foo",
- "options": [],
- "subCategory": "foo subCat",
- "type": "STRING",
- },
- "hasValue": true,
- "inherited": true,
- "key": "foo",
- "value": "42",
- }
- }
- value={
- [
- "foo",
- ]
- }
-/>
-`;
-
-exports[`should render correctly for TEXT 1`] = `
-<InputForText
- isDefault={true}
- name="name"
- onChange={[MockFunction]}
- setting={
- {
- "definition": {
- "category": "foo category",
- "fields": [],
- "key": "foo",
- "options": [],
- "subCategory": "foo subCat",
- "type": "TEXT",
- },
- "hasValue": true,
- "inherited": true,
- "key": "foo",
- "value": "42",
- }
- }
- value={
- [
- "foo",
- ]
- }
-/>
-`;
diff --git a/server/sonar-web/src/main/js/components/controls/Toggle.tsx b/server/sonar-web/src/main/js/components/controls/Toggle.tsx
index 9774b41a627..008c393d260 100644
--- a/server/sonar-web/src/main/js/components/controls/Toggle.tsx
+++ b/server/sonar-web/src/main/js/components/controls/Toggle.tsx
@@ -19,7 +19,6 @@
*/
import classNames from 'classnames';
import * as React from 'react';
-import { translate } from '../../helpers/l10n';
import CheckIcon from '../icons/CheckIcon';
import { Button } from './buttons';
import './Toggle.css';
@@ -32,10 +31,14 @@ interface Props {
value: boolean | string;
}
+export function getToggleValue(value: string | boolean) {
+ return typeof value === 'string' ? value === 'true' : value;
+}
+
export default class Toggle extends React.PureComponent<Props> {
getValue = () => {
const { value } = this.props;
- return typeof value === 'string' ? value === 'true' : value;
+ return getToggleValue(value);
};
handleClick = () => {
@@ -51,11 +54,16 @@ export default class Toggle extends React.PureComponent<Props> {
const className = classNames('boolean-toggle', { 'boolean-toggle-on': value });
return (
- <Button className={className} disabled={disabled} name={name} onClick={this.handleClick}>
- <div
- aria-label={ariaLabel ?? translate(value ? 'on' : 'off')}
- className="boolean-toggle-handle"
- >
+ <Button
+ className={className}
+ disabled={disabled}
+ aria-label={ariaLabel}
+ name={name}
+ onClick={this.handleClick}
+ role="switch"
+ aria-checked={value}
+ >
+ <div className="boolean-toggle-handle">
<CheckIcon size={12} />
</div>
</Button>
diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Toggle-test.tsx.snap b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Toggle-test.tsx.snap
index 8862993eb41..ac7aa845377 100644
--- a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Toggle-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Toggle-test.tsx.snap
@@ -2,13 +2,14 @@
exports[`should render correctly: disabled 1`] = `
<Button
+ aria-checked={true}
className="boolean-toggle boolean-toggle-on"
disabled={true}
name="toggle-name"
onClick={[Function]}
+ role="switch"
>
<div
- aria-label="on"
className="boolean-toggle-handle"
>
<CheckIcon
@@ -20,13 +21,14 @@ exports[`should render correctly: disabled 1`] = `
exports[`should render correctly: off 1`] = `
<Button
+ aria-checked={false}
className="boolean-toggle"
disabled={true}
name="toggle-name"
onClick={[Function]}
+ role="switch"
>
<div
- aria-label="off"
className="boolean-toggle-handle"
>
<CheckIcon
@@ -38,13 +40,14 @@ exports[`should render correctly: off 1`] = `
exports[`should render correctly: on 1`] = `
<Button
+ aria-checked={true}
className="boolean-toggle boolean-toggle-on"
disabled={true}
name="toggle-name"
onClick={[Function]}
+ role="switch"
>
<div
- aria-label="on"
className="boolean-toggle-handle"
>
<CheckIcon
diff --git a/server/sonar-web/src/main/js/components/controls/buttons.tsx b/server/sonar-web/src/main/js/components/controls/buttons.tsx
index 30e037e39b1..5137c5458fa 100644
--- a/server/sonar-web/src/main/js/components/controls/buttons.tsx
+++ b/server/sonar-web/src/main/js/components/controls/buttons.tsx
@@ -41,6 +41,7 @@ type AllowedButtonAttributes = Pick<
| 'onMouseOver'
| 'onMouseLeave'
| 'tabIndex'
+ | 'role'
>;
interface ButtonProps extends AllowedButtonAttributes {
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/periods-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/periods-test.ts
index a3b58d10491..59e62a8bf8d 100644
--- a/server/sonar-web/src/main/js/helpers/__tests__/periods-test.ts
+++ b/server/sonar-web/src/main/js/helpers/__tests__/periods-test.ts
@@ -17,6 +17,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { NewCodePeriodSettingType } from '../../types/types';
import { getPeriodLabel } from '../periods';
import { mockPeriod } from '../testMocks';
@@ -85,21 +86,27 @@ describe('getPeriodLabel', () => {
it('should handle SPECIFIC_ANALYSIS', () => {
expect(
- getPeriodLabel(mockPeriod({ mode: 'SPECIFIC_ANALYSIS', parameter: '7.1' }), formatter)
+ getPeriodLabel(
+ mockPeriod({ mode: NewCodePeriodSettingType.SPECIFIC_ANALYSIS, parameter: '7.1' }),
+ formatter
+ )
+ ).toBe('overview.period.specific_analysis.2019-04-23T02:12:32+0100');
+ expect(
+ getPeriodLabel(mockPeriod({ mode: NewCodePeriodSettingType.SPECIFIC_ANALYSIS }), formatter)
).toBe('overview.period.specific_analysis.2019-04-23T02:12:32+0100');
- expect(getPeriodLabel(mockPeriod({ mode: 'SPECIFIC_ANALYSIS' }), formatter)).toBe(
- 'overview.period.specific_analysis.2019-04-23T02:12:32+0100'
- );
expect(formatter).toHaveBeenCalledTimes(2);
});
it('should handle PREVIOUS_VERSION', () => {
expect(
- getPeriodLabel(mockPeriod({ mode: 'PREVIOUS_VERSION', modeParam: 'A658678DE' }), formatter)
+ getPeriodLabel(
+ mockPeriod({ mode: NewCodePeriodSettingType.PREVIOUS_VERSION, modeParam: 'A658678DE' }),
+ formatter
+ )
).toBe('overview.period.previous_version.A658678DE');
- expect(getPeriodLabel(mockPeriod({ mode: 'PREVIOUS_VERSION' }), formatter)).toBe(
- 'overview.period.previous_version.2019-04-23T02:12:32+0100'
- );
+ expect(
+ getPeriodLabel(mockPeriod({ mode: NewCodePeriodSettingType.PREVIOUS_VERSION }), formatter)
+ ).toBe('overview.period.previous_version.2019-04-23T02:12:32+0100');
expect(formatter).toHaveBeenCalledTimes(1);
});
});
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForString-test.tsx b/server/sonar-web/src/main/js/helpers/mocks/new-code-period.ts
index b1ae445fe68..b33d62943f0 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForString-test.tsx
+++ b/server/sonar-web/src/main/js/helpers/mocks/new-code-period.ts
@@ -17,26 +17,12 @@
* 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 { mockSetting } from '../../../../../helpers/mocks/settings';
-import InputForString from '../InputForString';
-import SimpleInput from '../SimpleInput';
-it('should render SimpleInput', () => {
- const onChange = jest.fn();
- const simpleInput = shallow(
- <InputForString
- isDefault={false}
- name="foo"
- onChange={onChange}
- setting={mockSetting()}
- value="bar"
- />
- ).find(SimpleInput);
- expect(simpleInput.length).toBe(1);
- expect(simpleInput.prop('name')).toBe('foo');
- expect(simpleInput.prop('value')).toBe('bar');
- expect(simpleInput.prop('type')).toBe('text');
- expect(simpleInput.prop('onChange')).toBeDefined();
-});
+import { NewCodePeriod, NewCodePeriodSettingType } from '../../types/types';
+
+export function mockNewCodePeriod(overrides: Partial<NewCodePeriod> = {}) {
+ return {
+ type: NewCodePeriodSettingType.PREVIOUS_VERSION,
+ ...overrides,
+ };
+}
diff --git a/server/sonar-web/src/main/js/helpers/mocks/settings.ts b/server/sonar-web/src/main/js/helpers/mocks/settings.ts
index a43ee13ac2e..92e7588b44e 100644
--- a/server/sonar-web/src/main/js/helpers/mocks/settings.ts
+++ b/server/sonar-web/src/main/js/helpers/mocks/settings.ts
@@ -20,6 +20,7 @@
import {
ExtendedSettingDefinition,
Setting,
+ SettingFieldDefinition,
SettingType,
SettingValue,
SettingWithCategory,
@@ -38,6 +39,12 @@ export function mockDefinition(
};
}
+export function mockSettingFieldDefinition(
+ overrides: Partial<SettingFieldDefinition> = {}
+): SettingFieldDefinition {
+ return { key: 'name', name: 'Name', options: [], ...overrides };
+}
+
export function mockSetting(overrides: Partial<Setting> = {}): Setting {
return {
key: 'foo',
diff --git a/server/sonar-web/src/main/js/helpers/periods.ts b/server/sonar-web/src/main/js/helpers/periods.ts
index 29434d4d2d1..376a61c2a9c 100644
--- a/server/sonar-web/src/main/js/helpers/periods.ts
+++ b/server/sonar-web/src/main/js/helpers/periods.ts
@@ -20,7 +20,7 @@
import { parseDate } from '../helpers/dates';
import { translate, translateWithParameters } from '../helpers/l10n';
import { ApplicationPeriod } from '../types/application';
-import { Period } from '../types/types';
+import { NewCodePeriodSettingType, Period } from '../types/types';
export function getPeriodLabel(
period: Period | undefined,
@@ -33,10 +33,10 @@ export function getPeriodLabel(
let parameter = period.modeParam || period.parameter || '';
switch (period.mode) {
- case 'SPECIFIC_ANALYSIS':
+ case NewCodePeriodSettingType.SPECIFIC_ANALYSIS:
parameter = dateFormatter(period.date);
break;
- case 'PREVIOUS_VERSION':
+ case NewCodePeriodSettingType.PREVIOUS_VERSION:
parameter = parameter || dateFormatter(period.date);
break;
/*
diff --git a/server/sonar-web/src/main/js/types/settings.ts b/server/sonar-web/src/main/js/types/settings.ts
index 819c1c0a08c..2412af05bf4 100644
--- a/server/sonar-web/src/main/js/types/settings.ts
+++ b/server/sonar-web/src/main/js/types/settings.ts
@@ -74,7 +74,6 @@ export interface SettingDefinition {
}
export interface SettingFieldDefinition extends SettingDefinition {
- description: string;
name: string;
}
diff --git a/server/sonar-web/src/main/js/types/types.ts b/server/sonar-web/src/main/js/types/types.ts
index 4a7bc7ab2e6..b921015846d 100644
--- a/server/sonar-web/src/main/js/types/types.ts
+++ b/server/sonar-web/src/main/js/types/types.ts
@@ -405,11 +405,12 @@ export interface NewCodePeriodBranch {
effectiveValue?: string;
}
-export type NewCodePeriodSettingType =
- | 'PREVIOUS_VERSION'
- | 'NUMBER_OF_DAYS'
- | 'SPECIFIC_ANALYSIS'
- | 'REFERENCE_BRANCH';
+export enum NewCodePeriodSettingType {
+ PREVIOUS_VERSION = 'PREVIOUS_VERSION',
+ NUMBER_OF_DAYS = 'NUMBER_OF_DAYS',
+ SPECIFIC_ANALYSIS = 'SPECIFIC_ANALYSIS',
+ REFERENCE_BRANCH = 'REFERENCE_BRANCH',
+}
export interface Paging {
pageIndex: number;
diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
index 7489c7bdc5c..9cd62fcc56e 100644
--- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties
+++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
@@ -140,8 +140,6 @@ new_name=New name
none=None
no_tags=No tags
not_now=Not now
-off=Off
-on=On
or=Or
open=Open
optional=Optional
@@ -244,7 +242,6 @@ no=No
valid_input=Valid input
-
#------------------------------------------------------------------------------
#
# GENERIC EXPRESSIONS, sorted alphabetically
@@ -1164,6 +1161,7 @@ settings.reset_confirm.title=Reset Setting
settings.reset_confirm.description=Are you sure that you want to reset this setting?
settings.definition.reset=Reset "{0}" to default values
settings.definition.delete_value=Delete value "{1}" for setting "{0}"
+settings.definitions.delete_fields=Delete row {1} for setting "{0}"
settings.search.placeholder=Find in Settings
settings.search.results=Search results list