return null;
}
- const isTaintAnalysis =
- this.props.issue.type === 'VULNERABILITY' && this.props.issue.flows.length > 0;
-
const locationComponents = [
this.props.issue.component,
...locations.map(location => location.component)
if (isCrossFile) {
return (
<CrossFileLocationsNavigator
- isTaintAnalysis={isTaintAnalysis}
issue={this.props.issue}
locations={locations}
onLocationSelect={this.props.onLocationSelect}
{locations.map((location, index) => (
<ConciseIssueLocationsNavigatorLocation
index={index}
- isTaintAnalysis={isTaintAnalysis}
key={index}
message={location.msg}
onClick={this.props.onLocationSelect}
scroll={this.props.scroll}
selected={index === this.props.selectedLocationIndex}
- totalCount={locations.length}
/>
))}
</div>
interface Props {
index: number;
- isTaintAnalysis: boolean;
message: string | undefined;
onClick: (index: number) => void;
scroll: (element: Element) => void;
selected: boolean;
- totalCount: number;
}
export default class ConciseIssueLocationsNavigatorLocation extends React.PureComponent<Props> {
this.props.onClick(this.props.index);
};
- prefixMessage(index: number, message = '', totalCount: number) {
- switch (index) {
- case 0:
- return 'source: ' + message;
- case totalCount - 1:
- return 'sink: ' + message;
- default:
- return message;
- }
- }
-
render() {
- const { index, isTaintAnalysis, message, selected, totalCount } = this.props;
+ const { index, message, selected } = this.props;
return (
<div className="little-spacer-top" ref={node => (this.node = node)}>
href="#"
onClick={this.handleClick}>
<LocationIndex selected={selected}>{index + 1}</LocationIndex>
- <LocationMessage selected={selected}>
- {isTaintAnalysis ? this.prefixMessage(index, message, totalCount) : message}
- </LocationMessage>
+ <LocationMessage selected={selected}>{message}</LocationMessage>
</a>
</div>
);
import ConciseIssueLocationsNavigatorLocation from './ConciseIssueLocationsNavigatorLocation';
interface Props {
- isTaintAnalysis: boolean;
issue: Pick<T.Issue, 'key' | 'type'>;
locations: T.FlowLocation[];
onLocationSelect: (index: number) => void;
locations: T.FlowLocation[];
}
+const MAX_PATH_LENGTH = 15;
+
export default class CrossFileLocationsNavigator extends React.PureComponent<Props, State> {
state: State = { collapsed: true };
return (
<ConciseIssueLocationsNavigatorLocation
index={index}
- isTaintAnalysis={this.props.isTaintAnalysis}
key={index}
message={message}
onClick={this.props.onLocationSelect}
scroll={this.props.scroll}
selected={index === this.props.selectedLocationIndex}
- totalCount={this.props.locations.length}
/>
);
};
<div className="concise-issue-locations-navigator-file" key={groupIndex}>
<div className="concise-issue-location-file">
<i className="concise-issue-location-file-circle little-spacer-right" />
- {collapsePath(group.componentName || '', 15)}
+ {collapsePath(group.componentName || '', MAX_PATH_LENGTH)}
</div>
{group.locations.length > 0 && (
<div className="concise-issue-location-file-locations">
import ConciseIssueLocationsNavigatorLocation from '../ConciseIssueLocationsNavigatorLocation';
it('should render correctly', () => {
- expect(shallowRender()).toMatchSnapshot();
-});
-it('should render vulnerabilities correctly', () => {
- expect(shallowRender({ index: 0, isTaintAnalysis: true, totalCount: 4 })).toMatchSnapshot();
- expect(shallowRender({ index: 1, isTaintAnalysis: true, totalCount: 4 })).toMatchSnapshot();
- expect(shallowRender({ index: 3, isTaintAnalysis: true, totalCount: 4 })).toMatchSnapshot();
+ expect(shallowRender()).toMatchSnapshot('index 1');
+ expect(shallowRender({ index: 1 })).toMatchSnapshot('index 2');
});
-const shallowRender = (props: Partial<ConciseIssueLocationsNavigatorLocation['props']> = {}) => {
+function shallowRender(props: Partial<ConciseIssueLocationsNavigatorLocation['props']> = {}) {
return shallow(
<ConciseIssueLocationsNavigatorLocation
index={0}
- isTaintAnalysis={false}
message=""
onClick={jest.fn()}
scroll={jest.fn()}
selected={true}
- totalCount={5}
{...props}
/>
);
-};
+}
import { shallow } from 'enzyme';
import * as React from 'react';
import { click } from 'sonar-ui-common/helpers/testUtils';
+import { mockFlowLocation } from '../../../../helpers/testMocks';
import CrossFileLocationsNavigator from '../CrossFileLocationsNavigator';
const location1: T.FlowLocation = {
textRange: { startLine: 15, endLine: 16, startOffset: 4, endOffset: 6 }
};
+it('should render with no locations', () => {
+ expect(shallowRender({ locations: [] })).toMatchSnapshot();
+});
+
+it('should render locations with no component name', () => {
+ expect(shallowRender({ locations: [mockFlowLocation({ componentName: '' })] })).toMatchSnapshot();
+});
+
it('should render', () => {
- const wrapper = shallow(
- <CrossFileLocationsNavigator
- isTaintAnalysis={false}
- issue={{ key: 'abcd', type: 'BUG' }}
- locations={[location1, location2, location3]}
- onLocationSelect={jest.fn()}
- scroll={jest.fn()}
- selectedLocationIndex={undefined}
- />
- );
+ const wrapper = shallowRender();
+
expect(wrapper).toMatchSnapshot();
expect(wrapper.find('ConciseIssueLocationsNavigatorLocation').length).toBe(2);
});
it('should render all locations', () => {
- const wrapper = shallow(
- <CrossFileLocationsNavigator
- isTaintAnalysis={false}
- issue={{ key: 'abcd', type: 'BUG' }}
- locations={[location1, location2]}
- onLocationSelect={jest.fn()}
- scroll={jest.fn()}
- selectedLocationIndex={undefined}
- />
- );
+ const wrapper = shallowRender({ locations: [location1, location2] });
+
expect(wrapper.find('ConciseIssueLocationsNavigatorLocation').length).toBe(2);
});
it('should expand all locations', () => {
- const wrapper = shallow(
- <CrossFileLocationsNavigator
- isTaintAnalysis={false}
- issue={{ key: 'abcd', type: 'BUG' }}
- locations={[location1, location2, location3]}
- onLocationSelect={jest.fn()}
- scroll={jest.fn()}
- selectedLocationIndex={undefined}
- />
- );
+ const wrapper = shallowRender();
expect(wrapper.find('ConciseIssueLocationsNavigatorLocation').length).toBe(2);
wrapper.setProps({ selectedLocationIndex: 1 });
});
it('should collapse locations when issue changes', () => {
- const wrapper = shallow(
+ const wrapper = shallowRender();
+
+ wrapper.setProps({ selectedLocationIndex: 1 });
+ expect(wrapper.find('ConciseIssueLocationsNavigatorLocation').length).toBe(3);
+
+ wrapper.setProps({ issue: { key: 'def', type: 'BUG' }, selectedLocationIndex: undefined });
+ expect(wrapper.find('ConciseIssueLocationsNavigatorLocation').length).toBe(2);
+});
+
+function shallowRender(props: Partial<CrossFileLocationsNavigator['props']> = {}) {
+ return shallow<CrossFileLocationsNavigator>(
<CrossFileLocationsNavigator
- isTaintAnalysis={false}
issue={{ key: 'abcd', type: 'BUG' }}
locations={[location1, location2, location3]}
onLocationSelect={jest.fn()}
scroll={jest.fn()}
selectedLocationIndex={undefined}
+ {...props}
/>
);
- wrapper.setProps({ selectedLocationIndex: 1 });
- expect(wrapper.find('ConciseIssueLocationsNavigatorLocation').length).toBe(3);
-
- wrapper.setProps({ issue: { key: 'def' }, selectedLocationIndex: undefined });
- expect(wrapper.find('ConciseIssueLocationsNavigatorLocation').length).toBe(2);
-});
+}
exports[`should render flow locations in different file 1`] = `
<CrossFileLocationsNavigator
- isTaintAnalysis={false}
issue={
Object {
"actions": Array [],
>
<ConciseIssueLocationsNavigatorLocation
index={0}
- isTaintAnalysis={false}
key="0"
message="Do not use foo"
onClick={[MockFunction]}
scroll={[MockFunction]}
selected={false}
- totalCount={2}
/>
<ConciseIssueLocationsNavigatorLocation
index={1}
- isTaintAnalysis={false}
key="1"
message="Do not use foo"
onClick={[MockFunction]}
scroll={[MockFunction]}
selected={false}
- totalCount={2}
/>
</div>
`;
>
<ConciseIssueLocationsNavigatorLocation
index={0}
- isTaintAnalysis={false}
key="0"
message="Do not use foo"
onClick={[MockFunction]}
scroll={[MockFunction]}
selected={false}
- totalCount={2}
/>
<ConciseIssueLocationsNavigatorLocation
index={1}
- isTaintAnalysis={false}
key="1"
message="Do not use foo"
onClick={[MockFunction]}
scroll={[MockFunction]}
selected={false}
- totalCount={2}
/>
</div>
`;
>
<ConciseIssueLocationsNavigatorLocation
index={0}
- isTaintAnalysis={false}
key="0"
message="Do not use foo"
onClick={[MockFunction]}
scroll={[MockFunction]}
selected={false}
- totalCount={2}
/>
<ConciseIssueLocationsNavigatorLocation
index={1}
- isTaintAnalysis={false}
key="1"
message="Do not use foo"
onClick={[MockFunction]}
scroll={[MockFunction]}
selected={false}
- totalCount={2}
/>
</div>
`;
exports[`should render taint analysis issues correctly 1`] = `
<CrossFileLocationsNavigator
- isTaintAnalysis={true}
issue={
Object {
"actions": Array [],
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`should render correctly 1`] = `
+exports[`should render correctly: index 1 1`] = `
<div
className="little-spacer-top"
>
</div>
`;
-exports[`should render vulnerabilities correctly 1`] = `
-<div
- className="little-spacer-top"
->
- <a
- className="concise-issue-locations-navigator-location"
- href="#"
- onClick={[Function]}
- >
- <LocationIndex
- selected={true}
- >
- 1
- </LocationIndex>
- <LocationMessage
- selected={true}
- >
- source:
- </LocationMessage>
- </a>
-</div>
-`;
-
-exports[`should render vulnerabilities correctly 2`] = `
+exports[`should render correctly: index 2 1`] = `
<div
className="little-spacer-top"
>
</a>
</div>
`;
-
-exports[`should render vulnerabilities correctly 3`] = `
-<div
- className="little-spacer-top"
->
- <a
- className="concise-issue-locations-navigator-location"
- href="#"
- onClick={[Function]}
- >
- <LocationIndex
- selected={true}
- >
- 4
- </LocationIndex>
- <LocationMessage
- selected={true}
- >
- sink:
- </LocationMessage>
- </a>
-</div>
-`;
>
<ConciseIssueLocationsNavigatorLocation
index={0}
- isTaintAnalysis={false}
key="0"
message="Do not use foo"
onClick={[MockFunction]}
scroll={[MockFunction]}
selected={false}
- totalCount={3}
/>
</div>
</div>
>
<ConciseIssueLocationsNavigatorLocation
index={2}
- isTaintAnalysis={false}
key="2"
message="Do not use bar"
onClick={[MockFunction]}
scroll={[MockFunction]}
selected={false}
- totalCount={3}
/>
</div>
</div>
</div>
`;
+
+exports[`should render locations with no component name 1`] = `
+<div
+ className="concise-issue-locations-navigator spacer-top"
+>
+ <div
+ className="concise-issue-locations-navigator-file"
+ key="0"
+ >
+ <div
+ className="concise-issue-location-file"
+ >
+ <i
+ className="concise-issue-location-file-circle little-spacer-right"
+ />
+ </div>
+ <div
+ className="concise-issue-location-file-locations"
+ >
+ <ConciseIssueLocationsNavigatorLocation
+ index={0}
+ key="0"
+ onClick={[MockFunction]}
+ scroll={[MockFunction]}
+ selected={false}
+ />
+ </div>
+ </div>
+</div>
+`;
+
+exports[`should render with no locations 1`] = `
+<div
+ className="concise-issue-locations-navigator spacer-top"
+/>
+`;