Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-12-20 21:09:05 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-12-20 21:09:05 +0300
commit883d5720994852248f18cb3053dc9f053f28d6f9 (patch)
tree409c976ddc659f34afaae3b2e97f1d0325f6455c /spec/frontend
parent5e97da08cba997aefba6f6d13850f95536a80477 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend')
-rw-r--r--spec/frontend/abuse_reports/components/abuse_category_selector_spec.js125
-rw-r--r--spec/frontend/behaviors/markdown/render_gfm_spec.js9
-rw-r--r--spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline_spec.js12
-rw-r--r--spec/frontend/gfm_auto_complete/mock_data.js24
-rw-r--r--spec/frontend/gfm_auto_complete_spec.js27
-rw-r--r--spec/frontend/jobs/components/table/jobs_table_spec.js6
-rw-r--r--spec/frontend/members/components/table/role_dropdown_spec.js58
-rw-r--r--spec/frontend/members/guest_overage_confirm_action_spec.js7
-rw-r--r--spec/frontend/pipelines/pipelines_table_spec.js8
-rw-r--r--spec/frontend/repository/commits_service_spec.js8
-rw-r--r--spec/frontend/repository/mock_data.js2
-rw-r--r--spec/frontend/repository/utils/ref_switcher_utils_spec.js7
-rw-r--r--spec/frontend/users/profile/components/report_abuse_button_spec.js72
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/__snapshots__/mr_widget_auto_merge_enabled_spec.js.snap163
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled_spec.js8
-rw-r--r--spec/frontend/vue_shared/components/ci_badge_link_spec.js4
16 files changed, 334 insertions, 206 deletions
diff --git a/spec/frontend/abuse_reports/components/abuse_category_selector_spec.js b/spec/frontend/abuse_reports/components/abuse_category_selector_spec.js
new file mode 100644
index 00000000000..4f66348f9cd
--- /dev/null
+++ b/spec/frontend/abuse_reports/components/abuse_category_selector_spec.js
@@ -0,0 +1,125 @@
+import { GlDrawer, GlForm, GlFormGroup, GlFormRadioGroup } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+
+import AbuseCategorySelector from '~/abuse_reports/components/abuse_category_selector.vue';
+
+jest.mock('~/lib/utils/common_utils', () => ({
+ contentTop: jest.fn(),
+}));
+
+jest.mock('~/lib/utils/csrf', () => ({ token: 'mock-csrf-token' }));
+
+describe('AbuseCategorySelector', () => {
+ let wrapper;
+
+ const ACTION_PATH = '/abuse_reports/add_category';
+ const USER_ID = '1';
+ const REPORTED_FROM_URL = 'http://example.com';
+
+ const createComponent = (props) => {
+ wrapper = shallowMountExtended(AbuseCategorySelector, {
+ propsData: {
+ ...props,
+ },
+ provide: {
+ formSubmitPath: ACTION_PATH,
+ userId: USER_ID,
+ reportedFromUrl: REPORTED_FROM_URL,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent({ showDrawer: true });
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ const findDrawer = () => wrapper.findComponent(GlDrawer);
+ const findTitle = () => wrapper.findByTestId('category-drawer-title');
+
+ const findForm = () => wrapper.findComponent(GlForm);
+ const findFormGroup = () => wrapper.findComponent(GlFormGroup);
+ const findRadioGroup = () => wrapper.findComponent(GlFormRadioGroup);
+
+ const findCSRFToken = () => findForm().find('input[name="authenticity_token"]');
+ const findUserId = () => wrapper.findByTestId('input-user-id');
+ const findReferer = () => wrapper.findByTestId('input-referer');
+
+ const findSubmitFormButton = () => wrapper.findByTestId('submit-form-button');
+
+ describe('Drawer', () => {
+ it('is open when prop showDrawer = true', () => {
+ expect(findDrawer().exists()).toBe(true);
+ expect(findDrawer().props('open')).toBe(true);
+ });
+
+ it('renders title', () => {
+ expect(findTitle().text()).toBe(wrapper.vm.$options.i18n.title);
+ });
+
+ it('emits close-drawer event', async () => {
+ await findDrawer().vm.$emit('close');
+
+ expect(wrapper.emitted('close-drawer')).toHaveLength(1);
+ });
+
+ describe('when props showDrawer = false', () => {
+ beforeEach(() => {
+ createComponent({ showDrawer: false });
+ });
+
+ it('hides the drawer', () => {
+ expect(findDrawer().props('open')).toBe(false);
+ });
+ });
+ });
+
+ describe('Select category form', () => {
+ it('renders POST form with path', () => {
+ expect(findForm().attributes()).toMatchObject({
+ method: 'post',
+ action: ACTION_PATH,
+ });
+ });
+
+ it('renders csrf token', () => {
+ expect(findCSRFToken().attributes('value')).toBe('mock-csrf-token');
+ });
+
+ it('renders label', () => {
+ expect(findFormGroup().exists()).toBe(true);
+ expect(findFormGroup().attributes('label')).toBe(wrapper.vm.$options.i18n.label);
+ });
+
+ it('renders radio group', () => {
+ expect(findRadioGroup().exists()).toBe(true);
+ expect(findRadioGroup().props('options')).toEqual(wrapper.vm.$options.categoryOptions);
+ expect(findRadioGroup().attributes('name')).toBe('abuse_report[category]');
+ expect(findRadioGroup().attributes('required')).not.toBeUndefined();
+ });
+
+ it('renders userId as a hidden fields', () => {
+ expect(findUserId().attributes()).toMatchObject({
+ type: 'hidden',
+ name: 'user_id',
+ value: USER_ID,
+ });
+ });
+
+ it('renders referer as a hidden fields', () => {
+ expect(findReferer().attributes()).toMatchObject({
+ type: 'hidden',
+ name: 'ref_url',
+ value: REPORTED_FROM_URL,
+ });
+ });
+
+ it('renders submit button', () => {
+ expect(findSubmitFormButton().exists()).toBe(true);
+ expect(findSubmitFormButton().text()).toBe(wrapper.vm.$options.i18n.next);
+ });
+ });
+});
diff --git a/spec/frontend/behaviors/markdown/render_gfm_spec.js b/spec/frontend/behaviors/markdown/render_gfm_spec.js
new file mode 100644
index 00000000000..0bbb92282e5
--- /dev/null
+++ b/spec/frontend/behaviors/markdown/render_gfm_spec.js
@@ -0,0 +1,9 @@
+import { renderGFM } from '~/behaviors/markdown/render_gfm';
+
+describe('renderGFM', () => {
+ it('handles a missing element', () => {
+ expect(() => {
+ renderGFM();
+ }).not.toThrow();
+ });
+});
diff --git a/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline_spec.js b/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline_spec.js
index 17bf465baf3..0821c59c8a0 100644
--- a/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline_spec.js
+++ b/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline_spec.js
@@ -1,5 +1,5 @@
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import CiBadge from '~/vue_shared/components/ci_badge_link.vue';
+import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue';
import PipelineScheduleLastPipeline from '~/ci/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline.vue';
import { mockPipelineScheduleNodes } from '../../../mock_data';
@@ -18,7 +18,7 @@ describe('Pipeline schedule last pipeline', () => {
});
};
- const findCIBadge = () => wrapper.findComponent(CiBadge);
+ const findCIBadgeLink = () => wrapper.findComponent(CiBadgeLink);
const findStatusText = () => wrapper.findByTestId('pipeline-schedule-status-text');
afterEach(() => {
@@ -28,8 +28,10 @@ describe('Pipeline schedule last pipeline', () => {
it('displays pipeline status', () => {
createComponent();
- expect(findCIBadge().exists()).toBe(true);
- expect(findCIBadge().props('status')).toBe(defaultProps.schedule.lastPipeline.detailedStatus);
+ expect(findCIBadgeLink().exists()).toBe(true);
+ expect(findCIBadgeLink().props('status')).toBe(
+ defaultProps.schedule.lastPipeline.detailedStatus,
+ );
expect(findStatusText().exists()).toBe(false);
});
@@ -37,6 +39,6 @@ describe('Pipeline schedule last pipeline', () => {
createComponent({ schedule: mockPipelineScheduleNodes[0] });
expect(findStatusText().text()).toBe('None');
- expect(findCIBadge().exists()).toBe(false);
+ expect(findCIBadgeLink().exists()).toBe(false);
});
});
diff --git a/spec/frontend/gfm_auto_complete/mock_data.js b/spec/frontend/gfm_auto_complete/mock_data.js
index 9c5a9d7ef3d..d58ccaf0f39 100644
--- a/spec/frontend/gfm_auto_complete/mock_data.js
+++ b/spec/frontend/gfm_auto_complete/mock_data.js
@@ -37,8 +37,8 @@ export const crmContactsMock = [
{
id: 1,
email: 'contact.1@email.com',
- firstName: 'Contact',
- lastName: 'One',
+ first_name: 'Contact',
+ last_name: 'One',
search: 'contact.1@email.com',
state: 'active',
set: false,
@@ -46,8 +46,8 @@ export const crmContactsMock = [
{
id: 2,
email: 'contact.2@email.com',
- firstName: 'Contact',
- lastName: 'Two',
+ first_name: 'Contact',
+ last_name: 'Two',
search: 'contact.2@email.com',
state: 'active',
set: false,
@@ -55,8 +55,8 @@ export const crmContactsMock = [
{
id: 3,
email: 'contact.3@email.com',
- firstName: 'Contact',
- lastName: 'Three',
+ first_name: 'Contact',
+ last_name: 'Three',
search: 'contact.3@email.com',
state: 'inactive',
set: false,
@@ -64,8 +64,8 @@ export const crmContactsMock = [
{
id: 4,
email: 'contact.4@email.com',
- firstName: 'Contact',
- lastName: 'Four',
+ first_name: 'Contact',
+ last_name: 'Four',
search: 'contact.4@email.com',
state: 'inactive',
set: true,
@@ -73,8 +73,8 @@ export const crmContactsMock = [
{
id: 5,
email: 'contact.5@email.com',
- firstName: 'Contact',
- lastName: 'Five',
+ first_name: 'Contact',
+ last_name: 'Five',
search: 'contact.5@email.com',
state: 'active',
set: true,
@@ -82,8 +82,8 @@ export const crmContactsMock = [
{
id: 5,
email: 'contact.6@email.com',
- firstName: 'Contact',
- lastName: 'Six',
+ first_name: 'Contact',
+ last_name: 'Six',
search: 'contact.6@email.com',
state: 'active',
set: undefined, // On purpose
diff --git a/spec/frontend/gfm_auto_complete_spec.js b/spec/frontend/gfm_auto_complete_spec.js
index eeef92d4183..cc2dc084e47 100644
--- a/spec/frontend/gfm_auto_complete_spec.js
+++ b/spec/frontend/gfm_auto_complete_spec.js
@@ -4,6 +4,7 @@ import $ from 'jquery';
import labelsFixture from 'test_fixtures/autocomplete_sources/labels.json';
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
import GfmAutoComplete, {
+ escape,
membersBeforeSave,
highlighter,
CONTACT_STATE_ACTIVE,
@@ -21,6 +22,20 @@ import {
crmContactsMock,
} from 'ee_else_ce_jest/gfm_auto_complete/mock_data';
+describe('escape', () => {
+ it.each`
+ xssPayload | escapedPayload
+ ${'<script>alert(1)</script>'} | ${'&lt;script&gt;alert(1)&lt;/script&gt;'}
+ ${'%3Cscript%3E alert(1) %3C%2Fscript%3E'} | ${'&lt;script&gt; alert(1) &lt;/script&gt;'}
+ ${'%253Cscript%253E alert(1) %253C%252Fscript%253E'} | ${'&lt;script&gt; alert(1) &lt;/script&gt;'}
+ `(
+ 'escapes the input string correctly accounting for multiple encoding',
+ ({ xssPayload, escapedPayload }) => {
+ expect(escape(xssPayload)).toBe(escapedPayload);
+ },
+ );
+});
+
describe('GfmAutoComplete', () => {
const fetchDataMock = { fetchData: jest.fn() };
let gfmAutoCompleteCallbacks = GfmAutoComplete.prototype.getDefaultCallbacks.call(fetchDataMock);
@@ -590,7 +605,7 @@ describe('GfmAutoComplete', () => {
id: 5,
title: '${search}<script>oh no $', // eslint-disable-line no-template-curly-in-string
}),
- ).toBe('<li><small>5</small> &dollar;{search}&lt;script&gt;oh no &dollar;</li>');
+ ).toBe('<li><small>5</small> &amp;dollar;{search}&lt;script&gt;oh no &amp;dollar;</li>');
});
});
@@ -636,7 +651,7 @@ describe('GfmAutoComplete', () => {
availabilityStatus: '',
}),
).toBe(
- '<li>IMG my-group <small>&dollar;{search}&lt;script&gt;oh no &dollar;</small> <i class="icon"/></li>',
+ '<li>IMG my-group <small>&amp;dollar;{search}&lt;script&gt;oh no &amp;dollar;</small> <i class="icon"/></li>',
);
});
@@ -813,7 +828,7 @@ describe('GfmAutoComplete', () => {
const title = '${search}<script>oh no $'; // eslint-disable-line no-template-curly-in-string
expect(GfmAutoComplete.Labels.templateFunction(color, title)).toBe(
- '<li><span class="dropdown-label-box" style="background: #123456"></span> &dollar;{search}&lt;script&gt;oh no &dollar;</li>',
+ '<li><span class="dropdown-label-box" style="background: #123456"></span> &amp;dollar;{search}&lt;script&gt;oh no &amp;dollar;</li>',
);
});
});
@@ -868,7 +883,7 @@ describe('GfmAutoComplete', () => {
const title = '${search}<script>oh no $'; // eslint-disable-line no-template-curly-in-string
expect(GfmAutoComplete.Milestones.templateFunction(title, expired)).toBe(
- '<li>&dollar;{search}&lt;script&gt;oh no &dollar;</li>',
+ '<li>&amp;dollar;{search}&lt;script&gt;oh no &amp;dollar;</li>',
);
});
});
@@ -925,7 +940,9 @@ describe('GfmAutoComplete', () => {
const expectContacts = ({ input, output }) => {
triggerDropdown(input);
- expect(getDropdownItems()).toEqual(output.map((contact) => contact.email));
+ expect(getDropdownItems()).toEqual(
+ output.map((contact) => `${contact.first_name} ${contact.last_name} ${contact.email}`),
+ );
};
describe('with no contacts assigned', () => {
diff --git a/spec/frontend/jobs/components/table/jobs_table_spec.js b/spec/frontend/jobs/components/table/jobs_table_spec.js
index 803df3df37f..3c4f2d624fe 100644
--- a/spec/frontend/jobs/components/table/jobs_table_spec.js
+++ b/spec/frontend/jobs/components/table/jobs_table_spec.js
@@ -2,14 +2,14 @@ import { GlTable } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import JobsTable from '~/jobs/components/table/jobs_table.vue';
-import CiBadge from '~/vue_shared/components/ci_badge_link.vue';
+import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue';
import { mockJobsNodes } from '../../mock_data';
describe('Jobs Table', () => {
let wrapper;
const findTable = () => wrapper.findComponent(GlTable);
- const findStatusBadge = () => wrapper.findComponent(CiBadge);
+ const findCiBadgeLink = () => wrapper.findComponent(CiBadgeLink);
const findTableRows = () => wrapper.findAllByTestId('jobs-table-row');
const findJobStage = () => wrapper.findByTestId('job-stage-name');
const findJobName = () => wrapper.findByTestId('job-name');
@@ -43,7 +43,7 @@ describe('Jobs Table', () => {
});
it('displays job status', () => {
- expect(findStatusBadge().exists()).toBe(true);
+ expect(findCiBadgeLink().exists()).toBe(true);
});
it('displays the job stage and name', () => {
diff --git a/spec/frontend/members/components/table/role_dropdown_spec.js b/spec/frontend/members/components/table/role_dropdown_spec.js
index b254cce4d72..3815064b3f6 100644
--- a/spec/frontend/members/components/table/role_dropdown_spec.js
+++ b/spec/frontend/members/components/table/role_dropdown_spec.js
@@ -4,11 +4,14 @@ import { within } from '@testing-library/dom';
import { mount, createWrapper } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
import Vuex from 'vuex';
+import waitForPromises from 'helpers/wait_for_promises';
import RoleDropdown from '~/members/components/table/role_dropdown.vue';
import { MEMBER_TYPES } from '~/members/constants';
+import { guestOverageConfirmAction } from 'ee_else_ce/members/guest_overage_confirm_action';
import { member } from '../../mock_data';
Vue.use(Vuex);
+jest.mock('ee_else_ce/members/guest_overage_confirm_action');
describe('RoleDropdown', () => {
let wrapper;
@@ -63,12 +66,21 @@ describe('RoleDropdown', () => {
const findDropdownToggle = () => wrapper.find('button[aria-haspopup="true"]');
const findDropdown = () => wrapper.findComponent(GlDropdown);
+ let originalGon;
+
+ beforeEach(() => {
+ originalGon = window.gon;
+ gon.features = { showOverageOnRolePromotion: true };
+ });
+
afterEach(() => {
+ window.gon = originalGon;
wrapper.destroy();
});
describe('when dropdown is open', () => {
beforeEach(() => {
+ guestOverageConfirmAction.mockReturnValue(true);
createComponent();
return findDropdownToggle().trigger('click');
@@ -117,8 +129,12 @@ describe('RoleDropdown', () => {
await getDropdownItemByText('Developer').trigger('click');
expect(findDropdown().props('disabled')).toBe(true);
+ });
- await nextTick();
+ it('enables dropdown after `updateMemberRole` resolves', async () => {
+ await getDropdownItemByText('Developer').trigger('click');
+
+ await waitForPromises();
expect(findDropdown().props('disabled')).toBe(false);
});
@@ -148,4 +164,44 @@ describe('RoleDropdown', () => {
expect(findDropdown().props('right')).toBe(false);
});
+
+ describe('guestOverageConfirmAction', () => {
+ const mockConfirmAction = ({ confirmed }) => {
+ guestOverageConfirmAction.mockResolvedValueOnce(confirmed);
+ };
+
+ beforeEach(() => {
+ createComponent();
+
+ findDropdownToggle().trigger('click');
+ });
+
+ afterEach(() => {
+ guestOverageConfirmAction.mockReset();
+ });
+
+ describe('when guestOverageConfirmAction returns true', () => {
+ beforeEach(() => {
+ mockConfirmAction({ confirmed: true });
+
+ getDropdownItemByText('Reporter').trigger('click');
+ });
+
+ it('calls updateMemberRole', () => {
+ expect(actions.updateMemberRole).toHaveBeenCalled();
+ });
+ });
+
+ describe('when guestOverageConfirmAction returns false', () => {
+ beforeEach(() => {
+ mockConfirmAction({ confirmed: false });
+
+ getDropdownItemByText('Reporter').trigger('click');
+ });
+
+ it('does not call updateMemberRole', () => {
+ expect(actions.updateMemberRole).not.toHaveBeenCalled();
+ });
+ });
+ });
});
diff --git a/spec/frontend/members/guest_overage_confirm_action_spec.js b/spec/frontend/members/guest_overage_confirm_action_spec.js
new file mode 100644
index 00000000000..d7ab54fa13b
--- /dev/null
+++ b/spec/frontend/members/guest_overage_confirm_action_spec.js
@@ -0,0 +1,7 @@
+import { guestOverageConfirmAction } from '~/members/guest_overage_confirm_action';
+
+describe('guestOverageConfirmAction', () => {
+ it('returns true', () => {
+ expect(guestOverageConfirmAction()).toBe(true);
+ });
+});
diff --git a/spec/frontend/pipelines/pipelines_table_spec.js b/spec/frontend/pipelines/pipelines_table_spec.js
index 740037a5ac8..9359bd9b95f 100644
--- a/spec/frontend/pipelines/pipelines_table_spec.js
+++ b/spec/frontend/pipelines/pipelines_table_spec.js
@@ -17,7 +17,7 @@ import {
TRACKING_CATEGORIES,
} from '~/pipelines/constants';
-import CiBadge from '~/vue_shared/components/ci_badge_link.vue';
+import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue';
jest.mock('~/pipelines/event_hub');
@@ -50,7 +50,7 @@ describe('Pipelines Table', () => {
};
const findGlTableLite = () => wrapper.findComponent(GlTableLite);
- const findStatusBadge = () => wrapper.findComponent(CiBadge);
+ const findCiBadgeLink = () => wrapper.findComponent(CiBadgeLink);
const findPipelineInfo = () => wrapper.findComponent(PipelineUrl);
const findTriggerer = () => wrapper.findComponent(PipelineTriggerer);
const findPipelineMiniGraph = () => wrapper.findComponent(PipelineMiniGraph);
@@ -97,7 +97,7 @@ describe('Pipelines Table', () => {
describe('status cell', () => {
it('should render a status badge', () => {
- expect(findStatusBadge().exists()).toBe(true);
+ expect(findCiBadgeLink().exists()).toBe(true);
});
});
@@ -171,7 +171,7 @@ describe('Pipelines Table', () => {
});
it('tracks status badge click', () => {
- findStatusBadge().vm.$emit('ciStatusBadgeClick');
+ findCiBadgeLink().vm.$emit('ciStatusBadgeClick');
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_ci_status_badge', {
label: TRACKING_CATEGORIES.table,
diff --git a/spec/frontend/repository/commits_service_spec.js b/spec/frontend/repository/commits_service_spec.js
index de7c56f239a..b7343bf3a7e 100644
--- a/spec/frontend/repository/commits_service_spec.js
+++ b/spec/frontend/repository/commits_service_spec.js
@@ -4,6 +4,7 @@ import { loadCommits, isRequested, resetRequestedCommits } from '~/repository/co
import httpStatus from '~/lib/utils/http_status';
import { createAlert } from '~/flash';
import { I18N_COMMIT_DATA_FETCH_ERROR } from '~/repository/constants';
+import { refWithSpecialCharMock, encodedRefWithSpecialCharMock } from './mock_data';
jest.mock('~/flash');
@@ -39,10 +40,11 @@ describe('commits service', () => {
expect(axios.get).toHaveBeenCalledWith(testUrl, { params: { format: 'json', offset } });
});
- it('encodes the path correctly', async () => {
- await requestCommits(1, 'some-project', 'with $peci@l ch@rs/');
+ it('encodes the path and ref', async () => {
+ const encodedUrl = `/some-project/-/refs/${encodedRefWithSpecialCharMock}/logs_tree/with%20%24peci%40l%20ch%40rs%2F`;
+
+ await requestCommits(1, 'some-project', 'with $peci@l ch@rs/', refWithSpecialCharMock);
- const encodedUrl = '/some-project/-/refs/main/logs_tree/with%20%24peci%40l%20ch%40rs%2F';
expect(axios.get).toHaveBeenCalledWith(encodedUrl, expect.anything());
});
diff --git a/spec/frontend/repository/mock_data.js b/spec/frontend/repository/mock_data.js
index cda47a5b0a5..c1b5f89c37f 100644
--- a/spec/frontend/repository/mock_data.js
+++ b/spec/frontend/repository/mock_data.js
@@ -87,6 +87,8 @@ export const applicationInfoMock = { gitpodEnabled: true };
export const propsMock = { path: 'some_file.js', projectPath: 'some/path' };
export const refMock = 'default-ref';
+export const refWithSpecialCharMock = 'selected-#-ref';
+export const encodedRefWithSpecialCharMock = encodeURIComponent(refWithSpecialCharMock);
export const blobControlsDataMock = {
id: '1234',
diff --git a/spec/frontend/repository/utils/ref_switcher_utils_spec.js b/spec/frontend/repository/utils/ref_switcher_utils_spec.js
index 3335059554f..4d0250fffbf 100644
--- a/spec/frontend/repository/utils/ref_switcher_utils_spec.js
+++ b/spec/frontend/repository/utils/ref_switcher_utils_spec.js
@@ -1,5 +1,6 @@
import { generateRefDestinationPath } from '~/repository/utils/ref_switcher_utils';
import setWindowLocation from 'helpers/set_window_location_helper';
+import { refWithSpecialCharMock, encodedRefWithSpecialCharMock } from '../mock_data';
const projectRootPath = 'root/Project1';
const currentRef = 'main';
@@ -19,4 +20,10 @@ describe('generateRefDestinationPath', () => {
setWindowLocation(currentPath);
expect(generateRefDestinationPath(projectRootPath, selectedRef)).toBe(result);
});
+
+ it('encodes the selected ref', () => {
+ const result = `${projectRootPath}/-/tree/${encodedRefWithSpecialCharMock}`;
+
+ expect(generateRefDestinationPath(projectRootPath, refWithSpecialCharMock)).toBe(result);
+ });
});
diff --git a/spec/frontend/users/profile/components/report_abuse_button_spec.js b/spec/frontend/users/profile/components/report_abuse_button_spec.js
new file mode 100644
index 00000000000..bd39a089473
--- /dev/null
+++ b/spec/frontend/users/profile/components/report_abuse_button_spec.js
@@ -0,0 +1,72 @@
+import { GlButton } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+
+import ReportAbuseButton from '~/users/profile/components/report_abuse_button.vue';
+import AbuseCategorySelector from '~/abuse_reports/components/abuse_category_selector.vue';
+
+describe('ReportAbuseButton', () => {
+ let wrapper;
+
+ const ACTION_PATH = '/abuse_reports/add_category';
+ const USER_ID = '1';
+ const REPORTED_FROM_URL = 'http://example.com';
+
+ const createComponent = (props) => {
+ wrapper = shallowMountExtended(ReportAbuseButton, {
+ propsData: {
+ ...props,
+ },
+ provide: {
+ formSubmitPath: ACTION_PATH,
+ userId: USER_ID,
+ reportedFromUrl: REPORTED_FROM_URL,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ const findReportAbuseButton = () => wrapper.findComponent(GlButton);
+ const findAbuseCategorySelector = () => wrapper.findComponent(AbuseCategorySelector);
+
+ it('renders report abuse button', () => {
+ expect(findReportAbuseButton().exists()).toBe(true);
+
+ expect(findReportAbuseButton().props()).toMatchObject({
+ category: 'primary',
+ icon: 'error',
+ });
+
+ expect(findReportAbuseButton().attributes('aria-label')).toBe(
+ wrapper.vm.$options.i18n.reportAbuse,
+ );
+ });
+
+ it('renders abuse category selector with the drawer initially closed', () => {
+ expect(findAbuseCategorySelector().exists()).toBe(true);
+
+ expect(findAbuseCategorySelector().props('showDrawer')).toBe(false);
+ });
+
+ describe('when button is clicked', () => {
+ beforeEach(async () => {
+ await findReportAbuseButton().vm.$emit('click');
+ });
+
+ it('opens the abuse category selector', () => {
+ expect(findAbuseCategorySelector().props('showDrawer')).toBe(true);
+ });
+
+ it('closes the abuse category selector', async () => {
+ await findAbuseCategorySelector().vm.$emit('close-drawer');
+
+ expect(findAbuseCategorySelector().props('showDrawer')).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/vue_merge_request_widget/components/states/__snapshots__/mr_widget_auto_merge_enabled_spec.js.snap b/spec/frontend/vue_merge_request_widget/components/states/__snapshots__/mr_widget_auto_merge_enabled_spec.js.snap
deleted file mode 100644
index 4077564486c..00000000000
--- a/spec/frontend/vue_merge_request_widget/components/states/__snapshots__/mr_widget_auto_merge_enabled_spec.js.snap
+++ /dev/null
@@ -1,163 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`MRWidgetAutoMergeEnabled template should have correct elements 1`] = `
-<div
- class="mr-widget-body media gl-display-flex gl-align-items-center"
->
- <div
- class="gl-w-6 gl-h-6 gl-display-flex gl-align-self-start gl-mr-3"
- >
- <div
- class="gl-display-flex gl-m-auto"
- >
- <div
- class="gl-mr-3 gl-p-2 gl-m-0! gl-text-blue-500 gl-w-6 gl-p-2"
- >
- <div
- class="gl-rounded-full gl-relative gl-display-flex mr-widget-extension-icon"
- >
- <div
- class="gl-absolute gl-top-half gl-left-50p gl-translate-x-n50 gl-display-flex gl-m-auto"
- >
- <div
- class="gl-display-flex gl-m-auto gl-translate-y-n50"
- >
- <svg
- aria-label="Scheduled "
- class="gl-display-block gl-icon s12"
- data-qa-selector="status_scheduled_icon"
- data-testid="status-scheduled-icon"
- role="img"
- >
- <use
- href="#status-scheduled"
- />
- </svg>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
-
- <div
- class="gl-display-flex gl-w-full"
- >
- <div
- class="media-body gl-display-flex gl-align-items-center"
- >
-
- <h4
- class="gl-mr-3"
- data-testid="statusText"
- >
- Set by to be merged automatically when the pipeline succeeds
- </h4>
-
- <div
- class="gl-display-flex gl-font-size-0 gl-ml-auto gl-gap-3"
- >
- <div
- class="gl-display-flex gl-align-items-flex-start"
- >
- <div
- class="dropdown b-dropdown gl-dropdown gl-display-block gl-md-display-none! btn-group"
- lazy=""
- no-caret=""
- title="Options"
- >
- <!---->
- <button
- aria-expanded="false"
- aria-haspopup="true"
- class="btn dropdown-toggle btn-default btn-sm gl-p-2! gl-button gl-dropdown-toggle btn-default-tertiary dropdown-icon-only dropdown-toggle-no-caret"
- type="button"
- >
- <!---->
-
- <svg
- aria-hidden="true"
- class="dropdown-icon gl-icon s16"
- data-testid="ellipsis_v-icon"
- role="img"
- >
- <use
- href="#ellipsis_v"
- />
- </svg>
-
- <span
- class="gl-dropdown-button-text gl-sr-only"
- >
-
- </span>
-
- <svg
- aria-hidden="true"
- class="gl-button-icon dropdown-chevron gl-icon s16"
- data-testid="chevron-down-icon"
- role="img"
- >
- <use
- href="#chevron-down"
- />
- </svg>
- </button>
- <ul
- class="dropdown-menu dropdown-menu-right"
- role="menu"
- tabindex="-1"
- >
- <!---->
- </ul>
- </div>
-
- <button
- class="btn gl-display-none gl-md-display-block gl-float-left btn-confirm btn-sm gl-button btn-confirm-tertiary js-cancel-auto-merge"
- data-qa-selector="cancel_auto_merge_button"
- data-testid="cancelAutomaticMergeButton"
- type="button"
- >
- <!---->
-
- <!---->
-
- <span
- class="gl-button-text"
- >
-
- Cancel auto-merge
-
- </span>
- </button>
- </div>
- </div>
- </div>
-
- <div
- class="gl-md-display-none gl-border-l-1 gl-border-l-solid gl-border-gray-100 gl-ml-3 gl-pl-3 gl-h-6 gl-mt-1"
- >
- <button
- class="btn gl-vertical-align-top btn-default btn-sm gl-button btn-default-tertiary btn-icon"
- title="Collapse merge details"
- type="button"
- >
- <!---->
-
- <svg
- aria-hidden="true"
- class="gl-button-icon gl-icon s16"
- data-testid="chevron-lg-up-icon"
- role="img"
- >
- <use
- href="#chevron-lg-up"
- />
- </svg>
-
- <!---->
- </button>
- </div>
- </div>
-</div>
-`;
diff --git a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled_spec.js b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled_spec.js
index 5b9f30dfb86..fef5fee5f19 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled_spec.js
@@ -128,14 +128,6 @@ describe('MRWidgetAutoMergeEnabled', () => {
});
describe('template', () => {
- it('should have correct elements', () => {
- factory({
- ...defaultMrProps(),
- });
-
- expect(wrapper.element).toMatchSnapshot();
- });
-
it('should disable cancel auto merge button when the action is in progress', async () => {
factory({
...defaultMrProps(),
diff --git a/spec/frontend/vue_shared/components/ci_badge_link_spec.js b/spec/frontend/vue_shared/components/ci_badge_link_spec.js
index 07cbfe1e79b..4f24ec2d015 100644
--- a/spec/frontend/vue_shared/components/ci_badge_link_spec.js
+++ b/spec/frontend/vue_shared/components/ci_badge_link_spec.js
@@ -1,6 +1,6 @@
import { GlLink } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
-import CiBadge from '~/vue_shared/components/ci_badge_link.vue';
+import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
jest.mock('~/lib/utils/url_utility', () => ({
@@ -79,7 +79,7 @@ describe('CI Badge Link Component', () => {
const findIcon = () => wrapper.findComponent(CiIcon);
const createComponent = (propsData) => {
- wrapper = shallowMount(CiBadge, { propsData });
+ wrapper = shallowMount(CiBadgeLink, { propsData });
};
afterEach(() => {