Browse Source

SONAR-18438 Migrating unit test for project quality profile page to RTL

tags/10.2.0.77647
Revanshu Paliwal 9 months ago
parent
commit
2c87d302b7
13 changed files with 261 additions and 2073 deletions
  1. 0
    235
      server/sonar-web/src/main/js/apps/projectQualityProfiles/__tests__/ProjectQualityProfilesApp-test.tsx
  2. 0
    91
      server/sonar-web/src/main/js/apps/projectQualityProfiles/__tests__/ProjectQualityProfilesAppRenderer-test.tsx
  3. 0
    51
      server/sonar-web/src/main/js/apps/projectQualityProfiles/__tests__/__snapshots__/ProjectQualityProfilesApp-test.tsx.snap
  4. 0
    920
      server/sonar-web/src/main/js/apps/projectQualityProfiles/__tests__/__snapshots__/ProjectQualityProfilesAppRenderer-test.tsx.snap
  5. 252
    0
      server/sonar-web/src/main/js/apps/projectQualityProfiles/__tests__/projectQualityProfilesApp-it.tsx
  6. 7
    1
      server/sonar-web/src/main/js/apps/projectQualityProfiles/components/AddLanguageModal.tsx
  7. 2
    1
      server/sonar-web/src/main/js/apps/projectQualityProfiles/components/SetQualityProfileModal.tsx
  8. 0
    106
      server/sonar-web/src/main/js/apps/projectQualityProfiles/components/__tests__/AddLanguageModal-test.tsx
  9. 0
    52
      server/sonar-web/src/main/js/apps/projectQualityProfiles/components/__tests__/LanguageProfileSelectOption-test.tsx
  10. 0
    82
      server/sonar-web/src/main/js/apps/projectQualityProfiles/components/__tests__/SetQualityProfileModal-test.tsx
  11. 0
    95
      server/sonar-web/src/main/js/apps/projectQualityProfiles/components/__tests__/__snapshots__/AddLanguageModal-test.tsx.snap
  12. 0
    55
      server/sonar-web/src/main/js/apps/projectQualityProfiles/components/__tests__/__snapshots__/LanguageProfileSelectOption-test.tsx.snap
  13. 0
    384
      server/sonar-web/src/main/js/apps/projectQualityProfiles/components/__tests__/__snapshots__/SetQualityProfileModal-test.tsx.snap

+ 0
- 235
server/sonar-web/src/main/js/apps/projectQualityProfiles/__tests__/ProjectQualityProfilesApp-test.tsx View File

@@ -1,235 +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 {
associateProject,
dissociateProject,
getProfileProjects,
ProfileProject,
searchQualityProfiles,
} from '../../../api/quality-profiles';
import handleRequiredAuthorization from '../../../app/utils/handleRequiredAuthorization';
import { mockComponent } from '../../../helpers/mocks/component';
import { waitAndUpdate } from '../../../helpers/testUtils';
import { ProjectQualityProfilesApp } from '../ProjectQualityProfilesApp';

jest.mock('../../../api/quality-profiles', () => {
const { mockQualityProfile } = jest.requireActual('../../../helpers/testMocks');

return {
associateProject: jest.fn().mockResolvedValue({}),
dissociateProject: jest.fn().mockResolvedValue({}),
searchQualityProfiles: jest.fn().mockResolvedValue({
profiles: [
mockQualityProfile({ key: 'css', language: 'css' }),
mockQualityProfile({ key: 'css2', language: 'css' }),
mockQualityProfile({ key: 'css_default', language: 'css', isDefault: true }),
mockQualityProfile({ key: 'java', language: 'java' }),
mockQualityProfile({ key: 'java_default', language: 'java', isDefault: true }),
mockQualityProfile({ key: 'js', language: 'js' }),
mockQualityProfile({ key: 'js_default', language: 'js', isDefault: true }),
mockQualityProfile({ key: 'ts_default', language: 'ts', isDefault: true }),
mockQualityProfile({ key: 'html', language: 'html' }),
mockQualityProfile({ key: 'html_default', language: 'html', isDefault: true }),
],
}),
getProfileProjects: jest.fn(({ key }) => {
const results: ProfileProject[] = [];
if (key === 'js' || key === 'css' || key === 'html_default') {
results.push({
key: 'foo',
name: 'Foo',
selected: true,
});
} else if (key === 'html') {
results.push({
key: 'foobar',
name: 'FooBar',
selected: true,
});
}
return Promise.resolve({ results });
}),
};
});

jest.mock('../../../helpers/globalMessages', () => ({
addGlobalSuccessMessage: jest.fn(),
}));

jest.mock('../../../app/utils/handleRequiredAuthorization', () => jest.fn());

beforeEach(jest.clearAllMocks);

it('renders correctly', () => {
expect(shallowRender()).toMatchSnapshot();
});

it('correctly checks permissions', () => {
const wrapper = shallowRender({
component: mockComponent({ configuration: { showQualityProfiles: false } }),
});
expect(wrapper.type()).toBeNull();
expect(handleRequiredAuthorization).toHaveBeenCalled();
});

it('correctly fetches and treats profile data', async () => {
const wrapper = shallowRender();
await waitAndUpdate(wrapper);

expect(searchQualityProfiles).toHaveBeenCalled();
expect(getProfileProjects).toHaveBeenCalledTimes(10);

expect(wrapper.state().projectProfiles).toEqual([
expect.objectContaining({
profile: expect.objectContaining({ key: 'css' }),
selected: true,
}),
expect.objectContaining({
profile: expect.objectContaining({ key: 'js' }),
selected: true,
}),
expect.objectContaining({
profile: expect.objectContaining({ key: 'html_default' }),
selected: true,
}),
expect.objectContaining({
profile: expect.objectContaining({ key: 'ts_default' }),
selected: false,
}),
]);
});

it('correctly sets a profile', async () => {
const wrapper = shallowRender();
const instance = wrapper.instance();
await waitAndUpdate(wrapper);

// Dissociate a selected profile.
instance.handleSetProfile(undefined, 'css');
expect(dissociateProject).toHaveBeenLastCalledWith(
expect.objectContaining({ key: 'css' }),
'foo'
);
await waitAndUpdate(wrapper);
expect(wrapper.state().projectProfiles).toEqual(
expect.arrayContaining([
{
profile: expect.objectContaining({ key: 'css_default' }),
// It's not explicitly selected, as we're inheriting the default.
selected: false,
},
])
);

// Associate a new profile.
instance.handleSetProfile('css2', 'css_default');
expect(associateProject).toHaveBeenLastCalledWith(
expect.objectContaining({ key: 'css2' }),
'foo'
);
await waitAndUpdate(wrapper);
expect(wrapper.state().projectProfiles).toEqual(
expect.arrayContaining([
{
profile: expect.objectContaining({ key: 'css2' }),
// It's explicitly selected.
selected: true,
},
])
);

// Dissociate a default profile that was inherited.
(dissociateProject as jest.Mock).mockClear();
instance.handleSetProfile(undefined, 'ts_default');
// It won't call the WS.
expect(dissociateProject).not.toHaveBeenCalled();

// Associate a default profile that was already inherited.
instance.handleSetProfile('ts_default', 'ts_default');
expect(associateProject).toHaveBeenLastCalledWith(
expect.objectContaining({ key: 'ts_default' }),
'foo'
);
await waitAndUpdate(wrapper);
expect(wrapper.state().projectProfiles).toEqual(
expect.arrayContaining([
{
profile: expect.objectContaining({ key: 'ts_default' }),
// It's explicitly selected, even though it is the default profile.
selected: true,
},
])
);
});

