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:
Diffstat (limited to 'spec/frontend/admin/abuse_report')
-rw-r--r--spec/frontend/admin/abuse_report/components/abuse_report_app_spec.js80
-rw-r--r--spec/frontend/admin/abuse_report/components/activity_events_list_spec.js30
-rw-r--r--spec/frontend/admin/abuse_report/components/activity_history_item_spec.js (renamed from spec/frontend/admin/abuse_report/components/history_items_spec.js)20
-rw-r--r--spec/frontend/admin/abuse_report/components/labels_select_spec.js297
-rw-r--r--spec/frontend/admin/abuse_report/components/report_actions_spec.js27
-rw-r--r--spec/frontend/admin/abuse_report/components/report_details_spec.js74
-rw-r--r--spec/frontend/admin/abuse_report/components/report_header_spec.js55
-rw-r--r--spec/frontend/admin/abuse_report/components/reported_content_spec.js11
-rw-r--r--spec/frontend/admin/abuse_report/components/user_details_spec.js62
-rw-r--r--spec/frontend/admin/abuse_report/mock_data.js88
10 files changed, 619 insertions, 125 deletions
diff --git a/spec/frontend/admin/abuse_report/components/abuse_report_app_spec.js b/spec/frontend/admin/abuse_report/components/abuse_report_app_spec.js
index e519684bbc5..4340699a7ed 100644
--- a/spec/frontend/admin/abuse_report/components/abuse_report_app_spec.js
+++ b/spec/frontend/admin/abuse_report/components/abuse_report_app_spec.js
@@ -1,28 +1,46 @@
-import { shallowMount } from '@vue/test-utils';
import { GlAlert } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import AbuseReportApp from '~/admin/abuse_report/components/abuse_report_app.vue';
import ReportHeader from '~/admin/abuse_report/components/report_header.vue';
import UserDetails from '~/admin/abuse_report/components/user_details.vue';
+import ReportDetails from '~/admin/abuse_report/components/report_details.vue';
import ReportedContent from '~/admin/abuse_report/components/reported_content.vue';
-import HistoryItems from '~/admin/abuse_report/components/history_items.vue';
+import ActivityEventsList from '~/admin/abuse_report/components/activity_events_list.vue';
+import ActivityHistoryItem from '~/admin/abuse_report/components/activity_history_item.vue';
import { SUCCESS_ALERT } from '~/admin/abuse_report/constants';
import { mockAbuseReport } from '../mock_data';
describe('AbuseReportApp', () => {
let wrapper;
+ const { similarOpenReports } = mockAbuseReport.user;
+
const findAlert = () => wrapper.findComponent(GlAlert);
const findReportHeader = () => wrapper.findComponent(ReportHeader);
const findUserDetails = () => wrapper.findComponent(UserDetails);
- const findReportedContent = () => wrapper.findComponent(ReportedContent);
- const findHistoryItems = () => wrapper.findComponent(HistoryItems);
- const createComponent = (props = {}) => {
- wrapper = shallowMount(AbuseReportApp, {
+ const findReportedContent = () => wrapper.findByTestId('reported-content');
+ const findReportedContentForSimilarReports = () =>
+ wrapper.findAllByTestId('reported-content-similar-open-reports');
+ const firstReportedContentForSimilarReports = () =>
+ findReportedContentForSimilarReports().at(0).findComponent(ReportedContent);
+
+ const findActivityList = () => wrapper.findComponent(ActivityEventsList);
+ const findActivityItem = () => wrapper.findByTestId('activity');
+ const findActivityForSimilarReports = () =>
+ wrapper.findAllByTestId('activity-similar-open-reports');
+ const firstActivityForSimilarReports = () =>
+ findActivityForSimilarReports().at(0).findComponent(ActivityHistoryItem);
+
+ const findReportDetails = () => wrapper.findComponent(ReportDetails);
+
+ const createComponent = (props = {}, provide = {}) => {
+ wrapper = shallowMountExtended(AbuseReportApp, {
propsData: {
abuseReport: mockAbuseReport,
...props,
},
+ provide,
});
};
@@ -64,7 +82,7 @@ describe('AbuseReportApp', () => {
});
});
- describe('ReportHeader', () => {
+ describe('Report header', () => {
it('renders ReportHeader', () => {
expect(findReportHeader().props('user')).toBe(mockAbuseReport.user);
expect(findReportHeader().props('report')).toBe(mockAbuseReport.report);
@@ -83,7 +101,7 @@ describe('AbuseReportApp', () => {
});
});
- describe('UserDetails', () => {
+ describe('User Details', () => {
it('renders UserDetails', () => {
expect(findUserDetails().props('user')).toBe(mockAbuseReport.user);
});
@@ -101,13 +119,47 @@ describe('AbuseReportApp', () => {
});
});
- it('renders ReportedContent', () => {
- expect(findReportedContent().props('report')).toBe(mockAbuseReport.report);
- expect(findReportedContent().props('reporter')).toBe(mockAbuseReport.reporter);
+ describe('Reported Content', () => {
+ it('renders ReportedContent', () => {
+ expect(findReportedContent().props('report')).toBe(mockAbuseReport.report);
+ });
+
+ it('renders similar abuse reports', () => {
+ expect(findReportedContentForSimilarReports()).toHaveLength(similarOpenReports.length);
+ expect(firstReportedContentForSimilarReports().props('report')).toBe(similarOpenReports[0]);
+ });
});
- it('renders HistoryItems', () => {
- expect(findHistoryItems().props('report')).toBe(mockAbuseReport.report);
- expect(findHistoryItems().props('reporter')).toBe(mockAbuseReport.reporter);
+ describe('ReportDetails', () => {
+ describe('when abuseReportLabels feature flag is enabled', () => {
+ it('renders ReportDetails', () => {
+ createComponent({}, { glFeatures: { abuseReportLabels: true } });
+
+ expect(findReportDetails().props('reportId')).toBe(mockAbuseReport.report.globalId);
+ });
+ });
+
+ describe('when abuseReportLabels feature flag is disabled', () => {
+ it('does not render ReportDetails', () => {
+ createComponent({}, { glFeatures: { abuseReportLabels: false } });
+
+ expect(findReportDetails().exists()).toBe(false);
+ });
+ });
+ });
+
+ describe('Activity', () => {
+ it('renders the activity events list', () => {
+ expect(findActivityList().exists()).toBe(true);
+ });
+
+ it('renders activity item for abuse report', () => {
+ expect(findActivityItem().props('report')).toBe(mockAbuseReport.report);
+ });
+
+ it('renders activity items for similar abuse reports', () => {
+ expect(findActivityForSimilarReports()).toHaveLength(similarOpenReports.length);
+ expect(firstActivityForSimilarReports().props('report')).toBe(similarOpenReports[0]);
+ });
});
});
diff --git a/spec/frontend/admin/abuse_report/components/activity_events_list_spec.js b/spec/frontend/admin/abuse_report/components/activity_events_list_spec.js
new file mode 100644
index 00000000000..cd1120d2db4
--- /dev/null
+++ b/spec/frontend/admin/abuse_report/components/activity_events_list_spec.js
@@ -0,0 +1,30 @@
+import { shallowMount } from '@vue/test-utils';
+import ActivityEventsList from '~/admin/abuse_report/components/activity_events_list.vue';
+
+describe('ActivityEventsList', () => {
+ let wrapper;
+
+ const mockSlotContent = 'Test slot content';
+
+ const findActivityEventsList = () => wrapper.findComponent(ActivityEventsList);
+
+ const createComponent = () => {
+ wrapper = shallowMount(ActivityEventsList, {
+ slots: {
+ 'history-items': mockSlotContent,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders activity title', () => {
+ expect(findActivityEventsList().text()).toContain('Activity');
+ });
+
+ it('renders history-items slot', () => {
+ expect(findActivityEventsList().text()).toContain(mockSlotContent);
+ });
+});
diff --git a/spec/frontend/admin/abuse_report/components/history_items_spec.js b/spec/frontend/admin/abuse_report/components/activity_history_item_spec.js
index 86e994fdc57..3f430b0143e 100644
--- a/spec/frontend/admin/abuse_report/components/history_items_spec.js
+++ b/spec/frontend/admin/abuse_report/components/activity_history_item_spec.js
@@ -1,25 +1,23 @@
import { GlSprintf } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { sprintf } from '~/locale';
-import HistoryItems from '~/admin/abuse_report/components/history_items.vue';
+import AcitivityHistoryItem from '~/admin/abuse_report/components/activity_history_item.vue';
import HistoryItem from '~/vue_shared/components/registry/history_item.vue';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
-import { HISTORY_ITEMS_I18N } from '~/admin/abuse_report/constants';
import { mockAbuseReport } from '../mock_data';
-describe('HistoryItems', () => {
+describe('AcitivityHistoryItem', () => {
let wrapper;
- const { report, reporter } = mockAbuseReport;
+ const { report } = mockAbuseReport;
const findHistoryItem = () => wrapper.findComponent(HistoryItem);
const findTimeAgo = () => wrapper.findComponent(TimeAgoTooltip);
const createComponent = (props = {}) => {
- wrapper = shallowMount(HistoryItems, {
+ wrapper = shallowMount(AcitivityHistoryItem, {
propsData: {
report,
- reporter,
...props,
},
stubs: {
@@ -38,8 +36,8 @@ describe('HistoryItems', () => {
describe('rendering the title', () => {
it('renders the reporters name and the category', () => {
- const title = sprintf(HISTORY_ITEMS_I18N.reportedByForCategory, {
- name: reporter.name,
+ const title = sprintf('Reported by %{name} for %{category}.', {
+ name: report.reporter.name,
category: report.category,
});
expect(findHistoryItem().text()).toContain(title);
@@ -47,12 +45,12 @@ describe('HistoryItems', () => {
describe('when the reporter is not defined', () => {
beforeEach(() => {
- createComponent({ reporter: undefined });
+ createComponent({ report: { ...report, reporter: undefined } });
});
it('renders the `No user found` as the reporters name and the category', () => {
- const title = sprintf(HISTORY_ITEMS_I18N.reportedByForCategory, {
- name: HISTORY_ITEMS_I18N.deletedReporter,
+ const title = sprintf('Reported by %{name} for %{category}.', {
+ name: 'No user found',
category: report.category,
});
expect(findHistoryItem().text()).toContain(title);
diff --git a/spec/frontend/admin/abuse_report/components/labels_select_spec.js b/spec/frontend/admin/abuse_report/components/labels_select_spec.js
new file mode 100644
index 00000000000..a22dcc18e10
--- /dev/null
+++ b/spec/frontend/admin/abuse_report/components/labels_select_spec.js
@@ -0,0 +1,297 @@
+import MockAdapter from 'axios-mock-adapter';
+import { GlButton, GlDropdown, GlDropdownItem, GlLoadingIcon } from '@gitlab/ui';
+import Vue, { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import axios from '~/lib/utils/axios_utils';
+import { HTTP_STATUS_OK, HTTP_STATUS_INTERNAL_SERVER_ERROR } from '~/lib/utils/http_status';
+import LabelsSelect from '~/admin/abuse_report/components/labels_select.vue';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { stubComponent, RENDER_ALL_SLOTS_TEMPLATE } from 'helpers/stub_component';
+import labelsQuery from '~/admin/abuse_report/components/graphql/abuse_report_labels.query.graphql';
+import DropdownWidget from '~/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.vue';
+import DropdownValue from '~/sidebar/components/labels/labels_select_widget/dropdown_value.vue';
+import DropdownHeader from '~/sidebar/components/labels/labels_select_widget/dropdown_header.vue';
+import DropdownContentsCreateView from '~/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view.vue';
+import DropdownFooter from '~/sidebar/components/labels/labels_select_widget/dropdown_footer.vue';
+import { createAlert } from '~/alert';
+import { mockLabelsQueryResponse, mockLabel1, mockLabel2 } from '../mock_data';
+
+jest.mock('~/alert');
+
+Vue.use(VueApollo);
+
+describe('Labels select component', () => {
+ let mock;
+ let wrapper;
+ let fakeApollo;
+
+ const selectedText = () => wrapper.findByTestId('selected-labels').text();
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+ const findEditButton = () => wrapper.findComponent(GlButton);
+ const findDropdown = () => wrapper.findComponent(DropdownWidget);
+ const findDropdownHeader = () => wrapper.findComponent(DropdownHeader);
+ const findDropdownValue = () => wrapper.findComponent(DropdownValue);
+ const findCreateView = () => wrapper.findComponent(DropdownContentsCreateView);
+ const findDropdownFooter = () => wrapper.findComponent(DropdownFooter);
+
+ const labelsQueryHandlerSuccess = jest.fn().mockResolvedValue(mockLabelsQueryResponse);
+ const labelsQueryHandlerFailure = jest.fn().mockRejectedValue(new Error());
+
+ const updatePath = '/admin/abuse_reports/1';
+ const listPath = '/admin/abuse_reports';
+
+ async function openLabelsDropdown() {
+ findEditButton().vm.$emit('click');
+ await waitForPromises();
+ }
+
+ const selectLabel = (label) => {
+ findDropdown().vm.$emit('set-option', label);
+ nextTick();
+ };
+
+ const createComponent = ({ props = {}, labelsQueryHandler = labelsQueryHandlerSuccess } = {}) => {
+ fakeApollo = createMockApollo([[labelsQuery, labelsQueryHandler]]);
+ wrapper = shallowMountExtended(LabelsSelect, {
+ apolloProvider: fakeApollo,
+ propsData: {
+ report: { labels: [] },
+ canEdit: true,
+ ...props,
+ },
+ provide: {
+ updatePath,
+ listPath,
+ },
+ stubs: {
+ GlDropdown,
+ GlDropdownItem,
+ DropdownWidget: stubComponent(DropdownWidget, {
+ template: RENDER_ALL_SLOTS_TEMPLATE,
+ methods: { showDropdown: jest.fn() },
+ }),
+ },
+ });
+ };
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ fakeApollo = null;
+ mock.restore();
+ });
+
+ describe('initial load', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('displays loading icon', () => {
+ expect(findLoadingIcon().exists()).toEqual(true);
+ });
+
+ it('disables edit button', () => {
+ expect(findEditButton().props('disabled')).toEqual(true);
+ });
+
+ describe('after initial load', () => {
+ beforeEach(() => {
+ wrapper.setProps({ report: { labels: [mockLabel1] } });
+ });
+
+ it('does not display loading icon', () => {
+ expect(findLoadingIcon().exists()).toEqual(false);
+ });
+
+ it('enables edit button', () => {
+ expect(findEditButton().props('disabled')).toEqual(false);
+ });
+
+ it('renders fetched DropdownValue with the correct props', () => {
+ const component = findDropdownValue();
+ expect(component.isVisible()).toBe(true);
+ expect(component.props('selectedLabels')).toEqual([mockLabel1]);
+ expect(component.props('labelsFilterBasePath')).toBe(listPath);
+ });
+ });
+ });
+
+ describe('when there are no selected labels', () => {
+ it('displays "None"', () => {
+ createComponent();
+
+ expect(selectedText()).toContain('None');
+ });
+ });
+
+ describe('when there are selected labels', () => {
+ beforeEach(() => {
+ createComponent({ props: { report: { labels: [mockLabel1, mockLabel2] } } });
+
+ mock.onPut(updatePath).reply(HTTP_STATUS_OK, {});
+ jest.spyOn(axios, 'put');
+ });
+
+ it('renders selected labels in DropdownValue', () => {
+ expect(findDropdownValue().isVisible()).toBe(true);
+ expect(findDropdownValue().props('selectedLabels')).toEqual([mockLabel1, mockLabel2]);
+ });
+
+ it('selected labels can be removed', async () => {
+ findDropdownValue().vm.$emit('onLabelRemove', mockLabel1.id);
+ await nextTick();
+
+ expect(findDropdownValue().props('selectedLabels')).toEqual([mockLabel2]);
+ expect(axios.put).toHaveBeenCalledWith(updatePath, {
+ label_ids: [mockLabel2.id],
+ });
+ });
+ });
+
+ describe('when not editing', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('does not trigger abuse report labels query', () => {
+ expect(labelsQueryHandlerSuccess).not.toHaveBeenCalled();
+ });
+
+ it('does not render the dropdown', () => {
+ expect(findDropdown().isVisible()).toBe(false);
+ });
+ });
+
+ describe('when editing', () => {
+ beforeEach(async () => {
+ createComponent();
+ await openLabelsDropdown();
+ });
+
+ it('triggers abuse report labels query', () => {
+ expect(labelsQueryHandlerSuccess).toHaveBeenCalledTimes(1);
+ });
+
+ it('renders dropdown with fetched labels', () => {
+ expect(findDropdown().isVisible()).toBe(true);
+ expect(findDropdown().props('options')).toEqual([mockLabel1, mockLabel2]);
+ });
+
+ it('selects/deselects a label', async () => {
+ await selectLabel(mockLabel1);
+
+ expect(findDropdownValue().props('selectedLabels')).toEqual([mockLabel1]);
+
+ await selectLabel(mockLabel1);
+
+ expect(selectedText()).toContain('None');
+ });
+
+ it('triggers abuse report labels query when search term is set', async () => {
+ findDropdown().vm.$emit('set-search', 'Dos');
+ await waitForPromises();
+
+ expect(labelsQueryHandlerSuccess).toHaveBeenCalledTimes(2);
+ expect(labelsQueryHandlerSuccess).toHaveBeenCalledWith({ searchTerm: 'Dos' });
+ });
+
+ it('does not render DropdownContentsCreateView', () => {
+ expect(findCreateView().exists()).toBe(false);
+ });
+
+ it('renders DropdownFooter', () => {
+ expect(findDropdownFooter().props('footerCreateLabelTitle')).toEqual('Create label');
+ expect(findDropdownFooter().props('footerManageLabelTitle')).toEqual('');
+ });
+
+ describe('when DropdownHeader emits `toggleDropdownContentsCreateView` event', () => {
+ beforeEach(() => {
+ findDropdownHeader().vm.$emit('toggleDropdownContentsCreateView');
+ });
+
+ it('renders DropdownContentsCreateView and removes DropdownFooter', () => {
+ expect(findCreateView().props('workspaceType')).toEqual('abuseReport');
+ expect(findDropdownFooter().exists()).toBe(false);
+ });
+
+ describe('when DropdownContentsCreateView emits `hideCreateView` event', () => {
+ it('removes itself', async () => {
+ findCreateView().vm.$emit('hideCreateView');
+ await nextTick();
+
+ expect(findCreateView().exists()).toBe(false);
+ });
+ });
+
+ describe('when DropdownContentsCreateView emits `labelCreated` event', () => {
+ it('selects created label', async () => {
+ findCreateView().vm.$emit('labelCreated', mockLabel1);
+ await nextTick();
+
+ expect(findDropdownValue().props('selectedLabels')).toEqual([mockLabel1]);
+ });
+ });
+ });
+
+ describe('when DropdownFooter emits `toggleDropdownContentsCreateView` event', () => {
+ it('renders DropdownContentsCreateView', async () => {
+ findDropdownFooter().vm.$emit('toggleDropdownContentsCreateView');
+ await nextTick();
+
+ expect(findCreateView().props('workspaceType')).toEqual('abuseReport');
+ });
+ });
+ });
+
+ describe('after edit', () => {
+ const setup = async (response) => {
+ mock.onPut(updatePath).reply(response, {});
+ jest.spyOn(axios, 'put');
+
+ createComponent();
+ await openLabelsDropdown();
+ await selectLabel(mockLabel1);
+
+ findDropdown().vm.$emit('hide');
+ };
+
+ describe('successful save', () => {
+ it('saves', async () => {
+ await setup(HTTP_STATUS_OK);
+
+ expect(axios.put).toHaveBeenCalledWith(updatePath, {
+ label_ids: [mockLabel1.id],
+ });
+ });
+ });
+
+ describe('unsuccessful save', () => {
+ it('creates an alert', async () => {
+ await setup(HTTP_STATUS_INTERNAL_SERVER_ERROR);
+
+ await waitForPromises();
+
+ expect(createAlert).toHaveBeenCalledWith({
+ message: 'An error occurred while updating labels.',
+ captureError: true,
+ error: expect.any(Error),
+ });
+ });
+ });
+ });
+
+ describe('failed abuse report labels query', () => {
+ it('creates an alert', async () => {
+ createComponent({ labelsQueryHandler: labelsQueryHandlerFailure });
+ await openLabelsDropdown();
+
+ expect(createAlert).toHaveBeenCalledWith({
+ message: 'An error occurred while searching for labels, please try again.',
+ });
+ });
+ });
+});
diff --git a/spec/frontend/admin/abuse_report/components/report_actions_spec.js b/spec/frontend/admin/abuse_report/components/report_actions_spec.js
index 6dd6d0e55c5..0e20630db14 100644
--- a/spec/frontend/admin/abuse_report/components/report_actions_spec.js
+++ b/spec/frontend/admin/abuse_report/components/report_actions_spec.js
@@ -191,31 +191,4 @@ describe('ReportActions', () => {
);
});
});
-
- describe('when moderateUserPath is not present', () => {
- it('sends the request to updatePath', async () => {
- jest.spyOn(axios, 'put');
- axiosMock.onPut(report.updatePath).replyOnce(HTTP_STATUS_OK, {});
-
- const reportWithoutModerateUserPath = { ...report };
- delete reportWithoutModerateUserPath.moderateUserPath;
-
- createComponent({ report: reportWithoutModerateUserPath });
-
- clickActionsButton();
-
- await nextTick();
-
- selectAction(params.user_action);
- selectReason(params.reason);
-
- await nextTick();
-
- submitForm();
-
- await waitForPromises();
-
- expect(axios.put).toHaveBeenCalledWith(report.updatePath, expect.any(Object));
- });
- });
});
diff --git a/spec/frontend/admin/abuse_report/components/report_details_spec.js b/spec/frontend/admin/abuse_report/components/report_details_spec.js
new file mode 100644
index 00000000000..a5c43dcb82b
--- /dev/null
+++ b/spec/frontend/admin/abuse_report/components/report_details_spec.js
@@ -0,0 +1,74 @@
+import { shallowMount } from '@vue/test-utils';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import LabelsSelect from '~/admin/abuse_report/components/labels_select.vue';
+import ReportDetails from '~/admin/abuse_report/components/report_details.vue';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import abuseReportQuery from '~/admin/abuse_report/components/graphql/abuse_report.query.graphql';
+import { createAlert } from '~/alert';
+import { mockAbuseReport, mockLabel1, mockReportQueryResponse } from '../mock_data';
+
+jest.mock('~/alert');
+
+Vue.use(VueApollo);
+
+describe('Report Details', () => {
+ let wrapper;
+ let fakeApollo;
+
+ const findLabelsSelect = () => wrapper.findComponent(LabelsSelect);
+
+ const abuseReportQueryHandlerSuccess = jest.fn().mockResolvedValue(mockReportQueryResponse);
+ const abuseReportQueryHandlerFailure = jest.fn().mockRejectedValue(new Error());
+
+ const createComponent = ({ abuseReportQueryHandler = abuseReportQueryHandlerSuccess } = {}) => {
+ fakeApollo = createMockApollo([[abuseReportQuery, abuseReportQueryHandler]]);
+ wrapper = shallowMount(ReportDetails, {
+ apolloProvider: fakeApollo,
+ propsData: {
+ reportId: mockAbuseReport.report.globalId,
+ },
+ });
+ };
+
+ afterEach(() => {
+ fakeApollo = null;
+ });
+
+ describe('successful abuse report query', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('triggers abuse report query', async () => {
+ await waitForPromises();
+
+ expect(abuseReportQueryHandlerSuccess).toHaveBeenCalledWith({
+ id: mockAbuseReport.report.globalId,
+ });
+ });
+
+ it('renders LabelsSelect with the fetched report', async () => {
+ expect(findLabelsSelect().props('report').labels).toEqual([]);
+
+ await waitForPromises();
+
+ expect(findLabelsSelect().props('report').labels).toEqual([mockLabel1]);
+ });
+ });
+
+ describe('failed abuse report query', () => {
+ beforeEach(async () => {
+ createComponent({ abuseReportQueryHandler: abuseReportQueryHandlerFailure });
+
+ await waitForPromises();
+ });
+
+ it('creates an alert', () => {
+ expect(createAlert).toHaveBeenCalledWith({
+ message: 'An error occurred while fetching labels, please try again.',
+ });
+ });
+ });
+});
diff --git a/spec/frontend/admin/abuse_report/components/report_header_spec.js b/spec/frontend/admin/abuse_report/components/report_header_spec.js
index f22f3af091f..6ec380f0387 100644
--- a/spec/frontend/admin/abuse_report/components/report_header_spec.js
+++ b/spec/frontend/admin/abuse_report/components/report_header_spec.js
@@ -54,37 +54,30 @@ describe('ReportHeader', () => {
});
describe.each`
- status | text | variant | className | badgeIcon
- ${STATUS_OPEN} | ${REPORT_HEADER_I18N[STATUS_OPEN]} | ${'success'} | ${'issuable-status-badge-open'} | ${'issues'}
- ${STATUS_CLOSED} | ${REPORT_HEADER_I18N[STATUS_CLOSED]} | ${'info'} | ${'issuable-status-badge-closed'} | ${'issue-closed'}
- `(
- 'rendering the report $status status badge',
- ({ status, text, variant, className, badgeIcon }) => {
- beforeEach(() => {
- createComponent({ report: { ...report, status } });
- });
-
- it(`indicates the ${status} status`, () => {
- expect(findBadge().text()).toBe(text);
- });
-
- it(`with the ${variant} variant`, () => {
- expect(findBadge().props('variant')).toBe(variant);
- });
-
- it(`with the text '${text}' as 'aria-label'`, () => {
- expect(findBadge().attributes('aria-label')).toBe(text);
- });
-
- it(`contains the ${className} class`, () => {
- expect(findBadge().element.classList).toContain(className);
- });
-
- it(`has an icon with the ${badgeIcon} name`, () => {
- expect(findIcon().props('name')).toBe(badgeIcon);
- });
- },
- );
+ status | text | variant | badgeIcon
+ ${STATUS_OPEN} | ${REPORT_HEADER_I18N[STATUS_OPEN]} | ${'success'} | ${'issues'}
+ ${STATUS_CLOSED} | ${REPORT_HEADER_I18N[STATUS_CLOSED]} | ${'info'} | ${'issue-closed'}
+ `('rendering the report $status status badge', ({ status, text, variant, badgeIcon }) => {
+ beforeEach(() => {
+ createComponent({ report: { ...report, status } });
+ });
+
+ it(`indicates the ${status} status`, () => {
+ expect(findBadge().text()).toBe(text);
+ });
+
+ it(`with the ${variant} variant`, () => {
+ expect(findBadge().props('variant')).toBe(variant);
+ });
+
+ it(`with the text '${text}' as 'aria-label'`, () => {
+ expect(findBadge().attributes('aria-label')).toBe(text);
+ });
+
+ it(`has an icon with the ${badgeIcon} name`, () => {
+ expect(findIcon().props('name')).toBe(badgeIcon);
+ });
+ });
it('renders the actions', () => {
const actionsComponent = findActions();
diff --git a/spec/frontend/admin/abuse_report/components/reported_content_spec.js b/spec/frontend/admin/abuse_report/components/reported_content_spec.js
index 9fc49f08f8c..2f16f5a7af2 100644
--- a/spec/frontend/admin/abuse_report/components/reported_content_spec.js
+++ b/spec/frontend/admin/abuse_report/components/reported_content_spec.js
@@ -14,7 +14,7 @@ const modalId = 'abuse-report-screenshot-modal';
describe('ReportedContent', () => {
let wrapper;
- const { report, reporter } = { ...mockAbuseReport };
+ const { report } = { ...mockAbuseReport };
const findScreenshotButton = () => wrapper.findByTestId('screenshot-button');
const findReportUrlButton = () => wrapper.findByTestId('report-url-button');
@@ -32,7 +32,6 @@ describe('ReportedContent', () => {
wrapper = shallowMountExtended(ReportedContent, {
propsData: {
report,
- reporter,
...props,
},
stubs: {
@@ -167,18 +166,18 @@ describe('ReportedContent', () => {
describe('rendering the card footer', () => {
it('renders the reporters avatar', () => {
- expect(findAvatar().props('src')).toBe(reporter.avatarUrl);
+ expect(findAvatar().props('src')).toBe(report.reporter.avatarUrl);
});
it('renders the users name', () => {
- expect(findCardFooter().text()).toContain(reporter.name);
+ expect(findCardFooter().text()).toContain(report.reporter.name);
});
it('renders a link to the users profile page', () => {
const link = findProfileLink();
- expect(link.attributes('href')).toBe(reporter.path);
- expect(link.text()).toBe(`@${reporter.username}`);
+ expect(link.attributes('href')).toBe(report.reporter.path);
+ expect(link.text()).toBe(`@${report.reporter.username}`);
});
it('renders the time-ago tooltip', () => {
diff --git a/spec/frontend/admin/abuse_report/components/user_details_spec.js b/spec/frontend/admin/abuse_report/components/user_details_spec.js
index ca499fbaa6e..f3d8d5bb610 100644
--- a/spec/frontend/admin/abuse_report/components/user_details_spec.js
+++ b/spec/frontend/admin/abuse_report/components/user_details_spec.js
@@ -18,7 +18,7 @@ describe('UserDetails', () => {
const findLinkFor = (attribute) => findLinkIn(findUserDetail(attribute));
const findTimeIn = (component) => component.findComponent(TimeAgoTooltip).props('time');
const findTimeFor = (attribute) => findTimeIn(findUserDetail(attribute));
- const findOtherReport = (index) => wrapper.findByTestId(`other-report-${index}`);
+ const findPastReport = (index) => wrapper.findByTestId(`past-report-${index}`);
const createComponent = (props = {}) => {
wrapper = shallowMountExtended(UserDetails, {
@@ -38,8 +38,8 @@ describe('UserDetails', () => {
describe('createdAt', () => {
it('renders the users createdAt with the correct label', () => {
- expect(findUserDetailLabel('createdAt')).toBe(USER_DETAILS_I18N.createdAt);
- expect(findTimeFor('createdAt')).toBe(user.createdAt);
+ expect(findUserDetailLabel('created-at')).toBe(USER_DETAILS_I18N.createdAt);
+ expect(findTimeFor('created-at')).toBe(user.createdAt);
});
});
@@ -67,32 +67,34 @@ describe('UserDetails', () => {
describe('creditCard', () => {
it('renders the correct label', () => {
- expect(findUserDetailLabel('creditCard')).toBe(USER_DETAILS_I18N.creditCard);
+ expect(findUserDetailLabel('credit-card-verification')).toBe(USER_DETAILS_I18N.creditCard);
});
it('renders the users name', () => {
- expect(findUserDetail('creditCard').text()).toContain(
+ expect(findUserDetail('credit-card-verification').text()).toContain(
sprintf(USER_DETAILS_I18N.registeredWith, { ...user.creditCard }),
);
- expect(findUserDetail('creditCard').text()).toContain(user.creditCard.name);
+ expect(findUserDetail('credit-card-verification').text()).toContain(user.creditCard.name);
});
describe('similar credit cards', () => {
it('renders the number of similar records', () => {
- expect(findUserDetail('creditCard').text()).toContain(
+ expect(findUserDetail('credit-card-verification').text()).toContain(
sprintf('Card matches %{similarRecordsCount} accounts', { ...user.creditCard }),
);
});
it('renders a link to the matching cards', () => {
- expect(findLinkFor('creditCard').attributes('href')).toBe(user.creditCard.cardMatchesLink);
+ expect(findLinkFor('credit-card-verification').attributes('href')).toBe(
+ user.creditCard.cardMatchesLink,
+ );
- expect(findLinkFor('creditCard').text()).toBe(
+ expect(findLinkFor('credit-card-verification').text()).toBe(
sprintf('%{similarRecordsCount} accounts', { ...user.creditCard }),
);
- expect(findLinkFor('creditCard').text()).toContain(
+ expect(findLinkFor('credit-card-verification').text()).toContain(
user.creditCard.similarRecordsCount.toString(),
);
});
@@ -105,13 +107,13 @@ describe('UserDetails', () => {
});
it('does not render the number of similar records', () => {
- expect(findUserDetail('creditCard').text()).not.toContain(
+ expect(findUserDetail('credit-card-verification').text()).not.toContain(
sprintf('Card matches %{similarRecordsCount} accounts', { ...user.creditCard }),
);
});
it('does not render a link to the matching cards', () => {
- expect(findLinkFor('creditCard').exists()).toBe(false);
+ expect(findLinkFor('credit-card-verification').exists()).toBe(false);
});
});
});
@@ -124,55 +126,55 @@ describe('UserDetails', () => {
});
it('does not render the users creditCard', () => {
- expect(findUserDetail('creditCard').exists()).toBe(false);
+ expect(findUserDetail('credit-card-verification').exists()).toBe(false);
});
});
});
describe('otherReports', () => {
it('renders the correct label', () => {
- expect(findUserDetailLabel('otherReports')).toBe(USER_DETAILS_I18N.otherReports);
+ expect(findUserDetailLabel('past-closed-reports')).toBe(USER_DETAILS_I18N.pastReports);
});
- describe.each(user.otherReports)('renders a line for report %#', (otherReport) => {
- const index = user.otherReports.indexOf(otherReport);
+ describe.each(user.pastClosedReports)('renders a line for report %#', (pastReport) => {
+ const index = user.pastClosedReports.indexOf(pastReport);
it('renders the category', () => {
- expect(findOtherReport(index).text()).toContain(
- sprintf('Reported for %{category}', { ...otherReport }),
+ expect(findPastReport(index).text()).toContain(
+ sprintf('Reported for %{category}', { ...pastReport }),
);
});
it('renders a link to the report', () => {
- expect(findLinkIn(findOtherReport(index)).attributes('href')).toBe(otherReport.reportPath);
+ expect(findLinkIn(findPastReport(index)).attributes('href')).toBe(pastReport.reportPath);
});
it('renders the time it was created', () => {
- expect(findTimeIn(findOtherReport(index))).toBe(otherReport.createdAt);
+ expect(findTimeIn(findPastReport(index))).toBe(pastReport.createdAt);
});
});
describe('when the users otherReports is empty', () => {
beforeEach(() => {
createComponent({
- user: { ...user, otherReports: [] },
+ user: { ...user, pastClosedReports: [] },
});
});
it('does not render the users otherReports', () => {
- expect(findUserDetail('otherReports').exists()).toBe(false);
+ expect(findUserDetail('past-closed-reports').exists()).toBe(false);
});
});
});
describe('normalLocation', () => {
it('renders the correct label', () => {
- expect(findUserDetailLabel('normalLocation')).toBe(USER_DETAILS_I18N.normalLocation);
+ expect(findUserDetailLabel('normal-location')).toBe(USER_DETAILS_I18N.normalLocation);
});
describe('when the users mostUsedIp is blank', () => {
it('renders the users lastSignInIp', () => {
- expect(findUserDetailValue('normalLocation')).toBe(user.lastSignInIp);
+ expect(findUserDetailValue('normal-location')).toBe(user.lastSignInIp);
});
});
@@ -186,23 +188,25 @@ describe('UserDetails', () => {
});
it('renders the users mostUsedIp', () => {
- expect(findUserDetailValue('normalLocation')).toBe(mostUsedIp);
+ expect(findUserDetailValue('normal-location')).toBe(mostUsedIp);
});
});
});
describe('lastSignInIp', () => {
it('renders the users lastSignInIp with the correct label', () => {
- expect(findUserDetailLabel('lastSignInIp')).toBe(USER_DETAILS_I18N.lastSignInIp);
- expect(findUserDetailValue('lastSignInIp')).toBe(user.lastSignInIp);
+ expect(findUserDetailLabel('last-sign-in-ip')).toBe(USER_DETAILS_I18N.lastSignInIp);
+ expect(findUserDetailValue('last-sign-in-ip')).toBe(user.lastSignInIp);
});
});
it.each(['snippets', 'groups', 'notes'])(
'renders the users %s with the correct label',
(attribute) => {
- expect(findUserDetailLabel(attribute)).toBe(USER_DETAILS_I18N[attribute]);
- expect(findUserDetailValue(attribute)).toBe(
+ const testId = `user-${attribute}-count`;
+
+ expect(findUserDetailLabel(testId)).toBe(USER_DETAILS_I18N[attribute]);
+ expect(findUserDetailValue(testId)).toBe(
USER_DETAILS_I18N[`${attribute}Count`](user[`${attribute}Count`]),
);
},
diff --git a/spec/frontend/admin/abuse_report/mock_data.js b/spec/frontend/admin/abuse_report/mock_data.js
index 8ff0c7d507a..ee61eabfa66 100644
--- a/spec/frontend/admin/abuse_report/mock_data.js
+++ b/spec/frontend/admin/abuse_report/mock_data.js
@@ -15,7 +15,7 @@ export const mockAbuseReport = {
similarRecordsCount: 2,
cardMatchesLink: '/admin/users/spamuser417/card_match',
},
- otherReports: [
+ pastClosedReports: [
{
category: 'offensive',
createdAt: '2023-02-28T10:09:54.982Z',
@@ -32,14 +32,27 @@ export const mockAbuseReport = {
snippetsCount: 0,
groupsCount: 0,
notesCount: 6,
- },
- reporter: {
- username: 'reporter',
- name: 'R Porter',
- avatarUrl: 'https://www.gravatar.com/avatar/a2579caffc69ea5d7606f9dd9d8504ba?s=80&d=identicon',
- path: '/reporter',
+ similarOpenReports: [
+ {
+ status: 'open',
+ message: 'This is obvious spam',
+ reportedAt: '2023-03-29T09:39:50.502Z',
+ category: 'spam',
+ type: 'issue',
+ content: '',
+ screenshot: null,
+ reporter: {
+ username: 'reporter 2',
+ name: 'Another Reporter',
+ avatarUrl: 'https://www.gravatar.com/avatar/anotherreporter',
+ path: '/reporter-2',
+ },
+ updatePath: '/admin/abuse_reports/28',
+ },
+ ],
},
report: {
+ globalId: 'gid://gitlab/AbuseReport/1',
status: 'open',
message: 'This is obvious spam',
reportedAt: '2023-03-29T09:39:50.502Z',
@@ -52,5 +65,66 @@ export const mockAbuseReport = {
'/uploads/-/system/abuse_report/screenshot/27/Screenshot_2023-03-30_at_16.56.37.png',
updatePath: '/admin/abuse_reports/27',
moderateUserPath: '/admin/abuse_reports/27/moderate_user',
+ reporter: {
+ username: 'reporter',
+ name: 'R Porter',
+ avatarUrl:
+ 'https://www.gravatar.com/avatar/a2579caffc69ea5d7606f9dd9d8504ba?s=80&d=identicon',
+ path: '/reporter',
+ },
+ },
+};
+
+export const mockLabel1 = {
+ id: 'gid://gitlab/Admin::AbuseReportLabel/1',
+ title: 'Uno',
+ color: '#F0AD4E',
+ textColor: '#FFFFFF',
+ description: null,
+};
+
+export const mockLabel2 = {
+ id: 'gid://gitlab/Admin::AbuseReportLabel/2',
+ title: 'Dos',
+ color: '#F0AD4E',
+ textColor: '#FFFFFF',
+ description: null,
+};
+
+export const mockLabelsQueryResponse = {
+ data: {
+ labels: {
+ nodes: [mockLabel1, mockLabel2],
+ __typename: 'LabelConnection',
+ },
+ },
+};
+
+export const mockReportQueryResponse = {
+ data: {
+ abuseReport: {
+ labels: {
+ nodes: [mockLabel1],
+ __typename: 'LabelConnection',
+ },
+ __typename: 'AbuseReport',
+ },
+ },
+};
+
+export const mockCreateLabelResponse = {
+ data: {
+ labelCreate: {
+ label: {
+ id: 'gid://gitlab/Admin::AbuseReportLabel/1',
+ color: '#ed9121',
+ description: null,
+ title: 'abuse report label',
+ textColor: '#FFFFFF',
+ __typename: 'Label',
+ },
+ errors: [],
+ __typename: 'AbuseReportLabelCreatePayload',
+ },
},
};