2021-09-30 14:11:31 -04:00
|
|
|
import { escape } from 'lodash';
|
|
|
|
import UsersSelect from '~/users_select/index';
|
2021-04-21 02:09:28 -04:00
|
|
|
import {
|
|
|
|
createInputsModelExpectation,
|
|
|
|
createUnassignedExpectation,
|
|
|
|
createAssignedExpectation,
|
|
|
|
createTestContext,
|
|
|
|
findDropdownItemsModel,
|
|
|
|
findDropdownItem,
|
|
|
|
findAssigneesInputsModel,
|
|
|
|
getUsersFixtureAt,
|
|
|
|
setAssignees,
|
|
|
|
toggleDropdown,
|
|
|
|
waitForDropdownItems,
|
|
|
|
} from './test_helper';
|
2021-04-14 11:09:04 -04:00
|
|
|
|
|
|
|
describe('~/users_select/index', () => {
|
2021-04-21 02:09:28 -04:00
|
|
|
const context = createTestContext({
|
|
|
|
fixturePath: 'merge_requests/merge_request_with_single_assignee_feature.html',
|
|
|
|
});
|
2021-04-14 11:09:04 -04:00
|
|
|
|
|
|
|
beforeEach(() => {
|
2021-04-21 02:09:28 -04:00
|
|
|
context.setup();
|
2021-04-14 11:09:04 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
afterEach(() => {
|
2021-04-21 02:09:28 -04:00
|
|
|
context.teardown();
|
2021-04-14 11:09:04 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
describe('when opened', () => {
|
|
|
|
beforeEach(async () => {
|
2021-04-21 02:09:28 -04:00
|
|
|
context.createSubject();
|
2021-04-14 11:09:04 -04:00
|
|
|
|
|
|
|
toggleDropdown();
|
|
|
|
await waitForDropdownItems();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('shows users', () => {
|
|
|
|
expect(findDropdownItemsModel()).toEqual(createUnassignedExpectation());
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('when users are selected', () => {
|
2021-04-21 02:09:28 -04:00
|
|
|
const selectedUsers = [getUsersFixtureAt(2), getUsersFixtureAt(4)];
|
|
|
|
const lastSelected = selectedUsers[selectedUsers.length - 1];
|
|
|
|
const expectation = createAssignedExpectation({
|
|
|
|
header: 'Assignee',
|
|
|
|
assigned: [lastSelected],
|
|
|
|
});
|
2021-04-14 11:09:04 -04:00
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
selectedUsers.forEach((user) => {
|
|
|
|
findDropdownItem(user).click();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('shows assignee', () => {
|
|
|
|
expect(findDropdownItemsModel()).toEqual(expectation);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('updates field', () => {
|
2021-04-21 02:09:28 -04:00
|
|
|
expect(findAssigneesInputsModel()).toEqual(createInputsModelExpectation([lastSelected]));
|
2021-04-14 11:09:04 -04:00
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('with preselected user and opened', () => {
|
2021-04-21 02:09:28 -04:00
|
|
|
const expectation = createAssignedExpectation({
|
|
|
|
header: 'Assignee',
|
|
|
|
assigned: [getUsersFixtureAt(0)],
|
|
|
|
});
|
2021-04-14 11:09:04 -04:00
|
|
|
|
|
|
|
beforeEach(async () => {
|
2021-04-21 02:09:28 -04:00
|
|
|
setAssignees(getUsersFixtureAt(0));
|
2021-04-14 11:09:04 -04:00
|
|
|
|
2021-04-21 02:09:28 -04:00
|
|
|
context.createSubject();
|
2021-04-14 11:09:04 -04:00
|
|
|
|
|
|
|
toggleDropdown();
|
|
|
|
await waitForDropdownItems();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('shows users', () => {
|
|
|
|
expect(findDropdownItemsModel()).toEqual(expectation);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Regression test for https://gitlab.com/gitlab-org/gitlab/-/issues/325991
|
|
|
|
describe('when closed and reopened', () => {
|
|
|
|
beforeEach(() => {
|
|
|
|
toggleDropdown();
|
|
|
|
toggleDropdown();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('shows users', () => {
|
|
|
|
expect(findDropdownItemsModel()).toEqual(expectation);
|
|
|
|
});
|
|
|
|
});
|
2021-09-30 14:11:31 -04:00
|
|
|
|
|
|
|
describe('renderApprovalRules', () => {
|
|
|
|
const ruleNames = ['simple-name', '"\'<>&', '"><script>alert(1)<script>'];
|
|
|
|
|
|
|
|
it.each(ruleNames)('escapes rule name correctly for %s', (name) => {
|
|
|
|
const escapedName = escape(name);
|
|
|
|
|
|
|
|
expect(
|
|
|
|
UsersSelect.prototype.renderApprovalRules('reviewer', [{ name }]),
|
|
|
|
).toMatchInterpolatedText(
|
|
|
|
`<div class="gl-display-flex gl-font-sm"> <span class="gl-text-truncate" title="${escapedName}">${escapedName}</span> </div>`,
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
2021-04-14 11:09:04 -04:00
|
|
|
});
|
2022-03-16 08:07:24 -04:00
|
|
|
|
|
|
|
describe('XSS', () => {
|
|
|
|
const escaped = '><script>alert(1)</script>';
|
|
|
|
const issuableType = 'merge_request';
|
|
|
|
const user = {
|
|
|
|
availability: 'not_set',
|
|
|
|
can_merge: true,
|
|
|
|
name: 'name',
|
|
|
|
};
|
|
|
|
const selected = true;
|
|
|
|
const username = 'username';
|
|
|
|
const img = '<img user-avatar />';
|
|
|
|
const elsClassName = 'elsclass';
|
|
|
|
|
|
|
|
it.each`
|
|
|
|
prop | val | element
|
|
|
|
${'username'} | ${'><script>alert(1)</script>'} | ${'.dropdown-menu-user-username'}
|
|
|
|
${'name'} | ${'><script>alert(1)</script>'} | ${'.dropdown-menu-user-full-name'}
|
|
|
|
`('properly escapes the $prop $val', ({ prop, val, element }) => {
|
|
|
|
const u = prop === 'username' ? val : username;
|
|
|
|
const n = prop === 'name' ? val : user.name;
|
|
|
|
const row = UsersSelect.prototype.renderRow(
|
|
|
|
issuableType,
|
|
|
|
{ ...user, name: n },
|
|
|
|
selected,
|
|
|
|
u,
|
|
|
|
img,
|
|
|
|
elsClassName,
|
|
|
|
);
|
|
|
|
const fragment = document.createRange().createContextualFragment(row);
|
|
|
|
const output = fragment.querySelector(element).innerHTML.trim();
|
|
|
|
|
|
|
|
expect(output).toBe(escaped);
|
|
|
|
});
|
|
|
|
});
|
2021-04-14 11:09:04 -04:00
|
|
|
});
|