it('correctly adds a new language', async () => {
const wrapper = shallowRender();
const instance = wrapper.instance();
await waitAndUpdate(wrapper);

instance.handleAddLanguage('java');
expect(associateProject).toHaveBeenLastCalledWith(
expect.objectContaining({ key: 'java' }),
'foo'
);
await waitAndUpdate(wrapper);
expect(wrapper.state().projectProfiles).toEqual(
expect.arrayContaining([
{
profile: expect.objectContaining({ key: 'java' }),
// It must be explicitly selected. Adding an unanalyzed language can
// only happen by explicitly choosing a profile.
selected: true,
},
])
);
});

it('correctly handles WS errors', async () => {
(searchQualityProfiles as jest.Mock).mockRejectedValueOnce(null);
(getProfileProjects as jest.Mock).mockRejectedValueOnce(null);

const wrapper = shallowRender();
await waitAndUpdate(wrapper);

expect(wrapper.state().allProfiles).toHaveLength(0);
expect(wrapper.state().projectProfiles).toHaveLength(0);
expect(wrapper.state().loading).toBe(false);
});

function shallowRender(props: Partial<ProjectQualityProfilesApp['props']> = {}) {
return shallow<ProjectQualityProfilesApp>(
<ProjectQualityProfilesApp
component={mockComponent({
key: 'foo',
configuration: { showQualityProfiles: true },
qualityProfiles: [
{ key: 'css2', name: 'CSS 2', language: 'css' },
{ key: 'js', name: 'JS', language: 'js' },
{ key: 'ts_default', name: 'TS (default)', language: 'ts' },
{ key: 'html', name: 'HTML', language: 'html' },
],
})}
{...props}
/>
);
}

+ 0
- 91
server/sonar-web/src/main/js/apps/projectQualityProfiles/__tests__/ProjectQualityProfilesAppRenderer-test.tsx View File

@@ -1,91 +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 { mockQualityProfile } from '../../../helpers/testMocks';
import ProjectQualityProfilesAppRenderer, {
ProjectQualityProfilesAppRendererProps,
} from '../ProjectQualityProfilesAppRenderer';

it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot('default');
expect(shallowRender({ loading: true })).toMatchSnapshot('loading');
expect(
shallowRender({
showProjectProfileInModal: {
profile: mockQualityProfile({ key: 'foo', language: 'js' }),
selected: false,
},
})
).toMatchSnapshot('open profile');
expect(shallowRender({ showAddLanguageModal: true })).toMatchSnapshot('add language');
});

function shallowRender(props: Partial<ProjectQualityProfilesAppRendererProps> = {}) {
return shallow<ProjectQualityProfilesAppRendererProps>(
<ProjectQualityProfilesAppRenderer
allProfiles={[
mockQualityProfile({ key: 'foo', language: 'js' }),
mockQualityProfile({ key: 'bar', language: 'css' }),
mockQualityProfile({ key: 'baz', language: 'html' }),
]}
component={mockComponent()}
loading={false}
onAddLanguage={jest.fn()}
onCloseModal={jest.fn()}
onOpenAddLanguageModal={jest.fn()}
onOpenSetProfileModal={jest.fn()}
onSetProfile={jest.fn()}
projectProfiles={[
{
profile: mockQualityProfile({
key: 'foo',
name: 'Foo',
isDefault: true,
language: 'js',
languageName: 'JS',
}),
selected: false,
},
{
profile: mockQualityProfile({
key: 'bar',
name: 'Bar',
isDefault: true,
language: 'css',
languageName: 'CSS',
}),
selected: false,
},
{
profile: mockQualityProfile({
key: 'baz',
name: 'Baz',
language: 'html',
languageName: 'HTML',
}),
selected: true,
},
]}
{...props}
/>
);
}

+ 0
- 51
server/sonar-web/src/main/js/apps/projectQualityProfiles/__tests__/__snapshots__/ProjectQualityProfilesApp-test.tsx.snap View File

@@ -1,51 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`renders correctly 1`] = `
<ProjectQualityProfilesAppRenderer
component={
{
"breadcrumbs": [],
"configuration": {
"showQualityProfiles": true,
},
"key": "foo",
"name": "MyProject",
"qualifier": "TRK",
"qualityGate": {
"isDefault": true,
"key": "30",
"name": "Sonar way",
},
"qualityProfiles": [
{
"key": "css2",
"language": "css",
"name": "CSS 2",
},
{
"key": "js",
"language": "js",
"name": "JS",
},
{
"key": "ts_default",
"language": "ts",
"name": "TS (default)",
},
{
"key": "html",
"language": "html",
"name": "HTML",
},
],
"tags": [],
}
}
loading={true}
onAddLanguage={[Function]}
onCloseModal={[Function]}
onOpenAddLanguageModal={[Function]}
onOpenSetProfileModal={[Function]}
onSetProfile={[Function]}
/>
`;

+ 0
- 920
server/sonar-web/src/main/js/apps/projectQualityProfiles/__tests__/__snapshots__/ProjectQualityProfilesAppRenderer-test.tsx.snap View File

