]> source.dussan.org Git - sonarqube.git/blob
87d6f8b15b2cdb570f693b7d586a98570fc34281
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2023 SonarSource SA
4  * mailto:info AT sonarsource DOT com
5  *
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.
10  *
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.
15  *
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.
19  */
20 import { shallow } from 'enzyme';
21 import * as React from 'react';
22 import {
23   associateProject,
24   dissociateProject,
25   getProfileProjects,
26   ProfileProject,
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';
33
34 jest.mock('../../../api/quality-profiles', () => {
35   const { mockQualityProfile } = jest.requireActual('../../../helpers/testMocks');
36
37   return {
38     associateProject: jest.fn().mockResolvedValue({}),
39     dissociateProject: jest.fn().mockResolvedValue({}),
40     searchQualityProfiles: jest.fn().mockResolvedValue({
41       profiles: [
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 }),
52       ],
53     }),
54     getProfileProjects: jest.fn(({ key }) => {
55       const results: ProfileProject[] = [];
56       if (key === 'js' || key === 'css' || key === 'html_default') {
57         results.push({
58           key: 'foo',
59           name: 'Foo',
60           selected: true,
61         });
62       } else if (key === 'html') {
63         results.push({
64           key: 'foobar',
65           name: 'FooBar',
66           selected: true,
67         });
68       }
69       return Promise.resolve({ results });
70     }),
71   };
72 });
73
74 jest.mock('../../../helpers/globalMessages', () => ({
75   addGlobalSuccessMessage: jest.fn(),
76 }));
77
78 jest.mock('../../../app/utils/handleRequiredAuthorization', () => jest.fn());
79
80 beforeEach(jest.clearAllMocks);
81
82 it('renders correctly', () => {
83   expect(shallowRender()).toMatchSnapshot();
84 });
85
86 it('correctly checks permissions', () => {
87   const wrapper = shallowRender({
88     component: mockComponent({ configuration: { showQualityProfiles: false } }),
89   });
90   expect(wrapper.type()).toBeNull();
91   expect(handleRequiredAuthorization).toHaveBeenCalled();
92 });
93
94 it('correctly fetches and treats profile data', async () => {
95   const wrapper = shallowRender();
96   await waitAndUpdate(wrapper);
97
98   expect(searchQualityProfiles).toHaveBeenCalled();
99   expect(getProfileProjects).toHaveBeenCalledTimes(10);
100
101   expect(wrapper.state().projectProfiles).toEqual([
102     expect.objectContaining({
103       profile: expect.objectContaining({ key: 'css' }),
104       selected: true,
105     }),
106     expect.objectContaining({
107       profile: expect.objectContaining({ key: 'js' }),
108       selected: true,
109     }),
110     expect.objectContaining({
111       profile: expect.objectContaining({ key: 'html_default' }),
112       selected: true,
113     }),
114     expect.objectContaining({
115       profile: expect.objectContaining({ key: 'ts_default' }),
116       selected: false,
117     }),
118   ]);
119 });
120
121 it('correctly sets a profile', async () => {
122   const wrapper = shallowRender();
123   const instance = wrapper.instance();
124   await waitAndUpdate(wrapper);
125
126   // Dissociate a selected profile.
127   instance.handleSetProfile(undefined, 'css');
128   expect(dissociateProject).toHaveBeenLastCalledWith(
129     expect.objectContaining({ key: 'css' }),
130     'foo'
131   );
132   await waitAndUpdate(wrapper);
133   expect(wrapper.state().projectProfiles).toEqual(
134     expect.arrayContaining([
135       {
136         profile: expect.objectContaining({ key: 'css_default' }),
137         // It's not explicitly selected, as we're inheriting the default.
138         selected: false,
139       },
140     ])
141   );
142
143   // Associate a new profile.
144   instance.handleSetProfile('css2', 'css_default');
145   expect(associateProject).toHaveBeenLastCalledWith(
146     expect.objectContaining({ key: 'css2' }),
147     'foo'
148   );
149   await waitAndUpdate(wrapper);
150   expect(wrapper.state().projectProfiles).toEqual(
151     expect.arrayContaining([
152       {
153         profile: expect.objectContaining({ key: 'css2' }),
154         // It's explicitly selected.
155         selected: true,
156       },
157     ])
158   );
159
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();
165
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' }),
170     'foo'
171   );
172   await waitAndUpdate(wrapper);
173   expect(wrapper.state().projectProfiles).toEqual(
174     expect.arrayContaining([
175       {
176         profile: expect.objectContaining({ key: 'ts_default' }),
177         // It's explicitly selected, even though it is the default profile.
178         selected: true,
179       },
180     ])
181   );
182 });
183
184 it('correctly adds a new language', async () => {
185   const wrapper = shallowRender();
186   const instance = wrapper.instance();
187   await waitAndUpdate(wrapper);
188
189   instance.handleAddLanguage('java');
190   expect(associateProject).toHaveBeenLastCalledWith(
191     expect.objectContaining({ key: 'java' }),
192     'foo'
193   );
194   await waitAndUpdate(wrapper);
195   expect(wrapper.state().projectProfiles).toEqual(
196     expect.arrayContaining([
197       {
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.
201         selected: true,
202       },
203     ])
204   );
205 });
206
207 it('correctly handles WS errors', async () => {
208   (searchQualityProfiles as jest.Mock).mockRejectedValueOnce(null);
209   (getProfileProjects as jest.Mock).mockRejectedValueOnce(null);
210
211   const wrapper = shallowRender();
212   await waitAndUpdate(wrapper);
213
214   expect(wrapper.state().allProfiles).toHaveLength(0);
215   expect(wrapper.state().projectProfiles).toHaveLength(0);
216   expect(wrapper.state().loading).toBe(false);
217 });
218
219 function shallowRender(props: Partial<ProjectQualityProfilesApp['props']> = {}) {
220   return shallow<ProjectQualityProfilesApp>(
221     <ProjectQualityProfilesApp
222       component={mockComponent({
223         key: 'foo',
224         configuration: { showQualityProfiles: true },
225         qualityProfiles: [
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' },
230         ],
231       })}
232       {...props}
233     />
234   );
235 }