aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--server/sonar-web/src/main/js/api/mocks/IssuesServiceMock.ts201
-rw-r--r--server/sonar-web/src/main/js/api/mocks/SourceViewerServiceMock.ts2
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/RuleDetails-test.tsx.snap8
-rw-r--r--server/sonar-web/src/main/js/apps/issues/__tests__/IssueApp-it.tsx49
-rw-r--r--server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/CrossComponentSourceViewerWrapper.tsx5
-rw-r--r--server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/ComponentSourceSnippetGroupViewer-test.tsx43
-rw-r--r--server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/CrossComponentSourceViewerWrapper-test.tsx7
-rw-r--r--server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/SnippetViewer-test.tsx5
-rw-r--r--server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/__snapshots__/ComponentSourceSnippetGroupViewer-test.tsx.snap8
-rw-r--r--server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/__snapshots__/CrossComponentSourceViewerWrapper-test.tsx.snap34
-rw-r--r--server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/utils-test.ts32
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotSnippetContainer-test.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotSnippetContainerRenderer-test.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotSnippetContainerRenderer-test.tsx.snap8
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/__tests__/SourceViewerBase-test.tsx3
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/__tests__/SourceViewerCode-test.tsx3
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/__tests__/SourceViewerHeader-test.tsx4
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/__tests__/SourceViewerHeaderSlim-test.tsx15
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/__tests__/__snapshots__/SourceViewerBase-test.tsx.snap8
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/__tests__/__snapshots__/SourceViewerHeader-test.tsx.snap28
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/Line-test.tsx3
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/LineCode-test.tsx2
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/LineIssueList-test.tsx3
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/issueLocations-test.ts3
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/sources.ts78
-rw-r--r--server/sonar-web/src/main/js/helpers/testMocks.ts69
-rw-r--r--server/sonar-web/src/main/js/types/issues.ts3
-rw-r--r--server/sonar-web/src/main/js/types/types.ts3
28 files changed, 475 insertions, 157 deletions
diff --git a/server/sonar-web/src/main/js/api/mocks/IssuesServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/IssuesServiceMock.ts
index 3d1ed2a6a22..e961edf5b66 100644
--- a/server/sonar-web/src/main/js/api/mocks/IssuesServiceMock.ts
+++ b/server/sonar-web/src/main/js/api/mocks/IssuesServiceMock.ts
@@ -17,13 +17,29 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { cloneDeep } from 'lodash';
+import { cloneDeep, keyBy, range, times } from 'lodash';
+import {
+ mockSnippetsByComponent,
+ mockSourceLine,
+ mockSourceViewerFile
+} from '../../helpers/mocks/sources';
import { RequestData } from '../../helpers/request';
import { getStandards } from '../../helpers/security-standard';
-import { mockPaging } from '../../helpers/testMocks';
-import { RawFacet, RawIssuesResponse, ReferencedComponent } from '../../types/issues';
+import { mockPaging, mockRawIssue, mockRuleDetails } from '../../helpers/testMocks';
+import { BranchParameters } from '../../types/branch-like';
+import { RawFacet, RawIssue, RawIssuesResponse, ReferencedComponent } from '../../types/issues';
import { Standards } from '../../types/security';
-import { searchIssues } from '../issues';
+import {
+ Dict,
+ RuleActivation,
+ RuleDescriptionSections,
+ RuleDetails,
+ SnippetsByComponent,
+ SourceViewerFile
+} from '../../types/types';
+import { getComponentForSourceViewer, getSources } from '../components';
+import { getIssueFlowSnippets, searchIssues } from '../issues';
+import { getRuleDetails } from '../rules';
function mockReferenceComponent(override?: Partial<ReferencedComponent>) {
return {
@@ -34,16 +50,123 @@ function mockReferenceComponent(override?: Partial<ReferencedComponent>) {
};
}
+interface IssueData {
+ issue: RawIssue;
+ snippets: Dict<SnippetsByComponent>;
+}
+
export default class IssuesServiceMock {
isAdmin = false;
standards?: Standards;
+ sourceViewerFiles: SourceViewerFile[];
+ list: IssueData[];
constructor() {
- (searchIssues as jest.Mock).mockImplementation(this.listHandler);
- }
-
- reset() {
- this.setIsAdmin(false);
+ this.sourceViewerFiles = [
+ mockSourceViewerFile('file.foo', 'project'),
+ mockSourceViewerFile('file.bar', 'project')
+ ];
+ this.list = [
+ {
+ issue: mockRawIssue(false, {
+ key: 'issue0',
+ component: 'project:file.foo',
+ message: 'Issue on file',
+ rule: 'simpleRuleId',
+ textRange: undefined,
+ line: undefined
+ }),
+ snippets: {}
+ },
+ {
+ issue: mockRawIssue(false, {
+ key: 'issue1',
+ component: 'project:file.foo',
+ message: 'Fix this',
+ rule: 'simpleRuleId',
+ textRange: {
+ startLine: 10,
+ endLine: 10,
+ startOffset: 0,
+ endOffset: 2
+ },
+ flows: [
+ {
+ locations: [
+ {
+ component: 'project:file.foo',
+ textRange: {
+ startLine: 1,
+ endLine: 1,
+ startOffset: 0,
+ endOffset: 1
+ }
+ }
+ ]
+ },
+ {
+ locations: [
+ {
+ component: 'project:file.bar',
+ textRange: {
+ startLine: 20,
+ endLine: 20,
+ startOffset: 0,
+ endOffset: 1
+ }
+ }
+ ]
+ }
+ ]
+ }),
+ snippets: keyBy(
+ [
+ mockSnippetsByComponent(
+ 'file.foo',
+ 'project',
+ times(40, i => i + 1)
+ ),
+ mockSnippetsByComponent(
+ 'file.bar',
+ 'project',
+ times(40, i => i + 1)
+ )
+ ],
+ 'component.key'
+ )
+ },
+ {
+ issue: mockRawIssue(false, {
+ key: 'issue2',
+ component: 'project:file.bar',
+ message: 'Fix that',
+ rule: 'advancedRuleId',
+ textRange: {
+ startLine: 25,
+ endLine: 25,
+ startOffset: 0,
+ endOffset: 1
+ }
+ }),
+ snippets: keyBy(
+ [
+ mockSnippetsByComponent(
+ 'file.bar',
+ 'project',
+ times(40, i => i + 20)
+ )
+ ],
+ 'component.key'
+ )
+ }
+ ];
+ (searchIssues as jest.Mock).mockImplementation(this.handleSearchIssues);
+ (getRuleDetails as jest.Mock).mockImplementation(this.handleGetRuleDetails);
+ (getIssueFlowSnippets as jest.Mock).mockImplementation(this.handleGetIssueFlowSnippets);
+ (getSources as jest.Mock).mockImplementation(this.handleGetSources);
+ (getComponentForSourceViewer as jest.Mock).mockImplementation(
+ this.handleGetComponentForSourceViewer
+ );
}
async getStandards(): Promise<Standards> {
@@ -65,7 +188,63 @@ export default class IssuesServiceMock {
this.isAdmin = isAdmin;
}
- listHandler = (query: RequestData): Promise<RawIssuesResponse> => {
+ handleGetSources = (data: { key: string; from?: number; to?: number } & BranchParameters) => {
+ return this.reply(range(data.from || 1, data.to || 10).map(line => mockSourceLine({ line })));
+ };
+
+ handleGetComponentForSourceViewer = (data: { component: string } & BranchParameters) => {
+ const file = this.sourceViewerFiles.find(f => f.key === data.component);
+ if (file === undefined) {
+ return Promise.reject({
+ errors: [{ msg: `No source file has been found for id ${data.component}` }]
+ });
+ }
+
+ return this.reply(file);
+ };
+
+ handleGetIssueFlowSnippets = (issueKey: string): Promise<Dict<SnippetsByComponent>> => {
+ const issue = this.list.find(i => i.issue.key === issueKey);
+ if (issue === undefined) {
+ return Promise.reject({ errors: [{ msg: `No issue has been found for id ${issueKey}` }] });
+ }
+ return this.reply(issue.snippets);
+ };
+
+ handleGetRuleDetails = (parameters: {
+ actives?: boolean;
+ key: string;
+ }): Promise<{ actives?: RuleActivation[]; rule: RuleDetails }> => {
+ if (parameters.key === 'advancedRuleId') {
+ return this.reply({
+ rule: mockRuleDetails({
+ key: parameters.key,
+ name: 'Advanced rule',
+ descriptionSections: [
+ { key: RuleDescriptionSections.INTRODUCTION, content: '<h1>Into</h1>' },
+ { key: RuleDescriptionSections.ROOT_CAUSE, content: '<h1>Because</h1>' },
+ { key: RuleDescriptionSections.HOW_TO_FIX, content: '<h1>Fix with</h1>' },
+ { key: RuleDescriptionSections.RESOURCES, content: '<h1>Link</h1>' }
+ ]
+ })
+ });
+ }
+ return this.reply({
+ rule: mockRuleDetails({
+ key: parameters.key,
+ name: 'Simple rule',
+ htmlNote: '<h1>Note</h1>',
+ descriptionSections: [
+ {
+ key: RuleDescriptionSections.DEFAULT,
+ content: '<h1>Default</h1> Default description'
+ }
+ ]
+ })
+ });
+ };
+
+ handleSearchIssues = (query: RequestData): Promise<RawIssuesResponse> => {
const facets = query.facets.split(',').map((name: string) => {
if (name === 'owaspTop10-2021') {
return this.owasp2021FacetList();
@@ -79,7 +258,7 @@ export default class IssuesServiceMock {
components: [mockReferenceComponent()],
effortTotal: 199629,
facets,
- issues: [],
+ issues: this.list.map(line => line.issue),
languages: [],
paging: mockPaging()
});
diff --git a/server/sonar-web/src/main/js/api/mocks/SourceViewerServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/SourceViewerServiceMock.ts
index 636c304c0d6..7179d0f26e0 100644
--- a/server/sonar-web/src/main/js/api/mocks/SourceViewerServiceMock.ts
+++ b/server/sonar-web/src/main/js/api/mocks/SourceViewerServiceMock.ts
@@ -26,7 +26,7 @@ import {
getDuplications,
getSources
} from '../../api/components';
-import { mockSourceLine } from '../../helpers/testMocks';
+import { mockSourceLine } from '../../helpers/mocks/sources';
import { BranchParameters } from '../../types/branch-like';
import { Dict } from '../../types/types';
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/RuleDetails-test.tsx.snap b/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/RuleDetails-test.tsx.snap
index d00bb73d453..a5cdd29cc53 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/RuleDetails-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/RuleDetails-test.tsx.snap
@@ -31,7 +31,7 @@ exports[`should render correctly: loaded 1`] = `
"defaultRemFnType": "CONSTANT_ISSUE",
"descriptionSections": Array [
Object {
- "content": "<b>Why<b/> Because",
+ "content": "<b>Why</b> Because",
"key": "root_cause",
},
],
@@ -73,7 +73,7 @@ exports[`should render correctly: loaded 1`] = `
"defaultRemFnType": "CONSTANT_ISSUE",
"descriptionSections": Array [
Object {
- "content": "<b>Why<b/> Because",
+ "content": "<b>Why</b> Because",
"key": "root_cause",
},
],
@@ -146,7 +146,7 @@ exports[`should render correctly: loaded 1`] = `
"defaultRemFnType": "CONSTANT_ISSUE",
"descriptionSections": Array [
Object {
- "content": "<b>Why<b/> Because",
+ "content": "<b>Why</b> Because",
"key": "root_cause",
},
],
@@ -187,7 +187,7 @@ exports[`should render correctly: loaded 1`] = `
"defaultRemFnType": "CONSTANT_ISSUE",
"descriptionSections": Array [
Object {
- "content": "<b>Why<b/> Because",
+ "content": "<b>Why</b> Because",
"key": "root_cause",
},
],
diff --git a/server/sonar-web/src/main/js/apps/issues/__tests__/IssueApp-it.tsx b/server/sonar-web/src/main/js/apps/issues/__tests__/IssueApp-it.tsx
index 0a99fb39b8f..8153bf39579 100644
--- a/server/sonar-web/src/main/js/apps/issues/__tests__/IssueApp-it.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/__tests__/IssueApp-it.tsx
@@ -25,14 +25,59 @@ import { renderComponentApp } from '../../../helpers/testReactTestingUtils';
import AppContainer from '../components/AppContainer';
jest.mock('../../../api/issues');
+jest.mock('../../../api/rules');
+jest.mock('../../../api/components');
let handler: IssuesServiceMock;
-beforeAll(() => {
+beforeEach(() => {
+ window.scrollTo = jest.fn();
handler = new IssuesServiceMock();
});
-afterEach(() => handler.reset());
+it('should open issue and navigate', async () => {
+ const user = userEvent.setup();
+ renderIssueApp();
+ expect(await screen.findByRole('region', { name: 'Fix that' })).toBeInTheDocument();
+ await user.click(screen.getByRole('region', { name: 'Fix that' }));
+ expect(screen.getByRole('heading', { level: 1, name: 'Fix that' })).toBeInTheDocument();
+ expect(screen.getByRole('link', { name: 'advancedRuleId' })).toBeInTheDocument();
+
+ expect(screen.getByRole('button', { name: `issue.tabs.resources` })).toBeInTheDocument();
+ await user.click(screen.getByRole('button', { name: `issue.tabs.resources` }));
+ expect(screen.getByRole('heading', { name: 'Link' })).toBeInTheDocument();
+
+ expect(screen.getByRole('button', { name: `issue.tabs.how` })).toBeInTheDocument();
+ await user.click(screen.getByRole('button', { name: `issue.tabs.how` }));
+ expect(screen.getByRole('heading', { name: 'Fix with' })).toBeInTheDocument();
+
+ expect(screen.getByRole('button', { name: `issue.tabs.why` })).toBeInTheDocument();
+ await user.click(screen.getByRole('button', { name: `issue.tabs.why` }));
+ expect(screen.getByRole('heading', { name: 'Because' })).toBeInTheDocument();
+
+ await user.keyboard('{ArrowUp}');
+
+ expect(screen.getByRole('heading', { level: 1, name: 'Fix this' })).toBeInTheDocument();
+ expect(screen.getByRole('link', { name: 'simpleRuleId' })).toBeInTheDocument();
+
+ expect(screen.getByRole('button', { name: `issue.tabs.why` })).toBeInTheDocument();
+ await user.click(screen.getByRole('button', { name: `issue.tabs.why` }));
+ expect(screen.getByRole('heading', { name: 'Default' })).toBeInTheDocument();
+
+ await user.keyboard('{ArrowUp}');
+
+ expect(screen.getByRole('heading', { level: 1, name: 'Issue on file' })).toBeInTheDocument();
+ expect(screen.getByRole('link', { name: 'simpleRuleId' })).toBeInTheDocument();
+
+ expect(screen.getByRole('button', { name: `issue.tabs.code` })).toBeInTheDocument();
+ await user.click(screen.getByRole('button', { name: `issue.tabs.code` }));
+ expect(screen.getByRole('region', { name: 'Issue on file' })).toBeInTheDocument();
+ expect(
+ screen.getByRole('row', {
+ name: '2 source_viewer.tooltip.covered import java.util. ArrayList ;'
+ })
+ ).toBeInTheDocument();
+});
it('should support OWASP Top 10 version 2021', async () => {
const user = userEvent.setup();
diff --git a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/CrossComponentSourceViewerWrapper.tsx b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/CrossComponentSourceViewerWrapper.tsx
index 676c7701ec6..2d20f25c5ac 100644
--- a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/CrossComponentSourceViewerWrapper.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/CrossComponentSourceViewerWrapper.tsx
@@ -38,6 +38,7 @@ import { WorkspaceContext } from '../../../components/workspace/context';
import { getBranchLikeQuery } from '../../../helpers/branch-like';
import { throwGlobalError } from '../../../helpers/error';
import { translate } from '../../../helpers/l10n';
+import { HttpStatus } from '../../../helpers/request';
import { BranchLike } from '../../../types/branch-like';
import { isFile } from '../../../types/component';
import {
@@ -151,11 +152,11 @@ export default class CrossComponentSourceViewerWrapper extends React.PureCompone
}
} catch (response) {
const rsp = response as Response;
- if (rsp.status !== 403) {
+ if (rsp.status !== HttpStatus.Forbidden) {
throwGlobalError(response);
}
if (this.mounted) {
- this.setState({ loading: false, notAccessible: rsp.status === 403 });
+ this.setState({ loading: false, notAccessible: rsp.status === HttpStatus.Forbidden });
}
}
}
diff --git a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/ComponentSourceSnippetGroupViewer-test.tsx b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/ComponentSourceSnippetGroupViewer-test.tsx
index 5db19b60cc0..cbbe8669da5 100644
--- a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/ComponentSourceSnippetGroupViewer-test.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/ComponentSourceSnippetGroupViewer-test.tsx
@@ -24,12 +24,11 @@ import { getSources } from '../../../../api/components';
import Issue from '../../../../components/issue/Issue';
import { mockBranch, mockMainBranch } from '../../../../helpers/mocks/branch-like';
import {
- mockFlowLocation,
- mockIssue,
mockSnippetsByComponent,
mockSourceLine,
mockSourceViewerFile
-} from '../../../../helpers/testMocks';
+} from '../../../../helpers/mocks/sources';
+import { mockFlowLocation, mockIssue } from '../../../../helpers/testMocks';
import { waitAndUpdate } from '../../../../helpers/testUtils';
import { SnippetGroup } from '../../../../types/types';
import ComponentSourceSnippetGroupViewer from '../ComponentSourceSnippetGroupViewer';
@@ -50,6 +49,7 @@ it('should render correctly', () => {
it('should render correctly with secondary locations', () => {
// issue with secondary locations but no flows
const issue = mockIssue(true, {
+ component: 'project:main.js',
flows: [],
textRange: { startLine: 7, endLine: 7, startOffset: 5, endOffset: 10 }
});
@@ -65,7 +65,7 @@ it('should render correctly with secondary locations', () => {
textRange: { startLine: 74, endLine: 74, startOffset: 0, endOffset: 0 }
})
],
- ...mockSnippetsByComponent(issue.component, [
+ ...mockSnippetsByComponent('main.js', 'project', [
...range(2, 17),
...range(29, 39),
...range(69, 79)
@@ -81,6 +81,7 @@ it('should render correctly with secondary locations', () => {
it('should render correctly with flows', () => {
// issue with flows but no secondary locations
const issue = mockIssue(true, {
+ component: 'project:main.js',
secondaryLocations: [],
textRange: { startLine: 7, endLine: 7, startOffset: 5, endOffset: 10 }
});
@@ -96,7 +97,7 @@ it('should render correctly with flows', () => {
textRange: { startLine: 74, endLine: 74, startOffset: 0, endOffset: 0 }
})
],
- ...mockSnippetsByComponent(issue.component, [
+ ...mockSnippetsByComponent('main.js', 'project', [
...range(2, 17),
...range(29, 39),
...range(69, 79)
@@ -129,6 +130,7 @@ it('should render correctly with flows', () => {
it('should render file-level issue correctly', () => {
// issue with secondary locations and no primary location
const issue = mockIssue(true, {
+ component: 'project:main.js',
flows: [],
textRange: undefined
});
@@ -142,7 +144,7 @@ it('should render file-level issue correctly', () => {
textRange: { startLine: 34, endLine: 34, startOffset: 0, endOffset: 0 }
})
],
- ...mockSnippetsByComponent(issue.component, range(29, 39))
+ ...mockSnippetsByComponent('main.js', 'project', range(29, 39))
}
});
@@ -151,7 +153,7 @@ it('should render file-level issue correctly', () => {
it('should expand block', async () => {
(getSources as jest.Mock).mockResolvedValueOnce(
- Object.values(mockSnippetsByComponent('a', range(6, 59)).sources)
+ Object.values(mockSnippetsByComponent('a', 'project', range(6, 59)).sources)
);
const issue = mockIssue(true, {
textRange: { startLine: 74, endLine: 74, startOffset: 5, endOffset: 10 }
@@ -167,7 +169,7 @@ it('should expand block', async () => {
textRange: { startLine: 107, endLine: 107, startOffset: 0, endOffset: 0 }
})
],
- ...mockSnippetsByComponent('a', [...range(69, 83), ...range(102, 112)])
+ ...mockSnippetsByComponent('a', 'project', [...range(69, 83), ...range(102, 112)])
};
const wrapper = shallowRender({ issue, snippetGroup });
@@ -175,7 +177,7 @@ it('should expand block', async () => {
wrapper.instance().expandBlock(0, 'up');
await waitAndUpdate(wrapper);
- expect(getSources).toHaveBeenCalledWith({ from: 9, key: 'a', to: 68 });
+ expect(getSources).toHaveBeenCalledWith({ from: 9, key: 'project:a', to: 68 });
expect(wrapper.state('snippets')).toHaveLength(2);
expect(wrapper.state('snippets')[0]).toEqual({ index: 0, start: 19, end: 83 });
expect(Object.keys(wrapper.state('additionalLines'))).toHaveLength(53);
@@ -183,7 +185,7 @@ it('should expand block', async () => {
it('should expand full component', async () => {
(getSources as jest.Mock).mockResolvedValueOnce(
- Object.values(mockSnippetsByComponent('a', times(14)).sources)
+ Object.values(mockSnippetsByComponent('a', 'project', times(14)).sources)
);
const snippetGroup: SnippetGroup = {
locations: [
@@ -196,7 +198,7 @@ it('should expand full component', async () => {
textRange: { startLine: 12, endLine: 12, startOffset: 0, endOffset: 0 }
})
],
- ...mockSnippetsByComponent('a', [1, 2, 3, 4, 5, 10, 11, 12, 13, 14])
+ ...mockSnippetsByComponent('a', 'project', [1, 2, 3, 4, 5, 10, 11, 12, 13, 14])
};
const wrapper = shallowRender({ snippetGroup });
@@ -204,7 +206,7 @@ it('should expand full component', async () => {
wrapper.instance().expandComponent();
await waitAndUpdate(wrapper);
- expect(getSources).toHaveBeenCalledWith({ key: 'a' });
+ expect(getSources).toHaveBeenCalledWith({ key: 'project:a' });
expect(wrapper.state('snippets')).toHaveLength(1);
expect(wrapper.state('snippets')[0]).toEqual({ index: -1, start: 0, end: 13 });
});
@@ -212,12 +214,13 @@ it('should expand full component', async () => {
it('should get the right branch when expanding', async () => {
(getSources as jest.Mock).mockResolvedValueOnce(
Object.values(
- mockSnippetsByComponent('a', [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]).sources
+ mockSnippetsByComponent('a', 'project', [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17])
+ .sources
)
);
const snippetGroup: SnippetGroup = {
locations: [mockFlowLocation()],
- ...mockSnippetsByComponent('a', [1, 2, 3, 4, 5, 6, 7])
+ ...mockSnippetsByComponent('a', 'project', [1, 2, 3, 4, 5, 6, 7])
};
const wrapper = shallowRender({
@@ -228,7 +231,7 @@ it('should get the right branch when expanding', async () => {
wrapper.instance().expandBlock(0, 'down');
await waitAndUpdate(wrapper);
- expect(getSources).toHaveBeenCalledWith({ branch: 'asdf', from: 8, key: 'a', to: 67 });
+ expect(getSources).toHaveBeenCalledWith({ branch: 'asdf', from: 8, key: 'project:a', to: 67 });
});
it('should handle correctly open/close issue', () => {
@@ -254,15 +257,15 @@ it('should correctly handle lines actions', () => {
const snippetGroup: SnippetGroup = {
locations: [
mockFlowLocation({
- component: 'a',
+ component: 'my-project:foo/bar.ts',
textRange: { startLine: 34, endLine: 34, startOffset: 0, endOffset: 0 }
}),
mockFlowLocation({
- component: 'a',
+ component: 'my-project:foo/bar.ts',
textRange: { startLine: 54, endLine: 54, startOffset: 0, endOffset: 0 }
})
],
- ...mockSnippetsByComponent('a', [32, 33, 34, 35, 36, 52, 53, 54, 55, 56])
+ ...mockSnippetsByComponent('foo/bar.ts', 'my-project', [32, 33, 34, 35, 36, 52, 53, 54, 55, 56])
};
const loadDuplications = jest.fn();
const renderDuplicationPopup = jest.fn();
@@ -278,14 +281,14 @@ it('should correctly handle lines actions', () => {
.find('SnippetViewer')
.first()
.prop<Function>('loadDuplications')(line);
- expect(loadDuplications).toHaveBeenCalledWith('a', line);
+ expect(loadDuplications).toHaveBeenCalledWith('my-project:foo/bar.ts', line);
wrapper
.find('SnippetViewer')
.first()
.prop<Function>('renderDuplicationPopup')(1, 13);
expect(renderDuplicationPopup).toHaveBeenCalledWith(
- mockSourceViewerFile({ key: 'a', path: 'a' }),
+ mockSourceViewerFile('foo/bar.ts', 'my-project'),
1,
13
);
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 bc2e2802079..050f69d8df6 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
@@ -22,17 +22,16 @@ import * as React from 'react';
import { getDuplications } from '../../../../api/components';
import { getIssueFlowSnippets } from '../../../../api/issues';
import {
- mockFlowLocation,
- mockIssue,
mockSnippetsByComponent,
mockSourceLine,
mockSourceViewerFile
-} from '../../../../helpers/testMocks';
+} from '../../../../helpers/mocks/sources';
+import { mockFlowLocation, mockIssue } from '../../../../helpers/testMocks';
import { waitAndUpdate } from '../../../../helpers/testUtils';
import CrossComponentSourceViewerWrapper from '../CrossComponentSourceViewerWrapper';
jest.mock('../../../../api/issues', () => {
- const { mockSnippetsByComponent } = jest.requireActual('../../../../helpers/testMocks');
+ const { mockSnippetsByComponent } = jest.requireActual('../../../../helpers/mocks/sources');
return {
getIssueFlowSnippets: jest.fn().mockResolvedValue({ 'main.js': mockSnippetsByComponent() })
};
diff --git a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/SnippetViewer-test.tsx b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/SnippetViewer-test.tsx
index 76fb05d7c18..579ca3c257b 100644
--- a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/SnippetViewer-test.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/SnippetViewer-test.tsx
@@ -20,8 +20,9 @@
import { mount, shallow } from 'enzyme';
import { range } from 'lodash';
import * as React from 'react';
+import { mockSourceLine, mockSourceViewerFile } from '../../../../helpers/mocks/sources';
import { scrollHorizontally } from '../../../../helpers/scrolling';
-import { mockIssue, mockSourceLine, mockSourceViewerFile } from '../../../../helpers/testMocks';
+import { mockIssue } from '../../../../helpers/testMocks';
import SnippetViewer from '../SnippetViewer';
jest.mock('../../../../helpers/scrolling', () => ({
@@ -82,7 +83,7 @@ it('should render correctly when at the top of the file', () => {
});
it('should render correctly when at the bottom of the file', () => {
- const component = mockSourceViewerFile({ measures: { lines: '14' } });
+ const component = mockSourceViewerFile('foo/bar.ts', 'my-project', { measures: { lines: '14' } });
const snippet = range(10, 14).map(line => mockSourceLine({ line }));
const wrapper = shallowRender({
component,
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 c98ca92f56f..c19827b9ef7 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
@@ -18,15 +18,19 @@ exports[`should render correctly 1`] = `
onExpand={[Function]}
sourceViewerFile={
Object {
- "key": "foo",
+ "canMarkAsFavorite": true,
+ "fav": false,
+ "key": "project:foo/bar.ts",
+ "longName": "foo/bar.ts",
"measures": Object {
"coverage": "85.2",
"duplicationDensity": "1.0",
"issues": "12",
"lines": "56",
},
+ "name": "foo/bar.ts",
"path": "foo/bar.ts",
- "project": "my-project",
+ "project": "project",
"projectName": "MyProject",
"q": "FIL",
"uuid": "foo-bar",
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 1c7210b0168..7027b2e58a7 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
@@ -29,15 +29,19 @@ exports[`should render correctly 2`] = `
Object {
"branchLike": undefined,
"file": Object {
- "key": "main.js",
+ "canMarkAsFavorite": true,
+ "fav": false,
+ "key": "project:main.js",
+ "longName": "main.js",
"measures": Object {
"coverage": "85.2",
"duplicationDensity": "1.0",
"issues": "12",
"lines": "56",
},
+ "name": "main.js",
"path": "main.js",
- "project": "my-project",
+ "project": "project",
"projectName": "MyProject",
"q": "FIL",
"uuid": "foo-bar",
@@ -47,7 +51,7 @@ exports[`should render correctly 2`] = `
>
<ComponentSourceSnippetGroupViewer
duplicationsByLine={Object {}}
- isLastOccurenceOfPrimaryComponent={true}
+ isLastOccurenceOfPrimaryComponent={false}
issue={
Object {
"actions": Array [],
@@ -173,15 +177,19 @@ exports[`should render correctly 2`] = `
snippetGroup={
Object {
"component": Object {
- "key": "main.js",
+ "canMarkAsFavorite": true,
+ "fav": false,
+ "key": "project:main.js",
+ "longName": "main.js",
"measures": Object {
"coverage": "85.2",
"duplicationDensity": "1.0",
"issues": "12",
"lines": "56",
},
+ "name": "main.js",
"path": "main.js",
- "project": "my-project",
+ "project": "project",
"projectName": "MyProject",
"q": "FIL",
"uuid": "foo-bar",
@@ -356,15 +364,19 @@ exports[`should render correctly: no component found 1`] = `
Object {
"branchLike": undefined,
"file": Object {
- "key": "main.js",
+ "canMarkAsFavorite": true,
+ "fav": false,
+ "key": "project:main.js",
+ "longName": "main.js",
"measures": Object {
"coverage": "85.2",
"duplicationDensity": "1.0",
"issues": "12",
"lines": "56",
},
+ "name": "main.js",
"path": "main.js",
- "project": "my-project",
+ "project": "project",
"projectName": "MyProject",
"q": "FIL",
"uuid": "foo-bar",
@@ -500,15 +512,19 @@ exports[`should render correctly: no component found 1`] = `
snippetGroup={
Object {
"component": Object {
- "key": "main.js",
+ "canMarkAsFavorite": true,
+ "fav": false,
+ "key": "project:main.js",
+ "longName": "main.js",
"measures": Object {
"coverage": "85.2",
"duplicationDensity": "1.0",
"issues": "12",
"lines": "56",
},
+ "name": "main.js",
"path": "main.js",
- "project": "my-project",
+ "project": "project",
"projectName": "MyProject",
"q": "FIL",
"uuid": "foo-bar",
diff --git a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/utils-test.ts b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/utils-test.ts
index 0d1e378c2c4..dadf1c31958 100644
--- a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/utils-test.ts
+++ b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/utils-test.ts
@@ -17,11 +17,8 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import {
- mockFlowLocation,
- mockIssue,
- mockSnippetsByComponent
-} from '../../../../helpers/testMocks';
+import { mockSnippetsByComponent } from '../../../../helpers/mocks/sources';
+import { mockFlowLocation, mockIssue } from '../../../../helpers/testMocks';
import { createSnippets, expandSnippet, groupLocationsByComponent } from '../utils';
describe('groupLocationsByComponent', () => {
@@ -43,7 +40,20 @@ describe('groupLocationsByComponent', () => {
textRange: { startLine: 24, startOffset: 1, endLine: 24, endOffset: 2 }
})
],
- { 'main.js': mockSnippetsByComponent('main.js', [14, 15, 16, 17, 18, 22, 23, 24, 25, 26]) }
+ {
+ 'main.js': mockSnippetsByComponent('main.js', 'project', [
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26
+ ])
+ }
);
expect(results).toHaveLength(1);
@@ -67,15 +77,15 @@ describe('groupLocationsByComponent', () => {
})
],
{
- 'A.js': mockSnippetsByComponent('A.js', [13, 14, 15, 16, 17, 18]),
- 'B.js': mockSnippetsByComponent('B.js', [14, 15, 16, 17, 18])
+ 'A.js': mockSnippetsByComponent('A.js', 'project', [13, 14, 15, 16, 17, 18]),
+ 'B.js': mockSnippetsByComponent('B.js', 'project', [14, 15, 16, 17, 18])
}
);
expect(results).toHaveLength(3);
- expect(results[0].component.key).toBe('A.js');
- expect(results[1].component.key).toBe('B.js');
- expect(results[2].component.key).toBe('A.js');
+ expect(results[0].component.key).toBe('project:A.js');
+ expect(results[1].component.key).toBe('project:B.js');
+ expect(results[2].component.key).toBe('project:A.js');
expect(results[0].locations).toHaveLength(1);
expect(results[1].locations).toHaveLength(1);
expect(results[2].locations).toHaveLength(1);
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 53ea02c8505..d984d488ec4 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
@@ -24,7 +24,8 @@ import { getSources } from '../../../../api/components';
import { mockBranch } from '../../../../helpers/mocks/branch-like';
import { mockComponent } from '../../../../helpers/mocks/component';
import { mockHotspot, mockHotspotComponent } from '../../../../helpers/mocks/security-hotspots';
-import { mockFlowLocation, mockSourceLine } from '../../../../helpers/testMocks';
+import { mockSourceLine } from '../../../../helpers/mocks/sources';
+import { mockFlowLocation } from '../../../../helpers/testMocks';
import { waitAndUpdate } from '../../../../helpers/testUtils';
import { ComponentQualifier } from '../../../../types/component';
import HotspotSnippetContainer from '../HotspotSnippetContainer';
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 1e58285c233..98aec410c5c 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
@@ -22,8 +22,8 @@ import React, { RefObject } from 'react';
import { mockMainBranch } from '../../../../helpers/mocks/branch-like';
import { mockComponent } from '../../../../helpers/mocks/component';
import { mockHotspot } from '../../../../helpers/mocks/security-hotspots';
+import { mockSourceLine, mockSourceViewerFile } from '../../../../helpers/mocks/sources';
import { scrollToElement } from '../../../../helpers/scrolling';
-import { mockSourceLine, mockSourceViewerFile } from '../../../../helpers/testMocks';
import SnippetViewer from '../../../issues/crossComponentSourceViewer/SnippetViewer';
import HotspotSnippetContainerRenderer, {
animateExpansion,
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotSnippetContainerRenderer-test.tsx.snap b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotSnippetContainerRenderer-test.tsx.snap
index be77b3e2008..a4ade78ebae 100644
--- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotSnippetContainerRenderer-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotSnippetContainerRenderer-test.tsx.snap
@@ -402,15 +402,19 @@ exports[`should render correctly: with sourcelines 1`] = `
<SnippetViewer
component={
Object {
- "key": "foo",
+ "canMarkAsFavorite": true,
+ "fav": false,
+ "key": "project:foo/bar.ts",
+ "longName": "foo/bar.ts",
"measures": Object {
"coverage": "85.2",
"duplicationDensity": "1.0",
"issues": "12",
"lines": "56",
},
+ "name": "foo/bar.ts",
"path": "foo/bar.ts",
- "project": "my-project",
+ "project": "project",
"projectName": "MyProject",
"q": "FIL",
"uuid": "foo-bar",
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/__tests__/SourceViewerBase-test.tsx b/server/sonar-web/src/main/js/components/SourceViewer/__tests__/SourceViewerBase-test.tsx
index 75a56e77b15..66cb69fdb7e 100644
--- a/server/sonar-web/src/main/js/components/SourceViewer/__tests__/SourceViewerBase-test.tsx
+++ b/server/sonar-web/src/main/js/components/SourceViewer/__tests__/SourceViewerBase-test.tsx
@@ -21,7 +21,8 @@ import { shallow } from 'enzyme';
import * as React from 'react';
import { getComponentData, getComponentForSourceViewer, getSources } from '../../../api/components';
import { mockMainBranch } from '../../../helpers/mocks/branch-like';
-import { mockIssue, mockSourceLine, mockSourceViewerFile } from '../../../helpers/testMocks';
+import { mockSourceLine, mockSourceViewerFile } from '../../../helpers/mocks/sources';
+import { mockIssue } from '../../../helpers/testMocks';
import { waitAndUpdate } from '../../../helpers/testUtils';
import defaultLoadIssues from '../helpers/loadIssues';
import SourceViewerBase from '../SourceViewerBase';
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/__tests__/SourceViewerCode-test.tsx b/server/sonar-web/src/main/js/components/SourceViewer/__tests__/SourceViewerCode-test.tsx
index df85f4381f5..746d7cd495b 100644
--- a/server/sonar-web/src/main/js/components/SourceViewer/__tests__/SourceViewerCode-test.tsx
+++ b/server/sonar-web/src/main/js/components/SourceViewer/__tests__/SourceViewerCode-test.tsx
@@ -20,7 +20,8 @@
import { shallow } from 'enzyme';
import * as React from 'react';
import { mockBranch } from '../../../helpers/mocks/branch-like';
-import { mockIssue, mockSourceLine } from '../../../helpers/testMocks';
+import { mockSourceLine } from '../../../helpers/mocks/sources';
+import { mockIssue } from '../../../helpers/testMocks';
import { MetricKey } from '../../../types/metrics';
import Line from '../components/Line';
import SourceViewerCode from '../SourceViewerCode';
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/__tests__/SourceViewerHeader-test.tsx b/server/sonar-web/src/main/js/components/SourceViewer/__tests__/SourceViewerHeader-test.tsx
index 2713a1e0ea4..fea1c7eda90 100644
--- a/server/sonar-web/src/main/js/components/SourceViewer/__tests__/SourceViewerHeader-test.tsx
+++ b/server/sonar-web/src/main/js/components/SourceViewer/__tests__/SourceViewerHeader-test.tsx
@@ -20,7 +20,7 @@
import { shallow } from 'enzyme';
import * as React from 'react';
import { mockMainBranch } from '../../../helpers/mocks/branch-like';
-import { mockSourceViewerFile } from '../../../helpers/testMocks';
+import { mockSourceViewerFile } from '../../../helpers/mocks/sources';
import { ComponentQualifier } from '../../../types/component';
import { MetricKey } from '../../../types/metrics';
import { Measure } from '../../../types/types';
@@ -34,7 +34,7 @@ it('should render correctly for a unit test', () => {
expect(
shallowRender({
showMeasures: true,
- sourceViewerFile: mockSourceViewerFile({
+ sourceViewerFile: mockSourceViewerFile('foo/bar.ts', 'my-project', {
q: ComponentQualifier.TestFile,
measures: { tests: '12' }
})
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/__tests__/SourceViewerHeaderSlim-test.tsx b/server/sonar-web/src/main/js/components/SourceViewer/__tests__/SourceViewerHeaderSlim-test.tsx
index 82232a309b3..86113ca61a2 100644
--- a/server/sonar-web/src/main/js/components/SourceViewer/__tests__/SourceViewerHeaderSlim-test.tsx
+++ b/server/sonar-web/src/main/js/components/SourceViewer/__tests__/SourceViewerHeaderSlim-test.tsx
@@ -20,7 +20,7 @@
import { shallow } from 'enzyme';
import * as React from 'react';
import { mockMainBranch } from '../../../helpers/mocks/branch-like';
-import { mockSourceViewerFile } from '../../../helpers/testMocks';
+import { mockSourceViewerFile } from '../../../helpers/mocks/sources';
import { ComponentQualifier } from '../../../types/component';
import SourceViewerHeaderSlim, { Props } from '../SourceViewerHeaderSlim';
@@ -29,14 +29,21 @@ it('should render correctly', () => {
expect(shallowRender({ linkToProject: false })).toMatchSnapshot('no link to project');
expect(shallowRender({ displayProjectName: false })).toMatchSnapshot('no project name');
expect(
- shallowRender({ sourceViewerFile: mockSourceViewerFile({ q: ComponentQualifier.Project }) })
+ shallowRender({
+ sourceViewerFile: mockSourceViewerFile('foo/bar.ts', 'my-project', {
+ q: ComponentQualifier.Project
+ })
+ })
).toMatchSnapshot('project root');
});
it('should render correctly for subproject', () => {
expect(
shallowRender({
- sourceViewerFile: mockSourceViewerFile({ subProject: 'foo', subProjectName: 'Foo' })
+ sourceViewerFile: mockSourceViewerFile('foo/bar.ts', 'my-project', {
+ subProject: 'foo',
+ subProjectName: 'Foo'
+ })
})
).toMatchSnapshot();
});
@@ -47,7 +54,7 @@ function shallowRender(props: Partial<Props> = {}) {
branchLike={mockMainBranch()}
expandable={true}
onExpand={jest.fn()}
- sourceViewerFile={mockSourceViewerFile()}
+ sourceViewerFile={mockSourceViewerFile('foo/bar.ts', 'my-project')}
{...props}
/>
);
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/__tests__/__snapshots__/SourceViewerBase-test.tsx.snap b/server/sonar-web/src/main/js/components/SourceViewer/__tests__/__snapshots__/SourceViewerBase-test.tsx.snap
index 62e0125c3de..ef8cdb4d1ba 100644
--- a/server/sonar-web/src/main/js/components/SourceViewer/__tests__/__snapshots__/SourceViewerBase-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/SourceViewer/__tests__/__snapshots__/SourceViewerBase-test.tsx.snap
@@ -11,16 +11,20 @@ exports[`should render correctly 1`] = `
"name": "master",
},
"file": Object {
- "key": "foo",
+ "canMarkAsFavorite": true,
+ "fav": false,
+ "key": "project:foo/bar.ts",
"leakPeriodDate": "2018-06-20T17:12:19+0200",
+ "longName": "foo/bar.ts",
"measures": Object {
"coverage": "85.2",
"duplicationDensity": "1.0",
"issues": "12",
"lines": "56",
},
+ "name": "foo/bar.ts",
"path": "foo/bar.ts",
- "project": "my-project",
+ "project": "project",
"projectName": "MyProject",
"q": "FIL",
"uuid": "foo-bar",
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/__tests__/__snapshots__/SourceViewerHeader-test.tsx.snap b/server/sonar-web/src/main/js/components/SourceViewer/__tests__/__snapshots__/SourceViewerHeader-test.tsx.snap
index eaf213f5dcf..58ecb2f6e0b 100644
--- a/server/sonar-web/src/main/js/components/SourceViewer/__tests__/__snapshots__/SourceViewerHeader-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/SourceViewer/__tests__/__snapshots__/SourceViewerHeader-test.tsx.snap
@@ -15,7 +15,7 @@ exports[`should render correctly for a regular file 1`] = `
>
<a
className="link-with-icon"
- href="/dashboard?id=my-project"
+ href="/dashboard?id=project"
>
<QualifierIcon
qualifier="TRK"
@@ -79,9 +79,9 @@ exports[`should render correctly for a regular file 1`] = `
Object {
"pathname": "/code",
"query": Object {
- "id": "my-project",
+ "id": "project",
"line": undefined,
- "selected": "foo",
+ "selected": "project:foo/bar.ts",
},
}
}
@@ -101,7 +101,7 @@ exports[`should render correctly for a regular file 1`] = `
<li>
<a
className="js-raw-source"
- href="/api/sources/raw?key=foo"
+ href="/api/sources/raw?key=project%3Afoo%2Fbar.ts"
rel="noopener noreferrer"
target="_blank"
>
@@ -220,7 +220,7 @@ exports[`should render correctly for a unit test 1`] = `
"query": Object {
"id": "my-project",
"line": undefined,
- "selected": "foo",
+ "selected": "my-project:foo/bar.ts",
},
}
}
@@ -240,7 +240,7 @@ exports[`should render correctly for a unit test 1`] = `
<li>
<a
className="js-raw-source"
- href="/api/sources/raw?key=foo"
+ href="/api/sources/raw?key=my-project%3Afoo%2Fbar.ts"
rel="noopener noreferrer"
target="_blank"
>
@@ -275,7 +275,7 @@ exports[`should render correctly if issue details are passed 1`] = `
>
<a
className="link-with-icon"
- href="/dashboard?id=my-project"
+ href="/dashboard?id=project"
>
<QualifierIcon
qualifier="TRK"
@@ -381,7 +381,7 @@ exports[`should render correctly if issue details are passed 1`] = `
"pathname": "/project/issues",
"query": Object {
"files": "foo/bar.ts",
- "id": "my-project",
+ "id": "project",
"resolved": "false",
"types": "BUG",
},
@@ -412,7 +412,7 @@ exports[`should render correctly if issue details are passed 1`] = `
"pathname": "/project/issues",
"query": Object {
"files": "foo/bar.ts",
- "id": "my-project",
+ "id": "project",
"resolved": "false",
"types": "VULNERABILITY",
},
@@ -443,7 +443,7 @@ exports[`should render correctly if issue details are passed 1`] = `
"pathname": "/project/issues",
"query": Object {
"files": "foo/bar.ts",
- "id": "my-project",
+ "id": "project",
"resolved": "false",
"types": "CODE_SMELL",
},
@@ -474,7 +474,7 @@ exports[`should render correctly if issue details are passed 1`] = `
"pathname": "/project/issues",
"query": Object {
"files": "foo/bar.ts",
- "id": "my-project",
+ "id": "project",
"resolved": "false",
"types": "SECURITY_HOTSPOT",
},
@@ -512,9 +512,9 @@ exports[`should render correctly if issue details are passed 1`] = `
Object {
"pathname": "/code",
"query": Object {
- "id": "my-project",
+ "id": "project",
"line": undefined,
- "selected": "foo",
+ "selected": "project:foo/bar.ts",
},
}
}
@@ -534,7 +534,7 @@ exports[`should render correctly if issue details are passed 1`] = `
<li>
<a
className="js-raw-source"
- href="/api/sources/raw?key=foo"
+ href="/api/sources/raw?key=project%3Afoo%2Fbar.ts"
rel="noopener noreferrer"
target="_blank"
>
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/Line-test.tsx b/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/Line-test.tsx
index cb3b97075cb..82add319eba 100644
--- a/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/Line-test.tsx
+++ b/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/Line-test.tsx
@@ -19,7 +19,8 @@
*/
import { shallow } from 'enzyme';
import * as React from 'react';
-import { mockIssue, mockSourceLine } from '../../../../helpers/testMocks';
+import { mockSourceLine } from '../../../../helpers/mocks/sources';
+import { mockIssue } from '../../../../helpers/testMocks';
import Line from '../Line';
it('should render correctly for last, new, and highlighted lines', () => {
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/LineCode-test.tsx b/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/LineCode-test.tsx
index 8d15db4f708..5339dfc9828 100644
--- a/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/LineCode-test.tsx
+++ b/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/LineCode-test.tsx
@@ -19,7 +19,7 @@
*/
import { shallow } from 'enzyme';
import * as React from 'react';
-import { mockSourceLine } from '../../../../helpers/testMocks';
+import { mockSourceLine } from '../../../../helpers/mocks/sources';
import LineCode from '../LineCode';
it('render code', () => {
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/LineIssueList-test.tsx b/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/LineIssueList-test.tsx
index 8d803bbb172..712221baa93 100644
--- a/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/LineIssueList-test.tsx
+++ b/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/LineIssueList-test.tsx
@@ -20,7 +20,8 @@
import { shallow } from 'enzyme';
import * as React from 'react';
import { mockBranch } from '../../../../helpers/mocks/branch-like';
-import { mockIssue, mockSourceLine } from '../../../../helpers/testMocks';
+import { mockSourceLine } from '../../../../helpers/mocks/sources';
+import { mockIssue } from '../../../../helpers/testMocks';
import LineIssuesList, { LineIssuesListProps } from '../LineIssuesList';
it('should render issues', () => {
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/issueLocations-test.ts b/server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/issueLocations-test.ts
index 5c1f9884ec5..265c7d58e14 100644
--- a/server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/issueLocations-test.ts
+++ b/server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/issueLocations-test.ts
@@ -17,7 +17,8 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { mockFlowLocation, mockSourceLine } from '../../../../helpers/testMocks';
+import { mockSourceLine } from '../../../../helpers/mocks/sources';
+import { mockFlowLocation } from '../../../../helpers/testMocks';
import { getLinearLocations, getSecondaryIssueLocationsForLine } from '../issueLocations';
describe('getSecondaryIssueLocationsForLine', () => {
diff --git a/server/sonar-web/src/main/js/helpers/mocks/sources.ts b/server/sonar-web/src/main/js/helpers/mocks/sources.ts
new file mode 100644
index 00000000000..72523c2add2
--- /dev/null
+++ b/server/sonar-web/src/main/js/helpers/mocks/sources.ts
@@ -0,0 +1,78 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * 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 { SnippetsByComponent, SourceLine, SourceViewerFile } from '../../types/types';
+
+export function mockSourceViewerFile(
+ name = 'foo/bar.ts',
+ project = 'project',
+ override?: Partial<SourceViewerFile>
+): SourceViewerFile {
+ return {
+ measures: {
+ coverage: '85.2',
+ duplicationDensity: '1.0',
+ issues: '12',
+ lines: '56'
+ },
+ project,
+ projectName: 'MyProject',
+ q: ComponentQualifier.File,
+ uuid: 'foo-bar',
+ key: `${project}:${name}`,
+ path: name,
+ name,
+ longName: name,
+ fav: false,
+ canMarkAsFavorite: true,
+ ...override
+ };
+}
+
+export function mockSourceLine(overrides: Partial<SourceLine> = {}): SourceLine {
+ return {
+ line: 16,
+ code: '<span class="k">import</span> java.util.<span class="sym-9 sym">ArrayList</span>;',
+ coverageStatus: 'covered',
+ coveredConditions: 2,
+ scmRevision: '80f564becc0c0a1c9abaa006eca83a4fd278c3f0',
+ scmAuthor: 'simon.brandhof@sonarsource.com',
+ scmDate: '2018-12-11T10:48:39+0100',
+ duplicated: false,
+ isNew: true,
+ ...overrides
+ };
+}
+
+export function mockSnippetsByComponent(
+ file = 'main.js',
+ project = 'project',
+ lines: number[] = [16]
+): SnippetsByComponent {
+ const sources = lines.reduce((lines: { [key: number]: SourceLine }, line) => {
+ lines[line] = mockSourceLine({ line });
+ return lines;
+ }, {});
+ return {
+ component: mockSourceViewerFile(file, project),
+ sources
+ };
+}
diff --git a/server/sonar-web/src/main/js/helpers/testMocks.ts b/server/sonar-web/src/main/js/helpers/testMocks.ts
index dd4270c4c43..80bab8e94d6 100644
--- a/server/sonar-web/src/main/js/helpers/testMocks.ts
+++ b/server/sonar-web/src/main/js/helpers/testMocks.ts
@@ -23,9 +23,8 @@ 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 { IssueType, RawIssue } from '../types/issues';
import { Language } from '../types/languages';
import { DumpStatus, DumpTask } from '../types/project-dump';
import { TaskStatuses } from '../types/tasks';
@@ -51,9 +50,6 @@ import {
RuleDescriptionSections,
RuleDetails,
RuleParameter,
- SnippetsByComponent,
- SourceLine,
- SourceViewerFile,
SysInfoBase,
SysInfoCluster,
SysInfoStandalone
@@ -301,38 +297,6 @@ export function mockCondition(overrides: Partial<Condition> = {}): Condition {
};
}
-export function mockSnippetsByComponent(
- component = 'main.js',
- lines: number[] = [16]
-): SnippetsByComponent {
- const sources = lines.reduce((lines: { [key: number]: SourceLine }, line) => {
- lines[line] = mockSourceLine({ line });
- return lines;
- }, {});
- return {
- component: mockSourceViewerFile({
- key: component,
- path: component
- }),
- sources
- };
-}
-
-export function mockSourceLine(overrides: Partial<SourceLine> = {}): SourceLine {
- return {
- line: 16,
- code: '<span class="k">import</span> java.util.<span class="sym-9 sym">ArrayList</span>;',
- coverageStatus: 'covered',
- coveredConditions: 2,
- scmRevision: '80f564becc0c0a1c9abaa006eca83a4fd278c3f0',
- scmAuthor: 'simon.brandhof@sonarsource.com',
- scmDate: '2018-12-11T10:48:39+0100',
- duplicated: false,
- isNew: true,
- ...overrides
- };
-}
-
export function mockCurrentUser(overrides: Partial<CurrentUser> = {}): CurrentUser {
return {
isLoggedIn: false,
@@ -372,6 +336,7 @@ export function mockEvent(overrides = {}) {
export function mockRawIssue(withLocations = false, overrides: Partial<RawIssue> = {}): RawIssue {
const rawIssue: RawIssue = {
+ actions: [],
component: 'main.js',
key: 'AVsae-CQS-9G3txfbFN2',
line: 25,
@@ -380,13 +345,21 @@ export function mockRawIssue(withLocations = false, overrides: Partial<RawIssue>
severity: 'MAJOR',
status: 'OPEN',
textRange: { startLine: 25, endLine: 26, startOffset: 0, endOffset: 15 },
+ type: IssueType.CodeSmell,
...overrides
};
if (withLocations) {
const loc = mockFlowLocation;
- rawIssue.flows = [{ locations: [loc(), loc()] }];
+ rawIssue.flows = [
+ {
+ locations: [
+ loc({ component: overrides.component }),
+ loc({ component: overrides.component })
+ ]
+ }
+ ];
}
return {
@@ -608,7 +581,7 @@ export function mockRuleDetails(overrides: Partial<RuleDetails> = {}): RuleDetai
descriptionSections: [
{
key: RuleDescriptionSections.ROOT_CAUSE,
- content: '<b>Why<b/> Because'
+ content: '<b>Why</b> Because'
}
],
htmlDesc: '',
@@ -648,24 +621,6 @@ export function mockRuleDetailsParameter(overrides: Partial<RuleParameter> = {})
};
}
-export function mockSourceViewerFile(overrides: Partial<SourceViewerFile> = {}): SourceViewerFile {
- return {
- key: 'foo',
- measures: {
- coverage: '85.2',
- duplicationDensity: '1.0',
- issues: '12',
- lines: '56'
- },
- path: 'foo/bar.ts',
- project: 'my-project',
- projectName: 'MyProject',
- q: ComponentQualifier.File,
- uuid: 'foo-bar',
- ...overrides
- };
-}
-
export function mockStandaloneSysInfo(overrides: Partial<any> = {}): SysInfoStandalone {
const baseInfo = mockBaseSysInfo(overrides);
return {
diff --git a/server/sonar-web/src/main/js/types/issues.ts b/server/sonar-web/src/main/js/types/issues.ts
index 18f6e322f19..360e4e15312 100644
--- a/server/sonar-web/src/main/js/types/issues.ts
+++ b/server/sonar-web/src/main/js/types/issues.ts
@@ -42,6 +42,7 @@ interface Comment {
}
export interface RawIssue {
+ actions: string[];
assignee?: string;
author?: string;
comments?: Array<Comment>;
@@ -54,10 +55,12 @@ export interface RawIssue {
line?: number;
project: string;
rule: string;
+ message?: string;
severity: string;
status: string;
subProject?: string;
textRange?: TextRange;
+ type: IssueType;
}
export interface IssueResponse {
diff --git a/server/sonar-web/src/main/js/types/types.ts b/server/sonar-web/src/main/js/types/types.ts
index 6d857540864..5691a852d8f 100644
--- a/server/sonar-web/src/main/js/types/types.ts
+++ b/server/sonar-web/src/main/js/types/types.ts
@@ -674,7 +674,10 @@ export interface SourceViewerFile {
lines?: string;
tests?: string;
};
+ canMarkAsFavorite?: boolean;
path: string;
+ name?: string;
+ longName?: string;
project: string;
projectName: string;
q: ComponentQualifier;