@@ -1,920 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should render correctly: add language 1`] = `
<div
className="page page-limited"
id="project-quality-profiles"
>
<Suggestions
suggestions="project_quality_profiles"
/>
<Helmet
defer={false}
encodeSpecialCharacters={true}
prioritizeSeoTags={false}
title="project_quality_profiles.page"
/>
<A11ySkipTarget
anchor="profiles_main"
/>
<header
className="page-header"
>
<div
className="page-title display-flex-center"
>
<h1>
project_quality_profiles.page
</h1>
<HelpTooltip
className="spacer-left"
overlay={
<div
className="big-padded-top big-padded-bottom"
>
quality_profiles.list.projects.help
</div>
}
/>
</div>
</header>
<div
className="boxed-group"
>
<h2
className="boxed-group-header"
>
project_quality_profile.subtitle
</h2>
<div
className="boxed-group-inner"
>
<p
className="big-spacer-bottom"
>
project_quality_profiles.page.description
</p>
<table
className="data zebra"
>
<thead>
<tr>
<th>
language
</th>
<th
className="thin nowrap"
>
project_quality_profile.current
</th>
<th
className="thin nowrap text-right"
>
coding_rules.filters.activation.active_rules
</th>
<th
aria-label="actions"
/>
</tr>
</thead>
<tbody>
<tr
key="css"
>
<td>
CSS
</td>
<td
className="thin nowrap"
>
<span
className="display-inline-flex-center"
>
<em>
project_quality_profile.instance_default
</em>
</span>
</td>
<td
className="nowrap text-right"
>
<ForwardRef(Link)
to={
{
"pathname": "/coding_rules",
"search": "?activation=true&qprofile=bar",
}
}
>
10
</ForwardRef(Link)>
</td>
<td
className="text-right"
>
<Button
onClick={[Function]}
>
<EditIcon
className="spacer-right"
/>
project_quality_profile.change_profile
</Button>
</td>
</tr>
<tr
key="html"
>
<td>
HTML
</td>
<td
className="thin nowrap"
>
<span
className="display-inline-flex-center"
>
Baz
</span>
</td>
<td
className="nowrap text-right"
>
<ForwardRef(Link)
to={
{
"pathname": "/coding_rules",
"search": "?activation=true&qprofile=baz",
}
}
>
10
</ForwardRef(Link)>
</td>
<td
className="text-right"
>
<Button
onClick={[Function]}
>
<EditIcon
className="spacer-right"
/>
project_quality_profile.change_profile
</Button>
</td>
</tr>
<tr
key="js"
>
<td>
JS
</td>
<td
className="thin nowrap"
>
<span
className="display-inline-flex-center"
>
<em>
project_quality_profile.instance_default
</em>
</span>
</td>
<td
className="nowrap text-right"
>
<ForwardRef(Link)
to={
{
"pathname": "/coding_rules",
"search": "?activation=true&qprofile=foo",
}
}
>
10
</ForwardRef(Link)>
</td>
<td
className="text-right"
>
<Button
onClick={[Function]}
>
<EditIcon
className="spacer-right"
/>
project_quality_profile.change_profile
</Button>
</td>
</tr>
</tbody>
</table>
<div
className="big-spacer-top"
>
<h2>
project_quality_profile.add_language.title
</h2>
<p
className="spacer-top big-spacer-bottom"
>
project_quality_profile.add_language.description
</p>
<Button
disabled={false}
onClick={[MockFunction]}
>
<PlusCircleIcon
className="little-spacer-right"
/>
project_quality_profile.add_language.action
</Button>
</div>
<withLanguagesContext(AddLanguageModal)
onClose={[MockFunction]}
onSubmit={[MockFunction]}
profilesByLanguage={
{
"css": [
{
"activeDeprecatedRuleCount": 2,
"activeRuleCount": 10,
"childrenCount": 0,
"depth": 1,
"isBuiltIn": false,
"isDefault": false,
"isInherited": false,
"key": "bar",
"language": "css",
"languageName": "JavaScript",
"name": "name",
"projectCount": 3,
},
],
"html": [
{
"activeDeprecatedRuleCount": 2,
"activeRuleCount": 10,
"childrenCount": 0,
"depth": 1,
"isBuiltIn": false,
"isDefault": false,
"isInherited": false,
"key": "baz",
"language": "html",
"languageName": "JavaScript",
"name": "name",
"projectCount": 3,
},
],
"js": [
{
"activeDeprecatedRuleCount": 2,
"activeRuleCount": 10,
"childrenCount": 0,
"depth": 1,
"isBuiltIn": false,
"isDefault": false,
"isInherited": false,
"key": "foo",
"language": "js",
"languageName": "JavaScript",
"name": "name",
"projectCount": 3,
},
],
}
}
unavailableLanguages={
[
"js",
"css",
"html",
]
}
/>
</div>
</div>
</div>
`;

exports[`should render correctly: default 1`] = `
<div
className="page page-limited"
id="project-quality-profiles"
>
<Suggestions
suggestions="project_quality_profiles"
/>
<Helmet
defer={false}
encodeSpecialCharacters={true}
prioritizeSeoTags={false}
title="project_quality_profiles.page"
/>
<A11ySkipTarget
anchor="profiles_main"
/>
<header
className="page-header"
>
<div
className="page-title display-flex-center"
>
<h1>
project_quality_profiles.page
</h1>
<HelpTooltip
className="spacer-left"
overlay={
<div
className="big-padded-top big-padded-bottom"
>
quality_profiles.list.projects.help
</div>
}
/>
</div>
</header>
<div
className="boxed-group"
>
<h2
className="boxed-group-header"
>
project_quality_profile.subtitle
</h2>
<div
className="boxed-group-inner"
>
<p
className="big-spacer-bottom"
>
project_quality_profiles.page.description
</p>
<table
className="data zebra"
>
<thead>
<tr>
<th>
language
</th>
<th
className="thin nowrap"
>
project_quality_profile.current
</th>
<th
className="thin nowrap text-right"
>
coding_rules.filters.activation.active_rules
</th>
<th
aria-label="actions"
/>
</tr>
</thead>
<tbody>
<tr
key="css"
>
<td>
CSS
</td>
<td
className="thin nowrap"
>
<span
className="display-inline-flex-center"
>
<em>
project_quality_profile.instance_default
</em>
</span>
</td>
<td
className="nowrap text-right"
>
<ForwardRef(Link)
to={
{
"pathname": "/coding_rules",
"search": "?activation=true&qprofile=bar",
}
}
>
10
</ForwardRef(Link)>
</td>
<td
className="text-right"
>
<Button
onClick={[Function]}
>
<EditIcon
className="spacer-right"
/>
project_quality_profile.change_profile
</Button>
</td>
</tr>
<tr
key="html"
>
<td>
HTML
</td>
<td
className="thin nowrap"
>
<span
className="display-inline-flex-center"
>
Baz
</span>
</td>
<td
className="nowrap text-right"
>
<ForwardRef(Link)
to={
{
"pathname": "/coding_rules",
"search": "?activation=true&qprofile=baz",
}
}
>
10
</ForwardRef(Link)>
</td>
<td
className="text-right"
>
<Button
onClick={[Function]}
>
<EditIcon
className="spacer-right"
/>
project_quality_profile.change_profile
</Button>
</td>
</tr>
<tr
key="js"
>
<td>
JS
</td>
<td
className="thin nowrap"
>
<span
className="display-inline-flex-center"
>
<em>
project_quality_profile.instance_default
</em>
</span>
</td>
<td
className="nowrap text-right"
>
<ForwardRef(Link)
to={
{
"pathname": "/coding_rules",
"search": "?activation=true&qprofile=foo",
}
}
>
10
</ForwardRef(Link)>
</td>
<td
className="text-right"
>
<Button
onClick={[Function]}
>
<EditIcon
className="spacer-right"
/>
project_quality_profile.change_profile
</Button>
</td>
</tr>
</tbody>
</table>
<div
className="big-spacer-top"
>
<h2>
project_quality_profile.add_language.title
</h2>
<p
className="spacer-top big-spacer-bottom"
>
project_quality_profile.add_language.description
</p>
<Button
disabled={false}
onClick={[MockFunction]}
>
<PlusCircleIcon
className="little-spacer-right"
/>
project_quality_profile.add_language.action
</Button>
</div>
</div>
</div>
</div>
`;

exports[`should render correctly: loading 1`] = `
<div
className="page page-limited"
id="project-quality-profiles"
>
<Suggestions
suggestions="project_quality_profiles"
/>
<Helmet
defer={false}
encodeSpecialCharacters={true}
prioritizeSeoTags={false}
title="project_quality_profiles.page"
/>
<A11ySkipTarget
anchor="profiles_main"
/>
<header
className="page-header"
>
<div
className="page-title display-flex-center"
>
<h1>
project_quality_profiles.page
</h1>
<HelpTooltip
className="spacer-left"
overlay={
<div
className="big-padded-top big-padded-bottom"
>
quality_profiles.list.projects.help
</div>
}
/>
</div>
</header>
<div
className="boxed-group"
>
<h2
className="boxed-group-header"
>
project_quality_profile.subtitle
</h2>
<div
className="boxed-group-inner"
>
<p
className="big-spacer-bottom"
>
project_quality_profiles.page.description
</p>
<i
className="spinner spacer-left"
/>
<div
className="big-spacer-top"
>
<h2>
project_quality_profile.add_language.title
</h2>
<p
className="spacer-top big-spacer-bottom"
>
project_quality_profile.add_language.description
</p>
<Button
disabled={true}
onClick={[MockFunction]}
>
<PlusCircleIcon
className="little-spacer-right"
/>
project_quality_profile.add_language.action
</Button>
</div>
</div>
</div>
</div>
`;

exports[`should render correctly: open profile 1`] = `
<div
className="page page-limited"
id="project-quality-profiles"
>
<Suggestions
suggestions="project_quality_profiles"
/>
<Helmet
defer={false}
encodeSpecialCharacters={true}
prioritizeSeoTags={false}
title="project_quality_profiles.page"
/>
<A11ySkipTarget
anchor="profiles_main"
/>
<header
className="page-header"
>
<div
className="page-title display-flex-center"
>
<h1>
project_quality_profiles.page
</h1>
<HelpTooltip
className="spacer-left"
overlay={
<div
className="big-padded-top big-padded-bottom"
>
quality_profiles.list.projects.help
</div>
}
/>
</div>
</header>
<div
className="boxed-group"
>
<h2
className="boxed-group-header"
>
project_quality_profile.subtitle
</h2>
<div
className="boxed-group-inner"
>
<p
className="big-spacer-bottom"
>
project_quality_profiles.page.description
</p>
<table
className="data zebra"
>
<thead>
<tr>
<th>
language
</th>
<th
className="thin nowrap"
>
project_quality_profile.current
</th>
<th
className="thin nowrap text-right"
>
coding_rules.filters.activation.active_rules
</th>
<th
aria-label="actions"
/>
</tr>
</thead>
<tbody>
<tr
key="css"
>
<td>
CSS
</td>
<td
className="thin nowrap"
>
<span
className="display-inline-flex-center"
>
<em>
project_quality_profile.instance_default
</em>
</span>
</td>
<td
className="nowrap text-right"
>
<ForwardRef(Link)
to={
{
"pathname": "/coding_rules",
"search": "?activation=true&qprofile=bar",
}
}
>
10
</ForwardRef(Link)>
</td>
<td
className="text-right"
>
<Button
onClick={[Function]}
>
<EditIcon
className="spacer-right"
/>
project_quality_profile.change_profile
</Button>
</td>
</tr>
<tr
key="html"
>
<td>
HTML
</td>
<td
className="thin nowrap"
>
<span
className="display-inline-flex-center"
>
Baz
</span>
</td>
<td
className="nowrap text-right"
>
<ForwardRef(Link)
to={
{
"pathname": "/coding_rules",
"search": "?activation=true&qprofile=baz",
}
}
>
10
</ForwardRef(Link)>
</td>
<td
className="text-right"
>
<Button
onClick={[Function]}
>
<EditIcon
className="spacer-right"
/>
project_quality_profile.change_profile
</Button>
</td>
</tr>
<tr
key="js"
>
<td>
JS
</td>
<td
className="thin nowrap"
>
<span
className="display-inline-flex-center"
>
<em>
project_quality_profile.instance_default
</em>
</span>
</td>
<td
className="nowrap text-right"
>
<ForwardRef(Link)
to={
{
"pathname": "/coding_rules",
"search": "?activation=true&qprofile=foo",
}
}
>
10
</ForwardRef(Link)>
</td>
<td
className="text-right"
>
<Button
onClick={[Function]}
>
<EditIcon
className="spacer-right"
/>
project_quality_profile.change_profile
</Button>
</td>
</tr>
</tbody>
</table>
<div
className="big-spacer-top"
>
<h2>
project_quality_profile.add_language.title
</h2>
<p
className="spacer-top big-spacer-bottom"
>
project_quality_profile.add_language.description
</p>
<Button
disabled={false}
onClick={[MockFunction]}
>
<PlusCircleIcon
className="little-spacer-right"
/>
project_quality_profile.add_language.action
</Button>
</div>
<SetQualityProfileModal
availableProfiles={
[
{
"activeDeprecatedRuleCount": 2,
"activeRuleCount": 10,
"childrenCount": 0,
"depth": 1,
"isBuiltIn": false,
"isDefault": false,
"isInherited": false,
"key": "foo",
"language": "js",
"languageName": "JavaScript",
"name": "name",
"projectCount": 3,
},
]
}
component={
{
"breadcrumbs": [],
"key": "my-project",
"name": "MyProject",
"qualifier": "TRK",
"qualityGate": {
"isDefault": true,
"key": "30",
"name": "Sonar way",
},
"qualityProfiles": [
{
"deleted": false,
"key": "my-qp",
"language": "ts",
"name": "Sonar way",
},
],
"tags": [],
}
}
currentProfile={
{
"activeDeprecatedRuleCount": 2,
"activeRuleCount": 10,
"childrenCount": 0,
"depth": 1,
"isBuiltIn": false,
"isDefault": false,
"isInherited": false,
"key": "foo",
"language": "js",
"languageName": "JavaScript",
"name": "name",
"projectCount": 3,
}
}
onClose={[MockFunction]}
onSubmit={[MockFunction]}
usesDefault={true}
/>
</div>
</div>
</div>
`;

+ 252
- 0
server/sonar-web/src/main/js/apps/projectQualityProfiles/__tests__/projectQualityProfilesApp-it.tsx View File

@@ -0,0 +1,252 @@
/*
* SonarQube
* Copyright (C) 2009-2023 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

import userEvent from '@testing-library/user-event';
import selectEvent from 'react-select-event';
import {
ProfileProject,
associateProject,
getProfileProjects,
searchQualityProfiles,
} from '../../../api/quality-profiles';
import handleRequiredAuthorization from '../../../app/utils/handleRequiredAuthorization';
import { addGlobalSuccessMessage } from '../../../helpers/globalMessages';
import { mockComponent } from '../../../helpers/mocks/component';
import {
RenderContext,
renderAppWithComponentContext,
} from '../../../helpers/testReactTestingUtils';
import { byLabelText, byRole, byText } from '../../../helpers/testSelector';
import { Component } from '../../../types/types';
import routes from '../routes';

jest.mock('../../../api/quality-profiles', () => {
const { mockQualityProfile } = jest.requireActual('../../../helpers/testMocks');

return {
associateProject: jest.fn().mockResolvedValue({}),
dissociateProject: jest.fn().mockResolvedValue({}),
searchQualityProfiles: jest.fn().mockResolvedValue({
profiles: [
mockQualityProfile({
key: 'css',
language: 'css',
name: 'css profile',
languageName: 'CSS',
}),
mockQualityProfile({
key: 'java',
language: 'java',
name: 'java profile',
languageName: 'Java',
}),
mockQualityProfile({
key: 'js',
language: 'js',
name: 'js profile',
languageName: 'JavaScript',
}),
mockQualityProfile({
key: 'ts',
language: 'ts',
isDefault: true,
name: 'ts profile',
languageName: 'Typescript',
}),
mockQualityProfile({
key: 'html',
language: 'html',
name: 'html profile',
languageName: 'HTML',
}),
mockQualityProfile({
key: 'html_default',
language: 'html',
isDefault: true,
isBuiltIn: true,
name: 'html default profile',
languageName: 'HTML',
}),
],
}),
getProfileProjects: jest.fn(({ key }) => {
const results: ProfileProject[] = [];
if (key === 'css' || key === 'java' || key === 'js' || key === 'ts' || key === 'java') {
results.push({
key: 'my-project',
name: 'My project',
selected: true,
});
}
return Promise.resolve({ results });
}),
};
});

jest.mock('../../../helpers/globalMessages', () => {
const globalMessages = jest.requireActual('../../../helpers/globalMessages');
return {
...globalMessages,
addGlobalSuccessMessage: jest.fn(),
};
});

jest.mock('../../../app/utils/handleRequiredAuthorization', () => jest.fn());

beforeEach(jest.clearAllMocks);

const ui = {
pageTitle: byText('project_quality_profiles.page'),
pageSubTitle: byText('project_quality_profile.subtitle'),
pageDescription: byText('project_quality_profiles.page.description'),
helpTooltip: byLabelText('help'),
profileRows: byRole('row'),
addLanguageButton: byRole('button', { name: 'project_quality_profile.add_language.action' }),
modalAddLanguageTitle: byText('project_quality_profile.add_language_modal.title'),
selectLanguage: byRole('combobox', {
name: 'project_quality_profile.add_language_modal.choose_language',
}),
selectProfile: byRole('combobox', {
name: 'project_quality_profile.add_language_modal.choose_profile',
}),
selectUseSpecificProfile: byRole('combobox', {
name: 'project_quality_profile.always_use_specific',
}),
buttonSave: byRole('button', { name: 'save' }),
buttonChangeProfile: byRole('button', { name: 'project_quality_profile.change_profile' }),
htmlLanguage: byText('HTML'),
htmlProfile: byText('html profile'),
cssLanguage: byText('CSS'),
cssProfile: byText('css profile'),
htmlDefaultProfile: byText('html default profile'),
htmlActiveRuleslink: byRole('link', { name: '10' }),
radioButtonUseInstanceDefault: byRole('radio', {
name: /project_quality_profile.always_use_default/,
}),
radioButtonUseSpecific: byRole('radio', { name: /project_quality_profile.always_use_specific/ }),
newAnalysisWarningMessage: byText('project_quality_profile.requires_new_analysis'),
builtInTag: byText('quality_profiles.built_in'),
};

it('should be able to add and change profile for languages', async () => {
const user = userEvent.setup();
renderProjectQualityProfilesApp({
languages: {
css: { key: 'css', name: 'CSS' },
ts: { key: 'ts', name: 'TS' },
js: { key: 'js', name: 'JS' },
java: { key: 'java', name: 'JAVA' },
html: { key: 'html', name: 'HTML' },
},
});

expect(ui.pageTitle.get()).toBeInTheDocument();
expect(ui.pageSubTitle.get()).toBeInTheDocument();
expect(ui.pageDescription.get()).toBeInTheDocument();
expect(ui.addLanguageButton.get()).toBeInTheDocument();
await expect(ui.helpTooltip.get()).toHaveATooltipWithContent(
'quality_profiles.list.projects.help'
);
expect(ui.profileRows.getAll()).toHaveLength(5);
expect(ui.cssLanguage.get()).toBeInTheDocument();
expect(ui.cssProfile.get()).toBeInTheDocument();

await user.click(ui.addLanguageButton.get());

// Opens the add language modal
expect(ui.modalAddLanguageTitle.get()).toBeInTheDocument();
expect(ui.selectLanguage.get()).toBeEnabled();
expect(ui.selectProfile.get()).toBeDisabled();
expect(ui.buttonSave.get()).toBeInTheDocument();

await selectEvent.select(ui.selectLanguage.get(), 'HTML');
expect(ui.selectProfile.get()).toBeEnabled();
await selectEvent.select(ui.selectProfile.get(), 'html profile');
await user.click(ui.buttonSave.get());
expect(associateProject).toHaveBeenLastCalledWith(
expect.objectContaining({ key: 'html', name: 'html profile' }),
'my-project'
);
expect(addGlobalSuccessMessage).toHaveBeenCalledWith(
'project_quality_profile.successfully_updated.HTML'
);

// Updates the page after API call
const htmlRow = byRole('row', {
name: 'HTML html profile 10 project_quality_profile.change_profile',
});

expect(ui.htmlLanguage.get()).toBeInTheDocument();
expect(ui.htmlProfile.get()).toBeInTheDocument();
expect(ui.profileRows.getAll()).toHaveLength(6);
expect(htmlRow.get()).toBeInTheDocument();
expect(htmlRow.byRole('link', { name: '10' }).get()).toHaveAttribute(
'href',
'/coding_rules?activation=true&qprofile=html'
);
expect(ui.builtInTag.query()).not.toBeInTheDocument();

await user.click(
htmlRow.byRole('button', { name: 'project_quality_profile.change_profile' }).get()
);

//Opens modal to change profile
expect(ui.radioButtonUseInstanceDefault.get()).not.toBeChecked();
expect(ui.radioButtonUseSpecific.get()).toBeChecked();
expect(ui.newAnalysisWarningMessage.get()).toBeInTheDocument();
expect(ui.selectUseSpecificProfile.get()).toBeInTheDocument();

await selectEvent.select(ui.selectUseSpecificProfile.get(), 'html default profile');
await user.click(ui.buttonSave.get());

expect(addGlobalSuccessMessage).toHaveBeenCalledWith(
'project_quality_profile.successfully_updated.HTML'
);

// Updates the page after API call
expect(ui.htmlProfile.query()).not.toBeInTheDocument();
expect(ui.htmlDefaultProfile.get()).toBeInTheDocument();
expect(ui.builtInTag.get()).toBeInTheDocument();
});

it('should call authorization api when permissions is not proper', () => {
renderProjectQualityProfilesApp({}, { configuration: { showQualityProfiles: false } });
expect(handleRequiredAuthorization).toHaveBeenCalled();
});

it('should still show page with add language button when api fails', () => {
jest.mocked(searchQualityProfiles).mockRejectedValueOnce(null);
jest.mocked(getProfileProjects).mockRejectedValueOnce(null);

renderProjectQualityProfilesApp();
expect(ui.pageTitle.get()).toBeInTheDocument();
expect(ui.pageSubTitle.get()).toBeInTheDocument();
expect(ui.pageDescription.get()).toBeInTheDocument();
expect(ui.addLanguageButton.get()).toBeInTheDocument();
});

function renderProjectQualityProfilesApp(
context?: RenderContext,
componentOverrides: Partial<Component> = { configuration: { showQualityProfiles: true } }
) {
return renderAppWithComponentContext('project/quality_profiles', routes, context, {
component: mockComponent(componentOverrides),
});
}

+ 7
- 1
server/sonar-web/src/main/js/apps/projectQualityProfiles/components/AddLanguageModal.tsx View File

@@ -21,9 +21,9 @@ import { difference } from 'lodash';
import * as React from 'react';
import { Profile } from '../../../api/quality-profiles';
import withLanguagesContext from '../../../app/components/languages/withLanguagesContext';
import { ButtonLink, SubmitButton } from '../../../components/controls/buttons';
import Select, { LabelValueSelectOption } from '../../../components/controls/Select';
import SimpleModal from '../../../components/controls/SimpleModal';
import { ButtonLink, SubmitButton } from '../../../components/controls/buttons';
import { translate } from '../../../helpers/l10n';
import { Languages } from '../../../types/languages';
import { Dict } from '../../../types/types';
@@ -90,6 +90,9 @@ export function AddLanguageModal(props: AddLanguageModalProps) {
className="abs-width-300"
isDisabled={submitting}
id="language"
aria-label={translate(
'project_quality_profile.add_language_modal.choose_language'
)}
onChange={({ value }: LabelValueSelectOption) => {
setSelected({ language: value, key: undefined });
}}
@@ -107,6 +110,9 @@ export function AddLanguageModal(props: AddLanguageModalProps) {
className="abs-width-300"
isDisabled={submitting || !language}
id="profiles"
aria-label={translate(
'project_quality_profile.add_language_modal.choose_profile'
)}
onChange={({ value }: ProfileOption) => setSelected({ language, key: value })}
options={profileOptions}
components={{

+ 2
- 1
server/sonar-web/src/main/js/apps/projectQualityProfiles/components/SetQualityProfileModal.tsx View File

@@ -19,10 +19,10 @@
*/
import * as React from 'react';
import { Profile } from '../../../api/quality-profiles';
import { ButtonLink, SubmitButton } from '../../../components/controls/buttons';
import Radio from '../../../components/controls/Radio';
import Select from '../../../components/controls/Select';
import SimpleModal from '../../../components/controls/SimpleModal';
import { ButtonLink, SubmitButton } from '../../../components/controls/buttons';
import { Alert } from '../../../components/ui/Alert';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { Component } from '../../../types/types';
@@ -126,6 +126,7 @@ export default function SetQualityProfileModal(props: SetQualityProfileModalProp
<div className="display-flex-center">
<Select
className="abs-width-300"
aria-label={translate('project_quality_profile.always_use_specific')}
isDisabled={submitting || hasSelectedSysDefault}
onChange={({ value }: ProfileOption) => setSelected(value)}
options={profileOptions}

+ 0
- 106
server/sonar-web/src/main/js/apps/projectQualityProfiles/components/__tests__/AddLanguageModal-test.tsx View File

@@ -1,106 +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 Select from '../../../../components/controls/Select';
import SimpleModal from '../../../../components/controls/SimpleModal';
import { mockQualityProfile } from '../../../../helpers/testMocks';
import { AddLanguageModal, AddLanguageModalProps } from '../AddLanguageModal';

it('should render correctly', () => {
expect(diveIntoSimpleModal(shallowRender())).toMatchSnapshot('default');
});

it('should correctly handle changes', () => {
const onSubmit = jest.fn();
const wrapper = shallowRender({ onSubmit });

const langSelect = getLanguageSelect(wrapper);
let profileSelect = getProfileSelect(wrapper);

// Language select should only have 2; JS is not available. Profile Select
// should have none, as no language is selected yet.
expect(langSelect.props().options).toHaveLength(2);
expect(profileSelect.props().options).toHaveLength(0);

// Choose CSS.
const langChange = langSelect.props().onChange;

expect(langChange).toBeDefined();

langChange!({ value: 'css' });

// Should now show 2 available profiles.
profileSelect = getProfileSelect(wrapper);
expect(profileSelect.props().options).toHaveLength(2);
expect(profileSelect.props().options).toEqual(
expect.arrayContaining([expect.objectContaining({ isDisabled: true })])
);

// Choose 1 profile.
const profileChange = profileSelect.props().onChange;

expect(profileChange).toBeDefined();

profileChange!({ value: 'css2' });

submitSimpleModal(wrapper);
expect(onSubmit).toHaveBeenLastCalledWith('css2');
});

function diveIntoSimpleModal(wrapper: ShallowWrapper) {
return wrapper.find(SimpleModal).dive().children();
}

function getLanguageSelect(wrapper: ShallowWrapper) {
return diveIntoSimpleModal(wrapper).find(Select).at(0);
}

function getProfileSelect(wrapper: ShallowWrapper) {
return diveIntoSimpleModal(wrapper).find(Select).at(1);
}

function submitSimpleModal(wrapper: ShallowWrapper) {
wrapper.find(SimpleModal).props().onSubmit();
}

function shallowRender(props: Partial<AddLanguageModalProps> = {}) {
return shallow<AddLanguageModalProps>(
<AddLanguageModal
languages={{
css: { key: 'css', name: 'CSS' },
ts: { key: 'ts', name: 'TS' },
js: { key: 'js', name: 'JS' },
}}
onClose={jest.fn()}
onSubmit={jest.fn()}
profilesByLanguage={{
css: [
mockQualityProfile({ key: 'css', name: 'CSS', activeRuleCount: 0 }),
mockQualityProfile({ key: 'css2', name: 'CSS 2' }),
],
ts: [mockQualityProfile({ key: 'ts', name: 'TS' })],
js: [mockQualityProfile({ key: 'js', name: 'JS' })],
}}
unavailableLanguages={['js']}
{...props}
/>
);
}

+ 0
- 52
server/sonar-web/src/main/js/apps/projectQualityProfiles/components/__tests__/LanguageProfileSelectOption-test.tsx View File

@@ -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 { shallow } from 'enzyme';
import * as React from 'react';
import DisableableSelectOption from '../../../../components/common/DisableableSelectOption';
import { mockProfileOption } from '../../../../helpers/mocks/quality-profiles';
import LanguageProfileSelectOption, {
LanguageProfileSelectOptionProps,
ProfileOption,
} from '../LanguageProfileSelectOption';

it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot('default');
});

describe('tooltip', () => {
it('should render correctly', () => {
expect(renderTooltipOverly()).toMatchSnapshot('default');
expect(renderTooltipOverly({ label: undefined })).toMatchSnapshot('no link');
});
});

function renderTooltipOverly(overrides: Partial<ProfileOption> = {}) {
const wrapper = shallowRender(overrides);
const { disableTooltipOverlay } = wrapper.find(DisableableSelectOption).props();
return disableTooltipOverlay();
}

function shallowRender(overrides: Partial<ProfileOption> = {}) {
// satisfy the required props that the option actually gets from the select
const optionProps = {} as LanguageProfileSelectOptionProps;
return shallow(
<LanguageProfileSelectOption {...optionProps} data={{ ...mockProfileOption(), ...overrides }} />
);
}

+ 0
- 82
server/sonar-web/src/main/js/apps/projectQualityProfiles/components/__tests__/SetQualityProfileModal-test.tsx View File

@@ -1,82 +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 Radio from '../../../../components/controls/Radio';
import Select from '../../../../components/controls/Select';
import SimpleModal from '../../../../components/controls/SimpleModal';
import { mockComponent } from '../../../../helpers/mocks/component';
import { mockQualityProfile } from '../../../../helpers/testMocks';
import SetQualityProfileModal, { SetQualityProfileModalProps } from '../SetQualityProfileModal';

it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot('default');
expect(shallowRender({ usesDefault: true })).toMatchSnapshot('inherits system default');
expect(shallowRender({ component: mockComponent() })).toMatchSnapshot('needs reanalysis');
});

it('should correctly handle changes', () => {
const onSubmit = jest.fn();
const wrapper = shallowRender({ onSubmit }, false);

diveIntoSimpleModal(wrapper).find(Radio).at(0).props().onCheck('');
submitSimpleModal(wrapper);
expect(onSubmit).toHaveBeenLastCalledWith(undefined, 'foo');

diveIntoSimpleModal(wrapper).find(Radio).at(1).props().onCheck('');
diveIntoSimpleModal(wrapper).find(Select).props().onChange({ value: 'bar' });
submitSimpleModal(wrapper);
expect(onSubmit).toHaveBeenLastCalledWith('bar', 'foo');

const change = diveIntoSimpleModal(wrapper).find(Select).props().onChange;

expect(change).toBeDefined();

change!({ value: 'bar' });
submitSimpleModal(wrapper);
expect(onSubmit).toHaveBeenLastCalledWith('bar', 'foo');
});

function diveIntoSimpleModal(wrapper: ShallowWrapper) {
return wrapper.find(SimpleModal).dive().children();
}

function submitSimpleModal(wrapper: ShallowWrapper) {
wrapper.find(SimpleModal).props().onSubmit();
}

function shallowRender(props: Partial<SetQualityProfileModalProps> = {}, dive = true) {
const wrapper = shallow<SetQualityProfileModalProps>(
<SetQualityProfileModal
availableProfiles={[
mockQualityProfile({ key: 'foo', isDefault: true, language: 'js' }),
mockQualityProfile({ key: 'bar', language: 'js', activeRuleCount: 0 }),
]}
component={mockComponent({ qualityProfiles: [{ key: 'foo', name: 'Foo', language: 'js' }] })}
currentProfile={mockQualityProfile({ key: 'foo', language: 'js' })}
onClose={jest.fn()}
onSubmit={jest.fn()}
usesDefault={false}
{...props}
/>
);

return dive ? diveIntoSimpleModal(wrapper) : wrapper;
}

+ 0
- 95
server/sonar-web/src/main/js/apps/projectQualityProfiles/components/__tests__/__snapshots__/AddLanguageModal-test.tsx.snap View File

@@ -1,95 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should render correctly: default 1`] = `
[
<div
className="modal-head"
>
<h2>
project_quality_profile.add_language_modal.title
</h2>
</div>,
<form
onSubmit={[Function]}
>
<div
className="modal-body"
>
<div
className="big-spacer-bottom"
>
<div
className="little-spacer-bottom"
>
<label
className="text-bold"
htmlFor="language"
>
project_quality_profile.add_language_modal.choose_language
</label>
</div>
<Select
className="abs-width-300"
id="language"
isDisabled={false}
onChange={[Function]}
options={
[
{
"label": "CSS",
"value": "css",
},
{
"label": "TS",
"value": "ts",
},
]
}
/>
</div>
<div
className="big-spacer-bottom"
>
<div
className="little-spacer-bottom"
>
<label
className="text-bold"
htmlFor="profiles"
>
project_quality_profile.add_language_modal.choose_profile
</label>
</div>
<Select
className="abs-width-300"
components={
{
"Option": [Function],
}
}
id="profiles"
isDisabled={true}
onChange={[Function]}
options={[]}
value={null}
/>
</div>
</div>
<div
className="modal-foot"
>
<SubmitButton
disabled={true}
>
save
</SubmitButton>
<ButtonLink
disabled={false}
onClick={[Function]}
>
cancel
</ButtonLink>
</div>
</form>,
]
`;

