]> source.dussan.org Git - sonarqube.git/blob
ccc25e4f5e2ceb12a6f02543391f277c589ab94d
[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 { range } from 'lodash';
22 import * as React from 'react';
23 import { getSources } from '../../../../api/components';
24 import { mockBranch } from '../../../../helpers/mocks/branch-like';
25 import { mockComponent } from '../../../../helpers/mocks/component';
26 import { mockHotspot, mockHotspotComponent } from '../../../../helpers/mocks/security-hotspots';
27 import { mockSourceLine } from '../../../../helpers/mocks/sources';
28 import { mockFlowLocation } from '../../../../helpers/testMocks';
29 import { waitAndUpdate } from '../../../../helpers/testUtils';
30 import { ComponentQualifier } from '../../../../types/component';
31 import HotspotSnippetContainer from '../HotspotSnippetContainer';
32 import HotspotSnippetContainerRenderer from '../HotspotSnippetContainerRenderer';
33
34 jest.mock('../../../../api/components', () => ({
35   getSources: jest.fn().mockResolvedValue([]),
36 }));
37
38 jest.mock('../../../../helpers/scrolling', () => ({
39   scrollToElement: jest.fn(),
40 }));
41
42 beforeEach(() => jest.clearAllMocks());
43
44 const branch = mockBranch();
45
46 it('should render correctly', () => {
47   expect(shallowRender()).toMatchSnapshot();
48 });
49
50 it('should load sources on mount', async () => {
51   (getSources as jest.Mock).mockResolvedValueOnce(
52     range(1, 25).map((line) => mockSourceLine({ line }))
53   );
54
55   const hotspot = mockHotspot({
56     project: mockHotspotComponent({ branch: branch.name, qualifier: ComponentQualifier.Project }),
57     textRange: { startLine: 10, endLine: 11, startOffset: 0, endOffset: 12 },
58     flows: [
59       {
60         locations: [
61           mockFlowLocation({
62             textRange: { startLine: 8, endLine: 8, startOffset: 0, endOffset: 1 },
63           }),
64           mockFlowLocation({
65             textRange: { startLine: 13, endLine: 13, startOffset: 0, endOffset: 1 },
66           }),
67         ],
68       },
69     ],
70   });
71
72   const wrapper = shallowRender({ hotspot });
73
74   await waitAndUpdate(wrapper);
75
76   expect(getSources).toHaveBeenCalledWith(
77     expect.objectContaining({
78       key: hotspot.component.key,
79       branch: branch.name,
80       from: 1,
81       to: 24,
82     })
83   );
84   expect(wrapper.state().lastLine).toBeUndefined();
85   expect(wrapper.state().sourceLines).toHaveLength(23);
86 });
87
88 it('should handle load sources failure', async () => {
89   (getSources as jest.Mock).mockRejectedValueOnce(null);
90
91   const wrapper = shallowRender();
92
93   await waitAndUpdate(wrapper);
94
95   expect(getSources).toHaveBeenCalled();
96   expect(wrapper.state().loading).toBe(false);
97   expect(wrapper.state().lastLine).toBeUndefined();
98   expect(wrapper.state().sourceLines).toHaveLength(0);
99 });
100
101 it('should not load sources on mount when the hotspot is not associated to any loc', async () => {
102   const hotspot = mockHotspot({
103     line: undefined,
104     textRange: undefined,
105   });
106
107   const wrapper = shallowRender({ hotspot });
108
109   await waitAndUpdate(wrapper);
110
111   expect(getSources).not.toHaveBeenCalled();
112   expect(wrapper.state().lastLine).toBeUndefined();
113   expect(wrapper.state().sourceLines).toHaveLength(0);
114 });
115
116 it('should handle end-of-file on mount', async () => {
117   (getSources as jest.Mock).mockResolvedValueOnce(
118     range(5, 15).map((line) => mockSourceLine({ line }))
119   );
120
121   const hotspot = mockHotspot({
122     textRange: { startLine: 10, endLine: 11, startOffset: 0, endOffset: 12 },
123   });
124
125   const wrapper = shallowRender({ hotspot });
126
127   await waitAndUpdate(wrapper);
128
129   expect(getSources).toHaveBeenCalled();
130   expect(wrapper.state().lastLine).toBe(14);
131   expect(wrapper.state().sourceLines).toHaveLength(10);
132 });
133
134 describe('Expansion', () => {
135   beforeEach(() => {
136     (getSources as jest.Mock).mockResolvedValueOnce(
137       range(10, 32).map((line) => mockSourceLine({ line }))
138     );
139   });
140
141   const hotspot = mockHotspot({
142     project: mockHotspotComponent({ branch: branch.name, qualifier: ComponentQualifier.Project }),
143     textRange: { startLine: 20, endLine: 21, startOffset: 0, endOffset: 12 },
144   });
145
146   it('up should work', async () => {
147     (getSources as jest.Mock).mockResolvedValueOnce(
148       range(1, 10).map((line) => mockSourceLine({ line }))
149     );
150
151     const wrapper = shallowRender({ hotspot });
152     await waitAndUpdate(wrapper);
153
154     wrapper.find(HotspotSnippetContainerRenderer).props().onExpandBlock('up');
155
156     await waitAndUpdate(wrapper);
157
158     expect(getSources).toHaveBeenCalledWith(
159       expect.objectContaining({
160         branch: branch.name,
161       })
162     );
163     expect(wrapper.state().sourceLines).toHaveLength(31);
164   });
165
166   it('down should work', async () => {
167     (getSources as jest.Mock).mockResolvedValueOnce(
168       // lastLine + expand + extra for EOF check + range end is excluded
169       // 31 + 50 + 1 + 1
170       range(32, 83).map((line) => mockSourceLine({ line }))
171     );
172
173     const wrapper = shallowRender({ hotspot });
174     await waitAndUpdate(wrapper);
175
176     wrapper.find(HotspotSnippetContainerRenderer).props().onExpandBlock('down');
177
178     await waitAndUpdate(wrapper);
179
180     expect(wrapper.state().lastLine).toBeUndefined();
181     expect(wrapper.state().sourceLines).toHaveLength(72);
182   });
183
184   it('down should work and handle EOF', async () => {
185     (getSources as jest.Mock).mockResolvedValueOnce(
186       // lastLine + expand + extra for EOF check + range end is excluded - 1 to trigger end-of-file
187       // 26 + 50 + 1 + 1 - 1
188       range(27, 77).map((line) => mockSourceLine({ line }))
189     );
190
191     const wrapper = shallowRender({ hotspot });
192     await waitAndUpdate(wrapper);
193
194     wrapper.find(HotspotSnippetContainerRenderer).props().onExpandBlock('down');
195
196     await waitAndUpdate(wrapper);
197
198     expect(wrapper.state().lastLine).toBe(76);
199     expect(wrapper.state().sourceLines).toHaveLength(72);
200   });
201 });
202
203 it('should handle symbol click', () => {
204   const wrapper = shallowRender();
205   const symbols = ['symbol'];
206   wrapper.find(HotspotSnippetContainerRenderer).props().onSymbolClick(symbols);
207   expect(wrapper.state().highlightedSymbols).toBe(symbols);
208 });
209
210 function shallowRender(props?: Partial<HotspotSnippetContainer['props']>) {
211   return shallow<HotspotSnippetContainer>(
212     <HotspotSnippetContainer
213       branchLike={branch}
214       component={mockComponent()}
215       hotspot={mockHotspot()}
216       onCommentButtonClick={jest.fn()}
217       onLocationSelect={jest.fn()}
218       {...props}
219     />
220   );
221 }