* 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, range, times } from 'lodash';
-import { mockHotspot, mockRawHotspot, mockStandards } from '../../helpers/mocks/security-hotspots';
+import { cloneDeep, times } from 'lodash';
+import {
+ mockHotspot,
+ mockHotspotComment,
+ mockRawHotspot,
+ mockStandards,
+} from '../../helpers/mocks/security-hotspots';
import { mockSourceLine } from '../../helpers/mocks/sources';
import { getStandards } from '../../helpers/security-standard';
import { mockPaging, mockRuleDetails, mockUser } from '../../helpers/testMocks';
import {
Hotspot,
HotspotAssignRequest,
+ HotspotComment,
HotspotResolution,
HotspotStatus,
} from '../../types/security-hotspots';
import { getRuleDetails } from '../rules';
import {
assignSecurityHotspot,
+ commentSecurityHotspot,
+ deleteSecurityHotspotComment,
+ editSecurityHotspotComment,
getSecurityHotspotDetails,
getSecurityHotspotList,
getSecurityHotspots,
import { searchUsers } from '../users';
const NUMBER_OF_LINES = 20;
-const MAX_END_RANGE = 10;
export default class SecurityHotspotServiceMock {
hotspots: Hotspot[] = [];
nextAssignee: string | undefined;
+ canChangeStatus: boolean = true;
+ hotspotsComments: HotspotComment[] = [];
constructor() {
this.reset();
})
)
);
+ jest.mocked(commentSecurityHotspot).mockImplementation(this.handleCommentSecurityHotspot);
+ jest
+ .mocked(deleteSecurityHotspotComment)
+ .mockImplementation(this.handleDeleteSecurityHotspotComment);
+ jest
+ .mocked(editSecurityHotspotComment)
+ .mockImplementation(this.handleEditSecurityHotspotComment);
jest.mocked(getStandards).mockImplementation(this.handleGetStandards);
}
- handleGetSources = (data: { key: string; from?: number; to?: number } & BranchParameters) => {
- return this.reply(
- range(data.from || 1, data.to || MAX_END_RANGE).map((line) => mockSourceLine({ line }))
- );
+ handleCommentSecurityHotspot = () => {
+ this.hotspotsComments = [
+ mockHotspotComment({
+ htmlText: 'This is a comment from john doe',
+ markdown: 'This is a comment from john doe',
+ updatable: true,
+ }),
+ ];
+ return Promise.resolve();
+ };
+
+ handleDeleteSecurityHotspotComment = () => {
+ this.hotspotsComments = [];
+ return Promise.resolve();
+ };
+
+ handleEditSecurityHotspotComment = () => {
+ const response = mockHotspotComment({
+ htmlText: 'This is a comment from john doe test',
+ markdown: 'This is a comment from john doe test',
+ updatable: true,
+ });
+ this.hotspotsComments = [response];
+ return Promise.resolve(response);
};
handleGetStandards = () => {
handleSearchUsers = () => {
return this.reply({
users: [
- mockUser({ name: 'User John' }),
- mockUser({ name: 'User Doe' }),
- mockUser({ name: 'User Foo' }),
+ mockUser({ name: 'User John', login: 'user.john' }),
+ mockUser({ name: 'User Doe', login: 'user.doe' }),
+ mockUser({ name: 'User Foo', login: 'user.foo' }),
],
paging: mockPaging(),
});
this.nextAssignee = undefined;
}
- hotspot.canChangeStatus = true;
+ hotspot.canChangeStatus = this.canChangeStatus;
+ hotspot.comment = this.hotspotsComments;
return this.reply(hotspot);
};
return Promise.resolve();
};
+ setHotspotChangeStatusPermission = (value: boolean) => (this.canChangeStatus = value);
+
reply<T>(response: T): Promise<T> {
return Promise.resolve(cloneDeep(response));
}
message: "'2' is a magic number.",
}),
];
+ this.canChangeStatus = true;
};
}
import React from 'react';
import { Route } from 'react-router-dom';
import selectEvent from 'react-select-event';
-import { byRole, byTestId, byText } from 'testing-library-selector';
+import { byDisplayValue, byRole, byTestId, byText } from 'testing-library-selector';
import SecurityHotspotServiceMock from '../../../api/mocks/SecurityHotspotServiceMock';
import { getSecurityHotspots, setSecurityHotspotStatus } from '../../../api/security-hotspots';
import { searchUsers } from '../../../api/users';
hotspotTitle: (name: string | RegExp) => byRole('heading', { name }),
hotspotStatus: byRole('heading', { name: 'status: hotspots.status_option.FIXED' }),
hotpostListTitle: byRole('heading', { name: 'hotspots.list_title.TO_REVIEW.2' }),
+ hotspotCommentBox: byRole('textbox', { name: 'hotspots.comment.field' }),
+ commentSubmitButton: byRole('button', { name: 'hotspots.comment.submit' }),
+ commentEditButton: byRole('button', { name: 'issue.comment.edit' }),
+ commentDeleteButton: byRole('button', { name: 'issue.comment.delete' }),
+ textboxWithText: (value: string) => byDisplayValue(value),
activeAssignee: byTestId('assignee-name'),
successGlobalMessage: byRole('status'),
currentUserSelectionItem: byText('foo'),
expect(ui.hotspotStatus.get()).toBeInTheDocument();
});
+it('should not be able to change the status if does not have edit permissions', async () => {
+ handler.setHotspotChangeStatusPermission(false);
+ renderSecurityHotspotsApp();
+ expect(await ui.selectStatus.find()).toBeDisabled();
+});
+
it('should remember the comment when toggling change status panel for the same security hotspot', async () => {
const user = userEvent.setup();
renderSecurityHotspotsApp();
expect(await screen.findByText(comment)).toBeInTheDocument();
});
+it('should be able to add, edit and remove own comments', async () => {
+ const uiComment = {
+ saveButton: byRole('button', { name: 'save' }),
+ deleteButton: byRole('button', { name: 'delete' }),
+ };
+ const user = userEvent.setup();
+ const comment = 'This is a comment from john doe';
+ renderSecurityHotspotsApp();
+
+ const commentSection = await ui.hotspotCommentBox.find();
+ const submitButton = ui.commentSubmitButton.get();
+
+ // Add a new comment
+ await user.click(commentSection);
+ await user.keyboard(comment);
+ await user.click(submitButton);
+
+ expect(await screen.findByText(comment)).toBeInTheDocument();
+
+ // Edit the comment
+ await user.click(ui.commentEditButton.get());
+ await user.click(ui.textboxWithText(comment).get());
+ await user.keyboard(' test');
+ await user.click(uiComment.saveButton.get());
+
+ expect(await byText(`${comment} test`).find()).toBeInTheDocument();
+
+ // Delete the comment
+ await user.click(ui.commentDeleteButton.get());
+ await user.click(uiComment.deleteButton.get());
+
+ expect(screen.queryByText(`${comment} test`)).not.toBeInTheDocument();
+});
+
function renderSecurityHotspotsApp(navigateTo?: string) {
renderAppWithComponentContext(
'security_hotspots',