+ 0
- 55
server/sonar-web/src/main/js/apps/projectQualityProfiles/components/__tests__/__snapshots__/LanguageProfileSelectOption-test.tsx.snap View File

@@ -1,55 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should render correctly: default 1`] = `
<Option
data={
{
"isDisabled": false,
"label": "Profile 1",
"language": "Java",
"value": "profile-1",
}
}
>
<div>
<DisableableSelectOption
disableTooltipOverlay={[Function]}
disabledReason="project_quality_profile.add_language_modal.no_active_rules"
option={
{
"isDisabled": false,
"label": "Profile 1",
"language": "Java",
"value": "profile-1",
}
}
/>
</div>
</Option>
`;

exports[`tooltip should render correctly: default 1`] = `
<React.Fragment>
<p>
project_quality_profile.add_language_modal.profile_unavailable_no_active_rules
</p>
<ForwardRef(Link)
to={
{
"pathname": "/profiles/show",
"search": "?name=Profile+1&language=Java",
}
}
>
project_quality_profile.add_language_modal.go_to_profile
</ForwardRef(Link)>
</React.Fragment>
`;

exports[`tooltip should render correctly: no link 1`] = `
<React.Fragment>
<p>
project_quality_profile.add_language_modal.profile_unavailable_no_active_rules
</p>
</React.Fragment>
`;

+ 0
- 384
server/sonar-web/src/main/js/apps/projectQualityProfiles/components/__tests__/__snapshots__/SetQualityProfileModal-test.tsx.snap View File

@@ -1,384 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should render correctly: default 1`] = `
[
<div
className="modal-head"
>
<h2>
project_quality_profile.change_lang_X_profile.JavaScript
</h2>
</div>,
<form
onSubmit={[Function]}
>
<div
className="modal-body"
>
<div
className="big-spacer-bottom"
>
<Radio
checked={false}
className="display-flex-start"
disabled={false}
onCheck={[Function]}
value="-1"
>
<div
className="spacer-left"
>
<div
className="little-spacer-bottom"
>
project_quality_profile.always_use_default
</div>
<div
className="display-flex-center"
>
<span
className="text-muted spacer-right"
>
current_noun
:
</span>
name
</div>
</div>
</Radio>
</div>
<div
className="big-spacer-bottom"
>
<Radio
checked={true}
className="display-flex-start"
disabled={false}
onCheck={[Function]}
value="foo"
>
<div
className="spacer-left"
>
<div
className="little-spacer-bottom"
>
project_quality_profile.always_use_specific
</div>
<div
className="display-flex-center"
>
<Select
className="abs-width-300"
components={
{
"Option": [Function],
}
}
isDisabled={false}
onChange={[Function]}
options={
[
{
"isDisabled": false,
"label": "name",
"language": "js",
"value": "foo",
},
{
"isDisabled": true,
"label": "name",
"language": "js",
"value": "bar",
},
]
}
value={
{
"isDisabled": false,
"label": "name",
"language": "js",
"value": "foo",
}
}
/>
</div>
</div>
</Radio>
</div>
</div>
<div
className="modal-foot"
>
<SubmitButton
disabled={true}
>
save
</SubmitButton>
<ButtonLink
disabled={false}
onClick={[Function]}
>
cancel
</ButtonLink>
</div>
</form>,
]
`;

