diff options
Diffstat (limited to 'server/sonar-web/src/main/js/apps/security-hotspots')
55 files changed, 445 insertions, 509 deletions
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/SecurityHotspotsApp.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/SecurityHotspotsApp.tsx index 3854bc3e60d..beaccb76e96 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/SecurityHotspotsApp.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/SecurityHotspotsApp.tsx @@ -36,7 +36,7 @@ import { HotspotResolution, HotspotStatus, HotspotStatusFilter, - RawHotspot + RawHotspot, } from '../../types/security-hotspots'; import { Component, Dict } from '../../types/types'; import { CurrentUser, isLoggedIn } from '../../types/users'; @@ -100,12 +100,12 @@ export class SecurityHotspotsApp extends React.PureComponent<Props, State> { [SecurityStandard.CWE]: {}, [SecurityStandard.PCI_DSS_3_2]: {}, [SecurityStandard.PCI_DSS_4_0]: {}, - [SecurityStandard.OWASP_ASVS_4_0]: {} + [SecurityStandard.OWASP_ASVS_4_0]: {}, }, filters: { ...this.constructFiltersFromProps(props), - status: HotspotStatusFilter.TO_REVIEW - } + status: HotspotStatusFilter.TO_REVIEW, + }, }; } @@ -119,7 +119,7 @@ export class SecurityHotspotsApp extends React.PureComponent<Props, State> { if ( this.props.component.key !== previous.component.key || this.props.location.query.hotspots !== previous.location.query.hotspots || - SECURITY_STANDARDS.some(s => this.props.location.query[s] !== previous.location.query[s]) || + SECURITY_STANDARDS.some((s) => this.props.location.query[s] !== previous.location.query[s]) || this.props.location.query.files !== previous.location.query.files ) { this.fetchInitialData(); @@ -132,7 +132,7 @@ export class SecurityHotspotsApp extends React.PureComponent<Props, State> { this.props.location.query.inNewCodePeriod !== previous.location.query.inNewCodePeriod ) { this.setState(({ filters }) => ({ - filters: { ...this.constructFiltersFromProps, ...filters } + filters: { ...this.constructFiltersFromProps, ...filters }, })); } } @@ -211,12 +211,12 @@ export class SecurityHotspotsApp extends React.PureComponent<Props, State> { selectNeighboringHotspot = (shift: number) => { this.setState({ selectedHotspotLocationIndex: undefined }); this.setState(({ hotspots, selectedHotspot }) => { - const index = selectedHotspot && hotspots.findIndex(h => h.key === selectedHotspot.key); + const index = selectedHotspot && hotspots.findIndex((h) => h.key === selectedHotspot.key); if (index !== undefined && index > -1) { const newIndex = Math.max(0, Math.min(hotspots.length - 1, index + shift)); return { - selectedHotspot: hotspots[newIndex] + selectedHotspot: hotspots[newIndex], }; } @@ -234,7 +234,7 @@ export class SecurityHotspotsApp extends React.PureComponent<Props, State> { return { assignedToMe: props.location.query.assignedToMe === 'true' && isLoggedIn(props.currentUser), inNewCodePeriod: - isPullRequest(props.branchLike) || props.location.query.inNewCodePeriod === 'true' + isPullRequest(props.branchLike) || props.location.query.inNewCodePeriod === 'true', }; } @@ -248,7 +248,7 @@ export class SecurityHotspotsApp extends React.PureComponent<Props, State> { return Promise.all([ getStandards(), this.fetchSecurityHotspots(), - this.fetchSecurityHotspotsReviewed() + this.fetchSecurityHotspotsReviewed(), ]) .then(([standards, { hotspots, paging }]) => { if (!this.mounted) { @@ -262,7 +262,7 @@ export class SecurityHotspotsApp extends React.PureComponent<Props, State> { hotspotsTotal: paging.total, loading: false, selectedHotspot, - standards + standards, }); }) .catch(this.handleCallFailure); @@ -280,9 +280,9 @@ export class SecurityHotspotsApp extends React.PureComponent<Props, State> { return getMeasures({ component: component.key, metricKeys: reviewedHotspotsMetricKey, - ...getBranchLikeQuery(branchLike) + ...getBranchLikeQuery(branchLike), }) - .then(measures => { + .then((measures) => { if (!this.mounted) { return; } @@ -309,7 +309,7 @@ export class SecurityHotspotsApp extends React.PureComponent<Props, State> { : undefined; const standard = SECURITY_STANDARDS.find( - stnd => stnd !== SecurityStandard.CWE && location.query[stnd] !== undefined + (stnd) => stnd !== SecurityStandard.CWE && location.query[stnd] !== undefined ); const filterByCategory = standard ? { standard, category: location.query[standard] } @@ -324,7 +324,7 @@ export class SecurityHotspotsApp extends React.PureComponent<Props, State> { if (hotspotKeys && hotspotKeys.length > 0) { return getSecurityHotspotList(hotspotKeys, { projectKey: component.key, - ...getBranchLikeQuery(branchLike) + ...getBranchLikeQuery(branchLike), }); } @@ -350,7 +350,7 @@ export class SecurityHotspotsApp extends React.PureComponent<Props, State> { ps: PAGE_SIZE, status: HotspotStatus.TO_REVIEW, // we're only interested in unresolved hotspots inNewCodePeriod: filters.inNewCodePeriod && Boolean(filterByFile), // only add leak period when filtering by file - ...getBranchLikeQuery(branchLike) + ...getBranchLikeQuery(branchLike), }); } @@ -372,7 +372,7 @@ export class SecurityHotspotsApp extends React.PureComponent<Props, State> { resolution, onlyMine: filters.assignedToMe, inNewCodePeriod: filters.inNewCodePeriod, - ...getBranchLikeQuery(branchLike) + ...getBranchLikeQuery(branchLike), }); } @@ -390,7 +390,7 @@ export class SecurityHotspotsApp extends React.PureComponent<Props, State> { hotspotsPageIndex: 1, hotspotsTotal: paging.total, loading: false, - selectedHotspot: hotspots.length > 0 ? hotspots[0] : undefined + selectedHotspot: hotspots.length > 0 ? hotspots[0] : undefined, }); }) .catch(this.handleCallFailure); @@ -418,16 +418,18 @@ export class SecurityHotspotsApp extends React.PureComponent<Props, State> { handleHotspotUpdate = (hotspotKey: string) => { const { hotspots, hotspotsPageIndex } = this.state; const { branchLike, component } = this.props; - const index = hotspots.findIndex(h => h.key === hotspotKey); + const index = hotspots.findIndex((h) => h.key === hotspotKey); if (isPullRequest(branchLike)) { this.props.fetchBranchStatus(branchLike, component.key); } return Promise.all( - range(hotspotsPageIndex).map(p => this.fetchSecurityHotspots(p + 1 /* pages are 1-indexed */)) + range(hotspotsPageIndex).map((p) => + this.fetchSecurityHotspots(p + 1 /* pages are 1-indexed */) + ) ) - .then(hotspotPages => { + .then((hotspotPages) => { const allHotspots = flatMap(hotspotPages, 'hotspots'); const { paging } = hotspotPages[hotspotPages.length - 1]; @@ -438,7 +440,7 @@ export class SecurityHotspotsApp extends React.PureComponent<Props, State> { hotspots: allHotspots, hotspotsPageIndex: paging.pageIndex, hotspotsTotal: paging.total, - selectedHotspot: selectedHotspot?.key === hotspotKey ? nextHotspot : selectedHotspot + selectedHotspot: selectedHotspot?.key === hotspotKey ? nextHotspot : selectedHotspot, })); }) .then(this.fetchSecurityHotspotsReviewed); @@ -458,8 +460,8 @@ export class SecurityHotspotsApp extends React.PureComponent<Props, State> { [SecurityStandard.PCI_DSS_3_2]: undefined, [SecurityStandard.PCI_DSS_4_0]: undefined, [SecurityStandard.OWASP_ASVS_4_0]: undefined, - file: undefined - } + file: undefined, + }, }); }; @@ -477,7 +479,7 @@ export class SecurityHotspotsApp extends React.PureComponent<Props, State> { this.setState({ hotspots: [...hotspots, ...additionalHotspots], hotspotsPageIndex: hotspotPages + 1, - loadingMore: false + loadingMore: false, }); }) .catch(this.handleCallFailure); @@ -488,11 +490,11 @@ export class SecurityHotspotsApp extends React.PureComponent<Props, State> { if (locationIndex === undefined || locationIndex === selectedHotspotLocationIndex) { this.setState({ - selectedHotspotLocationIndex: undefined + selectedHotspotLocationIndex: undefined, }); } else { this.setState({ - selectedHotspotLocationIndex: locationIndex + selectedHotspotLocationIndex: locationIndex, }); } }; @@ -513,7 +515,7 @@ export class SecurityHotspotsApp extends React.PureComponent<Props, State> { loadingMore, selectedHotspot, selectedHotspotLocationIndex, - standards + standards, } = this.state; return ( diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/SecurityHotspotsAppRenderer.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/SecurityHotspotsAppRenderer.tsx index 5de54085163..fc27424a6b6 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/SecurityHotspotsAppRenderer.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/SecurityHotspotsAppRenderer.tsx @@ -85,7 +85,7 @@ export default function SecurityHotspotsAppRenderer(props: SecurityHotspotsAppRe securityCategories, selectedHotspot, selectedHotspotLocation, - standards + standards, } = props; const scrollableRef = React.useRef(null); diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/__tests__/SecurityHotspotsApp-it.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/__tests__/SecurityHotspotsApp-it.tsx index 9bff505526e..922b3deb7f7 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/__tests__/SecurityHotspotsApp-it.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/__tests__/SecurityHotspotsApp-it.tsx @@ -35,9 +35,9 @@ jest.mock('../../../api/components'); const ui = { selectStatusButton: byRole('button', { - name: 'hotspots.status.select_status' + name: 'hotspots.status.select_status', }), - panel: byTestId('security-hotspot-test') + panel: byTestId('security-hotspot-test'), }; let handler: SecurityHotspotServiceMock; @@ -80,8 +80,8 @@ function renderSecurityHotspotsApp(navigateTo?: string) { navigateTo, currentUser: mockLoggedInUser({ login: 'foo', - name: 'foo' - }) + name: 'foo', + }), }, { branchLikes: [], @@ -89,8 +89,8 @@ function renderSecurityHotspotsApp(navigateTo?: string) { onComponentChange: jest.fn(), component: mockComponent({ key: 'guillaume-peoch-sonarsource_benflix_AYGpXq2bd8qy4i0eO9ed', - name: 'benflix' - }) + name: 'benflix', + }), } ); } diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/__tests__/SecurityHotspotsApp-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/__tests__/SecurityHotspotsApp-test.tsx index b22b3c6b1d5..1a3b82c8a98 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/__tests__/SecurityHotspotsApp-test.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/__tests__/SecurityHotspotsApp-test.tsx @@ -31,14 +31,14 @@ import { mockFlowLocation, mockLocation, mockLoggedInUser, - mockRouter + mockRouter, } from '../../../helpers/testMocks'; import { mockEvent, waitAndUpdate } from '../../../helpers/testUtils'; import { SecurityStandard } from '../../../types/security'; import { HotspotResolution, HotspotStatus, - HotspotStatusFilter + HotspotStatusFilter, } from '../../../types/security-hotspots'; import { SecurityHotspotsApp } from '../SecurityHotspotsApp'; import SecurityHotspotsAppRenderer from '../SecurityHotspotsAppRenderer'; @@ -48,20 +48,20 @@ beforeEach(() => { }); jest.mock('../../../api/measures', () => ({ - getMeasures: jest.fn().mockResolvedValue([]) + getMeasures: jest.fn().mockResolvedValue([]), })); jest.mock('../../../api/security-hotspots', () => ({ getSecurityHotspots: jest.fn().mockResolvedValue({ hotspots: [], paging: { total: 0 } }), - getSecurityHotspotList: jest.fn().mockResolvedValue({ hotspots: [], rules: [] }) + getSecurityHotspotList: jest.fn().mockResolvedValue({ hotspots: [], rules: [] }), })); jest.mock('../../../helpers/security-standard', () => ({ - getStandards: jest.fn().mockResolvedValue({ sonarsourceSecurity: { cat1: { title: 'cat 1' } } }) + getStandards: jest.fn().mockResolvedValue({ sonarsourceSecurity: { cat1: { title: 'cat 1' } } }), })); jest.mock('../../../helpers/scrolling', () => ({ - scrollToElement: jest.fn() + scrollToElement: jest.fn(), })); const branch = mockBranch(); @@ -75,8 +75,8 @@ it('should load data correctly', async () => { (getSecurityHotspots as jest.Mock).mockResolvedValue({ hotspots, paging: { - total: 1 - } + total: 1, + }, }); (getMeasures as jest.Mock).mockResolvedValue([{ value: '86.6' }]); @@ -88,12 +88,12 @@ it('should load data correctly', async () => { expect(getStandards).toHaveBeenCalled(); expect(getSecurityHotspots).toHaveBeenCalledWith( expect.objectContaining({ - branch: branch.name + branch: branch.name, }) ); expect(getMeasures).toHaveBeenCalledWith( expect.objectContaining({ - branch: branch.name + branch: branch.name, }) ); @@ -104,8 +104,8 @@ it('should load data correctly', async () => { expect(wrapper.state().selectedHotspot).toBe(hotspots[0]); expect(wrapper.state().standards).toEqual({ sonarsourceSecurity: { - cat1: { title: 'cat 1' } - } + cat1: { title: 'cat 1' }, + }, }); expect(wrapper.state().loadingMeasure).toBe(false); expect(wrapper.state().hotspotsReviewedMeasure).toBe('86.6'); @@ -116,7 +116,7 @@ it('should handle category request', () => { (getMeasures as jest.Mock).mockResolvedValue([{ value: '86.6' }]); shallowRender({ - location: mockLocation({ query: { [SecurityStandard.OWASP_TOP10]: 'a1' } }) + location: mockLocation({ query: { [SecurityStandard.OWASP_TOP10]: 'a1' } }), }); expect(getSecurityHotspots).toHaveBeenCalledWith( @@ -129,7 +129,7 @@ it('should handle cwe request', () => { (getMeasures as jest.Mock).mockResolvedValue([{ value: '86.6' }]); shallowRender({ - location: mockLocation({ query: { [SecurityStandard.CWE]: '1004' } }) + location: mockLocation({ query: { [SecurityStandard.CWE]: '1004' } }), }); expect(getSecurityHotspots).toHaveBeenCalledWith( @@ -144,7 +144,7 @@ it('should handle file request', () => { const filepath = 'src/path/to/file.java'; shallowRender({ - location: mockLocation({ query: { files: filepath } }) + location: mockLocation({ query: { files: filepath } }), }); expect(getSecurityHotspots).toHaveBeenCalledWith(expect.objectContaining({ files: filepath })); @@ -154,24 +154,24 @@ it('should load data correctly when hotspot key list is forced', async () => { const hotspots = [ mockRawHotspot({ key: 'test1' }), mockRawHotspot({ key: 'test2' }), - mockRawHotspot({ key: 'test3' }) + mockRawHotspot({ key: 'test3' }), ]; - const hotspotKeys = hotspots.map(h => h.key); + const hotspotKeys = hotspots.map((h) => h.key); (getSecurityHotspotList as jest.Mock).mockResolvedValueOnce({ - hotspots + hotspots, }); const location = mockLocation({ query: { hotspots: hotspotKeys.join() } }); const router = mockRouter(); const wrapper = shallowRender({ location, - router + router, }); await waitAndUpdate(wrapper); expect(getSecurityHotspotList).toHaveBeenCalledWith(hotspotKeys, { projectKey: 'my-project', - branch: 'branch-6.7' + branch: 'branch-6.7', }); expect(wrapper.state().hotspotKeys).toEqual(hotspotKeys); expect(wrapper.find(SecurityHotspotsAppRenderer).props().isStaticListOfHotspots).toBe(true); @@ -179,18 +179,15 @@ it('should load data correctly when hotspot key list is forced', async () => { // Reset (getSecurityHotspots as jest.Mock).mockClear(); (getSecurityHotspotList as jest.Mock).mockClear(); - wrapper - .find(SecurityHotspotsAppRenderer) - .props() - .onShowAllHotspots(); + wrapper.find(SecurityHotspotsAppRenderer).props().onShowAllHotspots(); expect(router.push).toHaveBeenCalledWith({ ...location, - query: { ...location.query, hotspots: undefined } + query: { ...location.query, hotspots: undefined }, }); // Simulate a new location wrapper.setProps({ - location: { ...location, query: { ...location.query, hotspots: undefined } } + location: { ...location, query: { ...location.query, hotspots: undefined } }, }); await waitAndUpdate(wrapper); expect(wrapper.state().hotspotKeys).toBeUndefined(); @@ -222,7 +219,7 @@ it('should set "assigned to me" filter according to context (logged in & explici expect( shallowRender({ location: mockLocation({ query: { assignedToMe: 'true' } }), - currentUser: mockLoggedInUser() + currentUser: mockLoggedInUser(), }).state().filters.assignedToMe ).toBe(true); }); @@ -233,11 +230,11 @@ it('should handle loading more', async () => { (getSecurityHotspots as jest.Mock) .mockResolvedValueOnce({ hotspots, - paging: { total: 5 } + paging: { total: 5 }, }) .mockResolvedValueOnce({ hotspots: hotspots2, - paging: { total: 5 } + paging: { total: 5 }, }); const wrapper = shallowRender(); @@ -266,7 +263,7 @@ it('should handle hotspot update', async () => { (getSecurityHotspots as jest.Mock).mockResolvedValueOnce({ hotspots, - paging: { pageIndex: 1, total: 1252 } + paging: { pageIndex: 1, total: 1252 }, }); let wrapper = shallowRender(); @@ -277,21 +274,18 @@ it('should handle hotspot update', async () => { (getSecurityHotspots as jest.Mock) .mockResolvedValueOnce({ hotspots: [mockRawHotspot()], - paging: { pageIndex: 1, total: 1251 } + paging: { pageIndex: 1, total: 1251 }, }) .mockResolvedValueOnce({ hotspots: [mockRawHotspot()], - paging: { pageIndex: 2, total: 1251 } + paging: { pageIndex: 2, total: 1251 }, }); const selectedHotspotIndex = wrapper .state() - .hotspots.findIndex(h => h.key === wrapper.state().selectedHotspot?.key); + .hotspots.findIndex((h) => h.key === wrapper.state().selectedHotspot?.key); - await wrapper - .find(SecurityHotspotsAppRenderer) - .props() - .onUpdateHotspot(key); + await wrapper.find(SecurityHotspotsAppRenderer).props().onUpdateHotspot(key); expect(getSecurityHotspots).toHaveBeenCalledTimes(2); @@ -299,25 +293,22 @@ it('should handle hotspot update', async () => { expect(wrapper.state().hotspotsPageIndex).toBe(2); expect(wrapper.state().hotspotsTotal).toBe(1251); expect( - wrapper.state().hotspots.findIndex(h => h.key === wrapper.state().selectedHotspot?.key) + wrapper.state().hotspots.findIndex((h) => h.key === wrapper.state().selectedHotspot?.key) ).toBe(selectedHotspotIndex); expect(getMeasures).toHaveBeenCalled(); (getSecurityHotspots as jest.Mock).mockResolvedValueOnce({ hotspots, - paging: { pageIndex: 1, total: 1252 } + paging: { pageIndex: 1, total: 1252 }, }); wrapper = shallowRender({ branchLike, fetchBranchStatus: fetchBranchStatusMock, - component: mockComponent({ key: componentKey }) + component: mockComponent({ key: componentKey }), }); - await wrapper - .find(SecurityHotspotsAppRenderer) - .props() - .onUpdateHotspot(key); + await wrapper.find(SecurityHotspotsAppRenderer).props().onUpdateHotspot(key); expect(fetchBranchStatusMock).toHaveBeenCalledWith(branchLike, componentKey); }); @@ -418,10 +409,10 @@ describe('keyboard navigation', () => { const hotspots = [ mockRawHotspot({ key: 'k1' }), mockRawHotspot({ key: 'k2' }), - mockRawHotspot({ key: 'k3' }) + mockRawHotspot({ key: 'k3' }), ]; const flowsData = { - flows: [{ locations: [mockFlowLocation(), mockFlowLocation(), mockFlowLocation()] }] + flows: [{ locations: [mockFlowLocation(), mockFlowLocation(), mockFlowLocation()] }], }; const hotspotsForLocation = mockRawHotspot(flowsData); @@ -436,7 +427,7 @@ describe('keyboard navigation', () => { ['selecting next, non-existent', 2, 1, 2], ['jumping down', 0, 18, 2], ['jumping up', 2, -18, 0], - ['none selected', 4, -2, 4] + ['none selected', 4, -2, 4], ])('should work when %s', (_, start, shift, expected) => { wrapper.setState({ selectedHotspot: hotspots[start] }); wrapper.instance().selectNeighboringHotspot(shift); @@ -447,7 +438,7 @@ describe('keyboard navigation', () => { it.each([ ['selecting next locations when nothing is selected', undefined, 0], ['selecting next locations', 0, 1], - ['selecting next locations, non-existent', 2, undefined] + ['selecting next locations, non-existent', 2, undefined], ])('should work when %s', (_, start, expected) => { wrapper.setState({ selectedHotspotLocationIndex: start, selectedHotspot: hotspotsForLocation }); wrapper.instance().handleKeyDown(mockEvent({ altKey: true, key: KeyboardKeys.DownArrow })); @@ -458,7 +449,7 @@ describe('keyboard navigation', () => { it.each([ ['selecting previous locations when nothing is selected', undefined, undefined], ['selecting previous locations', 1, 0], - ['selecting previous locations, non-existent', 0, undefined] + ['selecting previous locations, non-existent', 0, undefined], ])('should work when %s', (_, start, expected) => { wrapper.setState({ selectedHotspotLocationIndex: start, selectedHotspot: hotspotsForLocation }); wrapper.instance().handleKeyDown(mockEvent({ altKey: true, key: KeyboardKeys.UpArrow })); diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/__tests__/SecurityHotspotsAppRenderer-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/__tests__/SecurityHotspotsAppRenderer-test.tsx index e0e592c6f63..d5484ee24ee 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/__tests__/SecurityHotspotsAppRenderer-test.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/__tests__/SecurityHotspotsAppRenderer-test.tsx @@ -27,11 +27,11 @@ import { SecurityStandard } from '../../../types/security'; import { HotspotStatusFilter } from '../../../types/security-hotspots'; import FilterBar from '../components/FilterBar'; import SecurityHotspotsAppRenderer, { - SecurityHotspotsAppRendererProps + SecurityHotspotsAppRendererProps, } from '../SecurityHotspotsAppRenderer'; jest.mock('../../../helpers/scrolling', () => ({ - scrollToElement: jest.fn() + scrollToElement: jest.fn(), })); jest.mock('../../../components/common/ScreenPositionHelper'); @@ -44,7 +44,7 @@ jest.mock('react', () => { return { ...jest.requireActual('react'), useRef: jest.fn(), - useEffect: jest.fn() + useEffect: jest.fn(), }; }); @@ -52,7 +52,11 @@ it('should render correctly', () => { expect(shallowRender()).toMatchSnapshot(); expect( shallowRender({ - filters: { assignedToMe: true, inNewCodePeriod: false, status: HotspotStatusFilter.TO_REVIEW } + filters: { + assignedToMe: true, + inNewCodePeriod: false, + status: HotspotStatusFilter.TO_REVIEW, + }, }) ).toMatchSnapshot('no hotspots with filters'); expect(shallowRender({ loading: true })).toMatchSnapshot('loading'); @@ -81,7 +85,7 @@ it('should render correctly when filtered by category or cwe', () => { filterByCategory: { category: 'a1', standard: SecurityStandard.OWASP_TOP10 }, hotspots, hotspotsTotal: 2, - selectedHotspot: hotspots[0] + selectedHotspot: hotspots[0], }) .find(ScreenPositionHelper) .dive() @@ -92,10 +96,7 @@ it('should properly propagate the "show all" call', () => { const onShowAllHotspots = jest.fn(); const wrapper = shallowRender({ onShowAllHotspots }); - wrapper - .find(FilterBar) - .props() - .onShowAllHotspots(); + wrapper.find(FilterBar).props().onShowAllHotspots(); expect(onShowAllHotspots).toHaveBeenCalled(); }); @@ -105,7 +106,7 @@ describe('side effect', () => { const fakeParent = document.createElement('div'); beforeEach(() => { - (React.useEffect as jest.Mock).mockImplementationOnce(f => f()); + (React.useEffect as jest.Mock).mockImplementationOnce((f) => f()); jest.spyOn(document, 'querySelector').mockImplementationOnce(() => fakeElement); (React.useRef as jest.Mock).mockImplementationOnce(() => ({ current: fakeParent })); }); @@ -140,7 +141,7 @@ function shallowRender(props: Partial<SecurityHotspotsAppRendererProps> = {}) { filters={{ assignedToMe: false, inNewCodePeriod: false, - status: HotspotStatusFilter.TO_REVIEW + status: HotspotStatusFilter.TO_REVIEW, }} hotspots={[]} hotspotsTotal={0} diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/__tests__/utils-test.ts b/server/sonar-web/src/main/js/apps/security-hotspots/__tests__/utils-test.ts index 12856d774dd..2090d30ea9d 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/__tests__/utils-test.ts +++ b/server/sonar-web/src/main/js/apps/security-hotspots/__tests__/utils-test.ts @@ -26,7 +26,7 @@ import { HotspotStatusOption, RawHotspot, ReviewHistoryType, - RiskExposure + RiskExposure, } from '../../../types/security-hotspots'; import { FlowLocation, IssueChangelog } from '../../../types/types'; import { @@ -37,7 +37,7 @@ import { getStatusOptionFromStatusAndResolution, groupByCategory, mapRules, - sortHotspots + sortHotspots, } from '../utils'; const hotspots = [ @@ -45,87 +45,87 @@ const hotspots = [ key: '3', vulnerabilityProbability: RiskExposure.HIGH, securityCategory: 'object-injection', - message: 'tfdh' + message: 'tfdh', }), mockRawHotspot({ key: '5', vulnerabilityProbability: RiskExposure.MEDIUM, securityCategory: 'xpath-injection', - message: 'asdf' + message: 'asdf', }), mockRawHotspot({ key: '1', vulnerabilityProbability: RiskExposure.HIGH, securityCategory: 'dos', - message: 'a' + message: 'a', }), mockRawHotspot({ key: '7', vulnerabilityProbability: RiskExposure.LOW, securityCategory: 'ssrf', - message: 'rrrr' + message: 'rrrr', }), mockRawHotspot({ key: '2', vulnerabilityProbability: RiskExposure.HIGH, securityCategory: 'dos', - message: 'b' + message: 'b', }), mockRawHotspot({ key: '8', vulnerabilityProbability: RiskExposure.LOW, securityCategory: 'ssrf', - message: 'sssss' + message: 'sssss', }), mockRawHotspot({ key: '4', vulnerabilityProbability: RiskExposure.MEDIUM, securityCategory: 'log-injection', - message: 'asdf' + message: 'asdf', }), mockRawHotspot({ key: '9', vulnerabilityProbability: RiskExposure.LOW, securityCategory: 'xxe', - message: 'aaa' + message: 'aaa', }), mockRawHotspot({ key: '6', vulnerabilityProbability: RiskExposure.LOW, securityCategory: 'xss', - message: 'zzz' - }) + message: 'zzz', + }), ]; const categories = { 'object-injection': { - title: 'Object Injection' + title: 'Object Injection', }, 'xpath-injection': { - title: 'XPath Injection' + title: 'XPath Injection', }, 'log-injection': { - title: 'Log Injection' + title: 'Log Injection', }, dos: { - title: 'Denial of Service (DoS)' + title: 'Denial of Service (DoS)', }, ssrf: { - title: 'Server-Side Request Forgery (SSRF)' + title: 'Server-Side Request Forgery (SSRF)', }, xxe: { - title: 'XML External Entity (XXE)' + title: 'XML External Entity (XXE)', }, xss: { - title: 'Cross-Site Scripting (XSS)' - } + title: 'Cross-Site Scripting (XSS)', + }, }; describe('sortHotspots', () => { it('should sort properly', () => { const result = sortHotspots(hotspots, categories); - expect(result.map(h => h.key)).toEqual(['1', '2', '3', '4', '5', '6', '7', '8', '9']); + expect(result.map((h) => h.key)).toEqual(['1', '2', '3', '4', '5', '6', '7', '8', '9']); }); }); @@ -142,13 +142,13 @@ describe('mapRules', () => { const rules = [ { key: 'a', name: 'A rule' }, { key: 'b', name: 'B rule' }, - { key: 'c', name: 'C rule' } + { key: 'c', name: 'C rule' }, ]; expect(mapRules(rules)).toEqual({ a: 'A rule', b: 'B rule', - c: 'C rule' + c: 'C rule', }); }); }); @@ -164,9 +164,9 @@ describe('getHotspotReviewHistory', () => { { key: 'assign', newValue: 'me', - oldValue: 'him' - } - ] + oldValue: 'him', + }, + ], }; const commentElement = { key: 'comment-1', @@ -175,7 +175,7 @@ describe('getHotspotReviewHistory', () => { markdown: '*TEST*', updatable: true, login: 'dude-1', - user: mockUser({ login: 'dude-1' }) + user: mockUser({ login: 'dude-1' }), }; const commentElement1 = { key: 'comment-2', @@ -184,12 +184,12 @@ describe('getHotspotReviewHistory', () => { markdown: '*TEST*', updatable: true, login: 'dude-2', - user: mockUser({ login: 'dude-2' }) + user: mockUser({ login: 'dude-2' }), }; const hotspot = mockHotspot({ creationDate: '2018-09-01', changelog: [changelogElement], - comment: [commentElement, commentElement1] + comment: [commentElement, commentElement1], }); const reviewHistory = getHotspotReviewHistory(hotspot); @@ -198,7 +198,7 @@ describe('getHotspotReviewHistory', () => { expect.objectContaining({ type: ReviewHistoryType.Creation, date: hotspot.creationDate, - user: hotspot.authorUser + user: hotspot.authorUser, }) ); expect(reviewHistory[2]).toEqual( @@ -206,7 +206,7 @@ describe('getHotspotReviewHistory', () => { type: ReviewHistoryType.Comment, date: commentElement.createdAt, user: commentElement.user, - html: commentElement.htmlText + html: commentElement.htmlText, }) ); expect(reviewHistory[1]).toEqual( @@ -214,7 +214,7 @@ describe('getHotspotReviewHistory', () => { type: ReviewHistoryType.Comment, date: commentElement1.createdAt, user: commentElement1.user, - html: commentElement1.htmlText + html: commentElement1.htmlText, }) ); expect(reviewHistory[0]).toEqual( @@ -224,9 +224,9 @@ describe('getHotspotReviewHistory', () => { user: { avatar: changelogElement.avatar, name: changelogElement.userName, - active: changelogElement.isUserActive + active: changelogElement.isUserActive, }, - diffs: changelogElement.diffs + diffs: changelogElement.diffs, }) ); }); @@ -253,15 +253,15 @@ describe('getStatusAndResolutionFromStatusOption', () => { it('should return the correct values', () => { expect(getStatusAndResolutionFromStatusOption(HotspotStatusOption.TO_REVIEW)).toEqual({ status: HotspotStatus.TO_REVIEW, - resolution: undefined + resolution: undefined, }); expect(getStatusAndResolutionFromStatusOption(HotspotStatusOption.FIXED)).toEqual({ status: HotspotStatus.REVIEWED, - resolution: HotspotResolution.FIXED + resolution: HotspotResolution.FIXED, }); expect(getStatusAndResolutionFromStatusOption(HotspotStatusOption.SAFE)).toEqual({ status: HotspotStatus.REVIEWED, - resolution: HotspotResolution.SAFE + resolution: HotspotResolution.SAFE, }); }); }); @@ -285,36 +285,36 @@ describe('getLocations', () => { const location1: FlowLocation = { component: 'foo', msg: 'Do not use foo', - textRange: { startLine: 7, endLine: 7, startOffset: 5, endOffset: 8 } + textRange: { startLine: 7, endLine: 7, startOffset: 5, endOffset: 8 }, }; const location2: FlowLocation = { component: 'foo2', msg: 'Do not use foo2', - textRange: { startLine: 7, endLine: 7, startOffset: 5, endOffset: 8 } + textRange: { startLine: 7, endLine: 7, startOffset: 5, endOffset: 8 }, }; let rawFlows: RawHotspot['flows'] = [ { - locations: [location1] - } + locations: [location1], + }, ]; expect(getLocations(rawFlows, undefined)).toEqual([location1]); rawFlows = [ { - locations: [location1, location2] - } + locations: [location1, location2], + }, ]; expect(getLocations(rawFlows, undefined)).toEqual([location2, location1]); rawFlows = [ { - locations: [location1, location2] + locations: [location1, location2], }, { - locations: [] - } + locations: [], + }, ]; expect(getLocations(rawFlows, 0)).toEqual([location2, location1]); }); diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/FilterBar.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/FilterBar.tsx index 91409b6441a..40ff52e37c2 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/FilterBar.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/FilterBar.tsx @@ -47,25 +47,25 @@ const statusOptions: Array<{ label: string; value: HotspotStatusFilter }> = [ { value: HotspotStatusFilter.TO_REVIEW, label: translate('hotspot.filters.status.to_review') }, { value: HotspotStatusFilter.ACKNOWLEDGED, - label: translate('hotspot.filters.status.acknowledged') + label: translate('hotspot.filters.status.acknowledged'), }, { value: HotspotStatusFilter.FIXED, label: translate('hotspot.filters.status.fixed') }, - { value: HotspotStatusFilter.SAFE, label: translate('hotspot.filters.status.safe') } + { value: HotspotStatusFilter.SAFE, label: translate('hotspot.filters.status.safe') }, ]; const periodOptions = [ { value: true, label: translate('hotspot.filters.period.since_leak_period') }, - { value: false, label: translate('hotspot.filters.period.overall') } + { value: false, label: translate('hotspot.filters.period.overall') }, ]; export enum AssigneeFilterOption { ALL = 'all', - ME = 'me' + ME = 'me', } const assigneeFilterOptions = [ { value: AssigneeFilterOption.ME, label: translate('hotspot.filters.assignee.assigned_to_me') }, - { value: AssigneeFilterOption.ALL, label: translate('hotspot.filters.assignee.all') } + { value: AssigneeFilterOption.ALL, label: translate('hotspot.filters.assignee.all') }, ]; export function FilterBar(props: FilterBarProps) { @@ -76,7 +76,7 @@ export function FilterBar(props: FilterBarProps) { hotspotsReviewedMeasure, isStaticListOfHotspots, loadingMeasure, - onBranch + onBranch, } = props; const isProject = component.qualifier === ComponentQualifier.Project; @@ -89,7 +89,8 @@ export function FilterBar(props: FilterBarProps) { id="show_all_hotspot" onClick={() => props.onShowAllHotspots()} role="link" - tabIndex={0}> + tabIndex={0} + > {translate('hotspot.filters.show_all')} </a> ) : ( @@ -120,7 +121,7 @@ export function FilterBar(props: FilterBarProps) { } options={statusOptions} isSearchable={false} - value={statusOptions.find(status => status.value === filters.status)} + value={statusOptions.find((status) => status.value === filters.status)} /> {onBranch && ( @@ -132,7 +133,7 @@ export function FilterBar(props: FilterBarProps) { } options={periodOptions} isSearchable={false} - value={periodOptions.find(period => period.value === filters.inNewCodePeriod)} + value={periodOptions.find((period) => period.value === filters.inNewCodePeriod)} /> )} </div> diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotCategory.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotCategory.tsx index 8197e305607..3a475d06c48 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotCategory.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotCategory.tsx @@ -46,7 +46,7 @@ export default function HotspotCategory(props: HotspotCategoryProps) { selectedHotspot, title, isLastAndIncomplete, - selectedHotspotLocation + selectedHotspotLocation, } = props; if (hotspots.length < 1) { @@ -64,7 +64,8 @@ export default function HotspotCategory(props: HotspotCategoryProps) { { 'contains-selected-hotspot': selectedHotspot.securityCategory === categoryKey } )} onClick={() => props.onToggleExpand && props.onToggleExpand(categoryKey, !expanded)} - aria-expanded={expanded}> + aria-expanded={expanded} + > <strong className="flex-1 spacer-right break-word">{title}</strong> <span> <span className="counter-badge"> @@ -85,7 +86,7 @@ export default function HotspotCategory(props: HotspotCategoryProps) { )} {expanded && ( <ul> - {hotspots.map(h => ( + {hotspots.map((h) => ( <li data-hotspot-key={h.key} key={h.key}> <HotspotListItem hotspot={h} diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotCommentPopup.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotCommentPopup.tsx index eaaf49af299..bbc2e01417d 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotCommentPopup.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotCommentPopup.tsx @@ -36,7 +36,7 @@ export default function HotspotCommentPopup(props: HotspotCommentPopupProps) { <div className="issue-comment-form-text"> <textarea autoFocus={true} - onChange={event => setComment(event.target.value)} + onChange={(event) => setComment(event.target.value)} rows={2} value={comment} /> @@ -48,14 +48,16 @@ export default function HotspotCommentPopup(props: HotspotCommentPopupProps) { <div className=""> <Button className="little-spacer-right" - onClick={() => props.onCommentEditSubmit(comment)}> + onClick={() => props.onCommentEditSubmit(comment)} + > {translate('save')} </Button> <ResetButtonLink onClick={() => { setComment(''); props.onCancelEdit(); - }}> + }} + > {translate('cancel')} </ResetButtonLink> </div> diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotHeader.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotHeader.tsx index d9402440b4c..c35fa0359f9 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotHeader.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotHeader.tsx @@ -48,7 +48,7 @@ export function HotspotHeader(props: HotspotHeaderProps) { <div className="display-flex-space-between"> <Status hotspot={hotspot} - onStatusChange={statusOption => props.onUpdateHotspot(true, statusOption)} + onStatusChange={(statusOption) => props.onUpdateHotspot(true, statusOption)} /> <div className="display-flex-end"> <div className="display-inline-flex-center it__hs-assignee"> diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotList.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotList.tsx index a8d298b0d04..47ec65eef17 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotList.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotList.tsx @@ -58,7 +58,7 @@ export default class HotspotList extends React.Component<Props, State> { this.state = { expandedCategories: { [props.selectedHotspot.securityCategory]: true }, - groupedHotspots: this.groupHotspots(props.hotspots, props.securityCategories) + groupedHotspots: this.groupHotspots(props.hotspots, props.securityCategories), }; } @@ -100,17 +100,17 @@ export default class HotspotList extends React.Component<Props, State> { } groupHotspots = (hotspots: RawHotspot[], securityCategories: StandardSecurityCategories) => { - const risks = groupBy(hotspots, h => h.vulnerabilityProbability); + const risks = groupBy(hotspots, (h) => h.vulnerabilityProbability); - return RISK_EXPOSURE_LEVELS.map(risk => ({ + return RISK_EXPOSURE_LEVELS.map((risk) => ({ risk, - categories: groupByCategory(risks[risk], securityCategories) - })).filter(risk => risk.categories.length > 0); + categories: groupByCategory(risks[risk], securityCategories), + })).filter((risk) => risk.categories.length > 0); }; handleToggleCategory = (categoryKey: string, value: boolean) => { this.setState(({ expandedCategories }) => ({ - expandedCategories: { ...expandedCategories, [categoryKey]: value } + expandedCategories: { ...expandedCategories, [categoryKey]: value }, })); }; @@ -122,7 +122,7 @@ export default class HotspotList extends React.Component<Props, State> { loadingMore, selectedHotspot, selectedHotspotLocation, - statusFilter + statusFilter, } = this.props; const { expandedCategories, groupedHotspots } = this.state; diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotListItem.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotListItem.tsx index 81ed5460eda..df0e499d2e6 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotListItem.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotListItem.tsx @@ -43,12 +43,14 @@ export default function HotspotListItem(props: HotspotListItemProps) { <ButtonPlain aria-current={selected} className={classNames('hotspot-item', { highlight: selected })} - onClick={() => !selected && props.onClick(hotspot)}> + onClick={() => !selected && props.onClick(hotspot)} + > {/* This is not a real interaction it is only for scrolling */ /* eslint-disable-next-line jsx-a11y/no-static-element-interactions */} <div className={classNames('little-spacer-left text-bold', { 'cursor-pointer': selected })} - onClick={selected ? () => props.onLocationClick() : undefined}> + onClick={selected ? () => props.onLocationClick() : undefined} + > {hotspot.message} </div> <div className="display-flex-center big-spacer-top"> diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotOpenInIdeButton.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotOpenInIdeButton.tsx index c7f5bfbe1b5..efae47c0da9 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotOpenInIdeButton.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotOpenInIdeButton.tsx @@ -43,7 +43,7 @@ export default class HotspotOpenInIdeButton extends React.PureComponent<Props, S state = { loading: false, - ides: [] + ides: [], }; componentDidMount() { @@ -97,7 +97,8 @@ export default class HotspotOpenInIdeButton extends React.PureComponent<Props, S <DropdownOverlay> <HotspotOpenInIdeOverlay ides={this.state.ides} onIdeSelected={this.openHotspot} /> </DropdownOverlay> - }> + } + > <Button onClick={this.handleOnClick}> {translate('hotspots.open_in_ide.open')} <DeferredSpinner loading={this.state.loading} className="spacer-left" /> diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotOpenInIdeOverlay.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotOpenInIdeOverlay.tsx index de395abe329..d3511a7a8e8 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotOpenInIdeOverlay.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotOpenInIdeOverlay.tsx @@ -22,14 +22,14 @@ import { Ide } from '../../../types/sonarlint'; export const HotspotOpenInIdeOverlay = ({ ides, - onIdeSelected + onIdeSelected, }: { ides: Array<Ide>; onIdeSelected: (ide: Ide) => Promise<void>; }) => ides.length > 1 ? ( <ul className="menu"> - {ides.map(ide => { + {ides.map((ide) => { const { ideName, description } = ide; const label = ideName + (description ? ` - ${description}` : ''); return ( diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotPrimaryLocationBox.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotPrimaryLocationBox.tsx index 1720cd7d77e..bc297c01249 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotPrimaryLocationBox.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotPrimaryLocationBox.tsx @@ -53,12 +53,14 @@ export function HotspotPrimaryLocationBox(props: HotspotPrimaryLocationBoxProps) 'display-flex-space-between display-flex-center padded-top padded-bottom big-padded-left big-padded-right', `hotspot-risk-exposure-${hotspot.rule.vulnerabilityProbability}` )} - ref={locationRef}> + ref={locationRef} + > <div className="text-bold">{hotspot.message}</div> {isLoggedIn(currentUser) && ( <ButtonLink className="nowrap big-spacer-left it__hs-add-comment" - onClick={props.onCommentClick}> + onClick={props.onCommentClick} + > {translate('hotspots.comment.open')} </ButtonLink> )} diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotReviewHistory.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotReviewHistory.tsx index 4941f12ce08..87a55a8b372 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotReviewHistory.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotReviewHistory.tsx @@ -59,9 +59,10 @@ export default function HotspotReviewHistory(props: HotspotReviewHistoryProps) { return ( <li className={classNames('padded-top padded-bottom', { - 'bordered-top': historyIndex > 0 + 'bordered-top': historyIndex > 0, })} - key={historyIndex}> + key={historyIndex} + > <div className="display-flex-center"> {user.name && ( <> @@ -120,13 +121,14 @@ export default function HotspotReviewHistory(props: HotspotReviewHistoryProps) { <HotspotCommentPopup markdownComment={markdown} onCancelEdit={() => setEditedCommentKey('')} - onCommentEditSubmit={comment => { + onCommentEditSubmit={(comment) => { setEditedCommentKey(''); props.onEditComment(key, comment); }} /> </DropdownOverlay> - }> + } + > <EditButton className="button-small" onClick={() => setEditedCommentKey(key)} @@ -140,12 +142,14 @@ export default function HotspotReviewHistory(props: HotspotReviewHistoryProps) { <p>{translate('issue.comment.delete_confirm_message')}</p> <Button className="button-red big-spacer-top pull-right" - onClick={() => props.onDeleteComment(key)}> + onClick={() => props.onDeleteComment(key)} + > {translate('delete')} </Button> </div> } - overlayPlacement={PopupPlacement.BottomRight}> + overlayPlacement={PopupPlacement.BottomRight} + > <DeleteButton className="button-small" /> </Dropdown> </div> diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotReviewHistoryAndComments.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotReviewHistoryAndComments.tsx index 32e8ec99959..3f638901089 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotReviewHistoryAndComments.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotReviewHistoryAndComments.tsx @@ -21,7 +21,7 @@ import * as React from 'react'; import { commentSecurityHotspot, deleteSecurityHotspotComment, - editSecurityHotspotComment + editSecurityHotspotComment, } from '../../../api/security-hotspots'; import FormattingTips from '../../../components/common/FormattingTips'; import { Button } from '../../../components/controls/buttons'; @@ -47,7 +47,7 @@ export default class HotspotReviewHistoryAndComments extends React.PureComponent super(props); this.state = { comment: '', - showFullHistory: false + showFullHistory: false, }; } @@ -55,7 +55,7 @@ export default class HotspotReviewHistoryAndComments extends React.PureComponent if (prevProps.hotspot.key !== this.props.hotspot.key) { this.setState({ comment: '', - showFullHistory: false + showFullHistory: false, }); } } @@ -109,7 +109,8 @@ export default class HotspotReviewHistoryAndComments extends React.PureComponent <Button className="huge-spacer-bottom" id="hotspot-comment-box-submit" - onClick={this.handleSubmitComment}> + onClick={this.handleSubmitComment} + > {translate('hotspots.comment.submit')} </Button> </div> diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotSimpleList.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotSimpleList.tsx index 98128701214..ed432da965e 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotSimpleList.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotSimpleList.tsx @@ -68,7 +68,7 @@ export default class HotspotSimpleList extends React.Component<HotspotSimpleList loadingMore, selectedHotspot, selectedHotspotLocation, - standards + standards, } = this.props; const categoryLabel = @@ -108,7 +108,7 @@ export default class HotspotSimpleList extends React.Component<HotspotSimpleList </strong> </div> <ul> - {hotspots.map(h => ( + {hotspots.map((h) => ( <li data-hotspot-key={h.key} key={h.key}> <HotspotListItem hotspot={h} diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotSnippetContainer.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotSnippetContainer.tsx index 01f7f6821f5..8699d2c7de3 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotSnippetContainer.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotSnippetContainer.tsx @@ -53,7 +53,7 @@ export default class HotspotSnippetContainer extends React.Component<Props, Stat highlightedSymbols: [], loading: true, sourceLines: [], - secondaryLocations: [] + secondaryLocations: [], }; async componentDidMount() { @@ -87,7 +87,7 @@ export default class HotspotSnippetContainer extends React.Component<Props, Stat async fetchSources() { const { branchLike, - hotspot: { component, textRange } + hotspot: { component, textRange }, } = this.props; const { secondaryLocations } = this.state; @@ -102,16 +102,16 @@ export default class HotspotSnippetContainer extends React.Component<Props, Stat const from = Math.max( 1, Math.min( - ...[textRange, ...secondaryLocations.map(l => l.textRange)].map( - t => t.startLine - BUFFER_LINES + ...[textRange, ...secondaryLocations.map((l) => l.textRange)].map( + (t) => t.startLine - BUFFER_LINES ) ) ); // Search for the max endLine within primary and secondary locations const to = Math.max( - ...[textRange, ...secondaryLocations.map(l => l.textRange)].map( + ...[textRange, ...secondaryLocations.map((l) => l.textRange)].map( // Add 1 to check for end-of-file - t => t.endLine + BUFFER_LINES + 1 + (t) => t.endLine + BUFFER_LINES + 1 ) ); @@ -121,7 +121,7 @@ export default class HotspotSnippetContainer extends React.Component<Props, Stat key: component.key, from, to, - ...getBranchLikeQuery(branchLike) + ...getBranchLikeQuery(branchLike), }).catch(() => [] as SourceLine[]); if (this.mounted) { @@ -136,14 +136,14 @@ export default class HotspotSnippetContainer extends React.Component<Props, Stat initializeSecondaryLocations() { const { hotspot } = this.props; - return new Promise(resolve => { + return new Promise((resolve) => { this.setState( { secondaryLocations: getLocations(hotspot.flows, undefined).map((location, index) => ({ ...location, index, - text: location.msg - })) + text: location.msg, + })), }, () => resolve(undefined) ); @@ -158,19 +158,19 @@ export default class HotspotSnippetContainer extends React.Component<Props, Stat direction === 'up' ? { from: Math.max(1, sourceLines[0].line - EXPAND_BY_LINES), - to: sourceLines[0].line - 1 + to: sourceLines[0].line - 1, } : { from: sourceLines[sourceLines.length - 1].line + 1, // Add 1 to check for end-of-file: - to: sourceLines[sourceLines.length - 1].line + EXPAND_BY_LINES + 1 + to: sourceLines[sourceLines.length - 1].line + EXPAND_BY_LINES + 1, }; return getSources({ key: hotspot.component.key, ...range, - ...getBranchLikeQuery(branchLike) - }).then(additionalLines => { + ...getBranchLikeQuery(branchLike), + }).then((additionalLines) => { const { lastLine: previousLastLine } = this.state; const lastLine = @@ -188,7 +188,7 @@ export default class HotspotSnippetContainer extends React.Component<Props, Stat this.setState({ lastLine, - sourceLines: concatSourceLines + sourceLines: concatSourceLines, }); }); }; diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotSnippetContainerRenderer.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotSnippetContainerRenderer.tsx index 3c8f12e0557..1d5b6485ce1 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotSnippetContainerRenderer.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotSnippetContainerRenderer.tsx @@ -29,7 +29,7 @@ import { FlowLocation, LinearIssueLocation, SourceLine, - SourceViewerFile + SourceViewerFile, } from '../../../types/types'; import SnippetViewer from '../../issues/crossComponentSourceViewer/SnippetViewer'; import HotspotPrimaryLocationBox from './HotspotPrimaryLocationBox'; @@ -70,7 +70,7 @@ export function getScrollHandler(scrollableRef: React.RefObject<HTMLDivElement>) parent, topOffset: offset ?? TOP_OFFSET, bottomOffset: offset ?? BOTTOM_OFFSET, - smooth + smooth, }); } }, SCROLL_DELAY); @@ -141,7 +141,7 @@ export default function HotspotSnippetContainerRenderer( sourceViewerFile, secondaryLocations, component, - selectedHotspotLocation + selectedHotspotLocation, } = props; const scrollableRef = React.useRef<HTMLDivElement>(null); diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotSnippetHeader.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotSnippetHeader.tsx index 1ed19a6a947..ab4a739a34f 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotSnippetHeader.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotSnippetHeader.tsx @@ -47,7 +47,7 @@ export function HotspotSnippetHeader(props: HotspotSnippetHeaderProps) { const { hotspot, currentUser, component, branchLike } = props; const { project, - component: { qualifier, path } + component: { qualifier, path }, } = hotspot; const displayProjectName = component.qualifier === ComponentQualifier.Application; @@ -55,7 +55,7 @@ export function HotspotSnippetHeader(props: HotspotSnippetHeaderProps) { const permalink = getPathUrlAsString( getComponentSecurityHotspotsUrl(component.key, { ...getBranchLikeQuery(branchLike), - hotspots: hotspot?.key + hotspots: hotspot?.key, }), false ); diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewer.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewer.tsx index 85763e86b7b..b2bcf81952c 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewer.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewer.tsx @@ -24,7 +24,7 @@ import { scrollToElement } from '../../../helpers/scrolling'; import { Hotspot, HotspotStatusFilter, - HotspotStatusOption + HotspotStatusOption, } from '../../../types/security-hotspots'; import { Component } from '../../../types/types'; import { RuleDescriptionSection } from '../../coding-rules/rule'; @@ -81,13 +81,13 @@ export default class HotspotViewer extends React.PureComponent<Props, State> { this.setState({ loading: true }); try { const hotspot = await getSecurityHotspotDetails(this.props.hotspotKey); - const ruleDetails = await getRuleDetails({ key: hotspot.rule.key }).then(r => r.rule); + const ruleDetails = await getRuleDetails({ key: hotspot.rule.key }).then((r) => r.rule); if (this.mounted) { this.setState({ hotspot, loading: false, - ruleDescriptionSections: ruleDetails.descriptionSections + ruleDescriptionSections: ruleDetails.descriptionSections, }); } } catch (error) { @@ -112,7 +112,7 @@ export default class HotspotViewer extends React.PureComponent<Props, State> { if (this.commentTextRef.current) { this.commentTextRef.current.focus({ preventScroll: true }); scrollToElement(this.commentTextRef.current, { - bottomOffset: SCROLL_TO_COMMENT_BOTTOM_OFFSET + bottomOffset: SCROLL_TO_COMMENT_BOTTOM_OFFSET, }); } }; @@ -135,7 +135,7 @@ export default class HotspotViewer extends React.PureComponent<Props, State> { ruleDescriptionSections, lastStatusChangedTo, loading, - showStatusUpdateSuccessModal + showStatusUpdateSuccessModal, } = this.state; return ( diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerRenderer.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerRenderer.tsx index f4c1d8d06b3..0e46d5d5ded 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerRenderer.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerRenderer.tsx @@ -61,7 +61,7 @@ export function HotspotViewerRenderer(props: HotspotViewerRendererProps) { showStatusUpdateSuccessModal, commentTextRef, selectedHotspotLocation, - ruleDescriptionSections + ruleDescriptionSections, } = props; return ( diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerTabs.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerTabs.tsx index 5b0bd74fb42..fa63cc0a484 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerTabs.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerTabs.tsx @@ -49,7 +49,7 @@ export enum TabKeys { Code = 'code', RiskDescription = 'risk', VulnerabilityDescription = 'vulnerability', - FixRecommendation = 'fix' + FixRecommendation = 'fix', } export default class HotspotViewerTabs extends React.PureComponent<Props, State> { @@ -58,7 +58,7 @@ export default class HotspotViewerTabs extends React.PureComponent<Props, State> const tabs = this.computeTabs(); this.state = { currentTab: tabs[0], - tabs + tabs, }; } @@ -74,7 +74,7 @@ export default class HotspotViewerTabs extends React.PureComponent<Props, State> const tabs = this.computeTabs(); this.setState({ currentTab: tabs[0], - tabs + tabs, }); } else if ( this.props.selectedHotspotLocation !== undefined && @@ -82,7 +82,7 @@ export default class HotspotViewerTabs extends React.PureComponent<Props, State> ) { const { tabs } = this.state; this.setState({ - currentTab: tabs[0] + currentTab: tabs[0], }); } } @@ -114,13 +114,13 @@ export default class HotspotViewerTabs extends React.PureComponent<Props, State> handleSelectTabs = (tabKey: TabKeys) => { const { tabs } = this.state; - const currentTab = tabs.find(tab => tab.key === tabKey)!; + const currentTab = tabs.find((tab) => tab.key === tabKey)!; this.setState({ currentTab }); }; computeTabs() { const { ruleDescriptionSections, codeTabContent } = this.props; - const descriptionSectionsByKey = groupBy(ruleDescriptionSections, section => section.key); + const descriptionSectionsByKey = groupBy(ruleDescriptionSections, (section) => section.key); const rootCauseDescriptionSections = descriptionSectionsByKey[RuleDescriptionSections.DEFAULT] || descriptionSectionsByKey[RuleDescriptionSections.ROOT_CAUSE]; @@ -129,7 +129,7 @@ export default class HotspotViewerTabs extends React.PureComponent<Props, State> { key: TabKeys.Code, label: translate('hotspots.tabs.code'), - content: <div className="padded">{codeTabContent}</div> + content: <div className="padded">{codeTabContent}</div>, }, { key: TabKeys.RiskDescription, @@ -140,7 +140,7 @@ export default class HotspotViewerTabs extends React.PureComponent<Props, State> sections={rootCauseDescriptionSections} isDefault={true} /> - ) + ), }, { key: TabKeys.VulnerabilityDescription, @@ -151,7 +151,7 @@ export default class HotspotViewerTabs extends React.PureComponent<Props, State> sections={descriptionSectionsByKey[RuleDescriptionSections.ASSESS_THE_PROBLEM]} isDefault={true} /> - ) + ), }, { key: TabKeys.FixRecommendation, @@ -162,19 +162,19 @@ export default class HotspotViewerTabs extends React.PureComponent<Props, State> sections={descriptionSectionsByKey[RuleDescriptionSections.HOW_TO_FIX]} isDefault={true} /> - ) - } - ].filter(tab => tab.content); + ), + }, + ].filter((tab) => tab.content); } selectNeighboringTab(shift: number) { this.setState(({ tabs, currentTab }) => { - const index = currentTab && tabs.findIndex(tab => tab.key === currentTab.key); + const index = currentTab && tabs.findIndex((tab) => tab.key === currentTab.key); if (index !== undefined && index > -1) { const newIndex = Math.max(0, Math.min(tabs.length - 1, index + shift)); return { - currentTab: tabs[newIndex] + currentTab: tabs[newIndex], }; } @@ -191,7 +191,8 @@ export default class HotspotViewerTabs extends React.PureComponent<Props, State> className="bordered huge-spacer-bottom" role="tabpanel" aria-labelledby={getTabId(currentTab.key)} - id={getTabPanelId(currentTab.key)}> + id={getTabPanelId(currentTab.key)} + > {currentTab.content} </div> </> diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/StatusUpdateSuccessModal.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/StatusUpdateSuccessModal.tsx index 3cfd92e294d..6c8e3c9d932 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/StatusUpdateSuccessModal.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/StatusUpdateSuccessModal.tsx @@ -56,7 +56,7 @@ export default function StatusUpdateSuccessModal(props: StatusUpdateSuccessModal id="hotspots.successfully_changed_to_x" defaultMessage={translate('hotspots.find_in_status_filter_x')} values={{ - status_label: <strong>{statusLabel}</strong> + status_label: <strong>{statusLabel}</strong>, }} /> {closingHotspots && ( @@ -68,10 +68,10 @@ export default function StatusUpdateSuccessModal(props: StatusUpdateSuccessModal percentage: ( <strong> {formatMeasure(hotspotsReviewedMeasure, 'PERCENT', { - omitExtraDecimalZeros: true + omitExtraDecimalZeros: true, })} </strong> - ) + ), }} /> </p> diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/FilterBar-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/FilterBar-test.tsx index acaa4c993f6..4e1e145ad22 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/FilterBar-test.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/FilterBar-test.tsx @@ -37,7 +37,7 @@ it('should render correctly', () => { expect( shallowRender({ currentUser: mockLoggedInUser(), - component: mockComponent({ qualifier: ComponentQualifier.Application }) + component: mockComponent({ qualifier: ComponentQualifier.Application }), }) ).toMatchSnapshot('non-project'); }); @@ -47,7 +47,7 @@ it('should render correctly when the list of hotspot is static', () => { const wrapper = shallowRender({ isStaticListOfHotspots: true, - onShowAllHotspots + onShowAllHotspots, }); expect(wrapper).toMatchSnapshot(); @@ -59,10 +59,7 @@ it('should trigger onChange for status', () => { const onChangeFilters = jest.fn(); const wrapper = shallowRender({ onChangeFilters }); - const { onChange } = wrapper - .find(Select) - .at(0) - .props(); + const { onChange } = wrapper.find(Select).at(0).props(); onChange({ value: HotspotStatusFilter.SAFE }); expect(onChangeFilters).toHaveBeenCalledWith({ status: HotspotStatusFilter.SAFE }); @@ -82,10 +79,7 @@ it('should trigger onChange for leak period', () => { const onChangeFilters = jest.fn(); const wrapper = shallowRender({ onChangeFilters }); - const { onChange } = wrapper - .find(Select) - .at(1) - .props(); + const { onChange } = wrapper.find(Select).at(1).props(); onChange({ value: true }); expect(onChangeFilters).toHaveBeenCalledWith({ inNewCodePeriod: true }); @@ -99,7 +93,7 @@ function shallowRender(props: Partial<FilterBarProps> = {}) { filters={{ assignedToMe: false, inNewCodePeriod: false, - status: HotspotStatusFilter.TO_REVIEW + status: HotspotStatusFilter.TO_REVIEW, }} isStaticListOfHotspots={false} loadingMeasure={false} diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotCategory-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotCategory-test.tsx index d06f2f67b8b..050f84dfee0 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotCategory-test.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotCategory-test.tsx @@ -30,7 +30,7 @@ it('should render correctly with hotspots', () => { const securityCategory = 'command-injection'; const hotspots = [ mockRawHotspot({ key: 'h1', securityCategory }), - mockRawHotspot({ key: 'h2', securityCategory }) + mockRawHotspot({ key: 'h2', securityCategory }), ]; expect(shallowRender({ hotspots })).toMatchSnapshot(); expect(shallowRender({ hotspots, expanded: false })).toMatchSnapshot('collapsed'); @@ -51,7 +51,7 @@ it('should handle collapse and expand', () => { categoryKey, expanded: true, hotspots: [mockRawHotspot()], - onToggleExpand + onToggleExpand, }); wrapper.find('.hotspot-category-header').simulate('click'); diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotCommentPopup-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotCommentPopup-test.tsx index e04b4033888..666201b6bfc 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotCommentPopup-test.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotCommentPopup-test.tsx @@ -29,7 +29,7 @@ it('should render correclty', () => { it('should trigger update comment', () => { const props = { - onCommentEditSubmit: jest.fn() + onCommentEditSubmit: jest.fn(), }; const wrapper = shallowRender(props); wrapper.find('textarea').simulate('change', { target: { value: 'foo' } }); @@ -40,7 +40,7 @@ it('should trigger update comment', () => { it('should trigger cancel update comment', () => { const props = { - onCancelEdit: jest.fn() + onCancelEdit: jest.fn(), }; const wrapper = shallowRender(props); wrapper.find(ResetButtonLink).simulate('click'); diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotHeader-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotHeader-test.tsx index b285f794897..42e19038993 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotHeader-test.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotHeader-test.tsx @@ -33,10 +33,7 @@ it('correctly propagates the status change', () => { const onUpdateHotspot = jest.fn(); const wrapper = shallowRender({ onUpdateHotspot }); - wrapper - .find(Status) - .props() - .onStatusChange(HotspotStatusOption.FIXED); + wrapper.find(Status).props().onStatusChange(HotspotStatusOption.FIXED); expect(onUpdateHotspot).toHaveBeenCalledWith(true, HotspotStatusOption.FIXED); }); diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotList-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotList-test.tsx index 2876fa8dfa9..3094c3ea8b0 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotList-test.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotList-test.tsx @@ -27,7 +27,7 @@ import HotspotList from '../HotspotList'; jest.mock('../../../../helpers/pages', () => ({ addSideBarClass: jest.fn(), - removeSideBarClass: jest.fn() + removeSideBarClass: jest.fn(), })); it('should render correctly', () => { @@ -57,18 +57,18 @@ const hotspots = [ mockRawHotspot({ key: 'h3', securityCategory: 'cat1', - vulnerabilityProbability: RiskExposure.MEDIUM + vulnerabilityProbability: RiskExposure.MEDIUM, }), mockRawHotspot({ key: 'h4', securityCategory: 'cat1', - vulnerabilityProbability: RiskExposure.MEDIUM + vulnerabilityProbability: RiskExposure.MEDIUM, }), mockRawHotspot({ key: 'h5', securityCategory: 'cat2', - vulnerabilityProbability: RiskExposure.MEDIUM - }) + vulnerabilityProbability: RiskExposure.MEDIUM, + }), ]; it('should render correctly with hotspots', () => { diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotOpenInIdeButton-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotOpenInIdeButton-test.tsx index ef7dce2d793..6cabfb01a28 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotOpenInIdeButton-test.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotOpenInIdeButton-test.tsx @@ -39,7 +39,7 @@ describe('HotspotOpenInIdeButton', () => { expect(wrapper).toMatchSnapshot(); (sonarlint.probeSonarLintServers as jest.Mock).mockResolvedValue([ - { port, ideName: 'BlueJ IDE', description: 'Hello World' } + { port, ideName: 'BlueJ IDE', description: 'Hello World' }, ]); (sonarlint.openHotspot as jest.Mock).mockResolvedValue(null); @@ -71,7 +71,7 @@ describe('HotspotOpenInIdeButton', () => { (sonarlint.probeSonarLintServers as jest.Mock).mockResolvedValue([ { port: port1, ideName: 'BlueJ IDE', description: 'Hello World' }, - { port: port2, ideName: 'Arduino IDE', description: 'Blink' } + { port: port2, ideName: 'Arduino IDE', description: 'Blink' }, ]); wrapper.find(Button).simulate('click'); diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotOpenInIdeOverlay-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotOpenInIdeOverlay-test.tsx index a81b6cee33e..da90459e72f 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotOpenInIdeOverlay-test.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotOpenInIdeOverlay-test.tsx @@ -45,9 +45,6 @@ it('should render menu and select the right IDE', () => { ); expect(wrapper).toMatchSnapshot(); - wrapper - .find('a') - .last() - .simulate('click'); + wrapper.find('a').last().simulate('click'); expect(onIdeSelected).toHaveBeenCalledWith(ide2); }); diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotPrimaryLocationBox-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotPrimaryLocationBox-test.tsx index 8c05746529b..10099bd653a 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotPrimaryLocationBox-test.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotPrimaryLocationBox-test.tsx @@ -25,14 +25,14 @@ import { mockCurrentUser, mockLoggedInUser } from '../../../../helpers/testMocks import { RiskExposure } from '../../../../types/security-hotspots'; import { HotspotPrimaryLocationBox, - HotspotPrimaryLocationBoxProps + HotspotPrimaryLocationBoxProps, } from '../HotspotPrimaryLocationBox'; jest.mock('react', () => { return { ...jest.requireActual('react'), useRef: jest.fn(), - useEffect: jest.fn() + useEffect: jest.fn(), }; }); @@ -43,9 +43,9 @@ it('should render correctly', () => { it.each([[RiskExposure.HIGH], [RiskExposure.MEDIUM], [RiskExposure.LOW]])( 'should indicate risk exposure: %s', - vulnerabilityProbability => { + (vulnerabilityProbability) => { const wrapper = shallowRender({ - hotspot: mockHotspot({ rule: mockHotspotRule({ vulnerabilityProbability }) }) + hotspot: mockHotspot({ rule: mockHotspotRule({ vulnerabilityProbability }) }), }); expect(wrapper.hasClass(`hotspot-risk-exposure-${vulnerabilityProbability}`)).toBe(true); @@ -64,7 +64,7 @@ it('should handle click', () => { it('should scroll on load if no secondary locations selected', () => { const node = document.createElement('div'); (React.useRef as jest.Mock).mockImplementationOnce(() => ({ current: node })); - (React.useEffect as jest.Mock).mockImplementationOnce(f => f()); + (React.useEffect as jest.Mock).mockImplementationOnce((f) => f()); const scroll = jest.fn(); shallowRender({ scroll }); @@ -75,7 +75,7 @@ it('should scroll on load if no secondary locations selected', () => { it('should not scroll on load if a secondary location is selected', () => { const node = document.createElement('div'); (React.useRef as jest.Mock).mockImplementationOnce(() => ({ current: node })); - (React.useEffect as jest.Mock).mockImplementationOnce(f => f()); + (React.useEffect as jest.Mock).mockImplementationOnce((f) => f()); const scroll = jest.fn(); shallowRender({ scroll, secondaryLocationSelected: true }); @@ -85,7 +85,7 @@ it('should not scroll on load if a secondary location is selected', () => { it('should not scroll on load if node is not defined', () => { (React.useRef as jest.Mock).mockImplementationOnce(() => ({ current: undefined })); - (React.useEffect as jest.Mock).mockImplementationOnce(f => f()); + (React.useEffect as jest.Mock).mockImplementationOnce((f) => f()); const scroll = jest.fn(); shallowRender({ scroll }); diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotReviewHistory-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotReviewHistory-test.tsx index 86b9fefe76d..b2b46b00547 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotReviewHistory-test.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotReviewHistory-test.tsx @@ -31,23 +31,19 @@ import HotspotReviewHistory, { HotspotReviewHistoryProps } from '../HotspotRevie jest.mock('react', () => { return { ...jest.requireActual('react'), - useState: jest.fn().mockImplementation(() => ['', jest.fn()]) + useState: jest.fn().mockImplementation(() => ['', jest.fn()]), }; }); it('should render correctly', () => { expect(shallowRender()).toMatchSnapshot('default'); expect(shallowRender({ showFullHistory: true })).toMatchSnapshot('show full list'); - expect( - shallowRender({ showFullHistory: true }) - .find(Toggler) - .props().overlay - ).toMatchSnapshot('edit comment overlay'); - expect( - shallowRender({ showFullHistory: true }) - .find(Dropdown) - .props().overlay - ).toMatchSnapshot('delete comment overlay'); + expect(shallowRender({ showFullHistory: true }).find(Toggler).props().overlay).toMatchSnapshot( + 'edit comment overlay' + ); + expect(shallowRender({ showFullHistory: true }).find(Dropdown).props().overlay).toMatchSnapshot( + 'delete comment overlay' + ); }); it('should correctly handle comment updating', () => { @@ -59,17 +55,10 @@ it('should correctly handle comment updating', () => { const wrapper = shallowRender({ onEditComment, showFullHistory: true }); // Closing the Toggler sets the edited key back to an empty string. - wrapper - .find(Toggler) - .at(0) - .props() - .onRequestClose(); + wrapper.find(Toggler).at(0).props().onRequestClose(); expect(setEditedCommentKey).toHaveBeenCalledWith(''); - const editOnClick = wrapper - .find(EditButton) - .at(0) - .props().onClick; + const editOnClick = wrapper.find(EditButton).at(0).props().onClick; if (!editOnClick) { reject(); return; @@ -81,23 +70,14 @@ it('should correctly handle comment updating', () => { // Cancelling an edit sets the edited key back to an empty string const dropdownOverlay = shallow( - wrapper - .find(Toggler) - .at(0) - .props().overlay as React.ReactElement<DropdownOverlay> + wrapper.find(Toggler).at(0).props().overlay as React.ReactElement<DropdownOverlay> ); - dropdownOverlay - .find(HotspotCommentPopup) - .props() - .onCancelEdit(); + dropdownOverlay.find(HotspotCommentPopup).props().onCancelEdit(); expect(setEditedCommentKey).toHaveBeenLastCalledWith(''); // Updating the comment sets the edited key back to an empty string, and calls the // prop to update the comment value. - dropdownOverlay - .find(HotspotCommentPopup) - .props() - .onCommentEditSubmit('comment'); + dropdownOverlay.find(HotspotCommentPopup).props().onCommentEditSubmit('comment'); expect(onEditComment).toHaveBeenLastCalledWith('comment-1', 'comment'); expect(setEditedCommentKey).toHaveBeenLastCalledWith(''); expect(setEditedCommentKey).toHaveBeenCalledTimes(4); @@ -115,10 +95,7 @@ it('should correctly handle comment deleting', () => { const wrapper = shallowRender({ onDeleteComment, showFullHistory: true }); // Opening the deletion Dropdown sets the edited key back to an empty string. - const dropdownOnOpen = wrapper - .find(Dropdown) - .at(0) - .props().onOpen; + const dropdownOnOpen = wrapper.find(Dropdown).at(0).props().onOpen; if (!dropdownOnOpen) { reject(); return; @@ -128,10 +105,7 @@ it('should correctly handle comment deleting', () => { // Confirming deletion calls the prop to delete the comment. const dropdownOverlay = shallow( - wrapper - .find(Dropdown) - .at(0) - .props().overlay as React.ReactElement<HTMLDivElement> + wrapper.find(Dropdown).at(0).props().overlay as React.ReactElement<HTMLDivElement> ); const deleteButtonOnClick = dropdownOverlay.find(Button).props().onClick; if (!deleteButtonOnClick) { @@ -154,19 +128,19 @@ function shallowRender(props?: Partial<HotspotReviewHistoryProps>) { changelog: [ mockIssueChangelog(), mockIssueChangelog({ - creationDate: '2018-10-12' - }) + creationDate: '2018-10-12', + }), ], comment: [ mockHotspotComment({ key: 'comment-1', - updatable: true + updatable: true, }), mockHotspotComment({ key: 'comment-2', user: mockUser({ name: undefined }) }), mockHotspotComment({ key: 'comment-3', user: mockUser({ active: false }) }), mockHotspotComment({ key: 'comment-4' }), - mockHotspotComment({ key: 'comment-5' }) - ] + mockHotspotComment({ key: 'comment-5' }), + ], })} onDeleteComment={jest.fn()} onEditComment={jest.fn()} diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotReviewHistoryAndComments-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotReviewHistoryAndComments-test.tsx index 64ed9acdec8..efc48cb25ac 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotReviewHistoryAndComments-test.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotReviewHistoryAndComments-test.tsx @@ -22,7 +22,7 @@ import * as React from 'react'; import { commentSecurityHotspot, deleteSecurityHotspotComment, - editSecurityHotspotComment + editSecurityHotspotComment, } from '../../../../api/security-hotspots'; import { mockHotspot } from '../../../../helpers/mocks/security-hotspots'; import { mockCurrentUser } from '../../../../helpers/testMocks'; @@ -34,7 +34,7 @@ import HotspotReviewHistoryAndComments from '../HotspotReviewHistoryAndComments' jest.mock('../../../../api/security-hotspots', () => ({ commentSecurityHotspot: jest.fn().mockResolvedValue({}), deleteSecurityHotspotComment: jest.fn().mockResolvedValue({}), - editSecurityHotspotComment: jest.fn().mockResolvedValue({}) + editSecurityHotspotComment: jest.fn().mockResolvedValue({}), })); jest.mock('../../../../types/users', () => ({ isLoggedIn: jest.fn(() => true) })); @@ -45,7 +45,7 @@ it('should render correctly', () => { }); it('should render correctly without user', () => { - ((isLoggedIn as any) as jest.Mock<boolean, [boolean]>).mockReturnValueOnce(false); + (isLoggedIn as any as jest.Mock<boolean, [boolean]>).mockReturnValueOnce(false); const wrapper = shallowRender(); expect(wrapper).toMatchSnapshot(); }); @@ -104,10 +104,7 @@ it('should edit comment', async () => { it('should correctly toggle the show full history state', () => { const wrapper = shallowRender(); expect(wrapper.state().showFullHistory).toBe(false); - wrapper - .find(HotspotReviewHistory) - .props() - .onShowFullHistory(); + wrapper.find(HotspotReviewHistory).props().onShowFullHistory(); expect(wrapper.state().showFullHistory).toBe(true); }); diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotSimpleList-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotSimpleList-test.tsx index 29a57bf93fb..9f652d0fed3 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotSimpleList-test.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotSimpleList-test.tsx @@ -27,7 +27,7 @@ import HotspotSimpleList, { HotspotSimpleListProps } from '../HotspotSimpleList' jest.mock('../../../../helpers/pages', () => ({ addSideBarClass: jest.fn(), - removeSideBarClass: jest.fn() + removeSideBarClass: jest.fn(), })); it('should render correctly', () => { @@ -70,17 +70,17 @@ function shallowRender(props: Partial<HotspotSimpleListProps> = {}) { cwe: { 327: { title: 'Use of a Broken or Risky Cryptographic Algorithm' } }, owaspTop10: { a1: { title: 'A1 - SQL Injection' }, - a3: { title: 'A3 - Sensitive Data Exposure' } + a3: { title: 'A3 - Sensitive Data Exposure' }, }, 'owaspTop10-2021': { a1: { title: 'A1 - SQL Injection' }, - a3: { title: 'A3 - Sensitive Data Exposure' } + a3: { title: 'A3 - Sensitive Data Exposure' }, }, sansTop25: {}, sonarsourceSecurity: {}, 'pciDss-3.2': {}, 'pciDss-4.0': {}, - 'owaspAsvs-4.0': {} + 'owaspAsvs-4.0': {}, }} {...props} /> diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotSnippetContainer-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotSnippetContainer-test.tsx index a0207becc7d..331accc1d89 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotSnippetContainer-test.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotSnippetContainer-test.tsx @@ -32,11 +32,11 @@ import HotspotSnippetContainer from '../HotspotSnippetContainer'; import HotspotSnippetContainerRenderer from '../HotspotSnippetContainerRenderer'; jest.mock('../../../../api/components', () => ({ - getSources: jest.fn().mockResolvedValue([]) + getSources: jest.fn().mockResolvedValue([]), })); jest.mock('../../../../helpers/scrolling', () => ({ - scrollToElement: jest.fn() + scrollToElement: jest.fn(), })); beforeEach(() => jest.clearAllMocks()); @@ -49,7 +49,7 @@ it('should render correctly', () => { it('should load sources on mount', async () => { (getSources as jest.Mock).mockResolvedValueOnce( - range(1, 25).map(line => mockSourceLine({ line })) + range(1, 25).map((line) => mockSourceLine({ line })) ); const hotspot = mockHotspot({ @@ -59,14 +59,14 @@ it('should load sources on mount', async () => { { locations: [ mockFlowLocation({ - textRange: { startLine: 8, endLine: 8, startOffset: 0, endOffset: 1 } + textRange: { startLine: 8, endLine: 8, startOffset: 0, endOffset: 1 }, }), mockFlowLocation({ - textRange: { startLine: 13, endLine: 13, startOffset: 0, endOffset: 1 } - }) - ] - } - ] + textRange: { startLine: 13, endLine: 13, startOffset: 0, endOffset: 1 }, + }), + ], + }, + ], }); const wrapper = shallowRender({ hotspot }); @@ -78,7 +78,7 @@ it('should load sources on mount', async () => { key: hotspot.component.key, branch: branch.name, from: 1, - to: 24 + to: 24, }) ); expect(wrapper.state().lastLine).toBeUndefined(); @@ -101,7 +101,7 @@ it('should handle load sources failure', async () => { it('should not load sources on mount when the hotspot is not associated to any loc', async () => { const hotspot = mockHotspot({ line: undefined, - textRange: undefined + textRange: undefined, }); const wrapper = shallowRender({ hotspot }); @@ -115,11 +115,11 @@ it('should not load sources on mount when the hotspot is not associated to any l it('should handle end-of-file on mount', async () => { (getSources as jest.Mock).mockResolvedValueOnce( - range(5, 15).map(line => mockSourceLine({ line })) + range(5, 15).map((line) => mockSourceLine({ line })) ); const hotspot = mockHotspot({ - textRange: { startLine: 10, endLine: 11, startOffset: 0, endOffset: 12 } + textRange: { startLine: 10, endLine: 11, startOffset: 0, endOffset: 12 }, }); const wrapper = shallowRender({ hotspot }); @@ -134,33 +134,30 @@ it('should handle end-of-file on mount', async () => { describe('Expansion', () => { beforeEach(() => { (getSources as jest.Mock).mockResolvedValueOnce( - range(10, 32).map(line => mockSourceLine({ line })) + range(10, 32).map((line) => mockSourceLine({ line })) ); }); const hotspot = mockHotspot({ project: mockHotspotComponent({ branch: branch.name, qualifier: ComponentQualifier.Project }), - textRange: { startLine: 20, endLine: 21, startOffset: 0, endOffset: 12 } + textRange: { startLine: 20, endLine: 21, startOffset: 0, endOffset: 12 }, }); it('up should work', async () => { (getSources as jest.Mock).mockResolvedValueOnce( - range(1, 10).map(line => mockSourceLine({ line })) + range(1, 10).map((line) => mockSourceLine({ line })) ); const wrapper = shallowRender({ hotspot }); await waitAndUpdate(wrapper); - wrapper - .find(HotspotSnippetContainerRenderer) - .props() - .onExpandBlock('up'); + wrapper.find(HotspotSnippetContainerRenderer).props().onExpandBlock('up'); await waitAndUpdate(wrapper); expect(getSources).toHaveBeenCalledWith( expect.objectContaining({ - branch: branch.name + branch: branch.name, }) ); expect(wrapper.state().sourceLines).toHaveLength(31); @@ -170,16 +167,13 @@ describe('Expansion', () => { (getSources as jest.Mock).mockResolvedValueOnce( // lastLine + expand + extra for EOF check + range end is excluded // 31 + 50 + 1 + 1 - range(32, 83).map(line => mockSourceLine({ line })) + range(32, 83).map((line) => mockSourceLine({ line })) ); const wrapper = shallowRender({ hotspot }); await waitAndUpdate(wrapper); - wrapper - .find(HotspotSnippetContainerRenderer) - .props() - .onExpandBlock('down'); + wrapper.find(HotspotSnippetContainerRenderer).props().onExpandBlock('down'); await waitAndUpdate(wrapper); @@ -191,16 +185,13 @@ describe('Expansion', () => { (getSources as jest.Mock).mockResolvedValueOnce( // lastLine + expand + extra for EOF check + range end is excluded - 1 to trigger end-of-file // 26 + 50 + 1 + 1 - 1 - range(27, 77).map(line => mockSourceLine({ line })) + range(27, 77).map((line) => mockSourceLine({ line })) ); const wrapper = shallowRender({ hotspot }); await waitAndUpdate(wrapper); - wrapper - .find(HotspotSnippetContainerRenderer) - .props() - .onExpandBlock('down'); + wrapper.find(HotspotSnippetContainerRenderer).props().onExpandBlock('down'); await waitAndUpdate(wrapper); @@ -212,10 +203,7 @@ describe('Expansion', () => { it('should handle symbol click', () => { const wrapper = shallowRender(); const symbols = ['symbol']; - wrapper - .find(HotspotSnippetContainerRenderer) - .props() - .onSymbolClick(symbols); + wrapper.find(HotspotSnippetContainerRenderer).props().onSymbolClick(symbols); expect(wrapper.state().highlightedSymbols).toBe(symbols); }); diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotSnippetContainerRenderer-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotSnippetContainerRenderer-test.tsx index c062d19dda4..3764137be73 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotSnippetContainerRenderer-test.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotSnippetContainerRenderer-test.tsx @@ -28,15 +28,15 @@ import SnippetViewer from '../../../issues/crossComponentSourceViewer/SnippetVie import HotspotSnippetContainerRenderer, { animateExpansion, getScrollHandler, - HotspotSnippetContainerRendererProps + HotspotSnippetContainerRendererProps, } from '../HotspotSnippetContainerRenderer'; jest.mock('../../../../helpers/scrolling', () => ({ - scrollToElement: jest.fn() + scrollToElement: jest.fn(), })); beforeEach(() => { - jest.spyOn(React, 'useMemo').mockImplementationOnce(f => f()); + jest.spyOn(React, 'useMemo').mockImplementationOnce((f) => f()); }); it('should render correctly', () => { @@ -47,7 +47,7 @@ it('should render correctly', () => { it('should render a HotspotPrimaryLocationBox', () => { const wrapper = shallowRender({ hotspot: mockHotspot({ line: 42 }), - sourceLines: [mockSourceLine()] + sourceLines: [mockSourceLine()], }); const { renderAdditionalChildInLine } = wrapper.find(SnippetViewer).props(); @@ -58,7 +58,7 @@ it('should render a HotspotPrimaryLocationBox', () => { it('should render correctly when secondary location is selected', () => { const wrapper = shallowRender({ - selectedHotspotLocation: 1 + selectedHotspotLocation: 1, }); expect(wrapper).toMatchSnapshot('with selected hotspot location'); }); @@ -78,7 +78,7 @@ describe('scrolling', () => { it('should scroll to element if parent is defined', () => { const ref: RefObject<HTMLDivElement> = { - current: document.createElement('div') + current: document.createElement('div'), }; const scrollHandler = getScrollHandler(ref); @@ -93,7 +93,7 @@ describe('scrolling', () => { it('should not scroll if parent is undefined', () => { const ref: RefObject<HTMLDivElement> = { - current: null + current: null, }; const scrollHandler = getScrollHandler(ref); @@ -115,7 +115,7 @@ describe('expand', () => { const scrollableNode = document.createElement('div'); scrollableNode.scrollTo = jest.fn(); const ref: RefObject<HTMLDivElement> = { - current: scrollableNode + current: scrollableNode, }; jest.spyOn(React, 'useRef').mockReturnValue(ref); diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotSnippetHeader-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotSnippetHeader-test.tsx index 1a99931e45b..41ec8c1a201 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotSnippetHeader-test.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotSnippetHeader-test.tsx @@ -32,7 +32,7 @@ it('should render correctly', () => { expect( shallowRender({ currentUser: mockLoggedInUser(), - component: mockComponent({ qualifier: ComponentQualifier.Application }) + component: mockComponent({ qualifier: ComponentQualifier.Application }), }) ).toMatchSnapshot('user logged in with project Name'); }); diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewer-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewer-test.tsx index 47b69bf671c..03538f3bba0 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewer-test.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewer-test.tsx @@ -36,15 +36,15 @@ const hotspotKey = 'hotspot-key'; jest.mock('../../../../api/security-hotspots', () => ({ getSecurityHotspotDetails: jest .fn() - .mockResolvedValue({ id: `I am a detailled hotspot`, rule: {} }) + .mockResolvedValue({ id: `I am a detailled hotspot`, rule: {} }), })); jest.mock('../../../../api/rules', () => ({ - getRuleDetails: jest.fn().mockResolvedValue({ rule: { descriptionSections: [] } }) + getRuleDetails: jest.fn().mockResolvedValue({ rule: { descriptionSections: [] } }), })); jest.mock('../../../../helpers/scrolling', () => ({ - scrollToElement: jest.fn() + scrollToElement: jest.fn(), })); it('should render correctly', async () => { @@ -69,18 +69,18 @@ it('should render fetch rule details', async () => { descriptionSections: [ { key: RuleDescriptionSections.ASSESS_THE_PROBLEM, - content: 'assess' + content: 'assess', }, { key: RuleDescriptionSections.ROOT_CAUSE, - content: 'cause' + content: 'cause', }, { key: RuleDescriptionSections.HOW_TO_FIX, - content: 'how' - } - ] - }) + content: 'how', + }, + ], + }), }); const wrapper = shallowRender(); await waitAndUpdate(wrapper); @@ -88,26 +88,23 @@ it('should render fetch rule details', async () => { expect(wrapper.state().ruleDescriptionSections).toStrictEqual([ { key: RuleDescriptionSections.ASSESS_THE_PROBLEM, - content: 'assess' + content: 'assess', }, { key: RuleDescriptionSections.ROOT_CAUSE, - content: 'cause' + content: 'cause', }, { key: RuleDescriptionSections.HOW_TO_FIX, - content: 'how' - } + content: 'how', + }, ]); }); it('should refresh hotspot list on status update', () => { const onUpdateHotspot = jest.fn(); const wrapper = shallowRender({ onUpdateHotspot }); - wrapper - .find(HotspotViewerRenderer) - .props() - .onUpdateHotspot(true); + wrapper.find(HotspotViewerRenderer).props().onUpdateHotspot(true); expect(onUpdateHotspot).toHaveBeenCalled(); }); @@ -115,10 +112,7 @@ it('should store last status selected when updating a hotspot status', () => { const wrapper = shallowRender(); expect(wrapper.state().lastStatusChangedTo).toBeUndefined(); - wrapper - .find(HotspotViewerRenderer) - .props() - .onUpdateHotspot(true, HotspotStatusOption.FIXED); + wrapper.find(HotspotViewerRenderer).props().onUpdateHotspot(true, HotspotStatusOption.FIXED); expect(wrapper.state().lastStatusChangedTo).toBe(HotspotStatusOption.FIXED); }); @@ -144,18 +138,15 @@ it('should correctly close the success modal', () => { it('should NOT refresh hotspot list on assignee/comment updates', () => { const onUpdateHotspot = jest.fn(); const wrapper = shallowRender({ onUpdateHotspot }); - wrapper - .find(HotspotViewerRenderer) - .props() - .onUpdateHotspot(); + wrapper.find(HotspotViewerRenderer).props().onUpdateHotspot(); expect(onUpdateHotspot).not.toHaveBeenCalled(); }); it('should scroll to comment form', () => { const wrapper = shallowRender(); - const mockTextRef = ({ current: { focus: jest.fn() } } as any) as React.RefObject< - HTMLTextAreaElement - >; + const mockTextRef = { + current: { focus: jest.fn() }, + } as any as React.RefObject<HTMLTextAreaElement>; wrapper.instance().commentTextRef = mockTextRef; wrapper.find(HotspotViewerRenderer).simulate('showCommentForm'); diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewerRenderer-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewerRenderer-test.tsx index 391389ef308..b6abb00995d 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewerRenderer-test.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewerRenderer-test.tsx @@ -42,8 +42,8 @@ it('should render correctly', () => { expect( shallowRender({ hotspot: mockHotspot({ - assigneeUser: mockUser({ name: undefined, login: 'assignee_login' }) - }) + assigneeUser: mockUser({ name: undefined, login: 'assignee_login' }), + }), }) ).toMatchSnapshot('assignee without name'); expect(shallowRender()).toMatchSnapshot('anonymous user'); diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewerTabs-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewerTabs-test.tsx index 80edf167c92..1675cfd4f05 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewerTabs-test.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewerTabs-test.tsx @@ -32,19 +32,19 @@ const originalRemoveEventListener = window.removeEventListener; beforeEach(() => { Object.defineProperty(window, 'addEventListener', { - value: jest.fn() + value: jest.fn(), }); Object.defineProperty(window, 'removeEventListener', { - value: jest.fn() + value: jest.fn(), }); }); afterEach(() => { Object.defineProperty(window, 'addEventListener', { - value: originalAddEventListener + value: originalAddEventListener, }); Object.defineProperty(window, 'removeEventListener', { - value: originalRemoveEventListener + value: originalRemoveEventListener, }); }); @@ -63,9 +63,9 @@ it('should render correctly', () => { expect( shallowRender({ hotspot: mockHotspot({ - creationDate: undefined + creationDate: undefined, }), - ruleDescriptionSections: undefined + ruleDescriptionSections: undefined, }) .find<BoxedTabsProps<string>>(BoxedTabs) .props().tabs @@ -82,17 +82,17 @@ it('should render correctly', () => { login: 'me', markdown: '*test*', updatable: false, - user: mockUser() - } - ] - }) + user: mockUser(), + }, + ], + }), }) ).toMatchSnapshot('with comments or changelog element'); }); it('should filter empty tab', () => { const count = shallowRender({ - hotspot: mockHotspot() + hotspot: mockHotspot(), }).state().tabs.length; expect( @@ -100,13 +100,13 @@ it('should filter empty tab', () => { ruleDescriptionSections: [ { key: RuleDescriptionSections.ROOT_CAUSE, - content: 'cause' + content: 'cause', }, { key: RuleDescriptionSections.HOW_TO_FIX, - content: 'how' - } - ] + content: 'how', + }, + ], }).state().tabs.length ).toBe(count - 1); }); @@ -143,7 +143,7 @@ describe('keyboard navigation', () => { TabKeys.Code, TabKeys.RiskDescription, TabKeys.VulnerabilityDescription, - TabKeys.FixRecommendation + TabKeys.FixRecommendation, ]; const wrapper = shallowRender(); @@ -151,7 +151,7 @@ describe('keyboard navigation', () => { ['selecting next', 0, KeyboardKeys.RightArrow, 1], ['selecting previous', 1, KeyboardKeys.LeftArrow, 0], ['selecting previous, non-existent', 0, KeyboardKeys.LeftArrow, 0], - ['selecting next, non-existent', 3, KeyboardKeys.RightArrow, 3] + ['selecting next, non-existent', 3, KeyboardKeys.RightArrow, 3], ])('should work when %s', (_, start, key, expected) => { wrapper.setState({ currentTab: wrapper.state().tabs[start] }); wrapper.instance().handleKeyboardNavigation(mockEvent({ key })); @@ -193,16 +193,16 @@ function shallowRender(props?: Partial<HotspotViewerTabs['props']>) { ruleDescriptionSections={[ { key: RuleDescriptionSections.ASSESS_THE_PROBLEM, - content: 'assess' + content: 'assess', }, { key: RuleDescriptionSections.ROOT_CAUSE, - content: 'cause' + content: 'cause', }, { key: RuleDescriptionSections.HOW_TO_FIX, - content: 'how' - } + content: 'how', + }, ]} {...props} /> diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/StatusUpdateSuccessModal-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/StatusUpdateSuccessModal-test.tsx index 883f25b1b21..c53b605b4a5 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/StatusUpdateSuccessModal-test.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/StatusUpdateSuccessModal-test.tsx @@ -21,7 +21,7 @@ import { shallow } from 'enzyme'; import * as React from 'react'; import { HotspotStatusOption } from '../../../../types/security-hotspots'; import StatusUpdateSuccessModal, { - StatusUpdateSuccessModalProps + StatusUpdateSuccessModalProps, } from '../StatusUpdateSuccessModal'; it('should render correctly', () => { diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/Assignee.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/Assignee.tsx index 642e7a0ca2f..04b619a35d5 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/Assignee.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/Assignee.tsx @@ -42,7 +42,7 @@ export class Assignee extends React.PureComponent<Props, State> { mounted = false; state = { editing: false, - loading: false + loading: false, }; componentDidMount() { @@ -64,7 +64,7 @@ export class Assignee extends React.PureComponent<Props, State> { handleAssign = (newAssignee: UserActive) => { this.setState({ loading: true }); assignSecurityHotspot(this.props.hotspot.key, { - assignee: newAssignee?.login + assignee: newAssignee?.login, }) .then(() => { if (this.mounted) { @@ -85,7 +85,7 @@ export class Assignee extends React.PureComponent<Props, State> { render() { const { currentUser, - hotspot: { assigneeUser, status, resolution } + hotspot: { assigneeUser, status, resolution }, } = this.props; const { editing, loading } = this.state; diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/AssigneeSelection.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/AssigneeSelection.tsx index 8aef280c182..60c2544539c 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/AssigneeSelection.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/AssigneeSelection.tsx @@ -50,7 +50,7 @@ export default class AssigneeSelection extends React.PureComponent<Props, State> loading: false, suggestedUsers: props.allowCurrentUserSelection ? [props.loggedInUser, UNASSIGNED] - : [UNASSIGNED] + : [UNASSIGNED], }; this.handleSearch = debounce(this.handleSearch, 250); @@ -80,19 +80,19 @@ export default class AssigneeSelection extends React.PureComponent<Props, State> this.setState({ loading: false, query, - suggestedUsers: allowCurrentUserSelection ? [loggedInUser, UNASSIGNED] : [UNASSIGNED] + suggestedUsers: allowCurrentUserSelection ? [loggedInUser, UNASSIGNED] : [UNASSIGNED], }); }; handleActualSearch = (query: string) => { this.setState({ loading: true, query }); searchUsers({ q: query }) - .then(result => { + .then((result) => { if (this.mounted) { this.setState({ loading: false, query, - suggestedUsers: (result.users.filter(isUserActive) as UserActive[]).concat(UNASSIGNED) + suggestedUsers: (result.users.filter(isUserActive) as UserActive[]).concat(UNASSIGNED), }); } }) @@ -126,7 +126,7 @@ export default class AssigneeSelection extends React.PureComponent<Props, State> const { highlighted, suggestedUsers } = this.state; return highlighted - ? suggestedUsers.findIndex(suggestion => suggestion.login === highlighted.login) + ? suggestedUsers.findIndex((suggestion) => suggestion.login === highlighted.login) : -1; }; diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/AssigneeSelectionRenderer.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/AssigneeSelectionRenderer.tsx index 3610cfdc376..6f20cecc9f5 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/AssigneeSelectionRenderer.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/AssigneeSelectionRenderer.tsx @@ -58,13 +58,14 @@ export default function AssigneeSelectionRenderer(props: HotspotAssigneeSelectRe <DropdownOverlay noPadding={true} placement={PopupPlacement.BottomLeft}> <ul className="hotspot-assignee-search-results"> {suggestedUsers && - suggestedUsers.map(suggestion => ( + suggestedUsers.map((suggestion) => ( <li className={classNames('padded', { - active: highlighted && highlighted.login === suggestion.login + active: highlighted && highlighted.login === suggestion.login, })} key={suggestion.login} - onClick={() => props.onSelect(suggestion)}> + onClick={() => props.onSelect(suggestion)} + > {suggestion.login && ( <Avatar className="spacer-right" diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/Assignee-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/Assignee-test.tsx index cc9839ef45d..03aa5ded385 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/Assignee-test.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/Assignee-test.tsx @@ -30,11 +30,11 @@ import { Assignee } from '../Assignee'; import AssigneeRenderer from '../AssigneeRenderer'; jest.mock('../../../../../api/security-hotspots', () => ({ - assignSecurityHotspot: jest.fn() + assignSecurityHotspot: jest.fn(), })); jest.mock('../../../../../helpers/globalMessages', () => ({ - addGlobalSuccessMessage: jest.fn() + addGlobalSuccessMessage: jest.fn(), })); it('should render correctly', () => { @@ -45,7 +45,7 @@ it.each([ [HotspotStatus.TO_REVIEW, undefined, true], [HotspotStatus.REVIEWED, HotspotResolution.FIXED, false], [HotspotStatus.REVIEWED, HotspotResolution.SAFE, false], - [HotspotStatus.REVIEWED, HotspotResolution.ACKNOWLEDGED, true] + [HotspotStatus.REVIEWED, HotspotResolution.ACKNOWLEDGED, true], ])('should allow edition properly', (status, resolution, canEdit) => { expect( shallowRender({ hotspot: mockHotspot({ status, resolution }) }) @@ -57,22 +57,16 @@ it.each([ it('should handle edition event correctly', () => { const wrapper = shallowRender(); - wrapper - .find(AssigneeRenderer) - .props() - .onEnterEditionMode(); + wrapper.find(AssigneeRenderer).props().onEnterEditionMode(); expect(wrapper.state().editing).toBe(true); - wrapper - .find(AssigneeRenderer) - .props() - .onExitEditionMode(); + wrapper.find(AssigneeRenderer).props().onExitEditionMode(); expect(wrapper.state().editing).toBe(false); }); it.each([ ['assign to user', mockUser() as UserActive], - ['unassign', { login: '', name: 'unassigned' } as UserActive] + ['unassign', { login: '', name: 'unassigned' } as UserActive], ])('should handle %s event', async (_, user: UserActive) => { const hotspot = mockHotspot(); const onAssigneeChange = jest.fn(); @@ -80,10 +74,7 @@ it.each([ const wrapper = shallowRender({ hotspot, onAssigneeChange }); (assignSecurityHotspot as jest.Mock).mockResolvedValueOnce({}); - wrapper - .find(AssigneeRenderer) - .props() - .onAssign(user); + wrapper.find(AssigneeRenderer).props().onAssign(user); expect(wrapper.state().loading).toBe(true); expect(assignSecurityHotspot).toHaveBeenCalledWith(hotspot.key, { assignee: user?.login }); @@ -92,7 +83,7 @@ it.each([ expect(wrapper.state()).toEqual({ editing: false, - loading: false + loading: false, }); expect(onAssigneeChange).toHaveBeenCalled(); expect(addGlobalSuccessMessage).toHaveBeenCalled(); diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/AssigneeRenderer-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/AssigneeRenderer-test.tsx index 32e3de350ee..326d7cad18f 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/AssigneeRenderer-test.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/AssigneeRenderer-test.tsx @@ -38,9 +38,8 @@ it('should render correctly', () => { expect(shallowRender({ loggedInUser: undefined }).find(EditButton).length).toBe(0); expect(shallowRender({ canEdit: false }).find(EditButton).length).toBe(0); expect( - shallowRender({ editing: true, assignee: mockUser() }) - .find(AssigneeSelection) - .props().allowCurrentUserSelection + shallowRender({ editing: true, assignee: mockUser() }).find(AssigneeSelection).props() + .allowCurrentUserSelection ).toBe(true); }); @@ -61,10 +60,7 @@ it('should propagate calls correctly', () => { .onSelect(newAssignee as UserActive); expect(onAssign).toHaveBeenCalledWith(newAssignee); - wrapper - .find(OutsideClickHandler) - .props() - .onClickOutside(); + wrapper.find(OutsideClickHandler).props().onClickOutside(); expect(onExitEditionMode).toHaveBeenCalled(); }); diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/AssigneeSelection-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/AssigneeSelection-test.tsx index cb412eb9dd6..d341a86271a 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/AssigneeSelection-test.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/AssigneeSelection-test.tsx @@ -27,7 +27,7 @@ import { UserActive } from '../../../../../types/users'; import AssigneeSelection from '../AssigneeSelection'; jest.mock('../../../../../api/users', () => ({ - searchUsers: jest.fn().mockResolvedValue([]) + searchUsers: jest.fn().mockResolvedValue([]), })); it('should render correctly', () => { @@ -38,7 +38,7 @@ it('should handle keydown', () => { const suggestedUsers = [ mockUser({ login: '1' }) as UserActive, mockUser({ login: '2' }) as UserActive, - mockUser({ login: '3' }) as UserActive + mockUser({ login: '3' }) as UserActive, ]; const onSelect = jest.fn(); diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/AssigneeSelectionRenderer-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/AssigneeSelectionRenderer-test.tsx index 044572d300b..c9d581af313 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/AssigneeSelectionRenderer-test.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/AssigneeSelectionRenderer-test.tsx @@ -22,7 +22,7 @@ import * as React from 'react'; import { mockUser } from '../../../../../helpers/testMocks'; import { UserActive } from '../../../../../types/users'; import AssigneeSelectionRenderer, { - HotspotAssigneeSelectRendererProps + HotspotAssigneeSelectRendererProps, } from '../AssigneeSelectionRenderer'; it('should render correctly', () => { @@ -33,7 +33,7 @@ it('should render correctly', () => { expect( shallowRender({ highlighted: highlightedUser, - suggestedUsers: [mockUser() as UserActive, highlightedUser] + suggestedUsers: [mockUser() as UserActive, highlightedUser], }) ).toMatchSnapshot('open with results'); }); @@ -43,13 +43,10 @@ it('should call onSelect when clicked', () => { const onSelect = jest.fn(); const wrapper = shallowRender({ onSelect, - suggestedUsers: [user] + suggestedUsers: [user], }); - wrapper - .find('li') - .at(0) - .simulate('click'); + wrapper.find('li').at(0).simulate('click'); expect(onSelect).toHaveBeenCalledWith(user); }); diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/status/Status.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/status/Status.tsx index 94465cdbcb8..49e6dd0b8e9 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/status/Status.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/status/Status.tsx @@ -58,7 +58,8 @@ export function Status(props: StatusProps) { <div className="spacer-top"> <Tooltip overlay={readonly ? translate('hotspots.status.cannot_change_status') : null} - placement="bottom"> + placement="bottom" + > <div className="dropdown"> <Toggler closeOnClickOutside={true} @@ -69,7 +70,7 @@ export function Status(props: StatusProps) { <DropdownOverlay noPadding={true} placement={PopupPlacement.Bottom}> <StatusSelection hotspot={hotspot} - onStatusOptionChange={async status => { + onStatusOptionChange={async (status) => { await props.onStatusChange(status); setIsOpen(false); }} @@ -77,12 +78,14 @@ export function Status(props: StatusProps) { setComment={setComment} /> </DropdownOverlay> - }> + } + > <Button className="dropdown-toggle big-spacer-left" id="status-trigger" onClick={() => setIsOpen(true)} - disabled={readonly}> + disabled={readonly} + > <span>{translate('hotspots.status.select_status')}</span> <DropdownIcon className="little-spacer-left" /> </Button> diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/status/StatusSelection.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/status/StatusSelection.tsx index 02835044110..9cdb58e63db 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/status/StatusSelection.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/status/StatusSelection.tsx @@ -22,7 +22,7 @@ import { setSecurityHotspotStatus } from '../../../../api/security-hotspots'; import { Hotspot, HotspotStatusOption } from '../../../../types/security-hotspots'; import { getStatusAndResolutionFromStatusOption, - getStatusOptionFromStatusAndResolution + getStatusOptionFromStatusAndResolution, } from '../../utils'; import StatusSelectionRenderer from './StatusSelectionRenderer'; @@ -53,7 +53,7 @@ export default class StatusSelection extends React.PureComponent<Props, State> { this.state = { loading: false, initialStatus, - selectedStatus: initialStatus + selectedStatus: initialStatus, }; } @@ -81,7 +81,7 @@ export default class StatusSelection extends React.PureComponent<Props, State> { this.setState({ loading: true }); setSecurityHotspotStatus(hotspot.key, { ...getStatusAndResolutionFromStatusOption(selectedStatus), - comment: comment || undefined + comment: comment || undefined, }) .then(async () => { await this.props.onStatusOptionChange(selectedStatus); diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/status/StatusSelectionRenderer.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/status/StatusSelectionRenderer.tsx index 7db97ba0fdc..0b8ccf7ffb4 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/status/StatusSelectionRenderer.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/status/StatusSelectionRenderer.tsx @@ -48,7 +48,8 @@ export default function StatusSelectionRenderer(props: StatusSelectionRendererPr className="big-spacer-bottom status-radio" alignLabel={true} onCheck={props.onStatusChange} - value={status}> + value={status} + > <StatusDescription statusOption={status} statusInBadge={false} /> </Radio> ); diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/status/__tests__/Status-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/status/__tests__/Status-test.tsx index 3274b16a9c9..73fc3f7a001 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/status/__tests__/Status-test.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/status/__tests__/Status-test.tsx @@ -28,7 +28,7 @@ import { setSecurityHotspotStatus } from '../../../../../api/security-hotspots'; import { HotspotResolution, HotspotStatus } from '../../../../../types/security-hotspots'; jest.mock('../../../../../api/security-hotspots', () => ({ - setSecurityHotspotStatus: jest.fn().mockResolvedValue({}) + setSecurityHotspotStatus: jest.fn().mockResolvedValue({}), })); it('should properly deal with comment/status/submit events', async () => { @@ -41,7 +41,7 @@ it('should properly deal with comment/status/submit events', async () => { await user.click( screen.getByRole('radio', { - name: 'hotspots.status_option.SAFE hotspots.status_option.SAFE.description' + name: 'hotspots.status_option.SAFE hotspots.status_option.SAFE.description', }) ); @@ -53,7 +53,7 @@ it('should properly deal with comment/status/submit events', async () => { expect(setSecurityHotspotStatus).toHaveBeenCalledWith(hotspot.key, { status: HotspotStatus.REVIEWED, resolution: HotspotResolution.SAFE, - comment + comment, }); }); diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/utils.ts b/server/sonar-web/src/main/js/apps/security-hotspots/utils.ts index e425b2e8d94..faa901cc33d 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/utils.ts +++ b/server/sonar-web/src/main/js/apps/security-hotspots/utils.ts @@ -26,7 +26,7 @@ import { renderPciDss32Category, renderPciDss40Category, renderSansTop25Category, - renderSonarSourceSecurityCategory + renderSonarSourceSecurityCategory, } from '../../helpers/security-standard'; import { SecurityStandard } from '../../types/security'; import { @@ -38,13 +38,13 @@ import { RawHotspot, ReviewHistoryElement, ReviewHistoryType, - RiskExposure + RiskExposure, } from '../../types/security-hotspots'; import { Dict, FlowLocation, SourceViewerFile, - StandardSecurityCategories + StandardSecurityCategories, } from '../../types/types'; const OTHERS_SECURITY_CATEGORY = 'others'; @@ -58,7 +58,7 @@ export const SECURITY_STANDARDS = [ SecurityStandard.CWE, SecurityStandard.PCI_DSS_3_2, SecurityStandard.PCI_DSS_4_0, - SecurityStandard.OWASP_ASVS_4_0 + SecurityStandard.OWASP_ASVS_4_0, ]; export const SECURITY_STANDARD_RENDERER = { @@ -69,7 +69,7 @@ export const SECURITY_STANDARD_RENDERER = { [SecurityStandard.CWE]: renderCWECategory, [SecurityStandard.PCI_DSS_3_2]: renderPciDss32Category, [SecurityStandard.PCI_DSS_4_0]: renderPciDss40Category, - [SecurityStandard.OWASP_ASVS_4_0]: renderOwaspAsvs40Category + [SecurityStandard.OWASP_ASVS_4_0]: renderOwaspAsvs40Category, }; export function mapRules(rules: Array<{ key: string; name: string }>): Dict<string> { @@ -83,28 +83,28 @@ export function groupByCategory( hotspots: RawHotspot[] = [], securityCategories: StandardSecurityCategories ) { - const groups = groupBy(hotspots, h => h.securityCategory); + const groups = groupBy(hotspots, (h) => h.securityCategory); - const groupList = Object.keys(groups).map(key => ({ + const groupList = Object.keys(groups).map((key) => ({ key, title: getCategoryTitle(key, securityCategories), - hotspots: groups[key] + hotspots: groups[key], })); return [ ...sortBy( - groupList.filter(group => group.key !== OTHERS_SECURITY_CATEGORY), - group => group.title + groupList.filter((group) => group.key !== OTHERS_SECURITY_CATEGORY), + (group) => group.title ), - ...groupList.filter(({ key }) => key === OTHERS_SECURITY_CATEGORY) + ...groupList.filter(({ key }) => key === OTHERS_SECURITY_CATEGORY), ]; } export function sortHotspots(hotspots: RawHotspot[], securityCategories: Dict<{ title: string }>) { return sortBy(hotspots, [ - h => RISK_EXPOSURE_LEVELS.indexOf(h.vulnerabilityProbability), - h => getCategoryTitle(h.securityCategory, securityCategories), - h => h.message + (h) => RISK_EXPOSURE_LEVELS.indexOf(h.vulnerabilityProbability), + (h) => getCategoryTitle(h.securityCategory, securityCategories), + (h) => h.message, ]); } @@ -123,7 +123,7 @@ export function constructSourceViewerFile( project: project.key, projectName: project.name, q: component.qualifier, - uuid: '' + uuid: '', }; } @@ -136,44 +136,44 @@ export function getHotspotReviewHistory(hotspot: Hotspot): ReviewHistoryElement[ date: hotspot.creationDate, user: { ...hotspot.authorUser, - name: hotspot.authorUser.name || hotspot.authorUser.login - } + name: hotspot.authorUser.name || hotspot.authorUser.login, + }, }); } if (hotspot.changelog && hotspot.changelog.length > 0) { history.push( - ...hotspot.changelog.map(log => ({ + ...hotspot.changelog.map((log) => ({ type: ReviewHistoryType.Diff, date: log.creationDate, user: { active: log.isUserActive, avatar: log.avatar, - name: log.userName || log.user + name: log.userName || log.user, }, - diffs: log.diffs + diffs: log.diffs, })) ); } if (hotspot.comment && hotspot.comment.length > 0) { history.push( - ...hotspot.comment.map(comment => ({ + ...hotspot.comment.map((comment) => ({ type: ReviewHistoryType.Comment, date: comment.createdAt, updatable: comment.updatable, user: { ...comment.user, - name: comment.user.name || comment.user.login + name: comment.user.name || comment.user.login, }, html: comment.htmlText, key: comment.key, - markdown: comment.markdown + markdown: comment.markdown, })) ); } - return sortBy(history, elt => elt.date).reverse(); + return sortBy(history, (elt) => elt.date).reverse(); } const STATUS_AND_RESOLUTION_TO_STATUS_OPTION = { @@ -181,7 +181,7 @@ const STATUS_AND_RESOLUTION_TO_STATUS_OPTION = { [HotspotStatus.REVIEWED]: HotspotStatusOption.FIXED, [HotspotResolution.ACKNOWLEDGED]: HotspotStatusOption.ACKNOWLEDGED, [HotspotResolution.FIXED]: HotspotStatusOption.FIXED, - [HotspotResolution.SAFE]: HotspotStatusOption.SAFE + [HotspotResolution.SAFE]: HotspotStatusOption.SAFE, }; export function getStatusOptionFromStatusAndResolution( @@ -197,16 +197,16 @@ const STATUS_OPTION_TO_STATUS_AND_RESOLUTION_MAP = { [HotspotStatusOption.TO_REVIEW]: { status: HotspotStatus.TO_REVIEW, resolution: undefined }, [HotspotStatusOption.ACKNOWLEDGED]: { status: HotspotStatus.REVIEWED, - resolution: HotspotResolution.ACKNOWLEDGED + resolution: HotspotResolution.ACKNOWLEDGED, }, [HotspotStatusOption.FIXED]: { status: HotspotStatus.REVIEWED, - resolution: HotspotResolution.FIXED + resolution: HotspotResolution.FIXED, }, [HotspotStatusOption.SAFE]: { status: HotspotStatus.REVIEWED, - resolution: HotspotResolution.SAFE - } + resolution: HotspotResolution.SAFE, + }, }; export function getStatusAndResolutionFromStatusOption(statusOption: HotspotStatusOption) { @@ -217,7 +217,7 @@ const STATUS_OPTION_TO_STATUS_FILTER = { [HotspotStatusOption.TO_REVIEW]: HotspotStatusFilter.TO_REVIEW, [HotspotStatusOption.ACKNOWLEDGED]: HotspotStatusFilter.ACKNOWLEDGED, [HotspotStatusOption.FIXED]: HotspotStatusFilter.FIXED, - [HotspotStatusOption.SAFE]: HotspotStatusFilter.SAFE + [HotspotStatusOption.SAFE]: HotspotStatusFilter.SAFE, }; export function getStatusFilterFromStatusOption(statusOption: HotspotStatusOption) { @@ -226,15 +226,15 @@ export function getStatusFilterFromStatusOption(statusOption: HotspotStatusOptio function getSecondaryLocations(flows: RawHotspot['flows']) { const parsedFlows: FlowLocation[][] = (flows || []) - .filter(flow => flow.locations !== undefined) - .map(flow => flow.locations!.filter(location => location.textRange != null)) - .map(flow => - flow.map(location => { + .filter((flow) => flow.locations !== undefined) + .map((flow) => flow.locations!.filter((location) => location.textRange != null)) + .map((flow) => + flow.map((location) => { return { ...location }; }) ); - const onlySecondaryLocations = parsedFlows.every(flow => flow.length === 1); + const onlySecondaryLocations = parsedFlows.every((flow) => flow.length === 1); return onlySecondaryLocations ? { secondaryLocations: orderLocations(flatten(parsedFlows)), flows: [] } @@ -252,8 +252,8 @@ export function getLocations(rawFlows: RawHotspot['flows'], selectedFlowIndex: n function orderLocations(locations: FlowLocation[]) { return sortBy( locations, - location => location.textRange && location.textRange.startLine, - location => location.textRange && location.textRange.startOffset + (location) => location.textRange && location.textRange.startLine, + (location) => location.textRange && location.textRange.startOffset ); } |