3 * Copyright (C) 2009-2023 SonarSource SA
4 * mailto:info AT sonarsource DOT com
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 import { shallow } from 'enzyme';
21 import * as React from 'react';
27 searchQualityProfiles,
28 } from '../../../api/quality-profiles';
29 import handleRequiredAuthorization from '../../../app/utils/handleRequiredAuthorization';
30 import { mockComponent } from '../../../helpers/mocks/component';
31 import { waitAndUpdate } from '../../../helpers/testUtils';
32 import { ProjectQualityProfilesApp } from '../ProjectQualityProfilesApp';
34 jest.mock('../../../api/quality-profiles', () => {
35 const { mockQualityProfile } = jest.requireActual('../../../helpers/testMocks');
38 associateProject: jest.fn().mockResolvedValue({}),
39 dissociateProject: jest.fn().mockResolvedValue({}),
40 searchQualityProfiles: jest.fn().mockResolvedValue({
42 mockQualityProfile({ key: 'css', language: 'css' }),
43 mockQualityProfile({ key: 'css2', language: 'css' }),
44 mockQualityProfile({ key: 'css_default', language: 'css', isDefault: true }),
45 mockQualityProfile({ key: 'java', language: 'java' }),
46 mockQualityProfile({ key: 'java_default', language: 'java', isDefault: true }),
47 mockQualityProfile({ key: 'js', language: 'js' }),
48 mockQualityProfile({ key: 'js_default', language: 'js', isDefault: true }),
49 mockQualityProfile({ key: 'ts_default', language: 'ts', isDefault: true }),
50 mockQualityProfile({ key: 'html', language: 'html' }),
51 mockQualityProfile({ key: 'html_default', language: 'html', isDefault: true }),
54 getProfileProjects: jest.fn(({ key }) => {
55 const results: ProfileProject[] = [];
56 if (key === 'js' || key === 'css' || key === 'html_default') {
62 } else if (key === 'html') {
69 return Promise.resolve({ results });
74 jest.mock('../../../helpers/globalMessages', () => ({
75 addGlobalSuccessMessage: jest.fn(),
78 jest.mock('../../../app/utils/handleRequiredAuthorization', () => jest.fn());
80 beforeEach(jest.clearAllMocks);
82 it('renders correctly', () => {
83 expect(shallowRender()).toMatchSnapshot();
86 it('correctly checks permissions', () => {
87 const wrapper = shallowRender({
88 component: mockComponent({ configuration: { showQualityProfiles: false } }),
90 expect(wrapper.type()).toBeNull();
91 expect(handleRequiredAuthorization).toHaveBeenCalled();
94 it('correctly fetches and treats profile data', async () => {
95 const wrapper = shallowRender();
96 await waitAndUpdate(wrapper);
98 expect(searchQualityProfiles).toHaveBeenCalled();
99 expect(getProfileProjects).toHaveBeenCalledTimes(10);
101 expect(wrapper.state().projectProfiles).toEqual([
102 expect.objectContaining({
103 profile: expect.objectContaining({ key: 'css' }),
106 expect.objectContaining({
107 profile: expect.objectContaining({ key: 'js' }),
110 expect.objectContaining({
111 profile: expect.objectContaining({ key: 'html_default' }),
114 expect.objectContaining({
115 profile: expect.objectContaining({ key: 'ts_default' }),
121 it('correctly sets a profile', async () => {
122 const wrapper = shallowRender();
123 const instance = wrapper.instance();
124 await waitAndUpdate(wrapper);
126 // Dissociate a selected profile.
127 instance.handleSetProfile(undefined, 'css');
128 expect(dissociateProject).toHaveBeenLastCalledWith(
129 expect.objectContaining({ key: 'css' }),
132 await waitAndUpdate(wrapper);
133 expect(wrapper.state().projectProfiles).toEqual(
134 expect.arrayContaining([
136 profile: expect.objectContaining({ key: 'css_default' }),
137 // It's not explicitly selected, as we're inheriting the default.
143 // Associate a new profile.
144 instance.handleSetProfile('css2', 'css_default');
145 expect(associateProject).toHaveBeenLastCalledWith(
146 expect.objectContaining({ key: 'css2' }),
149 await waitAndUpdate(wrapper);
150 expect(wrapper.state().projectProfiles).toEqual(
151 expect.arrayContaining([
153 profile: expect.objectContaining({ key: 'css2' }),
154 // It's explicitly selected.
160 // Dissociate a default profile that was inherited.
161 (dissociateProject as jest.Mock).mockClear();
162 instance.handleSetProfile(undefined, 'ts_default');
163 // It won't call the WS.
164 expect(dissociateProject).not.toHaveBeenCalled();
166 // Associate a default profile that was already inherited.
167 instance.handleSetProfile('ts_default', 'ts_default');
168 expect(associateProject).toHaveBeenLastCalledWith(
169 expect.objectContaining({ key: 'ts_default' }),
172 await waitAndUpdate(wrapper);
173 expect(wrapper.state().projectProfiles).toEqual(
174 expect.arrayContaining([
176 profile: expect.objectContaining({ key: 'ts_default' }),
177 // It's explicitly selected, even though it is the default profile.
184 it('correctly adds a new language', async () => {
185 const wrapper = shallowRender();
186 const instance = wrapper.instance();
187 await waitAndUpdate(wrapper);
189 instance.handleAddLanguage('java');
190 expect(associateProject).toHaveBeenLastCalledWith(
191 expect.objectContaining({ key: 'java' }),
194 await waitAndUpdate(wrapper);
195 expect(wrapper.state().projectProfiles).toEqual(
196 expect.arrayContaining([
198 profile: expect.objectContaining({ key: 'java' }),
199 // It must be explicitly selected. Adding an unanalyzed language can
200 // only happen by explicitly choosing a profile.
207 it('correctly handles WS errors', async () => {
208 (searchQualityProfiles as jest.Mock).mockRejectedValueOnce(null);
209 (getProfileProjects as jest.Mock).mockRejectedValueOnce(null);
211 const wrapper = shallowRender();
212 await waitAndUpdate(wrapper);
214 expect(wrapper.state().allProfiles).toHaveLength(0);
215 expect(wrapper.state().projectProfiles).toHaveLength(0);
216 expect(wrapper.state().loading).toBe(false);
219 function shallowRender(props: Partial<ProjectQualityProfilesApp['props']> = {}) {
220 return shallow<ProjectQualityProfilesApp>(
221 <ProjectQualityProfilesApp
222 component={mockComponent({
224 configuration: { showQualityProfiles: true },
226 { key: 'css2', name: 'CSS 2', language: 'css' },
227 { key: 'js', name: 'JS', language: 'js' },
228 { key: 'ts_default', name: 'TS (default)', language: 'ts' },
229 { key: 'html', name: 'HTML', language: 'html' },