exports[`should render correctly: inherits system default 1`] = `
[
<div
className="modal-head"
>
<h2>
project_quality_profile.change_lang_X_profile.JavaScript
</h2>
</div>,
<form
onSubmit={[Function]}
>
<div
className="modal-body"
>
<div
className="big-spacer-bottom"
>
<Radio
checked={true}
className="display-flex-start"
disabled={false}
onCheck={[Function]}
value="-1"
>
<div
className="spacer-left"
>
<div
className="little-spacer-bottom"
>
project_quality_profile.always_use_default
</div>
<div
className="display-flex-center"
>
<span
className="text-muted spacer-right"
>
current_noun
:
</span>
name
</div>
</div>
</Radio>
</div>
<div
className="big-spacer-bottom"
>
<Radio
checked={false}
className="display-flex-start"
disabled={false}
onCheck={[Function]}
value="foo"
>
<div
className="spacer-left"
>
<div
className="little-spacer-bottom"
>
project_quality_profile.always_use_specific
</div>
<div
className="display-flex-center"
>
<Select
className="abs-width-300"
components={
{
"Option": [Function],
}
}
isDisabled={true}
onChange={[Function]}
options={
[
{
"isDisabled": false,
"label": "name",
"language": "js",
"value": "foo",
},
{
"isDisabled": true,
"label": "name",
"language": "js",
"value": "bar",
},
]
}
value={
{
"isDisabled": false,
"label": "name",
"language": "js",
"value": "foo",
}
}
/>
</div>
</div>
</Radio>
</div>
</div>
<div
className="modal-foot"
>
<SubmitButton
disabled={true}
>
save
</SubmitButton>
<ButtonLink
disabled={false}
onClick={[Function]}
>
cancel
</ButtonLink>
</div>
</form>,
]
`;

