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
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-09-04 15:10:22 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-09-04 15:10:22 +0300
commit25f102516f8d77c397c768baa2e550779cc9c60b (patch)
tree1dd1bf83ad767d76933708bf948a7a7ccc6ff1ae /spec
parentd246f33754d73408224d68e81e56fc2bd6f79301 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/frontend/admin/abuse_report/components/labels_select_spec.js74
-rw-r--r--spec/frontend/admin/abuse_report/mock_data.js23
-rw-r--r--spec/frontend/environments/edit_environment_spec.js20
-rw-r--r--spec/frontend/environments/environment_form_spec.js47
-rw-r--r--spec/frontend/environments/new_environment_item_spec.js45
-rw-r--r--spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view_spec.js27
-rw-r--r--spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_footer_spec.js37
-rw-r--r--spec/frontend/vue_merge_request_widget/components/widget/app_spec.js45
-rw-r--r--spec/frontend/vue_shared/components/__snapshots__/source_editor_spec.js.snap2
-rw-r--r--spec/helpers/admin/abuse_reports_helper_spec.rb8
-rw-r--r--spec/requests/api/graphql/mutations/admin/abuse_report_labels/create_spec.rb55
-rw-r--r--spec/services/admin/abuse_report_labels/create_service_spec.rb51
-rw-r--r--spec/services/gpg_keys/destroy_service_spec.rb22
13 files changed, 335 insertions, 121 deletions
diff --git a/spec/frontend/admin/abuse_report/components/labels_select_spec.js b/spec/frontend/admin/abuse_report/components/labels_select_spec.js
index 35d378b7258..a22dcc18e10 100644
--- a/spec/frontend/admin/abuse_report/components/labels_select_spec.js
+++ b/spec/frontend/admin/abuse_report/components/labels_select_spec.js
@@ -1,17 +1,20 @@
import MockAdapter from 'axios-mock-adapter';
import { GlButton, GlDropdown, GlDropdownItem, GlLoadingIcon } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
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 } from 'helpers/stub_component';
+import { stubComponent, RENDER_ALL_SLOTS_TEMPLATE } from 'helpers/stub_component';
import labelsQuery from '~/admin/abuse_report/components/graphql/abuse_report_labels.query.graphql';
-import DropdownValue from '~/sidebar/components/labels/labels_select_widget/dropdown_value.vue';
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';
@@ -24,16 +27,20 @@ describe('Labels select component', () => {
let wrapper;
let fakeApollo;
- const selectedText = () => wrapper.find('[data-testid="selected-labels"]').text();
+ 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');
@@ -47,7 +54,7 @@ describe('Labels select component', () => {
const createComponent = ({ props = {}, labelsQueryHandler = labelsQueryHandlerSuccess } = {}) => {
fakeApollo = createMockApollo([[labelsQuery, labelsQueryHandler]]);
- wrapper = shallowMount(LabelsSelect, {
+ wrapper = shallowMountExtended(LabelsSelect, {
apolloProvider: fakeApollo,
propsData: {
report: { labels: [] },
@@ -56,11 +63,13 @@ describe('Labels select component', () => {
},
provide: {
updatePath,
+ listPath,
},
stubs: {
GlDropdown,
GlDropdownItem,
DropdownWidget: stubComponent(DropdownWidget, {
+ template: RENDER_ALL_SLOTS_TEMPLATE,
methods: { showDropdown: jest.fn() },
}),
},
@@ -102,9 +111,11 @@ describe('Labels select component', () => {
expect(findEditButton().props('disabled')).toEqual(false);
});
- it('renders fetched labels in DropdownValue', () => {
- expect(findDropdownValue().isVisible()).toBe(true);
- expect(findDropdownValue().props('selectedLabels')).toEqual([mockLabel1]);
+ 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);
});
});
});
@@ -187,6 +198,53 @@ describe('Labels select component', () => {
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', () => {
diff --git a/spec/frontend/admin/abuse_report/mock_data.js b/spec/frontend/admin/abuse_report/mock_data.js
index 4777e5b9263..ee61eabfa66 100644
--- a/spec/frontend/admin/abuse_report/mock_data.js
+++ b/spec/frontend/admin/abuse_report/mock_data.js
@@ -76,7 +76,7 @@ export const mockAbuseReport = {
};
export const mockLabel1 = {
- id: 'gid://gitlab/AbuseReportLabel/1',
+ id: 'gid://gitlab/Admin::AbuseReportLabel/1',
title: 'Uno',
color: '#F0AD4E',
textColor: '#FFFFFF',
@@ -84,7 +84,7 @@ export const mockLabel1 = {
};
export const mockLabel2 = {
- id: 'gid://gitlab/AbuseReportLabel/2',
+ id: 'gid://gitlab/Admin::AbuseReportLabel/2',
title: 'Dos',
color: '#F0AD4E',
textColor: '#FFFFFF',
@@ -93,7 +93,7 @@ export const mockLabel2 = {
export const mockLabelsQueryResponse = {
data: {
- abuseReportLabels: {
+ labels: {
nodes: [mockLabel1, mockLabel2],
__typename: 'LabelConnection',
},
@@ -111,3 +111,20 @@ export const mockReportQueryResponse = {
},
},
};
+
+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',
+ },
+ },
+};
diff --git a/spec/frontend/environments/edit_environment_spec.js b/spec/frontend/environments/edit_environment_spec.js
index b55bbb34c65..9989c946800 100644
--- a/spec/frontend/environments/edit_environment_spec.js
+++ b/spec/frontend/environments/edit_environment_spec.js
@@ -7,7 +7,6 @@ import EditEnvironment from '~/environments/components/edit_environment.vue';
import { createAlert } from '~/alert';
import { visitUrl } from '~/lib/utils/url_utility';
import getEnvironment from '~/environments/graphql/queries/environment.query.graphql';
-import getEnvironmentWithFluxResource from '~/environments/graphql/queries/environment_with_flux_resource.query.graphql';
import updateEnvironment from '~/environments/graphql/mutations/update_environment.mutation.graphql';
import { __ } from '~/locale';
import createMockApollo from '../__helpers__/mock_apollo_helper';
@@ -44,9 +43,6 @@ describe('~/environments/components/edit.vue', () => {
let wrapper;
const getEnvironmentQuery = jest.fn().mockResolvedValue({ data: resolvedEnvironment });
- const getEnvironmentWithFluxResourceQuery = jest
- .fn()
- .mockResolvedValue({ data: resolvedEnvironment });
const updateEnvironmentSuccess = jest
.fn()
@@ -60,24 +56,17 @@ describe('~/environments/components/edit.vue', () => {
const mocks = [
[getEnvironment, getEnvironmentQuery],
- [getEnvironmentWithFluxResource, getEnvironmentWithFluxResourceQuery],
[updateEnvironment, mutationHandler],
];
return createMockApollo(mocks);
};
- const createWrapperWithApollo = async ({
- mutationHandler = updateEnvironmentSuccess,
- fluxResourceForEnvironment = false,
- } = {}) => {
+ const createWrapperWithApollo = async ({ mutationHandler = updateEnvironmentSuccess } = {}) => {
wrapper = mountExtended(EditEnvironment, {
propsData: { environment: {} },
provide: {
...provide,
- glFeatures: {
- fluxResourceForEnvironment,
- },
},
apolloProvider: createMockApolloProvider(mutationHandler),
});
@@ -170,11 +159,4 @@ describe('~/environments/components/edit.vue', () => {
});
});
});
-
- describe('when `fluxResourceForEnvironment` is enabled', () => {
- it('calls the `getEnvironmentWithFluxResource` query', () => {
- createWrapperWithApollo({ fluxResourceForEnvironment: true });
- expect(getEnvironmentWithFluxResourceQuery).toHaveBeenCalled();
- });
- });
});
diff --git a/spec/frontend/environments/environment_form_spec.js b/spec/frontend/environments/environment_form_spec.js
index 1b80b596db7..22dd7437d82 100644
--- a/spec/frontend/environments/environment_form_spec.js
+++ b/spec/frontend/environments/environment_form_spec.js
@@ -53,11 +53,7 @@ describe('~/environments/components/form.vue', () => {
},
});
- const createWrapperWithApollo = ({
- propsData = {},
- fluxResourceForEnvironment = false,
- queryResult = null,
- } = {}) => {
+ const createWrapperWithApollo = ({ propsData = {}, queryResult = null } = {}) => {
Vue.use(VueApollo);
const requestHandlers = [
@@ -83,9 +79,6 @@ describe('~/environments/components/form.vue', () => {
return mountExtended(EnvironmentForm, {
provide: {
...PROVIDE,
- glFeatures: {
- fluxResourceForEnvironment,
- },
},
propsData: {
...DEFAULT_PROPS,
@@ -422,39 +415,30 @@ describe('~/environments/components/form.vue', () => {
});
describe('flux resource selector', () => {
- it("doesn't render if `fluxResourceForEnvironment` feature flag is disabled", () => {
+ beforeEach(() => {
wrapper = createWrapperWithApollo();
+ });
+
+ it("doesn't render flux resource selector by default", () => {
expect(findFluxResourceSelector().exists()).toBe(false);
});
- describe('when `fluxResourceForEnvironment` feature flag is enabled', () => {
- beforeEach(() => {
- wrapper = createWrapperWithApollo({
- fluxResourceForEnvironment: true,
- });
+ describe('when the agent was selected', () => {
+ beforeEach(async () => {
+ await selectAgent();
});
- it("doesn't render flux resource selector by default", () => {
+ it("doesn't render flux resource selector", () => {
expect(findFluxResourceSelector().exists()).toBe(false);
});
- describe('when the agent was selected', () => {
- beforeEach(async () => {
- await selectAgent();
- });
-
- it("doesn't render flux resource selector", () => {
- expect(findFluxResourceSelector().exists()).toBe(false);
- });
-
- it('renders the flux resource selector when the namespace is selected', async () => {
- await findNamespaceSelector().vm.$emit('select', 'agent');
+ it('renders the flux resource selector when the namespace is selected', async () => {
+ await findNamespaceSelector().vm.$emit('select', 'agent');
- expect(findFluxResourceSelector().props()).toEqual({
- namespace: 'agent',
- fluxResourcePath: '',
- configuration,
- });
+ expect(findFluxResourceSelector().props()).toEqual({
+ namespace: 'agent',
+ fluxResourcePath: '',
+ configuration,
});
});
});
@@ -522,7 +506,6 @@ describe('~/environments/components/form.vue', () => {
beforeEach(() => {
wrapper = createWrapperWithApollo({
propsData: { environment: environmentWithAgentAndNamespace },
- fluxResourceForEnvironment: true,
});
});
diff --git a/spec/frontend/environments/new_environment_item_spec.js b/spec/frontend/environments/new_environment_item_spec.js
index bfcc4f4ebb6..7ee31bf2c62 100644
--- a/spec/frontend/environments/new_environment_item_spec.js
+++ b/spec/frontend/environments/new_environment_item_spec.js
@@ -13,7 +13,6 @@ import Deployment from '~/environments/components/deployment.vue';
import DeployBoardWrapper from '~/environments/components/deploy_board_wrapper.vue';
import KubernetesOverview from '~/environments/components/kubernetes_overview.vue';
import getEnvironmentClusterAgent from '~/environments/graphql/queries/environment_cluster_agent.query.graphql';
-import getEnvironmentClusterAgentWithFluxResource from '~/environments/graphql/queries/environment_cluster_agent_with_flux_resource.query.graphql';
import {
resolvedEnvironment,
rolloutStatus,
@@ -27,7 +26,6 @@ Vue.use(VueApollo);
describe('~/environments/components/new_environment_item.vue', () => {
let wrapper;
let queryResponseHandler;
- let queryWithFluxResourceResponseHandler;
const projectPath = '/1';
@@ -39,27 +37,14 @@ describe('~/environments/components/new_environment_item.vue', () => {
environment: {
id: '1',
kubernetesNamespace: 'default',
+ fluxResourcePath: fluxResourcePathMock,
clusterAgent,
},
},
},
};
queryResponseHandler = jest.fn().mockResolvedValue(response);
- queryWithFluxResourceResponseHandler = jest.fn().mockResolvedValue({
- data: {
- project: {
- id: response.data.project.id,
- environment: {
- ...response.data.project.environment,
- fluxResourcePath: fluxResourcePathMock,
- },
- },
- },
- });
- return createMockApollo([
- [getEnvironmentClusterAgent, queryResponseHandler],
- [getEnvironmentClusterAgentWithFluxResource, queryWithFluxResourceResponseHandler],
- ]);
+ return createMockApollo([[getEnvironmentClusterAgent, queryResponseHandler]]);
};
const createWrapper = ({ propsData = {}, provideData = {}, apolloProvider } = {}) =>
@@ -554,25 +539,6 @@ describe('~/environments/components/new_environment_item.vue', () => {
});
});
- it('should request agent data with Flux resource when `fluxResourceForEnvironment` feature flag is enabled', async () => {
- wrapper = createWrapper({
- propsData: { environment: resolvedEnvironment },
- provideData: {
- glFeatures: {
- fluxResourceForEnvironment: true,
- },
- },
- apolloProvider: createApolloProvider(agent),
- });
-
- await expandCollapsedSection();
-
- expect(queryWithFluxResourceResponseHandler).toHaveBeenCalledWith({
- environmentName: resolvedEnvironment.name,
- projectFullPath: projectPath,
- });
- });
-
it('should render if the environment has an agent associated', async () => {
wrapper = createWrapper({
propsData: { environment: resolvedEnvironment },
@@ -588,14 +554,9 @@ describe('~/environments/components/new_environment_item.vue', () => {
});
});
- it('should render with the namespace if `fluxResourceForEnvironment` feature flag is enabled and the environment has an agent associated', async () => {
+ it('should render with the namespace if the environment has an agent associated', async () => {
wrapper = createWrapper({
propsData: { environment: resolvedEnvironment },
- provideData: {
- glFeatures: {
- fluxResourceForEnvironment: true,
- },
- },
apolloProvider: createApolloProvider(agent),
});
diff --git a/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view_spec.js b/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view_spec.js
index 6de113ba1f9..5e2ff73878f 100644
--- a/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view_spec.js
+++ b/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view_spec.js
@@ -5,11 +5,14 @@ import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { createAlert } from '~/alert';
-import { workspaceLabelsQueries } from '~/sidebar/queries/constants';
+import { workspaceLabelsQueries, workspaceCreateLabelMutation } from '~/sidebar/queries/constants';
import DropdownContentsCreateView from '~/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view.vue';
-import createLabelMutation from '~/sidebar/components/labels/labels_select_widget/graphql/create_label.mutation.graphql';
import { DEFAULT_LABEL_COLOR } from '~/sidebar/components/labels/labels_select_widget/constants';
import {
+ mockCreateLabelResponse as createAbuseReportLabelSuccessfulResponse,
+ mockLabelsQueryResponse as abuseReportLabelsQueryResponse,
+} from '../../../../admin/abuse_report/mock_data';
+import {
mockRegularLabel,
mockSuggestedColors,
createLabelSuccessfulResponse,
@@ -38,6 +41,9 @@ const titleTakenError = {
};
const createLabelSuccessHandler = jest.fn().mockResolvedValue(createLabelSuccessfulResponse);
+const createAbuseReportLabelSuccessHandler = jest
+ .fn()
+ .mockResolvedValue(createAbuseReportLabelSuccessfulResponse);
const createLabelUserRecoverableErrorHandler = jest.fn().mockResolvedValue(userRecoverableError);
const createLabelDuplicateErrorHandler = jest.fn().mockResolvedValue(titleTakenError);
const createLabelErrorHandler = jest.fn().mockRejectedValue('Houston, we have a problem');
@@ -66,6 +72,7 @@ describe('DropdownContentsCreateView', () => {
labelsResponse = workspaceLabelsQueryResponse,
searchTerm = '',
} = {}) => {
+ const createLabelMutation = workspaceCreateLabelMutation[workspaceType];
const mockApollo = createMockApollo([[createLabelMutation, mutationHandler]]);
mockApollo.clients.defaultClient.cache.writeQuery({
query: workspaceLabelsQueries[workspaceType].query,
@@ -203,6 +210,22 @@ describe('DropdownContentsCreateView', () => {
});
});
+ it('calls the correct mutation when workspaceType is `abuseReport`', () => {
+ createComponent({
+ mutationHandler: createAbuseReportLabelSuccessHandler,
+ labelCreateType: '',
+ workspaceType: 'abuseReport',
+ labelsResponse: abuseReportLabelsQueryResponse,
+ });
+ fillLabelAttributes();
+ findCreateButton().vm.$emit('click');
+
+ expect(createAbuseReportLabelSuccessHandler).toHaveBeenCalledWith({
+ color: '#009966',
+ title: 'Test title',
+ });
+ });
+
it('calls createAlert is mutation has a user-recoverable error', async () => {
createComponent({ mutationHandler: createLabelUserRecoverableErrorHandler });
fillLabelAttributes();
diff --git a/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_footer_spec.js b/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_footer_spec.js
index ad1edaa6671..7a1131b8cce 100644
--- a/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_footer_spec.js
+++ b/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_footer_spec.js
@@ -1,12 +1,11 @@
-import { shallowMount } from '@vue/test-utils';
-import { nextTick } from 'vue';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import DropdownFooter from '~/sidebar/components/labels/labels_select_widget/dropdown_footer.vue';
describe('DropdownFooter', () => {
let wrapper;
const createComponent = ({ props = {}, injected = {} } = {}) => {
- wrapper = shallowMount(DropdownFooter, {
+ wrapper = shallowMountExtended(DropdownFooter, {
propsData: {
footerCreateLabelTitle: 'create',
footerManageLabelTitle: 'manage',
@@ -20,7 +19,8 @@ describe('DropdownFooter', () => {
});
};
- const findCreateLabelButton = () => wrapper.find('[data-testid="create-label-button"]');
+ const findCreateLabelButton = () => wrapper.findByTestId('create-label-button');
+ const findManageLabelsButton = () => wrapper.findByTestId('manage-labels-button');
describe('Labels view', () => {
beforeEach(() => {
@@ -42,12 +42,37 @@ describe('DropdownFooter', () => {
expect(findCreateLabelButton().exists()).toBe(true);
});
- it('emits `toggleDropdownContentsCreateView` event on create label button click', async () => {
+ it('emits `toggleDropdownContentsCreateView` event on create label button click', () => {
findCreateLabelButton().trigger('click');
- await nextTick();
expect(wrapper.emitted('toggleDropdownContentsCreateView')).toEqual([[]]);
});
});
+
+ describe('manage labels button', () => {
+ it('is rendered', () => {
+ expect(findManageLabelsButton().exists()).toBe(true);
+ });
+
+ describe('when footerManageLabelTitle is not given', () => {
+ beforeEach(() => {
+ createComponent({ props: { footerManageLabelTitle: undefined } });
+ });
+
+ it('does not render manage labels button', () => {
+ expect(findManageLabelsButton().exists()).toBe(false);
+ });
+ });
+
+ describe('when labelsManagePath is not provided', () => {
+ beforeEach(() => {
+ createComponent({ injected: { labelsManagePath: '' } });
+ });
+
+ it('does not render manage labels button', () => {
+ expect(findManageLabelsButton().exists()).toBe(false);
+ });
+ });
+ });
});
});
diff --git a/spec/frontend/vue_merge_request_widget/components/widget/app_spec.js b/spec/frontend/vue_merge_request_widget/components/widget/app_spec.js
index bf318cd6b88..205824c3edd 100644
--- a/spec/frontend/vue_merge_request_widget/components/widget/app_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/widget/app_spec.js
@@ -1,13 +1,23 @@
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import waitForPromises from 'helpers/wait_for_promises';
import App from '~/vue_merge_request_widget/components/widget/app.vue';
+import MrSecurityWidgetCE from '~/vue_merge_request_widget/extensions/security_reports/mr_widget_security_reports.vue';
+import MrTestReportWidget from '~/vue_merge_request_widget/extensions/test_report/index.vue';
+import MrTerraformWidget from '~/vue_merge_request_widget/extensions/terraform/index.vue';
+import MrCodeQualityWidget from '~/vue_merge_request_widget/extensions/code_quality/index.vue';
describe('MR Widget App', () => {
let wrapper;
- const createComponent = () => {
+ const createComponent = ({ mr = {} } = {}) => {
wrapper = shallowMountExtended(App, {
propsData: {
- mr: {},
+ mr: {
+ pipeline: {
+ path: '/path/to/pipeline',
+ },
+ ...mr,
+ },
},
});
};
@@ -16,4 +26,35 @@ describe('MR Widget App', () => {
createComponent();
expect(wrapper.findByTestId('mr-widget-app').exists()).toBe(true);
});
+
+ describe('MRSecurityWidget', () => {
+ it('mounts MrSecurityWidgetCE', async () => {
+ createComponent();
+
+ await waitForPromises();
+
+ expect(wrapper.findComponent(MrSecurityWidgetCE).exists()).toBe(true);
+ });
+ });
+
+ describe.each`
+ widgetName | widget | endpoint
+ ${'testReportWidget'} | ${MrTestReportWidget} | ${'testResultsPath'}
+ ${'terraformPlansWidget'} | ${MrTerraformWidget} | ${'terraformReportsPath'}
+ ${'codeQualityWidget'} | ${MrCodeQualityWidget} | ${'codequalityReportsPath'}
+ `('$widgetName', ({ widget, endpoint }) => {
+ it(`is mounted when ${endpoint} is defined`, async () => {
+ createComponent({ mr: { [endpoint]: `path/to/${endpoint}` } });
+ await waitForPromises();
+
+ expect(wrapper.findComponent(widget).exists()).toBe(true);
+ });
+
+ it(`is not mounted when ${endpoint} is not defined`, async () => {
+ createComponent();
+ await waitForPromises();
+
+ expect(wrapper.findComponent(widget).exists()).toBe(false);
+ });
+ });
});
diff --git a/spec/frontend/vue_shared/components/__snapshots__/source_editor_spec.js.snap b/spec/frontend/vue_shared/components/__snapshots__/source_editor_spec.js.snap
index d60fc4cb043..76deb4d0b36 100644
--- a/spec/frontend/vue_shared/components/__snapshots__/source_editor_spec.js.snap
+++ b/spec/frontend/vue_shared/components/__snapshots__/source_editor_spec.js.snap
@@ -3,7 +3,7 @@
exports[`Source Editor component rendering matches the snapshot 1`] = `
<div
data-editor-loading=""
- data-qa-selector="source_editor_container"
+ data-testid="source-editor-container"
id="reference-0"
>
<pre
diff --git a/spec/helpers/admin/abuse_reports_helper_spec.rb b/spec/helpers/admin/abuse_reports_helper_spec.rb
index 6a7630dc76a..d6f102682ba 100644
--- a/spec/helpers/admin/abuse_reports_helper_spec.rb
+++ b/spec/helpers/admin/abuse_reports_helper_spec.rb
@@ -25,10 +25,14 @@ RSpec.describe Admin::AbuseReportsHelper, feature_category: :insider_threat do
describe '#abuse_report_data' do
let(:report) { build_stubbed(:abuse_report) }
- subject(:data) { helper.abuse_report_data(report)[:abuse_report_data] }
+ subject(:data) { helper.abuse_report_data(report) }
it 'has the expected attributes' do
- expect(data).to include('user', 'reporter', 'report')
+ expect(data[:abuse_report_data]).to include('user', 'reporter', 'report')
+ end
+
+ it 'includes path to abuse reports list page' do
+ expect(data[:abuse_reports_list_path]).to eq admin_abuse_reports_path
end
end
end
diff --git a/spec/requests/api/graphql/mutations/admin/abuse_report_labels/create_spec.rb b/spec/requests/api/graphql/mutations/admin/abuse_report_labels/create_spec.rb
new file mode 100644
index 00000000000..2a20d96d9c8
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/admin/abuse_report_labels/create_spec.rb
@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::Admin::AbuseReportLabels::Create, feature_category: :insider_threat do
+ include GraphqlHelpers
+
+ let(:params) do
+ {
+ 'title' => 'foo',
+ 'color' => '#FF0000'
+ }
+ end
+
+ let(:mutation) { graphql_mutation(:abuse_report_label_create, params) }
+
+ subject { post_graphql_mutation(mutation, current_user: current_user) }
+
+ def mutation_response
+ graphql_mutation_response(:abuse_report_label_create)
+ end
+
+ context 'when the user does not have permission to create a label', :enable_admin_mode do
+ let_it_be(:current_user) { create(:user) }
+
+ it_behaves_like 'a mutation that returns a top-level access error'
+
+ it 'does not create the label' do
+ expect { subject }.not_to change { Admin::AbuseReportLabel.count }
+ end
+ end
+
+ context 'when the user has permission to create a label', :enable_admin_mode do
+ let_it_be(:current_user) { create(:admin) }
+
+ it 'creates the label' do
+ expect { subject }.to change { Admin::AbuseReportLabel.count }.to(1)
+
+ expect(mutation_response).to include('label' => a_hash_including(params))
+ end
+
+ context 'when there are errors' do
+ it 'does not create the label', :aggregate_failures do
+ create(:abuse_report_label, title: params['title'])
+
+ expect { subject }.not_to change { Label.count }
+
+ expect(mutation_response).to include({
+ 'label' => nil,
+ 'errors' => ['Title has already been taken']
+ })
+ end
+ end
+ end
+end
diff --git a/spec/services/admin/abuse_report_labels/create_service_spec.rb b/spec/services/admin/abuse_report_labels/create_service_spec.rb
new file mode 100644
index 00000000000..168229d6ed9
--- /dev/null
+++ b/spec/services/admin/abuse_report_labels/create_service_spec.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Admin::AbuseReportLabels::CreateService, feature_category: :insider_threat do
+ describe '#execute' do
+ let(:color) { 'red' }
+ let(:color_in_hex) { ::Gitlab::Color.of(color) }
+ let(:params) { { title: 'FancyLabel', color: color } }
+
+ subject(:execute) { described_class.new(params).execute }
+
+ shared_examples 'creates a label with the correct values' do
+ it 'creates a label with the correct values', :aggregate_failures do
+ expect { execute }.to change { Admin::AbuseReportLabel.count }.from(0).to(1)
+
+ label = Admin::AbuseReportLabel.last
+ expect(label.title).to eq params[:title]
+ expect(label.color).to eq color_in_hex
+ end
+
+ it 'returns the persisted label' do
+ result = execute
+ expect(result).to be_an_instance_of(Admin::AbuseReportLabel)
+ expect(result.persisted?).to eq true
+ end
+ end
+
+ it_behaves_like 'creates a label with the correct values'
+
+ context 'without color param' do
+ let(:params) { { title: 'FancyLabel' } }
+ let(:color_in_hex) { ::Gitlab::Color.of(Label::DEFAULT_COLOR) }
+
+ it_behaves_like 'creates a label with the correct values'
+ end
+
+ context 'with errors' do
+ let!(:existing_label) { create(:abuse_report_label, title: params[:title]) }
+
+ it 'does not create the label' do
+ expect { execute }.not_to change { Admin::AbuseReportLabel.count }
+ end
+
+ it 'returns the label with errors' do
+ label = execute
+ expect(label.errors.messages).to include({ title: ["has already been taken"] })
+ end
+ end
+ end
+end
diff --git a/spec/services/gpg_keys/destroy_service_spec.rb b/spec/services/gpg_keys/destroy_service_spec.rb
index b9aa3e351c9..85c1fc2893b 100644
--- a/spec/services/gpg_keys/destroy_service_spec.rb
+++ b/spec/services/gpg_keys/destroy_service_spec.rb
@@ -2,14 +2,28 @@
require 'spec_helper'
-RSpec.describe GpgKeys::DestroyService do
- let(:user) { create(:user) }
+RSpec.describe GpgKeys::DestroyService, feature_category: :source_code_management do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:gpg_key) { create(:gpg_key) }
subject { described_class.new(user) }
it 'destroys the GPG key' do
- gpg_key = create(:gpg_key)
-
expect { subject.execute(gpg_key) }.to change(GpgKey, :count).by(-1)
end
+
+ it 'nullifies the related signatures in batches' do
+ stub_const("#{described_class}::BATCH_SIZE", 1)
+
+ first_signature = create(:gpg_signature, gpg_key: gpg_key)
+ second_signature = create(:gpg_signature, gpg_key: gpg_key)
+ third_signature = create(:gpg_signature, gpg_key: create(:another_gpg_key))
+
+ control = ActiveRecord::QueryRecorder.new { subject.execute(gpg_key) }
+ expect(control.count).to eq(5)
+
+ expect(first_signature.reload.gpg_key).to be_nil
+ expect(second_signature.reload.gpg_key).to be_nil
+ expect(third_signature.reload.gpg_key).not_to be_nil
+ end
end