From: Mathieu Suen Date: Fri, 6 May 2022 12:06:18 +0000 (+0200) Subject: SONAR-16303 The 'Why is this an issue' button is not available anymore on the issue... X-Git-Tag: 9.5.0.56709~105 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=b1701e9a5149db353682c2627dfa39d720bb10f1;p=sonarqube.git SONAR-16303 The 'Why is this an issue' button is not available anymore on the issue page --- diff --git a/server/sonar-web/src/main/js/api/issues.ts b/server/sonar-web/src/main/js/api/issues.ts index b4e6509c10c..6518a532e41 100644 --- a/server/sonar-web/src/main/js/api/issues.ts +++ b/server/sonar-web/src/main/js/api/issues.ts @@ -19,7 +19,15 @@ */ import getCoverageStatus from '../components/SourceViewer/helpers/getCoverageStatus'; import { throwGlobalError } from '../helpers/error'; -import { getJSON, post, postJSON, RequestData } from '../helpers/request'; +import { + get, + getJSON, + HttpStatus, + parseJSON, + post, + postJSON, + RequestData +} from '../helpers/request'; import { IssueResponse, RawIssuesResponse } from '../types/issues'; import { Dict, FacetValue, IssueChangelog, SnippetsByComponent, SourceLine } from '../types/types'; @@ -145,19 +153,26 @@ export function searchIssueAuthors(data: { } export function getIssueFlowSnippets(issueKey: string): Promise> { - return getJSON('/api/sources/issue_snippets', { issueKey }).then(result => { - Object.keys(result).forEach(k => { - if (result[k].sources) { - result[k].sources = result[k].sources.reduce( - (lineMap: Dict, line: SourceLine) => { - line.coverageStatus = getCoverageStatus(line); - lineMap[line.line] = line; - return lineMap; - }, - {} - ); + return get('/api/sources/issue_snippets', { issueKey }) + .then(r => { + if (r.status === HttpStatus.NoContent) { + return {} as any; } + return parseJSON(r); + }) + .then(result => { + Object.keys(result).forEach(k => { + if (result[k].sources) { + result[k].sources = result[k].sources.reduce( + (lineMap: Dict, line: SourceLine) => { + line.coverageStatus = getCoverageStatus(line); + lineMap[line.line] = line; + return lineMap; + }, + {} + ); + } + }); + return result; }); - return result; - }); } diff --git a/server/sonar-web/src/main/js/apps/issues/components/IssuesApp.tsx b/server/sonar-web/src/main/js/apps/issues/components/IssuesApp.tsx index e3c5384f700..34864825c2e 100644 --- a/server/sonar-web/src/main/js/apps/issues/components/IssuesApp.tsx +++ b/server/sonar-web/src/main/js/apps/issues/components/IssuesApp.tsx @@ -581,52 +581,6 @@ export default class App extends React.PureComponent { ); }; - fetchIssuesForComponent = (_component: string, _from: number, to: number) => { - const { issues, openIssue, paging } = this.state; - - if (!openIssue || !paging) { - return Promise.reject(undefined); - } - - const isSameComponent = (issue: Issue) => issue.component === openIssue.component; - - const done = (pageIssues: Issue[], p: Paging) => { - const lastIssue = pageIssues[pageIssues.length - 1]; - if (p.total <= p.pageIndex * p.pageSize) { - return true; - } - if (lastIssue.component !== openIssue.component) { - return true; - } - return lastIssue.textRange !== undefined && lastIssue.textRange.endLine > to; - }; - - if (done(issues, paging)) { - return Promise.resolve(issues.filter(isSameComponent)); - } - - this.setState({ loading: true }); - return this.fetchIssuesUntil(paging.pageIndex + 1, done).then( - response => { - const nextIssues = [...issues, ...response.issues]; - if (this.mounted) { - this.setState({ - issues: nextIssues, - loading: false, - paging: response.paging - }); - } - return nextIssues.filter(isSameComponent); - }, - () => { - if (this.mounted) { - this.setState({ loading: false }); - } - return []; - } - ); - }; - fetchFacet = (facet: string) => { return this.fetchIssues({ ps: 1, facets: facet }, false).then( ({ facets, ...other }) => { @@ -1130,10 +1084,8 @@ export default class App extends React.PureComponent { Promise; locationsNavigator: boolean; onIssueChange: (issue: Issue) => void; - onIssueSelect: (issueKey: string) => void; onLocationSelect: (index: number) => void; openIssue: Issue; selectedFlowIndex: number | undefined; @@ -90,68 +87,21 @@ export default class IssuesSourceViewer extends React.PureComponent { ? selectedLocation && { index: selectedLocationIndex, text: selectedLocation.msg } : undefined; - const startLines = locations.map(l => l.textRange.startLine); - const showCrossComponentSourceViewer = - startLines.length > 0 ? Math.max(...startLines) !== Math.min(...startLines) : false; - - if (showCrossComponentSourceViewer) { - return ( -
(this.node = node)}> - -
- ); - } else { - // if location is selected, show (and load) code around it - // otherwise show code around the open issue - const aroundLine = selectedLocation - ? selectedLocation.textRange.startLine - : openIssue.textRange && openIssue.textRange.endLine; - - const component = selectedLocation ? selectedLocation.component : openIssue.component; - const allMessagesEmpty = - locations !== undefined && locations.every(location => !location.msg); - - const highlightedLocations = locations.filter(location => location.component === component); - - // do not load issues when open another file for a location - const loadIssues = - component === openIssue.component ? this.props.loadIssues : () => Promise.resolve([]); - const selectedIssue = component === openIssue.component ? openIssue.key : undefined; - - return ( -
(this.node = node)}> - -
- ); - } + return ( +
(this.node = node)}> + +
+ ); } } diff --git a/server/sonar-web/src/main/js/apps/issues/components/__tests__/IssuesApp-test.tsx b/server/sonar-web/src/main/js/apps/issues/components/__tests__/IssuesApp-test.tsx index b1f3ebc1418..689eec93251 100644 --- a/server/sonar-web/src/main/js/apps/issues/components/__tests__/IssuesApp-test.tsx +++ b/server/sonar-web/src/main/js/apps/issues/components/__tests__/IssuesApp-test.tsx @@ -350,21 +350,6 @@ it('should check max 500 issues', async () => { expect(wrapper.find('#issues-bulk-change')).toMatchSnapshot(); }); -it('should fetch issues for component', async () => { - (searchIssues as jest.Mock).mockImplementation(mockSearchIssuesResponse()); - const wrapper = shallowRender({ - location: mockLocation({ - query: { open: '0' } - }) - }); - const instance = wrapper.instance(); - await waitAndUpdate(wrapper); - expect(wrapper.state('issues')).toHaveLength(2); - - await instance.fetchIssuesForComponent('', 0, 30); - expect(wrapper.state('issues')).toHaveLength(6); -}); - it('should display the right facets open', () => { expect( shallowRender({ diff --git a/server/sonar-web/src/main/js/apps/issues/components/__tests__/IssuesSourceViewer-test.tsx b/server/sonar-web/src/main/js/apps/issues/components/__tests__/IssuesSourceViewer-test.tsx index ec035492f45..e1e2a957372 100644 --- a/server/sonar-web/src/main/js/apps/issues/components/__tests__/IssuesSourceViewer-test.tsx +++ b/server/sonar-web/src/main/js/apps/issues/components/__tests__/IssuesSourceViewer-test.tsx @@ -69,10 +69,8 @@ function shallowRender(props: Partial = {}) { - `; exports[`should render SourceViewer correctly: default 1`] = `
-
`; exports[`should render SourceViewer correctly: single secondary location 1`] = `
-
`; diff --git a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/ComponentSourceSnippetGroupViewer.tsx b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/ComponentSourceSnippetGroupViewer.tsx index aad18317be3..d54d1f0ad95 100644 --- a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/ComponentSourceSnippetGroupViewer.tsx +++ b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/ComponentSourceSnippetGroupViewer.tsx @@ -335,6 +335,7 @@ export default class ComponentSourceSnippetGroupViewer extends React.PureCompone const issueLocationsByLine = includeIssueLocation ? locations : {}; return ( { - if (this.mounted) { - this.setState({ - components, - issuePopup: undefined, - loading: false - }); - if (this.props.onLoaded) { - this.props.onLoaded(); - } - } - }, - (response: Response) => { - if (response.status !== 403) { - throwGlobalError(response); + + try { + const components = await getIssueFlowSnippets(issue.key); + if (components[issue.component] === undefined) { + const issueComponent = await getComponentForSourceViewer({ + component: issue.component, + ...getBranchLikeQuery(branchLike) + }); + components[issue.component] = { component: issueComponent, sources: [] }; + if (isFile(issueComponent.q)) { + const sources = await getSources({ + key: issueComponent.key, + ...getBranchLikeQuery(branchLike), + from: 1, + to: 10 + }).then(lines => keyBy(lines, 'line')); + components[issue.component].sources = sources; } - if (this.mounted) { - this.setState({ loading: false, notAccessible: response.status === 403 }); + } + if (this.mounted) { + this.setState({ + components, + issuePopup: undefined, + loading: false + }); + if (this.props.onLoaded) { + this.props.onLoaded(); } } - ); + } catch (response) { + const rsp = response as Response; + if (rsp.status !== 403) { + throwGlobalError(response); + } + if (this.mounted) { + this.setState({ loading: false, notAccessible: rsp.status === 403 }); + } + } } handleIssuePopupToggle = (issue: string, popupName: string, open?: boolean) => { @@ -209,6 +227,10 @@ export default class CrossComponentSourceViewerWrapper extends React.PureCompone ({ component }) => component.key === issue.component ); + if (components[issue.component] === undefined) { + return null; + } + return (
{locationsByComponent.map((snippetGroup, i) => { @@ -239,6 +261,31 @@ export default class CrossComponentSourceViewerWrapper extends React.PureCompone ); })} + + {locationsByComponent.length === 0 && ( + + )}
); } diff --git a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/CrossComponentSourceViewerWrapper-test.tsx b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/CrossComponentSourceViewerWrapper-test.tsx index f22bc08b354..bc2e2802079 100644 --- a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/CrossComponentSourceViewerWrapper-test.tsx +++ b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/CrossComponentSourceViewerWrapper-test.tsx @@ -39,7 +39,8 @@ jest.mock('../../../../api/issues', () => { }); jest.mock('../../../../api/components', () => ({ - getDuplications: jest.fn().mockResolvedValue({}) + getDuplications: jest.fn().mockResolvedValue({}), + getComponentForSourceViewer: jest.fn().mockResolvedValue({}) })); beforeEach(() => { @@ -47,19 +48,26 @@ beforeEach(() => { }); it('should render correctly', async () => { - const wrapper = shallowRender(); + let wrapper = shallowRender(); expect(wrapper).toMatchSnapshot(); await waitAndUpdate(wrapper); expect(wrapper).toMatchSnapshot(); + + wrapper = shallowRender({ issue: mockIssue(true, { component: 'test.js', key: 'unknown' }) }); + await waitAndUpdate(wrapper); + + expect(wrapper).toMatchSnapshot('no component found'); }); it('Should fetch data', async () => { const wrapper = shallowRender(); - wrapper.instance().fetchIssueFlowSnippets('124'); + wrapper.instance().fetchIssueFlowSnippets(); await waitAndUpdate(wrapper); expect(getIssueFlowSnippets).toHaveBeenCalledWith('1'); - expect(wrapper.state('components')).toEqual({ 'main.js': mockSnippetsByComponent() }); + expect(wrapper.state('components')).toEqual( + expect.objectContaining({ 'main.js': mockSnippetsByComponent() }) + ); (getIssueFlowSnippets as jest.Mock).mockClear(); wrapper.setProps({ issue: mockIssue(true, { key: 'foo' }) }); diff --git a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/__snapshots__/ComponentSourceSnippetGroupViewer-test.tsx.snap b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/__snapshots__/ComponentSourceSnippetGroupViewer-test.tsx.snap index 4d100ae4cf3..c98ca92f56f 100644 --- a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/__snapshots__/ComponentSourceSnippetGroupViewer-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/__snapshots__/ComponentSourceSnippetGroupViewer-test.tsx.snap @@ -49,6 +49,7 @@ exports[`should render correctly line with issue 1`] = ` "name": "master", } } + displayWhyIsThisAnIssue={false} issue={ Object { "actions": Array [], diff --git a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/__snapshots__/CrossComponentSourceViewerWrapper-test.tsx.snap b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/__snapshots__/CrossComponentSourceViewerWrapper-test.tsx.snap index 06624417ee0..1c7210b0168 100644 --- a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/__snapshots__/CrossComponentSourceViewerWrapper-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/__snapshots__/CrossComponentSourceViewerWrapper-test.tsx.snap @@ -217,3 +217,330 @@ exports[`should render correctly 2`] = ` `; + +exports[`should render correctly: no component found 1`] = ` +
+ + + + + import java.util.ArrayList;", + "coverageStatus": "covered", + "coveredConditions": 2, + "duplicated": false, + "isNew": true, + "line": 16, + "scmAuthor": "simon.brandhof@sonarsource.com", + "scmDate": "2018-12-11T10:48:39+0100", + "scmRevision": "80f564becc0c0a1c9abaa006eca83a4fd278c3f0", + }, + }, + } + } + /> + +
+`; diff --git a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/utils.ts b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/utils.ts index 69409b43cdc..d41b61cbe0d 100644 --- a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/utils.ts +++ b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/utils.ts @@ -17,6 +17,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +import { ComponentQualifier } from '../../../types/component'; import { ExpandDirection, FlowLocation, @@ -42,7 +43,7 @@ function unknownComponent(key: string): SnippetsByComponent { path: '', project: '', projectName: '', - q: 'FIL', + q: ComponentQualifier.File, uuid: '' }, sources: [] diff --git a/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerCode.tsx b/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerCode.tsx index c591c404cde..2d681daf14f 100644 --- a/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerCode.tsx +++ b/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerCode.tsx @@ -189,6 +189,7 @@ export default class SourceViewerCode extends React.PureComponent { scrollToUncoveredLine={scrollToUncoveredLine} secondaryIssueLocations={secondaryIssueLocations}> { expect( shallowRender({ showMeasures: true, - sourceViewerFile: mockSourceViewerFile({ q: 'UTS', measures: { tests: '12' } }) + sourceViewerFile: mockSourceViewerFile({ + q: ComponentQualifier.TestFile, + measures: { tests: '12' } + }) }) ).toMatchSnapshot(); }); diff --git a/server/sonar-web/src/main/js/components/SourceViewer/components/LineIssuesList.tsx b/server/sonar-web/src/main/js/components/SourceViewer/components/LineIssuesList.tsx index 5584d032e47..3bd7852163b 100644 --- a/server/sonar-web/src/main/js/components/SourceViewer/components/LineIssuesList.tsx +++ b/server/sonar-web/src/main/js/components/SourceViewer/components/LineIssuesList.tsx @@ -25,6 +25,7 @@ import Issue from '../../issue/Issue'; export interface LineIssuesListProps { branchLike: BranchLike | undefined; displayAllIssues?: boolean; + displayWhyIsThisAnIssue: boolean; displayIssueLocationsCount?: boolean; displayIssueLocationsLink?: boolean; issuesForLine: TypeIssue[]; @@ -41,6 +42,7 @@ export interface LineIssuesListProps { export default function LineIssuesList(props: LineIssuesListProps) { const { line, + displayWhyIsThisAnIssue, displayAllIssues, openIssuesByLine, selectedIssue, @@ -66,6 +68,7 @@ export default function LineIssuesList(props: LineIssuesListProps) { {displayedIssue.map(issue => ( { +it('should render issues', () => { const wrapper = shallowRender({ selectedIssue: 'issue', issueLocationsByLine: { '1': [{ from: 1, to: 1, line: 1 }] }, @@ -37,6 +37,7 @@ function shallowRender(props: Partial = {}) { return shallow( { }); it('should render test file', async () => { - const wrapper = shallowRender({ sourceViewerFile: { ...sourceViewerFile, q: 'UTS' } }); + const wrapper = shallowRender({ + sourceViewerFile: { ...sourceViewerFile, q: ComponentQualifier.TestFile } + }); await waitAndUpdate(wrapper); expect(wrapper).toMatchSnapshot(); }); diff --git a/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/LineIssueList-test.tsx.snap b/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/LineIssueList-test.tsx.snap index eef65511cda..4a7b0a9eff5 100644 --- a/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/LineIssueList-test.tsx.snap +++ b/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/LineIssueList-test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`shoule render issues 1`] = ` +exports[`should render issues 1`] = `
@@ -13,6 +13,7 @@ exports[`shoule render issues 1`] = ` "name": "branch-6.7", } } + displayWhyIsThisAnIssue={true} issue={ Object { "actions": Array [], diff --git a/server/sonar-web/src/main/js/components/issue/Issue.tsx b/server/sonar-web/src/main/js/components/issue/Issue.tsx index c06a7d5d694..76de0d88fa3 100644 --- a/server/sonar-web/src/main/js/components/issue/Issue.tsx +++ b/server/sonar-web/src/main/js/components/issue/Issue.tsx @@ -29,6 +29,7 @@ import IssueView from './IssueView'; interface Props { branchLike?: BranchLike; checked?: boolean; + displayWhyIsThisAnIssue?: boolean; displayLocationsCount?: boolean; displayLocationsLink?: boolean; issue: TypeIssue; @@ -116,6 +117,7 @@ export default class Issue extends React.PureComponent { branchLike={this.props.branchLike} checked={this.props.checked} currentPopup={this.props.openPopup} + displayWhyIsThisAnIssue={this.props.displayWhyIsThisAnIssue} displayLocationsCount={this.props.displayLocationsCount} displayLocationsLink={this.props.displayLocationsLink} issue={this.props.issue} diff --git a/server/sonar-web/src/main/js/components/issue/IssueView.tsx b/server/sonar-web/src/main/js/components/issue/IssueView.tsx index e42903a8c15..919237c89c8 100644 --- a/server/sonar-web/src/main/js/components/issue/IssueView.tsx +++ b/server/sonar-web/src/main/js/components/issue/IssueView.tsx @@ -33,6 +33,7 @@ interface Props { branchLike?: BranchLike; checked?: boolean; currentPopup?: string; + displayWhyIsThisAnIssue?: boolean; displayLocationsCount?: boolean; displayLocationsLink?: boolean; issue: Issue; @@ -68,7 +69,15 @@ export default class IssueView extends React.PureComponent { }; render() { - const { issue } = this.props; + const { + issue, + branchLike, + checked, + currentPopup, + displayWhyIsThisAnIssue, + displayLocationsLink, + displayLocationsCount + } = this.props; const hasCheckbox = this.props.onCheck != null; @@ -86,16 +95,17 @@ export default class IssueView extends React.PureComponent { role="region" aria-label={issue.message}> { )} {hasCheckbox && ( @@ -106,16 +107,18 @@ export default function IssueMessage(props: IssueMessageProps) { )}
- - props.onOpenRule({ - key: ruleKey - }) - }> - {translate('issue.why_this_issue')} - + {displayWhyIsThisAnIssue && ( + + openRule({ + key: ruleKey + }) + }> + {translate('issue.why_this_issue')} + + )} ); } diff --git a/server/sonar-web/src/main/js/components/issue/components/IssueTitleBar.tsx b/server/sonar-web/src/main/js/components/issue/components/IssueTitleBar.tsx index 82fd5adc024..b010d31c688 100644 --- a/server/sonar-web/src/main/js/components/issue/components/IssueTitleBar.tsx +++ b/server/sonar-web/src/main/js/components/issue/components/IssueTitleBar.tsx @@ -29,7 +29,6 @@ import { BranchLike } from '../../../types/branch-like'; import { RuleStatus } from '../../../types/rules'; import { Issue } from '../../../types/types'; import LocationIndex from '../../common/LocationIndex'; -import { WorkspaceContext } from '../../workspace/context'; import IssueChangelog from './IssueChangelog'; import IssueMessage from './IssueMessage'; import SimilarIssuesFilter from './SimilarIssuesFilter'; @@ -37,6 +36,7 @@ import SimilarIssuesFilter from './SimilarIssuesFilter'; export interface IssueTitleBarProps { branchLike?: BranchLike; currentPopup?: string; + displayWhyIsThisAnIssue?: boolean; displayLocationsCount?: boolean; displayLocationsLink?: boolean; issue: Issue; @@ -45,7 +45,7 @@ export interface IssueTitleBarProps { } export default function IssueTitleBar(props: IssueTitleBarProps) { - const { issue } = props; + const { issue, displayWhyIsThisAnIssue } = props; const hasSimilarIssuesFilter = props.onFilter != null; const locationsCount = @@ -73,25 +73,15 @@ export default function IssueTitleBar(props: IssueTitleBarProps) { return (
- - {({ externalRulesRepoNames, openRule }) => ( - - )} - - +
diff --git a/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueMessage-test.tsx b/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueMessage-test.tsx index 13b5bf2b677..c11c314aaa1 100644 --- a/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueMessage-test.tsx +++ b/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueMessage-test.tsx @@ -19,30 +19,43 @@ */ import { shallow } from 'enzyme'; import * as React from 'react'; -import { ButtonLink } from '../../../../components/controls/buttons'; -import { click } from '../../../../helpers/testUtils'; import { RuleStatus } from '../../../../types/rules'; +import { ButtonLink } from '../../../controls/buttons'; import IssueMessage, { IssueMessageProps } from '../IssueMessage'; +jest.mock('react', () => { + return { + ...jest.requireActual('react'), + useContext: jest + .fn() + .mockImplementation(() => ({ externalRulesRepoNames: {}, openRule: jest.fn() })) + }; +}); + it('should render correctly', () => { expect(shallowRender()).toMatchSnapshot('default'); expect(shallowRender({ engine: 'js' })).toMatchSnapshot('with engine info'); expect(shallowRender({ quickFixAvailable: true })).toMatchSnapshot('with quick fix'); - expect(shallowRender({ engineName: 'JS' })).toMatchSnapshot('with engine name'); expect(shallowRender({ manualVulnerability: true })).toMatchSnapshot('is manual vulnerability'); expect(shallowRender({ ruleStatus: RuleStatus.Deprecated })).toMatchSnapshot( 'is deprecated rule' ); expect(shallowRender({ ruleStatus: RuleStatus.Removed })).toMatchSnapshot('is removed rule'); + expect(shallowRender({ displayWhyIsThisAnIssue: false })).toMatchSnapshot( + 'hide why is it an issue' + ); }); -it('should handle click correctly', () => { - const onOpenRule = jest.fn(); - const wrapper = shallowRender({ onOpenRule }); - click(wrapper.find(ButtonLink)); - expect(onOpenRule).toBeCalledWith({ - key: 'javascript:S1067' - }); +it('should open why is this an issue workspace', () => { + const openRule = jest.fn(); + (React.useContext as jest.Mock).mockImplementationOnce(() => ({ + externalRulesRepoNames: {}, + openRule + })); + const wrapper = shallowRender(); + wrapper.find(ButtonLink).simulate('click'); + + expect(openRule).toBeCalled(); }); function shallowRender(props: Partial = {}) { @@ -50,7 +63,7 @@ function shallowRender(props: Partial = {}) { diff --git a/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueTitleBar-test.tsx b/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueTitleBar-test.tsx index 29d1882b8f5..7178fa1a17a 100644 --- a/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueTitleBar-test.tsx +++ b/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueTitleBar-test.tsx @@ -21,7 +21,6 @@ import { shallow } from 'enzyme'; import * as React from 'react'; import { mockBranch } from '../../../../helpers/mocks/branch-like'; import { mockIssue } from '../../../../helpers/testMocks'; -import { WorkspaceContext } from '../../../workspace/context'; import IssueTitleBar, { IssueTitleBarProps } from '../IssueTitleBar'; it('should render correctly', () => { @@ -38,11 +37,6 @@ it('should render correctly', () => { issue: mockIssue(true) }) ).toMatchSnapshot('with multi locations and link'); - expect( - shallowRender() - .find(WorkspaceContext.Consumer) - .dive() - ).toMatchSnapshot('issue message'); }); function shallowRender(props: Partial = {}) { diff --git a/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueMessage-test.tsx.snap b/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueMessage-test.tsx.snap index ad368c1d951..efae668c86c 100644 --- a/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueMessage-test.tsx.snap +++ b/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueMessage-test.tsx.snap @@ -21,6 +21,20 @@ exports[`should render correctly: default 1`] = ` `; +exports[`should render correctly: hide why is it an issue 1`] = ` + +
+ + Reduce the number of conditional operators (4) used in the expression + +
+
+`; + exports[`should render correctly: is deprecated rule 1`] = `
`; -exports[`should render correctly: with engine name 1`] = ` - -
- - Reduce the number of conditional operators (4) used in the expression - - -
- JS -
-
-
- - issue.why_this_issue - -
-`; - exports[`should render correctly: with quick fix 1`] = `
- - - +
@@ -94,23 +97,16 @@ exports[`should render correctly: default 1`] = `
`; -exports[`should render correctly: issue message 1`] = ` - -`; - exports[`should render correctly: with filter 1`] = `
- - - +
@@ -243,9 +239,11 @@ exports[`should render correctly: with multi locations 1`] = `
- - - +
@@ -416,9 +414,11 @@ exports[`should render correctly: with multi locations and link 1`] = `
- - - +
diff --git a/server/sonar-web/src/main/js/helpers/request.ts b/server/sonar-web/src/main/js/helpers/request.ts index ac1644791f7..569ea04e610 100644 --- a/server/sonar-web/src/main/js/helpers/request.ts +++ b/server/sonar-web/src/main/js/helpers/request.ts @@ -323,6 +323,7 @@ export function isSuccessStatus(status: number) { export enum HttpStatus { Ok = 200, Created = 201, + NoContent = 204, MultipleChoices = 300, MovedPermanently = 301, Found = 302, diff --git a/server/sonar-web/src/main/js/helpers/testMocks.ts b/server/sonar-web/src/main/js/helpers/testMocks.ts index 4cc1426456a..dd4270c4c43 100644 --- a/server/sonar-web/src/main/js/helpers/testMocks.ts +++ b/server/sonar-web/src/main/js/helpers/testMocks.ts @@ -23,6 +23,7 @@ import { DocumentationEntry } from '../apps/documentation/utils'; import { Exporter, Profile } from '../apps/quality-profiles/types'; import { AppState } from '../types/appstate'; import { RuleRepository } from '../types/coding-rules'; +import { ComponentQualifier } from '../types/component'; import { EditionKey } from '../types/editions'; import { RawIssue } from '../types/issues'; import { Language } from '../types/languages'; @@ -659,7 +660,7 @@ export function mockSourceViewerFile(overrides: Partial = {}): path: 'foo/bar.ts', project: 'my-project', projectName: 'MyProject', - q: 'FIL', + q: ComponentQualifier.File, uuid: 'foo-bar', ...overrides }; diff --git a/server/sonar-web/src/main/js/types/types.ts b/server/sonar-web/src/main/js/types/types.ts index 890237e2040..6d857540864 100644 --- a/server/sonar-web/src/main/js/types/types.ts +++ b/server/sonar-web/src/main/js/types/types.ts @@ -18,6 +18,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +import { ComponentQualifier } from './component'; import { UserActive, UserBase } from './users'; export type Dict = { [key: string]: T }; @@ -676,7 +677,7 @@ export interface SourceViewerFile { path: string; project: string; projectName: string; - q: string; + q: ComponentQualifier; subProject?: string; subProjectName?: string; uuid: string;