exports[`should render correctly: needs reanalysis 1`] = `
[
<div
className="modal-head"
>
<h2>
project_quality_profile.change_lang_X_profile.JavaScript
</h2>
</div>,
<form
onSubmit={[Function]}
>
<div
className="modal-body"
>
<div
className="big-spacer-bottom"
>
<Radio
checked={false}
className="display-flex-start"
disabled={false}
onCheck={[Function]}
value="-1"
>
<div
className="spacer-left"
>
<div
className="little-spacer-bottom"
>
project_quality_profile.always_use_default
</div>
<div
className="display-flex-center"
>
<span
className="text-muted spacer-right"
>
current_noun
:
</span>
name
</div>
</div>
</Radio>
</div>
<div
className="big-spacer-bottom"
>
<Radio
checked={true}
className="display-flex-start"
disabled={false}
onCheck={[Function]}
value="foo"
>
<div
className="spacer-left"
>
<div
className="little-spacer-bottom"
>
project_quality_profile.always_use_specific
</div>
<div
className="display-flex-center"
>
<Select
className="abs-width-300"
components={
{
"Option": [Function],
}
}
isDisabled={false}
onChange={[Function]}
options={
[
{
"isDisabled": false,
"label": "name",
"language": "js",
"value": "foo",
},
{
"isDisabled": true,
"label": "name",
"language": "js",
"value": "bar",
},
]
}
value={
{
"isDisabled": false,
"label": "name",
"language": "js",
"value": "foo",
}
}
/>
</div>
</div>
</Radio>
</div>
<Alert
variant="warning"
>
project_quality_profile.requires_new_analysis
</Alert>
</div>
<div
className="modal-foot"
>
<SubmitButton
disabled={true}
>
save
</SubmitButton>
<ButtonLink
disabled={false}
onClick={[Function]}
>
cancel
</ButtonLink>
</div>
</form>,
]
`;

Loading…
Cancel
Save