From 58abe872d6edb1ec16b2e78dc5d952085be64f0d Mon Sep 17 00:00:00 2001 From: stanislavh Date: Wed, 1 Mar 2023 13:32:28 +0100 Subject: [PATCH] SONAR-18580 add RTL for settings (part1) --- .../main/js/api/mocks/SettingsServiceMock.ts | 149 ++++- .../js/apps/settings/__tests__/utils-test.ts | 29 +- .../settings/components/AllCategoriesList.tsx | 2 +- .../settings/components/DefinitionActions.tsx | 13 +- .../apps/settings/components/SettingsApp.tsx | 2 +- .../components/SettingsAppRenderer.tsx | 4 +- .../components/SettingsSearchRenderer.tsx | 6 +- .../components/SubCategoryDefinitionsList.tsx | 2 +- .../__tests__/AdditionalCategories-test.tsx | 52 -- .../__tests__/AllCategoriesList-test.tsx | 2 +- .../__tests__/AnalysisScope-test.tsx | 38 -- .../CategoryDefinitionsList-test.tsx | 79 --- ...{Definition-test.tsx => Definition-it.tsx} | 0 .../__tests__/DefinitionActions-test.tsx | 87 --- .../__tests__/DefinitionRenderer-test.tsx | 58 -- .../components/__tests__/EmailForm-test.tsx | 90 --- .../components/__tests__/Languages-it.tsx | 132 ++++ .../components/__tests__/Languages-test.tsx | 68 --- ...dePeriod-test.tsx => NewCodePeriod-it.tsx} | 0 .../components/__tests__/PageHeader-test.tsx | 32 - .../components/__tests__/SettingsApp-it.tsx | 191 ++++++ .../components/__tests__/SettingsApp-test.tsx | 71 --- .../__tests__/SettingsAppRenderer-test.tsx | 69 --- .../__tests__/SettingsSearch-test.tsx | 154 ----- .../__tests__/SettingsSearchRenderer-test.tsx | 86 --- .../SubCategoryDefinitionsList-test.tsx | 75 --- .../AdditionalCategories-test.tsx.snap | 150 ----- .../__snapshots__/AnalysisScope-test.tsx.snap | 77 --- .../DefinitionActions-test.tsx.snap | 143 ----- .../DefinitionRenderer-test.tsx.snap | 571 ------------------ .../__snapshots__/EmailForm-test.tsx.snap | 358 ----------- .../__snapshots__/Languages-test.tsx.snap | 96 --- ...est.tsx.snap => NewCodePeriod-it.tsx.snap} | 0 .../__snapshots__/PageHeader-test.tsx.snap | 83 --- .../__snapshots__/SettingsApp-test.tsx.snap | 8 - .../SettingsAppRenderer-test.tsx.snap | 503 --------------- .../SettingsSearchRenderer-test.tsx.snap | 134 ---- .../SubCategoryDefinitionsList-test.tsx.snap | 135 ----- .../components/inputs/MultiValueInput.tsx | 8 +- .../components/inputs/SimpleInput.tsx | 5 +- .../src/main/js/apps/settings/styles.css | 10 + .../src/main/js/apps/settings/utils.ts | 6 +- .../resources/org/sonar/l10n/core.properties | 3 + 43 files changed, 533 insertions(+), 3248 deletions(-) delete mode 100644 server/sonar-web/src/main/js/apps/settings/components/__tests__/AdditionalCategories-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/settings/components/__tests__/AnalysisScope-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/settings/components/__tests__/CategoryDefinitionsList-test.tsx rename server/sonar-web/src/main/js/apps/settings/components/__tests__/{Definition-test.tsx => Definition-it.tsx} (100%) delete mode 100644 server/sonar-web/src/main/js/apps/settings/components/__tests__/DefinitionActions-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/settings/components/__tests__/DefinitionRenderer-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/settings/components/__tests__/EmailForm-test.tsx create mode 100644 server/sonar-web/src/main/js/apps/settings/components/__tests__/Languages-it.tsx delete mode 100644 server/sonar-web/src/main/js/apps/settings/components/__tests__/Languages-test.tsx rename server/sonar-web/src/main/js/apps/settings/components/__tests__/{NewCodePeriod-test.tsx => NewCodePeriod-it.tsx} (100%) delete mode 100644 server/sonar-web/src/main/js/apps/settings/components/__tests__/PageHeader-test.tsx create mode 100644 server/sonar-web/src/main/js/apps/settings/components/__tests__/SettingsApp-it.tsx delete mode 100644 server/sonar-web/src/main/js/apps/settings/components/__tests__/SettingsApp-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/settings/components/__tests__/SettingsAppRenderer-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/settings/components/__tests__/SettingsSearch-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/settings/components/__tests__/SettingsSearchRenderer-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/settings/components/__tests__/SubCategoryDefinitionsList-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AdditionalCategories-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AnalysisScope-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/DefinitionActions-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/DefinitionRenderer-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/EmailForm-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/Languages-test.tsx.snap rename server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/{NewCodePeriod-test.tsx.snap => NewCodePeriod-it.tsx.snap} (100%) delete mode 100644 server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/PageHeader-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/SettingsApp-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/SettingsAppRenderer-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/SettingsSearchRenderer-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/SubCategoryDefinitionsList-test.tsx.snap 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 ac36f1448f1..abfd964dcb8 100644 --- a/server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts +++ b/server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts @@ -19,57 +19,164 @@ */ import { cloneDeep } from 'lodash'; import { HousekeepingPolicy } from '../../apps/audit-logs/utils'; +import { mockDefinition } from '../../helpers/mocks/settings'; import { BranchParameters } from '../../types/branch-like'; -import { SettingsKey, SettingValue } from '../../types/settings'; -import { getAllValues, getValue, getValues } from '../settings'; +import { + ExtendedSettingDefinition, + SettingDefinition, + SettingsKey, + SettingType, + SettingValue, +} from '../../types/settings'; +import { + getAllValues, + getDefinitions, + getValue, + getValues, + resetSettingValue, + setSettingValue, +} from '../settings'; + +const isEmptyString = (i: string) => i.trim() === ''; + +export const DEFAULT_DEFINITIONS_MOCK = [ + mockDefinition({ + category: 'general', + key: 'sonar.announcement.message', + subCategory: 'Announcement', + name: 'Announcement message', + description: 'Enter message', + defaultValue: '.js,.jsx,.cjs,.vue,.mjs', + type: SettingType.TEXT, + }), + mockDefinition({ + category: 'general', + key: 'sonar.ce.parallelProjectTasks', + subCategory: 'Compute Engine', + name: 'Run analysis in paralel', + description: 'Enter message', + defaultValue: '.js,.jsx,.cjs,.vue,.mjs', + type: SettingType.TEXT, + }), + mockDefinition({ + category: 'javascript', + key: 'sonar.javascript.globals', + subCategory: 'General', + name: 'Global Variables', + description: 'List of Global variables', + multiValues: true, + defaultValue: 'angular,google,d3', + }), + mockDefinition({ + category: 'javascript', + key: 'sonar.javascript.file.suffixes', + subCategory: 'General', + name: 'JavaScript File Suffixes', + description: 'List of suffixes for files to analyze', + multiValues: true, + defaultValue: '.js,.jsx,.cjs,.vue,.mjs', + }), + mockDefinition({ + category: 'External Analyzers', + key: 'sonar.androidLint.reportPaths', + subCategory: 'Android', + name: 'Android Lint Report Files', + description: 'Paths to xml files', + multiValues: true, + }), +]; export default class SettingsServiceMock { - settingValues: SettingValue[]; - defaultValues: SettingValue[] = [ + #defaultValues: SettingValue[] = [ { key: SettingsKey.AuditHouseKeeping, value: HousekeepingPolicy.Weekly, }, + { + key: 'sonar.javascript.globals', + values: ['angular', 'google', 'd3'], + }, ]; + #settingValues: SettingValue[] = cloneDeep(this.#defaultValues); + + #definitions: ExtendedSettingDefinition[] = cloneDeep(DEFAULT_DEFINITIONS_MOCK); + constructor() { - this.settingValues = cloneDeep(this.defaultValues); - (getValue as jest.Mock).mockImplementation(this.handleGetValue); - (getValues as jest.Mock).mockImplementation(this.handleGetValues); - (getAllValues as jest.Mock).mockImplementation(this.handleGetAllValues); + jest.mocked(getDefinitions).mockImplementation(this.handleGetDefinitions); + jest.mocked(getValue).mockImplementation(this.handleGetValue); + jest.mocked(getValues).mockImplementation(this.handleGetValues); + jest.mocked(getAllValues).mockImplementation(this.handleGetAllValues); + jest.mocked(setSettingValue).mockImplementation(this.handleSetSettingValue); + jest.mocked(resetSettingValue).mockImplementation(this.handleResetSettingValue); } handleGetValue = (data: { key: string; component?: string } & BranchParameters) => { - const setting = this.settingValues.find((s) => s.key === data.key); + const setting = this.#settingValues.find((s) => s.key === data.key) as SettingValue; return this.reply(setting); }; handleGetValues = (data: { keys: string[]; component?: string } & BranchParameters) => { - const settings = this.settingValues.filter((s) => data.keys.includes(s.key)); + const settings = this.#settingValues.filter((s) => data.keys.includes(s.key)); return this.reply(settings); }; handleGetAllValues = () => { - return this.reply(this.settingValues); + return this.reply(this.#settingValues); + }; + + handleGetDefinitions = () => { + return this.reply(this.#definitions); + }; + + handleSetSettingValue = (definition: SettingDefinition, value: any): Promise => { + if ( + (typeof value === 'string' && isEmptyString(value)) || + (value instanceof Array && value.some(isEmptyString)) + ) { + throw new ResponseError('validation error', { + errors: [{ msg: 'A non empty value must be provided' }], + }); + } + + this.set(definition.key, value); + + return this.reply(undefined); + }; + + handleResetSettingValue = (data: { keys: string; component?: string } & BranchParameters) => { + const setting = this.#settingValues.find((s) => s.key === data.keys) as SettingValue; + const definition = this.#definitions.find( + (d) => d.key === data.keys + ) as ExtendedSettingDefinition; + if (definition.multiValues === true) { + setting.values = definition.defaultValue?.split(',') ?? []; + } else { + setting.value = definition.defaultValue ?? ''; + } + + return this.reply(undefined); }; emptySettings = () => { - this.settingValues = []; + this.#settingValues = []; return this; }; - set = (key: SettingsKey, value: string) => { - const setting = this.settingValues.find((s) => s.key === key); + set = (key: string | SettingsKey, value: any) => { + const setting = this.#settingValues.find((s) => s.key === key); if (setting) { setting.value = value; + setting.values = value; } else { - this.settingValues.push({ key, value }); + this.#settingValues.push({ key, value }); } return this; }; reset = () => { - this.settingValues = cloneDeep(this.defaultValues); + this.#settingValues = cloneDeep(this.#defaultValues); + this.#definitions = cloneDeep(DEFAULT_DEFINITIONS_MOCK); return this; }; @@ -77,3 +184,13 @@ export default class SettingsServiceMock { return Promise.resolve(cloneDeep(response)); } } + +class ResponseError extends Error { + #response: any; + constructor(name: string, response: any) { + super(name); + this.#response = response; + } + + json = () => Promise.resolve(this.#response); +} diff --git a/server/sonar-web/src/main/js/apps/settings/__tests__/utils-test.ts b/server/sonar-web/src/main/js/apps/settings/__tests__/utils-test.ts index fde31d3de76..c3643ff8af2 100644 --- a/server/sonar-web/src/main/js/apps/settings/__tests__/utils-test.ts +++ b/server/sonar-web/src/main/js/apps/settings/__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 { hasMessage } from '../../../helpers/l10n'; import { mockComponent } from '../../../helpers/mocks/component'; import { mockDefinition, mockSettingValue } from '../../../helpers/mocks/settings'; import { @@ -25,7 +26,18 @@ import { SettingFieldDefinition, SettingType, } from '../../../types/settings'; -import { buildSettingLink, getDefaultValue, getEmptyValue, getSettingValue } from '../utils'; +import { + buildSettingLink, + getDefaultValue, + getEmptyValue, + getPropertyName, + getSettingValue, +} from '../utils'; + +jest.mock('../../../helpers/l10n', () => ({ + ...jest.requireActual('../../../helpers/l10n'), + hasMessage: jest.fn(), +})); const fields = [ { key: 'foo', type: 'STRING' } as SettingFieldDefinition, @@ -40,6 +52,21 @@ const settingDefinition: ExtendedSettingDefinition = { subCategory: 'subtest', }; +describe('getPropertyName', () => { + it('should return correct value for existing translation', () => { + jest.mocked(hasMessage).mockImplementation(() => true); + expect(getPropertyName(mockDefinition())).toBe('property.foo.name'); + }); + + it('should return a name when translation doesn`t exist', () => { + jest.mocked(hasMessage).mockImplementation(() => false); + expect(getPropertyName(mockDefinition({ name: 'nicename', key: 'keey' }))).toBe('nicename'); + }); + it('should return a key when translation and name dont exist', () => { + expect(getPropertyName(mockDefinition({ key: 'keey' }))).toBe('keey'); + }); +}); + describe('#getEmptyValue()', () => { it('should work for property sets', () => { const setting: ExtendedSettingDefinition = { diff --git a/server/sonar-web/src/main/js/apps/settings/components/AllCategoriesList.tsx b/server/sonar-web/src/main/js/apps/settings/components/AllCategoriesList.tsx index a9e7f6f89f7..a039b597626 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/AllCategoriesList.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/AllCategoriesList.tsx @@ -38,7 +38,7 @@ export interface CategoriesListProps extends WithAvailableFeaturesProps { selectedCategory: string; } -export function CategoriesList(props: CategoriesListProps) { +function CategoriesList(props: CategoriesListProps) { const { categories, component, defaultCategory, selectedCategory } = props; const categoriesWithName = categories diff --git a/server/sonar-web/src/main/js/apps/settings/components/DefinitionActions.tsx b/server/sonar-web/src/main/js/apps/settings/components/DefinitionActions.tsx index 22130b7493d..f90f0072f7c 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/DefinitionActions.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/DefinitionActions.tsx @@ -20,9 +20,9 @@ import * as React from 'react'; import { Button, ResetButtonLink, SubmitButton } from '../../../components/controls/buttons'; import Modal from '../../../components/controls/Modal'; -import { translate } from '../../../helpers/l10n'; +import { translate, translateWithParameters } from '../../../helpers/l10n'; import { Setting } from '../../../types/settings'; -import { getDefaultValue, isEmptyValue } from '../utils'; +import { getDefaultValue, getPropertyName, isEmptyValue } from '../utils'; type Props = { changedValue?: string; @@ -100,7 +100,14 @@ export default class DefinitionActions extends React.PureComponent )} {showReset && ( - )} diff --git a/server/sonar-web/src/main/js/apps/settings/components/SettingsApp.tsx b/server/sonar-web/src/main/js/apps/settings/components/SettingsApp.tsx index f9d2306f11e..e05ce398856 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/SettingsApp.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/SettingsApp.tsx @@ -40,7 +40,7 @@ interface State { loading: boolean; } -export class SettingsApp extends React.PureComponent { +class SettingsApp extends React.PureComponent { mounted = false; state: State = { definitions: [], loading: true }; diff --git a/server/sonar-web/src/main/js/apps/settings/components/SettingsAppRenderer.tsx b/server/sonar-web/src/main/js/apps/settings/components/SettingsAppRenderer.tsx index 9d844cc2133..7bc291da1a8 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/SettingsAppRenderer.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/SettingsAppRenderer.tsx @@ -40,7 +40,7 @@ export interface SettingsAppRendererProps { location: Location; } -export function SettingsAppRenderer(props: SettingsAppRendererProps) { +function SettingsAppRenderer(props: SettingsAppRendererProps) { const { definitions, component, loading, location } = props; const categories = React.useMemo(() => { @@ -92,7 +92,7 @@ export function SettingsAppRenderer(props: SettingsAppRendererProps) {
{/* Adding a key to force re-rendering of the category content, so that it resets the scroll position */}
- {foundAdditionalCategory && shouldRenderAdditionalCategory ? ( + {shouldRenderAdditionalCategory ? ( foundAdditionalCategory.renderComponent({ categories, component, diff --git a/server/sonar-web/src/main/js/apps/settings/components/SettingsSearchRenderer.tsx b/server/sonar-web/src/main/js/apps/settings/components/SettingsSearchRenderer.tsx index f79861d91bf..c1cfa10fca9 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/SettingsSearchRenderer.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/SettingsSearchRenderer.tsx @@ -69,7 +69,11 @@ export default function SettingsSearchRenderer(props: SettingsSearchRendererProp /> {showResults && ( -
    +
      {results && results.length > 0 ? ( results.map((r) => (
    • { +class SubCategoryDefinitionsList extends React.PureComponent { componentDidUpdate(prevProps: SubCategoryDefinitionsListProps) { const { hash } = this.props.location; if (hash && prevProps.location.hash !== hash) { diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/AdditionalCategories-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/__tests__/AdditionalCategories-test.tsx deleted file mode 100644 index a9977f29685..00000000000 --- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/AdditionalCategories-test.tsx +++ /dev/null @@ -1,52 +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 { find } from 'lodash'; -import { mockComponent } from '../../../../helpers/mocks/component'; -import { PULL_REQUEST_DECORATION_BINDING_CATEGORY } from '../../constants'; -import { ADDITIONAL_CATEGORIES } from '../AdditionalCategories'; - -it('should render additional categories component correctly', () => { - ADDITIONAL_CATEGORIES.forEach((cat) => { - expect( - cat.renderComponent({ - categories: [], - component: mockComponent(), - definitions: [], - selectedCategory: 'TEST', - }) - ).toMatchSnapshot(); - }); -}); - -it('should not render pull request decoration binding component when the component is not defined', () => { - const category = find( - ADDITIONAL_CATEGORIES, - (c) => c.key === PULL_REQUEST_DECORATION_BINDING_CATEGORY - ); - - expect( - category!.renderComponent({ - categories: [], - component: undefined, - definitions: [], - selectedCategory: '', - }) - ).toBeUndefined(); -}); diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/AllCategoriesList-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/__tests__/AllCategoriesList-test.tsx index e66cafe8d49..f860ebab0ab 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/AllCategoriesList-test.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/__tests__/AllCategoriesList-test.tsx @@ -22,7 +22,7 @@ import * as React from 'react'; import { mockComponent } from '../../../../helpers/mocks/component'; import { renderComponent } from '../../../../helpers/testReactTestingUtils'; import { AdditionalCategory } from '../AdditionalCategories'; -import { CategoriesList, CategoriesListProps } from '../AllCategoriesList'; +import CategoriesList, { CategoriesListProps } from '../AllCategoriesList'; jest.mock('../AdditionalCategories', () => ({ ADDITIONAL_CATEGORIES: [ 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 deleted file mode 100644 index c7ad9c69876..00000000000 --- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/AnalysisScope-test.tsx +++ /dev/null @@ -1,38 +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 { mockComponent } from '../../../../helpers/mocks/component'; -import { AnalysisScope } from '../AnalysisScope'; - -it('should render correctly', () => { - expect(shallowRender()).toMatchSnapshot(); -}); - -function shallowRender() { - return shallow( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/CategoryDefinitionsList-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/__tests__/CategoryDefinitionsList-test.tsx deleted file mode 100644 index 926c874e2b6..00000000000 --- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/CategoryDefinitionsList-test.tsx +++ /dev/null @@ -1,79 +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 { getValues } from '../../../../api/settings'; -import { mockComponent } from '../../../../helpers/mocks/component'; -import { mockDefinition, mockSettingValue } from '../../../../helpers/mocks/settings'; -import { waitAndUpdate } from '../../../../helpers/testUtils'; -import CategoryDefinitionsList from '../CategoryDefinitionsList'; - -jest.mock('../../../../api/settings', () => ({ - getValues: jest.fn().mockResolvedValue([]), -})); - -it('should load settings values', async () => { - const settings = [mockSettingValue({ key: 'yes' }), mockSettingValue({ key: 'yesagain' })]; - (getValues as jest.Mock).mockResolvedValueOnce(settings); - - const definitions = [ - mockDefinition({ category: 'general', key: 'yes' }), - mockDefinition({ category: 'other', key: 'nope' }), - mockDefinition({ category: 'general', key: 'yesagain' }), - ]; - - const wrapper = shallowRender({ - definitions, - }); - - await waitAndUpdate(wrapper); - - expect(getValues).toHaveBeenCalledWith({ keys: ['yes', 'yesagain'], component: undefined }); - - expect(wrapper.state().settings).toEqual([ - { definition: definitions[0], settingValue: settings[0] }, - { definition: definitions[2], settingValue: settings[1] }, - ]); -}); - -it('should reload on category change', async () => { - const definitions = [ - mockDefinition({ category: 'general', key: 'yes' }), - mockDefinition({ category: 'other', key: 'nope' }), - mockDefinition({ category: 'general', key: 'yesagain' }), - ]; - const wrapper = shallowRender({ component: mockComponent({ key: 'comp-key' }), definitions }); - - await waitAndUpdate(wrapper); - - expect(getValues).toHaveBeenCalledWith({ keys: ['yes', 'yesagain'], component: 'comp-key' }); - - wrapper.setProps({ category: 'other' }); - - await waitAndUpdate(wrapper); - - expect(getValues).toHaveBeenCalledWith({ keys: ['nope'], component: 'comp-key' }); -}); - -function shallowRender(props: Partial = {}) { - return shallow( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/Definition-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/__tests__/Definition-it.tsx similarity index 100% rename from server/sonar-web/src/main/js/apps/settings/components/__tests__/Definition-test.tsx rename to server/sonar-web/src/main/js/apps/settings/components/__tests__/Definition-it.tsx diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/DefinitionActions-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/__tests__/DefinitionActions-test.tsx deleted file mode 100644 index d542b9a7030..00000000000 --- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/DefinitionActions-test.tsx +++ /dev/null @@ -1,87 +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 { ExtendedSettingDefinition, SettingType } from '../../../../types/settings'; -import DefinitionActions from '../DefinitionActions'; - -const definition: ExtendedSettingDefinition = { - category: 'baz', - description: 'lorem', - fields: [], - key: 'key', - name: 'foobar', - options: [], - subCategory: 'bar', - type: SettingType.STRING, -}; - -const settings = { - key: 'key', - hasValue: true, - definition, - value: 'baz', -}; - -it('displays default message when value is default', () => { - const wrapper = shallowRender('', false, true); - expect(wrapper).toMatchSnapshot(); -}); - -it('displays save button when it can be saved', () => { - const wrapper = shallowRender('foo', false, true); - expect(wrapper).toMatchSnapshot(); -}); - -it('displays cancel button when value changed and no error', () => { - const wrapper = shallowRender('foo', false, true); - expect(wrapper).toMatchSnapshot(); -}); - -it('displays cancel button when value changed and has error', () => { - const wrapper = shallowRender('foo', true, true); - expect(wrapper).toMatchSnapshot(); -}); - -it('disables save button on error', () => { - const wrapper = shallowRender('foo', true, true); - expect(wrapper).toMatchSnapshot(); -}); - -it('displays reset button when empty and not default', () => { - const wrapper = shallowRender('', true, false); - expect(wrapper).toMatchSnapshot(); -}); - -function shallowRender(changedValue: string, hasError: boolean, isDefault: boolean) { - return shallow( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/DefinitionRenderer-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/__tests__/DefinitionRenderer-test.tsx deleted file mode 100644 index 0010f95432d..00000000000 --- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/DefinitionRenderer-test.tsx +++ /dev/null @@ -1,58 +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, mockSettingValue } from '../../../../helpers/mocks/settings'; -import DefinitionRenderer, { DefinitionRendererProps } from '../DefinitionRenderer'; - -it('should render correctly', () => { - expect(shallowRender({ loading: true })).toMatchSnapshot('loading'); - expect( - shallowRender({ definition: mockDefinition({ description: 'description' }) }) - ).toMatchSnapshot('with description'); - expect( - shallowRender({ - validationMessage: 'validation message', - }) - ).toMatchSnapshot('in error'); - expect(shallowRender({ success: true })).toMatchSnapshot('success'); - expect( - shallowRender({ settingValue: mockSettingValue({ key: 'foo', value: 'original value' }) }) - ).toMatchSnapshot('original value'); - - expect(shallowRender({ changedValue: 'new value' })).toMatchSnapshot('changed value'); -}); - -function shallowRender(props: Partial = {}) { - return shallow( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/EmailForm-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/__tests__/EmailForm-test.tsx deleted file mode 100644 index c0ccbc0a228..00000000000 --- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/EmailForm-test.tsx +++ /dev/null @@ -1,90 +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 { sendTestEmail } from '../../../../api/settings'; -import { mockLoggedInUser } from '../../../../helpers/testMocks'; -import { change, submit, waitAndUpdate } from '../../../../helpers/testUtils'; -import { EmailForm } from '../EmailForm'; - -jest.mock('../../../../helpers/request', () => ({ - parseError: jest.fn().mockResolvedValue('Error message'), -})); - -jest.mock('../../../../api/settings', () => ({ - sendTestEmail: jest.fn().mockResolvedValue(null), -})); - -it('should render correctly', () => { - const wrapper = shallowRender(); - expect(wrapper).toMatchSnapshot('default'); - wrapper.setState({ loading: true }); - expect(wrapper).toMatchSnapshot('sending'); - wrapper.setState({ loading: false, success: 'email@example.com' }); - expect(wrapper).toMatchSnapshot('success'); - wrapper.setState({ success: undefined, error: 'Some error message' }); - expect(wrapper).toMatchSnapshot('error'); -}); - -it('should correctly control the inputs', () => { - const wrapper = shallowRender(); - - change(wrapper.find('#test-email-to'), 'new@recipient.com'); - expect(wrapper.state().recipient).toBe('new@recipient.com'); - - change(wrapper.find('#test-email-subject'), 'New subject'); - expect(wrapper.state().subject).toBe('New subject'); - - change(wrapper.find('#test-email-message'), 'New message'); - expect(wrapper.state().message).toBe('New message'); -}); - -it('should correctly test the email sending', async () => { - const wrapper = shallowRender(); - - submit(wrapper.find('form')); - expect(sendTestEmail).toHaveBeenCalledWith( - 'luke@skywalker.biz', - 'email_configuration.test.subject', - 'email_configuration.test.message_text' - ); - expect(wrapper.state().loading).toBe(true); - - await waitAndUpdate(wrapper); - - expect(wrapper.state().loading).toBe(false); - expect(wrapper.state().error).toBeUndefined(); - expect(wrapper.state().success).toBe('luke@skywalker.biz'); - - (sendTestEmail as jest.Mock).mockRejectedValueOnce(null); - - submit(wrapper.find('form')); - - await waitAndUpdate(wrapper); - - expect(wrapper.state().success).toBeUndefined(); - expect(wrapper.state().error).toBe('Error message'); -}); - -function shallowRender(props: Partial = {}) { - return shallow( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/Languages-it.tsx b/server/sonar-web/src/main/js/apps/settings/components/__tests__/Languages-it.tsx new file mode 100644 index 00000000000..9e0868ebbf4 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/settings/components/__tests__/Languages-it.tsx @@ -0,0 +1,132 @@ +/* + * 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 { last } from 'lodash'; +import React from 'react'; +import { byRole, byText } from 'testing-library-selector'; +import SettingsServiceMock, { + DEFAULT_DEFINITIONS_MOCK, +} from '../../../../api/mocks/SettingsServiceMock'; +import { mockComponent } from '../../../../helpers/mocks/component'; +import { renderApp } from '../../../../helpers/testReactTestingUtils'; +import { AdditionalCategoryComponentProps } from '../AdditionalCategories'; +import Languages from '../Languages'; + +jest.mock('../../../../api/settings'); + +let settingsMock: SettingsServiceMock; + +beforeAll(() => { + settingsMock = new SettingsServiceMock(); +}); + +afterEach(() => { + settingsMock.reset(); +}); + +beforeEach(jest.clearAllMocks); + +const ui = { + languagesHeading: byRole('heading', { name: 'property.category.languages' }), + languagesSelect: byRole('combobox', { name: 'property.category.languages' }), + jsGeneralSubCategoryHeading: byRole('heading', { name: 'property.category.javascript.General' }), + jsGlobalVariablesHeading: byRole('heading', { + name: 'property.sonar.javascript.globals.name', + }), + jsGlobalVariablesDescription: byText('List of Global variables'), + jsFileSuffixesHeading: byRole('heading', { + name: 'property.sonar.javascript.file.suffixes.name', + }), + jsGlobalVariablesInput: byRole('textbox', { name: 'property.sonar.javascript.globals.name' }), + jsResetGlobalVariablesButton: byRole('button', { + name: 'settings.definition.reset.property.sonar.javascript.globals.name', + }), + + validationMsg: byText('settings.state.validation_failed.A non empty value must be provided'), + saveButton: byRole('button', { name: 'save' }), + cancelButton: byRole('button', { name: 'cancel' }), + resetButton: byRole('button', { name: 'reset_verb' }), +}; + +it('renders Language with selected Javascript category', async () => { + renderLanguages({ selectedCategory: 'javascript' }); + + expect(await ui.languagesHeading.find()).toBeInTheDocument(); + expect(await ui.jsGeneralSubCategoryHeading.find()).toBeInTheDocument(); + expect(ui.jsGlobalVariablesHeading.get()).toBeInTheDocument(); + expect(ui.jsFileSuffixesHeading.get()).toBeInTheDocument(); +}); + +it('render Language without definitions', async () => { + renderLanguages({ selectedCategory: 'niceLanguage' }); + + expect(await ui.languagesHeading.find()).toBeInTheDocument(); + expect(screen.queryByText(/niceLanguage/)).not.toBeInTheDocument(); +}); + +it('can save/reset/cancel or see error for custom mocked multi values definition Global Variables', async () => { + const user = userEvent.setup(); + renderLanguages({ selectedCategory: 'javascript' }); + + const jsVarsInputs = await ui.jsGlobalVariablesInput.findAll(); + const lastInput = last(jsVarsInputs); + // Adding new js variable (multi-values input) + expect(jsVarsInputs).toHaveLength(4); + + // Should see a validation message on typing empty string + await user.type(lastInput as HTMLElement, ' '); + await user.click(await ui.saveButton.find()); + expect(await ui.validationMsg.find()).toBeInTheDocument(); + + // Should save variable + await user.type(lastInput as HTMLElement, 'Testing'); + await user.click(await ui.saveButton.find()); + expect(ui.validationMsg.query()).not.toBeInTheDocument(); + expect(lastInput).toHaveValue(' Testing'); + + // Should reset to previous state on clicking cancel + await user.type(last(ui.jsGlobalVariablesInput.getAll()) as HTMLElement, 'Testing2'); + await user.click(ui.cancelButton.get()); + expect(last(ui.jsGlobalVariablesInput.getAll())).not.toHaveValue('Testing2'); + + // Clicking reset opens dialog and reset to default on confirm + const defaultValues = ['angular', 'google', 'd3', '']; + await user.click(ui.jsResetGlobalVariablesButton.get()); + await user.click(ui.resetButton.get()); + const newInputs = ui.jsGlobalVariablesInput.getAll(); + defaultValues.forEach((value, index) => expect(newInputs[index]).toHaveValue(value)); +}); + +function renderLanguages( + overrides: Partial = {}, + component = mockComponent() +) { + return renderApp( + '/', + + ); +} diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/Languages-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/__tests__/Languages-test.tsx deleted file mode 100644 index 2a54262416e..00000000000 --- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/Languages-test.tsx +++ /dev/null @@ -1,68 +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 { mockComponent } from '../../../../helpers/mocks/component'; -import { mockLocation, mockRouter } from '../../../../helpers/testMocks'; -import CategoryDefinitionsList from '../CategoryDefinitionsList'; -import { Languages, LanguagesProps } from '../Languages'; - -it('should render correctly', () => { - const wrapper = shallowRender(); - expect(wrapper).toMatchSnapshot(); -}); - -it('should render correctly with an unknow language', () => { - const wrapper = shallowRender({ selectedCategory: 'unknown' }); - expect(wrapper).toMatchSnapshot(); -}); - -it('should correctly handle a change of the selected language', () => { - const push = jest.fn(); - const router = mockRouter({ push }); - const wrapper = shallowRender({ router }); - expect(wrapper.find(CategoryDefinitionsList).props().category).toBe('java'); - - const { onChange } = wrapper.find(Select).props(); - - onChange({ label: '', originalValue: 'CoBoL', value: 'cobol' }); - expect(push).toHaveBeenCalledWith(expect.objectContaining({ query: { category: 'CoBoL' } })); -}); - -it('should correctly show the subcategory for a component', () => { - const component = mockComponent(); - const wrapper = shallowRender({ component }); - expect(wrapper.find(CategoryDefinitionsList).props().component).toBe(component); -}); - -function shallowRender(props: Partial = {}) { - return shallow( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/NewCodePeriod-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/__tests__/NewCodePeriod-it.tsx similarity index 100% rename from server/sonar-web/src/main/js/apps/settings/components/__tests__/NewCodePeriod-test.tsx rename to server/sonar-web/src/main/js/apps/settings/components/__tests__/NewCodePeriod-it.tsx diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/PageHeader-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/__tests__/PageHeader-test.tsx deleted file mode 100644 index 41843017237..00000000000 --- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/PageHeader-test.tsx +++ /dev/null @@ -1,32 +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 { mockComponent } from '../../../../helpers/mocks/component'; -import PageHeader, { PageHeaderProps } from '../PageHeader'; - -it('should render correctly', () => { - expect(shallowRender()).toMatchSnapshot('global'); - expect(shallowRender({ component: mockComponent() })).toMatchSnapshot('for project'); -}); - -function shallowRender(props: Partial = {}) { - return shallow(); -} diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/SettingsApp-it.tsx b/server/sonar-web/src/main/js/apps/settings/components/__tests__/SettingsApp-it.tsx new file mode 100644 index 00000000000..c4a7d2582f7 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/settings/components/__tests__/SettingsApp-it.tsx @@ -0,0 +1,191 @@ +/* + * 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 { within } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import React from 'react'; +import { Route } from 'react-router-dom'; +import selectEvent from 'react-select-event'; +import { byRole } from 'testing-library-selector'; +import SettingsServiceMock from '../../../../api/mocks/SettingsServiceMock'; +import { KeyboardKeys } from '../../../../helpers/keycodes'; +import { mockComponent } from '../../../../helpers/mocks/component'; +import { + renderAppRoutes, + renderAppWithComponentContext, + RenderContext, +} from '../../../../helpers/testReactTestingUtils'; +import { Feature } from '../../../../types/features'; +import { Component } from '../../../../types/types'; +import routes from '../../routes'; + +jest.mock('../../../../api/settings'); + +let settingsMock: SettingsServiceMock; + +beforeAll(() => { + settingsMock = new SettingsServiceMock(); +}); + +afterEach(() => { + settingsMock.reset(); +}); + +beforeEach(jest.clearAllMocks); + +const ui = { + categoryLink: (category: string) => byRole('link', { name: category }), + announcementHeading: byRole('heading', { name: 'property.category.general.Announcement' }), + + languagesHeading: byRole('heading', { name: 'property.category.languages' }), + languagesSelect: byRole('combobox', { name: 'property.category.languages' }), + jsGeneralSubCategoryHeading: byRole('heading', { name: 'property.category.javascript.General' }), + + settingsSearchInput: byRole('searchbox', { name: 'settings.search.placeholder' }), + searchList: byRole('list', { name: 'settings.search.results' }), + searchItem: (key: string) => byRole('link', { name: new RegExp(key) }), + searchClear: byRole('button', { name: 'clear' }), + + externalAnalyzersAndroidHeading: byRole('heading', { + name: 'property.category.External Analyzers.Android', + }), + generalComputeEngineHeading: byRole('heading', { + name: 'property.category.general.Compute Engine', + }), +}; + +describe('Global Settings', () => { + it('renders categories list and definitions', async () => { + const user = userEvent.setup(); + renderSettingsApp(); + + const globalCategories = [ + 'property.category.general', + 'property.category.languages', + 'property.category.External Analyzers', + 'settings.new_code_period.category', + 'property.category.almintegration', + ]; + + expect(await ui.categoryLink(globalCategories[0]).find()).toBeInTheDocument(); + globalCategories.forEach((name) => { + expect(ui.categoryLink(name).get()).toBeInTheDocument(); + }); + + expect(await ui.announcementHeading.find()).toBeInTheDocument(); + + // Navigating to Languages category + await user.click(await ui.categoryLink('property.category.languages').find()); + expect(await ui.languagesHeading.find()).toBeInTheDocument(); + }); + + it('renders Language category and can select any language', async () => { + const user = userEvent.setup(); + renderSettingsApp(); + + // Navigating to Languages category + await user.click(await ui.categoryLink('property.category.languages').find()); + expect(await ui.languagesHeading.find()).toBeInTheDocument(); + + await selectEvent.select(ui.languagesSelect.get(), 'property.category.javascript'); + expect(await ui.jsGeneralSubCategoryHeading.find()).toBeInTheDocument(); + }); + + it('can search definitions by name or key', async () => { + const user = userEvent.setup(); + renderSettingsApp(); + + expect(await ui.settingsSearchInput.find()).toBeInTheDocument(); + + // List popup should be closed if input is empty + await user.click(ui.settingsSearchInput.get()); + expect(ui.searchList.query()).not.toBeInTheDocument(); + + // Should shot 'no results' based on input value + await user.type(ui.settingsSearchInput.get(), 'asdjasnd'); + expect(ui.searchList.get()).toBeInTheDocument(); + expect(within(ui.searchList.get()).getByText('no_results')).toBeInTheDocument(); + await user.click(ui.searchClear.get()); + + // Should show results based on input value + const searchResultsKeys = [ + 'sonar.announcement.message', + 'sonar.ce.parallelProjectTasks', + 'sonar.androidLint.reportPaths', + ]; + + await user.type(ui.settingsSearchInput.get(), 'an'); + searchResultsKeys.forEach((key) => expect(ui.searchItem(key).get()).toBeInTheDocument()); + expect(ui.searchItem('sonar.javascript.globals').query()).not.toBeInTheDocument(); + + // Navigating through keyboard + await user.keyboard(`{${KeyboardKeys.DownArrow}}`); + await user.keyboard(`{${KeyboardKeys.UpArrow}}`); + await user.keyboard(`{${KeyboardKeys.DownArrow}}`); + await user.keyboard(`{${KeyboardKeys.Enter}}`); + + expect(await ui.externalAnalyzersAndroidHeading.find()).toBeInTheDocument(); + + // Navigating through link + await user.click(ui.searchClear.get()); + await user.type(ui.settingsSearchInput.get(), 'an'); + await user.click(ui.searchItem(searchResultsKeys[1]).get()); + + expect(await ui.generalComputeEngineHeading.find()).toBeInTheDocument(); + }); +}); + +describe('Project Settings', () => { + it('renders categories list and definitions', async () => { + const user = userEvent.setup(); + renderSettingsApp(mockComponent(), { featureList: [Feature.BranchSupport] }); + + const projectCategories = [ + 'property.category.general', + 'property.category.languages', + 'property.category.External Analyzers', + 'settings.pr_decoration.binding.category', + ]; + + expect(await ui.categoryLink(projectCategories[0]).find()).toBeInTheDocument(); + projectCategories.forEach((name) => { + expect(ui.categoryLink(name).get()).toBeInTheDocument(); + }); + + expect(await ui.announcementHeading.find()).toBeInTheDocument(); + + // Navigating to Languages category + await user.click(await ui.categoryLink('property.category.languages').find()); + expect(await ui.languagesHeading.find()).toBeInTheDocument(); + }); +}); + +function renderSettingsApp(component?: Component, context: RenderContext = {}) { + const path = component ? 'project' : 'admin'; + const wrapperRoutes = () => {routes()}; + const params: [string, typeof routes, RenderContext] = [ + `${path}/settings`, + wrapperRoutes, + context, + ]; + + return component + ? renderAppWithComponentContext(...params, { component }) + : renderAppRoutes(...params); +} diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/SettingsApp-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/__tests__/SettingsApp-test.tsx deleted file mode 100644 index a4677e66bd5..00000000000 --- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/SettingsApp-test.tsx +++ /dev/null @@ -1,71 +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 { getDefinitions } from '../../../../api/settings'; -import { mockComponent } from '../../../../helpers/mocks/component'; -import { - addSideBarClass, - addWhitePageClass, - removeSideBarClass, - removeWhitePageClass, -} from '../../../../helpers/pages'; -import { waitAndUpdate } from '../../../../helpers/testUtils'; -import { SettingsApp } from '../SettingsApp'; - -jest.mock('../../../../helpers/pages', () => ({ - addSideBarClass: jest.fn(), - addWhitePageClass: jest.fn(), - removeSideBarClass: jest.fn(), - removeWhitePageClass: jest.fn(), -})); - -jest.mock('../../../../api/settings', () => ({ - getDefinitions: jest.fn().mockResolvedValue([]), -})); - -it('should render default view correctly', async () => { - const wrapper = shallowRender(); - - expect(addSideBarClass).toHaveBeenCalled(); - expect(addWhitePageClass).toHaveBeenCalled(); - - await waitAndUpdate(wrapper); - expect(wrapper).toMatchSnapshot(); - - expect(getDefinitions).toHaveBeenCalledWith(undefined); - - wrapper.unmount(); - - expect(removeSideBarClass).toHaveBeenCalled(); - expect(removeWhitePageClass).toHaveBeenCalled(); -}); - -it('should fetch definitions for component', async () => { - const key = 'component-key'; - const wrapper = shallowRender({ component: mockComponent({ key }) }); - - await waitAndUpdate(wrapper); - expect(getDefinitions).toHaveBeenCalledWith(key); -}); - -function shallowRender(props: Partial = {}) { - return shallow(); -} diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/SettingsAppRenderer-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/__tests__/SettingsAppRenderer-test.tsx deleted file mode 100644 index e88fe230b01..00000000000 --- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/SettingsAppRenderer-test.tsx +++ /dev/null @@ -1,69 +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 ScreenPositionHelper from '../../../../components/common/ScreenPositionHelper'; -import { mockDefinition } from '../../../../helpers/mocks/settings'; -import { mockLocation } from '../../../../helpers/testMocks'; -import { - ALM_INTEGRATION_CATEGORY, - ANALYSIS_SCOPE_CATEGORY, - LANGUAGES_CATEGORY, - NEW_CODE_PERIOD_CATEGORY, - PULL_REQUEST_DECORATION_BINDING_CATEGORY, -} from '../../constants'; -import { SettingsAppRenderer, SettingsAppRendererProps } from '../SettingsAppRenderer'; - -it('should render loading correctly', () => { - expect(shallowRender({ loading: true }).type()).toBeNull(); -}); - -it('should render default view correctly', () => { - const wrapper = shallowRender(); - - expect(wrapper).toMatchSnapshot(); - expect(wrapper.find(ScreenPositionHelper).dive()).toMatchSnapshot('All Categories List'); -}); - -it.each([ - [NEW_CODE_PERIOD_CATEGORY], - [LANGUAGES_CATEGORY], - [ANALYSIS_SCOPE_CATEGORY], - [ALM_INTEGRATION_CATEGORY], - [PULL_REQUEST_DECORATION_BINDING_CATEGORY], -])('should render %s correctly', (category) => { - const wrapper = shallowRender({ - location: mockLocation({ query: { category } }), - }); - - expect(wrapper).toMatchSnapshot(); -}); - -function shallowRender(props: Partial = {}) { - const definitions = [mockDefinition(), mockDefinition({ key: 'bar', category: 'general' })]; - return shallow( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/SettingsSearch-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/__tests__/SettingsSearch-test.tsx deleted file mode 100644 index bc6705d11fe..00000000000 --- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/SettingsSearch-test.tsx +++ /dev/null @@ -1,154 +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 { mockComponent } from '../../../../helpers/mocks/component'; -import { mockDefinition } from '../../../../helpers/mocks/settings'; -import { mockRouter } from '../../../../helpers/testMocks'; -import { mockEvent, waitAndUpdate } from '../../../../helpers/testUtils'; -import { queryToSearch } from '../../../../helpers/urls'; -import { SettingsSearch } from '../SettingsSearch'; - -jest.mock('lunr', () => - jest.fn(() => ({ - search: jest.fn(() => [ - { - ref: 'foo', - }, - { - ref: 'sonar.new_code_period', - }, - ]), - })) -); - -describe('instance', () => { - const router = mockRouter(); - const wrapper = shallowRender({ router }); - - it('should build the index', () => { - expect(wrapper.instance().index).not.toBeNull(); - - const def = mockDefinition(); - expect(wrapper.instance().definitionsByKey).toEqual( - expect.objectContaining({ [def.key]: def }) - ); - }); - - it('should handle search', async () => { - wrapper.instance().handleSearchChange('query'); - - await waitAndUpdate(wrapper); - expect(wrapper.state().searchQuery).toBe('query'); - - expect(wrapper.instance().index.search).toHaveBeenCalled(); - expect(wrapper.state().showResults).toBe(true); - expect(wrapper.state().results).toHaveLength(2); - }); - - it('should handle empty search', async () => { - wrapper.instance().handleSearchChange(''); - - await waitAndUpdate(wrapper); - expect(wrapper.state().searchQuery).toBe(''); - - expect(wrapper.instance().index.search).toHaveBeenCalled(); - expect(wrapper.state().showResults).toBe(false); - }); - - it('should hide results', () => { - wrapper.setState({ showResults: true }); - wrapper.instance().hideResults(); - expect(wrapper.state().showResults).toBe(false); - wrapper.instance().hideResults(); - }); - - it('should handle focus', () => { - wrapper.setState({ searchQuery: 'hi', showResults: false }); - wrapper.instance().handleFocus(); - expect(wrapper.state().showResults).toBe(true); - - wrapper.setState({ searchQuery: '', showResults: false }); - wrapper.instance().handleFocus(); - expect(wrapper.state().showResults).toBe(false); - }); - - it('should handle mouseover', () => { - wrapper.setState({ selectedResult: undefined }); - wrapper.instance().handleMouseOverResult('selection'); - expect(wrapper.state().selectedResult).toBe('selection'); - }); - - it('should handle "enter" keyboard event', () => { - wrapper.setState({ selectedResult: undefined }); - wrapper.instance().handleKeyDown(mockEvent({ nativeEvent: { key: KeyboardKeys.Enter } })); - expect(router.push).not.toHaveBeenCalled(); - - wrapper.setState({ selectedResult: 'foo' }); - wrapper.instance().handleKeyDown(mockEvent({ nativeEvent: { key: KeyboardKeys.Enter } })); - - expect(router.push).toHaveBeenCalledWith({ - hash: '#foo', - pathname: '/admin/settings', - search: queryToSearch({ category: 'foo category' }), - }); - }); - - it('should handle "down" keyboard event', () => { - wrapper.setState({ selectedResult: undefined }); - wrapper.instance().handleKeyDown(mockEvent({ nativeEvent: { key: KeyboardKeys.DownArrow } })); - expect(wrapper.state().selectedResult).toBeUndefined(); - - wrapper.setState({ selectedResult: 'foo' }); - wrapper.instance().handleKeyDown(mockEvent({ nativeEvent: { key: KeyboardKeys.DownArrow } })); - expect(wrapper.state().selectedResult).toBe('sonar.new_code_period'); - - wrapper.instance().handleKeyDown(mockEvent({ nativeEvent: { key: KeyboardKeys.DownArrow } })); - expect(wrapper.state().selectedResult).toBe('sonar.new_code_period'); - }); - - it('should handle "up" keyboard event', () => { - wrapper.setState({ selectedResult: undefined }); - wrapper.instance().handleKeyDown(mockEvent({ nativeEvent: { key: KeyboardKeys.UpArrow } })); - expect(wrapper.state().selectedResult).toBeUndefined(); - - wrapper.setState({ selectedResult: 'sonar.new_code_period' }); - wrapper.instance().handleKeyDown(mockEvent({ nativeEvent: { key: KeyboardKeys.UpArrow } })); - expect(wrapper.state().selectedResult).toBe('foo'); - - wrapper.instance().handleKeyDown(mockEvent({ nativeEvent: { key: KeyboardKeys.UpArrow } })); - expect(wrapper.state().selectedResult).toBe('foo'); - }); -}); - -describe('project settings search', () => { - it('should load the correct definitions', () => { - const wrapper = shallowRender({ component: mockComponent(), definitions: [] }); - - expect(Object.keys(wrapper.instance().definitionsByKey)).toHaveLength(1); - }); -}); - -function shallowRender(overrides: Partial = {}) { - return shallow( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/SettingsSearchRenderer-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/__tests__/SettingsSearchRenderer-test.tsx deleted file mode 100644 index 184dea62b53..00000000000 --- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/SettingsSearchRenderer-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 { mockDefinition } from '../../../../helpers/mocks/settings'; -import { scrollToElement } from '../../../../helpers/scrolling'; -import SettingsSearchRenderer, { SettingsSearchRendererProps } from '../SettingsSearchRenderer'; - -jest.mock('../../../../helpers/scrolling', () => ({ - scrollToElement: jest.fn(), -})); - -jest.mock('react', () => { - return { - ...jest.requireActual('react'), - useRef: jest.fn(), - useEffect: jest.fn(), - }; -}); - -afterAll(() => { - jest.clearAllMocks(); -}); - -it('should render correctly when closed', () => { - expect(shallowRender()).toMatchSnapshot(); -}); - -it('should render correctly when open', () => { - expect(shallowRender({ showResults: true })).toMatchSnapshot('no results'); - expect( - shallowRender({ - results: [mockDefinition({ name: 'Foo!' }), mockDefinition({ key: 'bar' })], - selectedResult: 'bar', - showResults: true, - }) - ).toMatchSnapshot('results'); -}); - -it('should scroll to selected element', () => { - const scrollable = {}; - const scrollableRef = { current: scrollable }; - const selected = {}; - const selectedRef = { current: selected }; - - (React.useRef as jest.Mock) - .mockImplementationOnce(() => scrollableRef) - .mockImplementationOnce(() => selectedRef); - (React.useEffect as jest.Mock).mockImplementationOnce((f) => f()); - - shallowRender(); - - expect(scrollToElement).toHaveBeenCalled(); -}); - -function shallowRender(overrides: Partial = {}) { - return shallow( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/SubCategoryDefinitionsList-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/__tests__/SubCategoryDefinitionsList-test.tsx deleted file mode 100644 index f71fec69b3a..00000000000 --- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/SubCategoryDefinitionsList-test.tsx +++ /dev/null @@ -1,75 +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 { mount, shallow } from 'enzyme'; -import * as React from 'react'; -import { mockSettingWithCategory } from '../../../../helpers/mocks/settings'; -import { mockLocation } from '../../../../helpers/testMocks'; -import { waitAndUpdate } from '../../../../helpers/testUtils'; -import { - SubCategoryDefinitionsList, - SubCategoryDefinitionsListProps, -} from '../SubCategoryDefinitionsList'; - -jest.mock('../../../../helpers/scrolling', () => ({ - scrollToElement: jest.fn(), -})); - -it('should render correctly', () => { - expect(shallowRender()).toMatchSnapshot(''); - expect(shallowRender({ subCategory: 'qg' })).toMatchSnapshot('subcategory'); -}); - -it('should scroll if hash is defined and updated', async () => { - window.HTMLElement.prototype.scrollIntoView = jest.fn(); - const wrapper = shallowRender({ location: mockLocation({ hash: '#qg' }) }); - - await waitAndUpdate(wrapper); - - wrapper.find('h2').forEach((node) => mount(node.getElement())); - - expect(window.HTMLElement.prototype.scrollIntoView).toHaveBeenCalled(); - - wrapper.setProps({ location: mockLocation({ hash: '#email' }) }); - - expect(window.HTMLElement.prototype.scrollIntoView).toHaveBeenCalled(); -}); - -function shallowRender(props: Partial = {}) { - return shallow( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AdditionalCategories-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AdditionalCategories-test.tsx.snap deleted file mode 100644 index 1458c61e3d4..00000000000 --- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AdditionalCategories-test.tsx.snap +++ /dev/null @@ -1,150 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render additional categories component correctly 1`] = ` - -`; - -exports[`should render additional categories component correctly 2`] = ``; - -exports[`should render additional categories component correctly 3`] = ` - -`; - -exports[`should render additional categories component correctly 4`] = ` - -`; - -exports[`should render additional categories component correctly 5`] = ` - -`; - -exports[`should render additional categories component correctly 6`] = ` - -`; diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AnalysisScope-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AnalysisScope-test.tsx.snap deleted file mode 100644 index 1a40aa6ea1d..00000000000 --- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AnalysisScope-test.tsx.snap +++ /dev/null @@ -1,77 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly 1`] = ` - -

      - settings.analysis_scope.wildcards.introduction - - learn_more - -

      - - - - - - - - - - - - - - - -
      - * - - settings.analysis_scope.wildcards.zero_more_char -
      - ** - - settings.analysis_scope.wildcards.zero_more_dir -
      - ? - - settings.analysis_scope.wildcards.single_char -
      -
      - -
      -
      -`; diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/DefinitionActions-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/DefinitionActions-test.tsx.snap deleted file mode 100644 index dddb190a866..00000000000 --- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/DefinitionActions-test.tsx.snap +++ /dev/null @@ -1,143 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`disables save button on error 1`] = ` - -
      - - - cancel - -
      -
      -`; - -exports[`displays cancel button when value changed and has error 1`] = ` - -
      - - - cancel - -
      -
      -`; - -exports[`displays cancel button when value changed and no error 1`] = ` - -
      - - - cancel - -
      -
      -`; - -exports[`displays default message when value is default 1`] = ` - -
      - settings._default -
      -
      - - - default - : - settings.default.no_value - -
      -
      -`; - -exports[`displays reset button when empty and not default 1`] = ` - -
      - - - default - : - settings.default.no_value - -
      -
      -`; - -exports[`displays save button when it can be saved 1`] = ` - -
      - - - cancel - -
      -
      -`; diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/DefinitionRenderer-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/DefinitionRenderer-test.tsx.snap deleted file mode 100644 index 021e807d1af..00000000000 --- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/DefinitionRenderer-test.tsx.snap +++ /dev/null @@ -1,571 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly: changed value 1`] = ` -
      -
      -

      - property.foo.name -

      -
      - -
      - settings.key_x.foo -
      -
      -
      -
      -
      -
      - - - -
      -
      -`; - -exports[`should render correctly: in error 1`] = ` -
      -
      -

      - property.foo.name -

      -
      - -
      - settings.key_x.foo -
      -
      -
      -
      -
      - - - - settings.state.validation_failed.validation message - - -
      -
      - - - -
      -
      -`; - -exports[`should render correctly: loading 1`] = ` -
      -
      -

      - property.foo.name -

      -
      - -
      - settings.key_x.foo -
      -
      -
      -
      -
      - - - settings.state.saving - -
      -
      - - - -
      -
      -`; - -exports[`should render correctly: original value 1`] = ` -
      -
      -

      - property.foo.name -

      -
      - -
      - settings.key_x.foo -
      -
      -
      -
      -
      -
      - - - -
      -
      -`; - -exports[`should render correctly: success 1`] = ` -
      -
      -

      - property.foo.name -

      -
      - -
      - settings.key_x.foo -
      -
      -
      -
      -
      - - - settings.state.saved - -
      -
      - - - -
      -
      -`; - -exports[`should render correctly: with description 1`] = ` -
      -
      -

      - property.foo.name -

      -
      - -
      - settings.key_x.foo -
      -
      -
      -
      -
      -
      - - - -
      -
      -`; diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/EmailForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/EmailForm-test.tsx.snap deleted file mode 100644 index a27318bce98..00000000000 --- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/EmailForm-test.tsx.snap +++ /dev/null @@ -1,358 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly: default 1`] = ` -
      -
      -

      - email_configuration.test.title -

      -
      -
      - -
      - - -
      -
      - - -
      -
      - -