Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

HotspotSnippetContainer-test.tsx 7.0KB

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