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-01-23 15:08:48 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-01-23 15:08:48 +0300
commit8137303e47baaff97a36396cfb05efc0d99879a2 (patch)
tree89dc777fd2d63e259e4b8b2d781baf472d3429a0 /spec
parent5b1258ee90fb29779d6c9da3f488ebff61e243a3 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/db/schema_spec.rb2
-rw-r--r--spec/features/abuse_report_spec.rb4
-rw-r--r--spec/features/projects/settings/packages_settings_spec.rb35
-rw-r--r--spec/frontend/abuse_reports/components/abuse_category_selector_spec.js8
-rw-r--r--spec/frontend/boards/components/sidebar/board_sidebar_title_spec.js11
-rw-r--r--spec/frontend/issues/show/components/header_actions_spec.js2
-rw-r--r--spec/frontend/notes/components/note_actions_spec.js58
-rw-r--r--spec/frontend/notes/components/noteable_note_spec.js7
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/functional/delete_packages_spec.js (renamed from spec/frontend/packages_and_registries/package_registry/components/functional/delete_package_spec.js)78
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/list/packages_list_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/package_registry/mock_data.js27
-rw-r--r--spec/frontend/packages_and_registries/package_registry/pages/details_spec.js10
-rw-r--r--spec/frontend/packages_and_registries/package_registry/pages/list_spec.js75
-rw-r--r--spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js237
-rw-r--r--spec/frontend/projects/merge_requests/components/report_abuse_dropdown_item_spec.js2
-rw-r--r--spec/frontend/users/profile/components/report_abuse_button_spec.js2
-rw-r--r--spec/frontend/vue_shared/security_reports/store/utils_spec.js63
-rw-r--r--spec/models/ci/build_metadata_spec.rb4
-rw-r--r--spec/models/ci/runner_machine_spec.rb1
-rw-r--r--spec/policies/packages/policies/project_policy_spec.rb33
-rw-r--r--spec/requests/abuse_reports_controller_spec.rb38
-rw-r--r--spec/requests/api/internal/kubernetes_spec.rb2
-rw-r--r--spec/support/shared_examples/features/reportable_note_shared_examples.rb20
23 files changed, 370 insertions, 353 deletions
diff --git a/spec/db/schema_spec.rb b/spec/db/schema_spec.rb
index 4c2383292c7..4af901e4cf6 100644
--- a/spec/db/schema_spec.rb
+++ b/spec/db/schema_spec.rb
@@ -39,7 +39,7 @@ RSpec.describe 'Database schema', feature_category: :database do
ci_build_trace_metadata: %w[partition_id],
ci_builds: %w[erased_by_id trigger_request_id partition_id],
ci_builds_runner_session: %w[partition_id],
- p_ci_builds_metadata: %w[partition_id runner_machine_id], # NOTE: FK will be added in follow-up https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108167
+ p_ci_builds_metadata: %w[partition_id],
ci_job_artifacts: %w[partition_id],
ci_job_variables: %w[partition_id],
ci_namespace_monthly_usages: %w[namespace_id],
diff --git a/spec/features/abuse_report_spec.rb b/spec/features/abuse_report_spec.rb
index e0a61656a88..31b86244dd1 100644
--- a/spec/features/abuse_report_spec.rb
+++ b/spec/features/abuse_report_spec.rb
@@ -82,7 +82,7 @@ RSpec.describe 'Abuse reports', :js, feature_category: :insider_threat do
visit user_path(abusive_user)
- fill_and_submit_abuse_category_form("They're being offsensive or abusive.")
+ fill_and_submit_abuse_category_form("They're being offensive or abusive.")
fill_and_submit_report_abuse_form
expect(page).to have_content 'Thank you for your report'
@@ -136,7 +136,7 @@ RSpec.describe 'Abuse reports', :js, feature_category: :insider_threat do
click_button 'More actions'
end
- it_behaves_like 'reports the user without an abuse category'
+ it_behaves_like 'reports the user with an abuse category'
end
end
diff --git a/spec/features/projects/settings/packages_settings_spec.rb b/spec/features/projects/settings/packages_settings_spec.rb
index 4ef17830f81..bf5c779b109 100644
--- a/spec/features/projects/settings/packages_settings_spec.rb
+++ b/spec/features/projects/settings/packages_settings_spec.rb
@@ -11,7 +11,6 @@ RSpec.describe 'Projects > Settings > Packages', :js, feature_category: :project
sign_in(user)
stub_config(packages: { enabled: packages_enabled })
- stub_feature_flags(package_registry_access_level: package_registry_access_level)
visit edit_project_path(project)
end
@@ -19,35 +18,21 @@ RSpec.describe 'Projects > Settings > Packages', :js, feature_category: :project
context 'Packages enabled in config' do
let(:packages_enabled) { true }
- context 'with feature flag disabled' do
- let(:package_registry_access_level) { false }
-
- it 'displays the packages toggle button' do
- expect(page).to have_selector('[data-testid="toggle-label"]', text: 'Packages')
- expect(page).to have_selector('input[name="project[packages_enabled]"] + button', visible: true)
- end
- end
-
- context 'with feature flag enabled' do
- let(:package_registry_access_level) { true }
-
- it 'displays the packages access level setting' do
- expect(page).to have_selector('[data-testid="package-registry-access-level"] > label', text: 'Package registry')
- expect(page).to have_selector('input[name="package_registry_enabled"]', visible: false)
- expect(page).to have_selector('input[name="package_registry_enabled"] + button', visible: true)
- expect(page).to have_selector('input[name="package_registry_api_for_everyone_enabled"]', visible: false)
- expect(page).to have_selector('input[name="package_registry_api_for_everyone_enabled"] + button', visible: true)
- expect(page).to have_selector(
- 'input[name="project[project_feature_attributes][package_registry_access_level]"]',
- visible: false
- )
- end
+ it 'displays the packages access level setting' do
+ expect(page).to have_selector('[data-testid="package-registry-access-level"] > label', text: 'Package registry')
+ expect(page).to have_selector('input[name="package_registry_enabled"]', visible: false)
+ expect(page).to have_selector('input[name="package_registry_enabled"] + button', visible: true)
+ expect(page).to have_selector('input[name="package_registry_api_for_everyone_enabled"]', visible: false)
+ expect(page).to have_selector('input[name="package_registry_api_for_everyone_enabled"] + button', visible: true)
+ expect(page).to have_selector(
+ 'input[name="project[project_feature_attributes][package_registry_access_level]"]',
+ visible: false
+ )
end
end
context 'Packages disabled in config' do
let(:packages_enabled) { false }
- let(:package_registry_access_level) { false }
it 'does not show up in UI' do
expect(page).not_to have_selector('[data-testid="toggle-label"]', text: 'Packages')
diff --git a/spec/frontend/abuse_reports/components/abuse_category_selector_spec.js b/spec/frontend/abuse_reports/components/abuse_category_selector_spec.js
index 6efd9fb1dd0..3383a5c86ec 100644
--- a/spec/frontend/abuse_reports/components/abuse_category_selector_spec.js
+++ b/spec/frontend/abuse_reports/components/abuse_category_selector_spec.js
@@ -13,18 +13,18 @@ describe('AbuseCategorySelector', () => {
let wrapper;
const ACTION_PATH = '/abuse_reports/add_category';
- const USER_ID = '1';
+ const USER_ID = 1;
const REPORTED_FROM_URL = 'http://example.com';
const createComponent = (props) => {
wrapper = shallowMountExtended(AbuseCategorySelector, {
propsData: {
+ reportedUserId: USER_ID,
+ reportedFromUrl: REPORTED_FROM_URL,
...props,
},
provide: {
reportAbusePath: ACTION_PATH,
- reportedUserId: USER_ID,
- reportedFromUrl: REPORTED_FROM_URL,
},
});
};
@@ -106,7 +106,7 @@ describe('AbuseCategorySelector', () => {
expect(findUserId().attributes()).toMatchObject({
type: 'hidden',
name: 'user_id',
- value: USER_ID,
+ value: `${USER_ID}`,
});
});
diff --git a/spec/frontend/boards/components/sidebar/board_sidebar_title_spec.js b/spec/frontend/boards/components/sidebar/board_sidebar_title_spec.js
index cc1e5de15c1..bc66a0515aa 100644
--- a/spec/frontend/boards/components/sidebar/board_sidebar_title_spec.js
+++ b/spec/frontend/boards/components/sidebar/board_sidebar_title_spec.js
@@ -1,4 +1,4 @@
-import { GlAlert, GlFormInput, GlForm } from '@gitlab/ui';
+import { GlAlert, GlFormInput, GlForm, GlLink } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue';
import BoardEditableItem from '~/boards/components/sidebar/board_editable_item.vue';
@@ -11,12 +11,14 @@ const TEST_ISSUE_A = {
iid: 8,
title: 'Issue 1',
referencePath: 'h/b#1',
+ webUrl: 'webUrl',
};
const TEST_ISSUE_B = {
id: 'gid://gitlab/Issue/2',
iid: 9,
title: 'Issue 2',
referencePath: 'h/b#2',
+ webUrl: 'webUrl',
};
describe('~/boards/components/sidebar/board_sidebar_title.vue', () => {
@@ -49,6 +51,7 @@ describe('~/boards/components/sidebar/board_sidebar_title.vue', () => {
const findForm = () => wrapper.findComponent(GlForm);
const findAlert = () => wrapper.findComponent(GlAlert);
const findFormInput = () => wrapper.findComponent(GlFormInput);
+ const findGlLink = () => wrapper.findComponent(GlLink);
const findEditableItem = () => wrapper.findComponent(BoardEditableItem);
const findCancelButton = () => wrapper.find('[data-testid="cancel-button"]');
const findTitle = () => wrapper.find('[data-testid="item-title"]');
@@ -67,6 +70,12 @@ describe('~/boards/components/sidebar/board_sidebar_title.vue', () => {
expect(findAlert().exists()).toBe(false);
});
+ it('links title to the corresponding issue', () => {
+ createWrapper();
+
+ expect(findGlLink().attributes('href')).toBe('webUrl');
+ });
+
describe('when new title is submitted', () => {
beforeEach(async () => {
createWrapper();
diff --git a/spec/frontend/issues/show/components/header_actions_spec.js b/spec/frontend/issues/show/components/header_actions_spec.js
index aaf228ae181..8a0fdcb50d0 100644
--- a/spec/frontend/issues/show/components/header_actions_spec.js
+++ b/spec/frontend/issues/show/components/header_actions_spec.js
@@ -40,7 +40,7 @@ describe('HeaderActions component', () => {
newIssuePath: 'gitlab-org/gitlab-test/-/issues/new',
projectPath: 'gitlab-org/gitlab-test',
reportAbusePath: '-/abuse_reports/add_category',
- reportedUserId: '1',
+ reportedUserId: 1,
reportedFromUrl: 'http://localhost:/gitlab-org/-/issues/32',
submitAsSpamPath: 'gitlab-org/gitlab-test/-/issues/32/submit_as_spam',
};
diff --git a/spec/frontend/notes/components/note_actions_spec.js b/spec/frontend/notes/components/note_actions_spec.js
index c7420ca9c48..d95e357f24c 100644
--- a/spec/frontend/notes/components/note_actions_spec.js
+++ b/spec/frontend/notes/components/note_actions_spec.js
@@ -7,6 +7,7 @@ import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
import noteActions from '~/notes/components/note_actions.vue';
import { NOTEABLE_TYPE_MAPPING } from '~/notes/constants';
import TimelineEventButton from '~/notes/components/note_actions/timeline_event_button.vue';
+import AbuseCategorySelector from '~/abuse_reports/components/abuse_category_selector.vue';
import createStore from '~/notes/stores';
import UserAccessRoleBadge from '~/vue_shared/components/user_access_role_badge.vue';
import { userDataMock } from '../mock_data';
@@ -21,6 +22,7 @@ describe('noteActions', () => {
const findUserAccessRoleBadge = (idx) => wrapper.findAllComponents(UserAccessRoleBadge).at(idx);
const findUserAccessRoleBadgeText = (idx) => findUserAccessRoleBadge(idx).text().trim();
const findTimelineButton = () => wrapper.findComponent(TimelineEventButton);
+ const findReportAbuseButton = () => wrapper.find(`[data-testid="report-abuse-button"]`);
const setupStoreForIncidentTimelineEvents = ({
userCanAdd,
@@ -63,7 +65,6 @@ describe('noteActions', () => {
noteId: '539',
noteUrl: `${TEST_HOST}/group/project/-/merge_requests/1#note_1`,
projectName: 'project',
- reportAbusePath: `${TEST_HOST}/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%3A3000%2Fgitlab-org%2Fgitlab-ce%2Fissues%2F7%23note_539&user_id=26`,
showReply: false,
awardPath: `${TEST_HOST}/award_emoji`,
};
@@ -115,7 +116,7 @@ describe('noteActions', () => {
});
it('should be possible to report abuse to admin', () => {
- expect(wrapper.find(`a[href="${props.reportAbusePath}"]`).exists()).toBe(true);
+ expect(findReportAbuseButton().exists()).toBe(true);
});
it('should be possible to copy link to a note', () => {
@@ -373,4 +374,57 @@ describe('noteActions', () => {
});
});
});
+
+ describe('report abuse button', () => {
+ const findAbuseCategorySelector = () => wrapper.findComponent(AbuseCategorySelector);
+
+ describe('when user is not allowed to report abuse', () => {
+ beforeEach(() => {
+ store.dispatch('setUserData', userDataMock);
+ wrapper = mountNoteActions({ ...props, canReportAsAbuse: false });
+ });
+
+ it('does not render the report abuse', () => {
+ expect(findReportAbuseButton().exists()).toBe(false);
+ });
+
+ it('does not render the abuse category drawer', () => {
+ expect(findAbuseCategorySelector().exists()).toBe(false);
+ });
+ });
+
+ describe('when user is allowed to report abuse', () => {
+ beforeEach(() => {
+ store.dispatch('setUserData', userDataMock);
+ wrapper = mountNoteActions({ ...props, canReportAsAbuse: true });
+ });
+
+ it('renders report abuse button', () => {
+ expect(findReportAbuseButton().exists()).toBe(true);
+ });
+
+ it('renders abuse category drawer', () => {
+ expect(findAbuseCategorySelector().exists()).toBe(true);
+ expect(findAbuseCategorySelector().props()).toMatchObject({
+ showDrawer: false,
+ reportedUserId: props.authorId,
+ reportedFromUrl: props.noteUrl,
+ });
+ });
+
+ it('opens the drawer when report abuse button is clicked', async () => {
+ findReportAbuseButton().trigger('click');
+
+ await nextTick();
+
+ expect(findAbuseCategorySelector().props('showDrawer')).toEqual(true);
+ });
+
+ it('closes the drawer', async () => {
+ await findAbuseCategorySelector().vm.$emit('close-drawer');
+
+ expect(findAbuseCategorySelector().props('showDrawer')).toEqual(false);
+ });
+ });
+ });
});
diff --git a/spec/frontend/notes/components/noteable_note_spec.js b/spec/frontend/notes/components/noteable_note_spec.js
index 3d7195752d3..af1b4f64037 100644
--- a/spec/frontend/notes/components/noteable_note_spec.js
+++ b/spec/frontend/notes/components/noteable_note_spec.js
@@ -34,6 +34,9 @@ const singleLineNotePosition = {
describe('issue_note', () => {
let store;
let wrapper;
+
+ const REPORT_ABUSE_PATH = '/abuse_reports/add_category';
+
const findMultilineComment = () => wrapper.find('[data-testid="multiline-comment"]');
const createWrapper = (props = {}, storeUpdater = (s) => s) => {
@@ -62,6 +65,9 @@ describe('issue_note', () => {
'note-body',
'multiline-comment-form',
],
+ provide: {
+ reportAbusePath: REPORT_ABUSE_PATH,
+ },
});
};
@@ -241,7 +247,6 @@ describe('issue_note', () => {
expect(noteActionsProps.canDelete).toBe(note.current_user.can_edit);
expect(noteActionsProps.canReportAsAbuse).toBe(true);
expect(noteActionsProps.canResolve).toBe(false);
- expect(noteActionsProps.reportAbusePath).toBe(note.report_abuse_path);
expect(noteActionsProps.resolvable).toBe(false);
expect(noteActionsProps.isResolved).toBe(false);
expect(noteActionsProps.isResolving).toBe(false);
diff --git a/spec/frontend/packages_and_registries/package_registry/components/functional/delete_package_spec.js b/spec/frontend/packages_and_registries/package_registry/components/functional/delete_packages_spec.js
index 93c2196b210..689b53fa2a4 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/functional/delete_package_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/functional/delete_packages_spec.js
@@ -4,36 +4,38 @@ import waitForPromises from 'helpers/wait_for_promises';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import createMockApollo from 'helpers/mock_apollo_helper';
import { createAlert, VARIANT_SUCCESS, VARIANT_WARNING } from '~/flash';
-import DeletePackage from '~/packages_and_registries/package_registry/components/functional/delete_package.vue';
+import DeletePackages from '~/packages_and_registries/package_registry/components/functional/delete_packages.vue';
-import destroyPackageMutation from '~/packages_and_registries/package_registry/graphql/mutations/destroy_package.mutation.graphql';
+import destroyPackagesMutation from '~/packages_and_registries/package_registry/graphql/mutations/destroy_packages.mutation.graphql';
import getPackagesQuery from '~/packages_and_registries/package_registry/graphql/queries/get_packages.query.graphql';
import {
- packageDestroyMutation,
- packageDestroyMutationError,
+ packagesDestroyMutation,
+ packagesDestroyMutationError,
packagesListQuery,
} from '../../mock_data';
jest.mock('~/flash');
-describe('DeletePackage', () => {
+describe('DeletePackages', () => {
let wrapper;
let apolloProvider;
let resolver;
let mutationResolver;
- const eventPayload = { id: '1' };
+ const eventPayload = [{ id: '1' }];
+ const eventPayloadMultiple = [{ id: '1' }, { id: '2' }];
+ const mutationPayload = { ids: ['1'] };
function createComponent(propsData = {}) {
Vue.use(VueApollo);
const requestHandlers = [
[getPackagesQuery, resolver],
- [destroyPackageMutation, mutationResolver],
+ [destroyPackagesMutation, mutationResolver],
];
apolloProvider = createMockApollo(requestHandlers);
- wrapper = shallowMountExtended(DeletePackage, {
+ wrapper = shallowMountExtended(DeletePackages, {
propsData,
apolloProvider,
scopedSlots: {
@@ -43,7 +45,9 @@ describe('DeletePackage', () => {
'data-testid': 'trigger-button',
},
on: {
- click: props.deletePackage,
+ click: (payload) => {
+ return props.deletePackages(payload[0]);
+ },
},
});
},
@@ -54,23 +58,23 @@ describe('DeletePackage', () => {
const findButton = () => wrapper.findByTestId('trigger-button');
const clickOnButtonAndWait = (payload) => {
- findButton().trigger('click', payload);
+ findButton().trigger('click', [payload]);
return waitForPromises();
};
beforeEach(() => {
resolver = jest.fn().mockResolvedValue(packagesListQuery());
- mutationResolver = jest.fn().mockResolvedValue(packageDestroyMutation());
+ mutationResolver = jest.fn().mockResolvedValue(packagesDestroyMutation());
});
afterEach(() => {
wrapper.destroy();
});
- it('binds deletePackage method to the default slot', () => {
+ it('binds deletePackages method to the default slot', () => {
createComponent();
- findButton().trigger('click');
+ findButton().trigger('click', eventPayload);
expect(wrapper.emitted('start')).toEqual([[]]);
});
@@ -80,7 +84,7 @@ describe('DeletePackage', () => {
await clickOnButtonAndWait(eventPayload);
- expect(mutationResolver).toHaveBeenCalledWith(eventPayload);
+ expect(mutationResolver).toHaveBeenCalledWith(mutationPayload);
});
it('passes refetchQueries to apollo mutate', async () => {
@@ -91,10 +95,20 @@ describe('DeletePackage', () => {
await clickOnButtonAndWait(eventPayload);
- expect(mutationResolver).toHaveBeenCalledWith(eventPayload);
+ expect(mutationResolver).toHaveBeenCalledWith(mutationPayload);
expect(resolver).toHaveBeenCalledWith(variables);
});
+ describe('when payload contains multiple packages', () => {
+ it('calls apollo mutation with different payload', async () => {
+ createComponent();
+
+ await clickOnButtonAndWait(eventPayloadMultiple);
+
+ expect(mutationResolver).toHaveBeenCalledWith({ ids: ['1', '2'] });
+ });
+ });
+
describe('on mutation success', () => {
it('emits end event', async () => {
createComponent();
@@ -118,16 +132,29 @@ describe('DeletePackage', () => {
await clickOnButtonAndWait(eventPayload);
expect(createAlert).toHaveBeenCalledWith({
- message: DeletePackage.i18n.successMessage,
+ message: DeletePackages.i18n.successMessage,
variant: VARIANT_SUCCESS,
});
});
+
+ describe('when payload contains multiple packages', () => {
+ it('calls createAlert with success message when showSuccessAlert is true', async () => {
+ createComponent({ showSuccessAlert: true });
+
+ await clickOnButtonAndWait(eventPayloadMultiple);
+
+ expect(createAlert).toHaveBeenCalledWith({
+ message: DeletePackages.i18n.successMessageMultiple,
+ variant: VARIANT_SUCCESS,
+ });
+ });
+ });
});
describe.each`
errorType | mutationResolverResponse
${'connectionError'} | ${jest.fn().mockRejectedValue()}
- ${'localError'} | ${jest.fn().mockResolvedValue(packageDestroyMutationError())}
+ ${'localError'} | ${jest.fn().mockResolvedValue(packagesDestroyMutationError())}
`('on mutation $errorType', ({ mutationResolverResponse }) => {
beforeEach(() => {
mutationResolver = mutationResolverResponse;
@@ -147,11 +174,26 @@ describe('DeletePackage', () => {
await clickOnButtonAndWait(eventPayload);
expect(createAlert).toHaveBeenCalledWith({
- message: DeletePackage.i18n.errorMessage,
+ message: DeletePackages.i18n.errorMessage,
variant: VARIANT_WARNING,
captureError: true,
error: expect.any(Error),
});
});
+
+ describe('when payload contains multiple packages', () => {
+ it('calls createAlert with error message', async () => {
+ createComponent({ showSuccessAlert: true });
+
+ await clickOnButtonAndWait(eventPayloadMultiple);
+
+ expect(createAlert).toHaveBeenCalledWith({
+ message: DeletePackages.i18n.errorMessageMultiple,
+ variant: VARIANT_WARNING,
+ captureError: true,
+ error: expect.any(Error),
+ });
+ });
+ });
});
});
diff --git a/spec/frontend/packages_and_registries/package_registry/components/list/packages_list_spec.js b/spec/frontend/packages_and_registries/package_registry/components/list/packages_list_spec.js
index 5e9cb8fbb0b..610640e0ca3 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/list/packages_list_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/list/packages_list_spec.js
@@ -167,8 +167,8 @@ describe('packages_list', () => {
findPackageListDeleteModal().vm.$emit('ok');
});
- it('emits package:delete when modal confirms', () => {
- expect(wrapper.emitted('package:delete')[0]).toEqual([firstPackage]);
+ it('emits delete when modal confirms', () => {
+ expect(wrapper.emitted('delete')[0][0]).toEqual([firstPackage]);
});
it('tracks the right action', () => {
diff --git a/spec/frontend/packages_and_registries/package_registry/mock_data.js b/spec/frontend/packages_and_registries/package_registry/mock_data.js
index 9e9e08bc196..8c532f31499 100644
--- a/spec/frontend/packages_and_registries/package_registry/mock_data.js
+++ b/spec/frontend/packages_and_registries/package_registry/mock_data.js
@@ -294,14 +294,6 @@ export const packageMetadataQuery = (packageType) => {
};
};
-export const packageDestroyMutation = () => ({
- data: {
- destroyPackage: {
- errors: [],
- },
- },
-});
-
export const packagesDestroyMutation = () => ({
data: {
destroyPackages: {
@@ -329,25 +321,6 @@ export const packagesDestroyMutationError = () => ({
],
});
-export const packageDestroyMutationError = () => ({
- data: {
- destroyPackage: null,
- },
- errors: [
- {
- message:
- "The resource that you are attempting to access does not exist or you don't have permission to perform this action",
- locations: [
- {
- line: 2,
- column: 3,
- },
- ],
- path: ['destroyPackage'],
- },
- ],
-});
-
export const packageDestroyFilesMutation = () => ({
data: {
destroyPackageFiles: {
diff --git a/spec/frontend/packages_and_registries/package_registry/pages/details_spec.js b/spec/frontend/packages_and_registries/package_registry/pages/details_spec.js
index eb3b999c1ca..c6a770fad76 100644
--- a/spec/frontend/packages_and_registries/package_registry/pages/details_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/pages/details_spec.js
@@ -15,7 +15,7 @@ import InstallationCommands from '~/packages_and_registries/package_registry/com
import PackageFiles from '~/packages_and_registries/package_registry/components/details/package_files.vue';
import PackageHistory from '~/packages_and_registries/package_registry/components/details/package_history.vue';
import PackageTitle from '~/packages_and_registries/package_registry/components/details/package_title.vue';
-import DeletePackage from '~/packages_and_registries/package_registry/components/functional/delete_package.vue';
+import DeletePackages from '~/packages_and_registries/package_registry/components/functional/delete_packages.vue';
import PackageVersionsList from '~/packages_and_registries/package_registry/components/details/package_versions_list.vue';
import {
FETCH_PACKAGE_DETAILS_ERROR_MESSAGE,
@@ -85,7 +85,7 @@ describe('PackagesApp', () => {
provide,
stubs: {
PackageTitle,
- DeletePackage,
+ DeletePackages,
GlModal: {
template: `
<div>
@@ -128,7 +128,7 @@ describe('PackagesApp', () => {
const findDependenciesCountBadge = () => wrapper.findByTestId('dependencies-badge');
const findNoDependenciesMessage = () => wrapper.findByTestId('no-dependencies-message');
const findDependencyRows = () => wrapper.findAllComponents(DependencyRow);
- const findDeletePackage = () => wrapper.findComponent(DeletePackage);
+ const findDeletePackages = () => wrapper.findComponent(DeletePackages);
afterEach(() => {
wrapper.destroy();
@@ -267,7 +267,7 @@ describe('PackagesApp', () => {
await waitForPromises();
- findDeletePackage().vm.$emit('end');
+ findDeletePackages().vm.$emit('end');
expect(window.location.replace).toHaveBeenCalledWith(
'projectListUrl?showSuccessDeleteAlert=true',
@@ -281,7 +281,7 @@ describe('PackagesApp', () => {
await waitForPromises();
- findDeletePackage().vm.$emit('end');
+ findDeletePackages().vm.$emit('end');
expect(window.location.replace).toHaveBeenCalledWith(
'groupListUrl?showSuccessDeleteAlert=true',
diff --git a/spec/frontend/packages_and_registries/package_registry/pages/list_spec.js b/spec/frontend/packages_and_registries/package_registry/pages/list_spec.js
index b3cbd9f5dcf..a2ec527ce12 100644
--- a/spec/frontend/packages_and_registries/package_registry/pages/list_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/pages/list_spec.js
@@ -1,4 +1,4 @@
-import { GlAlert, GlEmptyState, GlSprintf, GlLink } from '@gitlab/ui';
+import { GlEmptyState, GlSprintf, GlLink } from '@gitlab/ui';
import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
@@ -8,26 +8,18 @@ import ListPage from '~/packages_and_registries/package_registry/pages/list.vue'
import PackageTitle from '~/packages_and_registries/package_registry/components/list/package_title.vue';
import PackageSearch from '~/packages_and_registries/package_registry/components/list/package_search.vue';
import OriginalPackageList from '~/packages_and_registries/package_registry/components/list/packages_list.vue';
-import DeletePackage from '~/packages_and_registries/package_registry/components/functional/delete_package.vue';
+import DeletePackages from '~/packages_and_registries/package_registry/components/functional/delete_packages.vue';
import {
PROJECT_RESOURCE_TYPE,
GROUP_RESOURCE_TYPE,
GRAPHQL_PAGE_SIZE,
EMPTY_LIST_HELP_URL,
PACKAGE_HELP_URL,
- DELETE_PACKAGES_ERROR_MESSAGE,
- DELETE_PACKAGES_SUCCESS_MESSAGE,
} from '~/packages_and_registries/package_registry/constants';
import getPackagesQuery from '~/packages_and_registries/package_registry/graphql/queries/get_packages.query.graphql';
import destroyPackagesMutation from '~/packages_and_registries/package_registry/graphql/mutations/destroy_packages.mutation.graphql';
-import {
- packagesListQuery,
- packageData,
- pagination,
- packagesDestroyMutation,
- packagesDestroyMutationError,
-} from '../mock_data';
+import { packagesListQuery, packageData, pagination } from '../mock_data';
jest.mock('~/flash');
@@ -53,12 +45,11 @@ describe('PackagesListApp', () => {
filters: { packageName: 'foo', packageType: 'CONAN' },
};
- const findAlert = () => wrapper.findComponent(GlAlert);
const findPackageTitle = () => wrapper.findComponent(PackageTitle);
const findSearch = () => wrapper.findComponent(PackageSearch);
const findListComponent = () => wrapper.findComponent(PackageList);
const findEmptyState = () => wrapper.findComponent(GlEmptyState);
- const findDeletePackage = () => wrapper.findComponent(DeletePackage);
+ const findDeletePackages = () => wrapper.findComponent(DeletePackages);
const mountComponent = ({
resolver = jest.fn().mockResolvedValue(packagesListQuery()),
@@ -82,7 +73,7 @@ describe('PackagesListApp', () => {
GlSprintf,
GlLink,
PackageList,
- DeletePackage,
+ DeletePackages,
},
});
};
@@ -243,26 +234,26 @@ describe('PackagesListApp', () => {
});
});
- describe('delete package', () => {
+ describe('delete packages', () => {
it('exists and has the correct props', async () => {
mountComponent();
await waitForFirstRequest();
- expect(findDeletePackage().props()).toMatchObject({
+ expect(findDeletePackages().props()).toMatchObject({
refetchQueries: [{ query: getPackagesQuery, variables: {} }],
showSuccessAlert: true,
});
});
- it('deletePackage is bound to package-list package:delete event', async () => {
+ it('deletePackages is bound to package-list delete event', async () => {
mountComponent();
await waitForFirstRequest();
- findListComponent().vm.$emit('package:delete', { id: 1 });
+ findListComponent().vm.$emit('delete', [{ id: 1 }]);
- expect(findDeletePackage().emitted('start')).toEqual([[]]);
+ expect(findDeletePackages().emitted('start')).toEqual([[]]);
});
it('start and end event set loading correctly', async () => {
@@ -270,59 +261,17 @@ describe('PackagesListApp', () => {
await waitForFirstRequest();
- findDeletePackage().vm.$emit('start');
+ findDeletePackages().vm.$emit('start');
await nextTick();
expect(findListComponent().props('isLoading')).toBe(true);
- findDeletePackage().vm.$emit('end');
+ findDeletePackages().vm.$emit('end');
await nextTick();
expect(findListComponent().props('isLoading')).toBe(false);
});
});
-
- describe('bulk delete package', () => {
- const items = [{ id: '1' }, { id: '2' }];
-
- it('calls mutation with the right values and shows success alert', async () => {
- const mutationResolver = jest.fn().mockResolvedValue(packagesDestroyMutation());
- mountComponent({
- mutationResolver,
- });
-
- await waitForFirstRequest();
-
- findListComponent().vm.$emit('delete', items);
-
- expect(mutationResolver).toHaveBeenCalledWith({
- ids: items.map((item) => item.id),
- });
-
- await waitForPromises();
-
- expect(findAlert().exists()).toBe(true);
- expect(findAlert().props('variant')).toEqual('success');
- expect(findAlert().text()).toMatchInterpolatedText(DELETE_PACKAGES_SUCCESS_MESSAGE);
- });
-
- it('on error shows danger alert', async () => {
- const mutationResolver = jest.fn().mockResolvedValue(packagesDestroyMutationError());
- mountComponent({
- mutationResolver,
- });
-
- await waitForFirstRequest();
-
- findListComponent().vm.$emit('delete', items);
-
- await waitForPromises();
-
- expect(findAlert().exists()).toBe(true);
- expect(findAlert().props('variant')).toEqual('danger');
- expect(findAlert().text()).toMatchInterpolatedText(DELETE_PACKAGES_ERROR_MESSAGE);
- });
- });
});
diff --git a/spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js b/spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js
index 38f7a2e919d..ff20b72c72c 100644
--- a/spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js
+++ b/spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js
@@ -75,10 +75,7 @@ describe('Settings Panel', () => {
return mountFn(settingsPanel, {
propsData,
provide: {
- glFeatures: {
- packageRegistryAccessLevel: false,
- ...glFeatures,
- },
+ glFeatures,
},
stubs,
});
@@ -110,10 +107,8 @@ describe('Settings Panel', () => {
findContainerRegistrySettings().findComponent(GlSprintf);
const findContainerRegistryAccessLevelInput = () =>
wrapper.find('[name="project[project_feature_attributes][container_registry_access_level]"]');
- const findPackageSettings = () => wrapper.findComponent({ ref: 'package-settings' });
const findPackageAccessLevel = () =>
wrapper.find('[data-testid="package-registry-access-level"]');
- const findPackagesEnabledInput = () => wrapper.find('[name="project[packages_enabled]"]');
const findPackageRegistryEnabledInput = () => wrapper.find('[name="package_registry_enabled"]');
const findPackageRegistryAccessLevelHiddenInput = () =>
wrapper.find(
@@ -512,180 +507,108 @@ describe('Settings Panel', () => {
});
describe('Packages', () => {
- it('should show the packages settings if packages are available', () => {
- wrapper = mountComponent({ packagesAvailable: true });
-
- expect(findPackageSettings().exists()).toBe(true);
- });
-
- it('should hide the packages settings if packages are not available', () => {
- wrapper = mountComponent({ packagesAvailable: false });
+ it('should hide the package access level settings with packagesAvailable = false', () => {
+ wrapper = mountComponent();
- expect(findPackageSettings().exists()).toBe(false);
+ expect(findPackageAccessLevel().exists()).toBe(false);
});
- it('should set the package settings help path', () => {
+ it('renders the package access level settings with packagesAvailable = true', () => {
wrapper = mountComponent({ packagesAvailable: true });
- expect(findPackageSettings().props('helpPath')).toBe(defaultProps.packagesHelpPath);
+ expect(findPackageAccessLevel().exists()).toBe(true);
});
- it('should enable the packages input when the repository is enabled', () => {
- wrapper = mountComponent({
- currentSettings: { repositoryAccessLevel: featureAccessLevel.EVERYONE },
- packagesAvailable: true,
- });
-
- expect(findPackagesEnabledInput().props('disabled')).toBe(false);
- });
-
- it('should disable the packages input when the repository is disabled', () => {
- wrapper = mountComponent({
- currentSettings: { repositoryAccessLevel: featureAccessLevel.NOT_ENABLED },
- packagesAvailable: true,
- });
-
- expect(findPackagesEnabledInput().props('disabled')).toBe(true);
- });
-
- it('has label for toggle', () => {
- wrapper = mountComponent({
- currentSettings: { repositoryAccessLevel: featureAccessLevel.EVERYONE },
- packagesAvailable: true,
- });
-
- expect(findPackagesEnabledInput().findComponent(GlToggle).props('label')).toBe(
- settingsPanel.i18n.packagesLabel,
- );
- });
-
- it('should hide the package access level settings', () => {
- wrapper = mountComponent();
+ it('has hidden input field for package registry access level', () => {
+ wrapper = mountComponent({ packagesAvailable: true });
- expect(findPackageAccessLevel().exists()).toBe(false);
+ expect(findPackageRegistryAccessLevelHiddenInput().exists()).toBe(true);
});
- describe('packageRegistryAccessLevel feature flag = true', () => {
- it('should hide the packages settings', () => {
+ it.each`
+ projectVisibilityLevel | packageRegistryEnabled | packageRegistryApiForEveryoneEnabled | expectedAccessLevel
+ ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${false} | ${'disabled'} | ${featureAccessLevel.NOT_ENABLED}
+ ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${true} | ${false} | ${featureAccessLevel.PROJECT_MEMBERS}
+ ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${true} | ${true} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS}
+ ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${false} | ${'disabled'} | ${featureAccessLevel.NOT_ENABLED}
+ ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${true} | ${false} | ${featureAccessLevel.EVERYONE}
+ ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${true} | ${true} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS}
+ ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${false} | ${'hidden'} | ${featureAccessLevel.NOT_ENABLED}
+ ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${true} | ${'hidden'} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS}
+ `(
+ 'sets correct access level',
+ async ({
+ projectVisibilityLevel,
+ packageRegistryEnabled,
+ packageRegistryApiForEveryoneEnabled,
+ expectedAccessLevel,
+ }) => {
wrapper = mountComponent({
- glFeatures: { packageRegistryAccessLevel: true },
packagesAvailable: true,
+ currentSettings: {
+ visibilityLevel: projectVisibilityLevel,
+ },
});
- expect(findPackageSettings().exists()).toBe(false);
- });
-
- it('should hide the package access level settings with packagesAvailable = false', () => {
- wrapper = mountComponent({ glFeatures: { packageRegistryAccessLevel: true } });
+ await findPackageRegistryEnabledInput().vm.$emit('change', packageRegistryEnabled);
- expect(findPackageAccessLevel().exists()).toBe(false);
- });
+ const packageRegistryApiForEveryoneEnabledInput = findPackageRegistryApiForEveryoneEnabledInput();
- it('renders the package access level settings with packagesAvailable = true', () => {
- wrapper = mountComponent({
- glFeatures: { packageRegistryAccessLevel: true },
- packagesAvailable: true,
- });
+ if (packageRegistryApiForEveryoneEnabled === 'hidden') {
+ expect(packageRegistryApiForEveryoneEnabledInput.exists()).toBe(false);
+ } else if (packageRegistryApiForEveryoneEnabled === 'disabled') {
+ expect(packageRegistryApiForEveryoneEnabledInput.props('disabled')).toBe(true);
+ } else {
+ expect(packageRegistryApiForEveryoneEnabledInput.props('disabled')).toBe(false);
+ await packageRegistryApiForEveryoneEnabledInput.vm.$emit(
+ 'change',
+ packageRegistryApiForEveryoneEnabled,
+ );
+ }
- expect(findPackageAccessLevel().exists()).toBe(true);
- });
+ expect(wrapper.vm.packageRegistryAccessLevel).toBe(expectedAccessLevel);
+ },
+ );
- it('has hidden input field for package registry access level', () => {
+ it.each`
+ initialProjectVisibilityLevel | newProjectVisibilityLevel | initialAccessLevel | expectedAccessLevel
+ ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${featureAccessLevel.NOT_ENABLED} | ${featureAccessLevel.NOT_ENABLED}
+ ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${featureAccessLevel.PROJECT_MEMBERS} | ${featureAccessLevel.EVERYONE}
+ ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS}
+ ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${featureAccessLevel.NOT_ENABLED} | ${featureAccessLevel.NOT_ENABLED}
+ ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${featureAccessLevel.PROJECT_MEMBERS} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS}
+ ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS}
+ ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${featureAccessLevel.NOT_ENABLED} | ${featureAccessLevel.NOT_ENABLED}
+ ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${featureAccessLevel.EVERYONE} | ${featureAccessLevel.PROJECT_MEMBERS}
+ ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS}
+ ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${featureAccessLevel.NOT_ENABLED} | ${featureAccessLevel.NOT_ENABLED}
+ ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${featureAccessLevel.EVERYONE} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS}
+ ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS}
+ ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${featureAccessLevel.NOT_ENABLED} | ${featureAccessLevel.NOT_ENABLED}
+ ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS} | ${featureAccessLevel.PROJECT_MEMBERS}
+ ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${featureAccessLevel.NOT_ENABLED} | ${featureAccessLevel.NOT_ENABLED}
+ ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS} | ${featureAccessLevel.EVERYONE}
+ `(
+ 'changes access level when project visibility level changed',
+ async ({
+ initialProjectVisibilityLevel,
+ newProjectVisibilityLevel,
+ initialAccessLevel,
+ expectedAccessLevel,
+ }) => {
wrapper = mountComponent({
- glFeatures: { packageRegistryAccessLevel: true },
packagesAvailable: true,
+ currentSettings: {
+ visibilityLevel: initialProjectVisibilityLevel,
+ packageRegistryAccessLevel: initialAccessLevel,
+ },
});
- expect(findPackageRegistryAccessLevelHiddenInput().exists()).toBe(true);
- });
-
- it.each`
- projectVisibilityLevel | packageRegistryEnabled | packageRegistryApiForEveryoneEnabled | expectedAccessLevel
- ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${false} | ${'disabled'} | ${featureAccessLevel.NOT_ENABLED}
- ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${true} | ${false} | ${featureAccessLevel.PROJECT_MEMBERS}
- ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${true} | ${true} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS}
- ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${false} | ${'disabled'} | ${featureAccessLevel.NOT_ENABLED}
- ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${true} | ${false} | ${featureAccessLevel.EVERYONE}
- ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${true} | ${true} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS}
- ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${false} | ${'hidden'} | ${featureAccessLevel.NOT_ENABLED}
- ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${true} | ${'hidden'} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS}
- `(
- 'sets correct access level',
- async ({
- projectVisibilityLevel,
- packageRegistryEnabled,
- packageRegistryApiForEveryoneEnabled,
- expectedAccessLevel,
- }) => {
- wrapper = mountComponent({
- glFeatures: { packageRegistryAccessLevel: true },
- packagesAvailable: true,
- currentSettings: {
- visibilityLevel: projectVisibilityLevel,
- },
- });
-
- await findPackageRegistryEnabledInput().vm.$emit('change', packageRegistryEnabled);
-
- const packageRegistryApiForEveryoneEnabledInput = findPackageRegistryApiForEveryoneEnabledInput();
-
- if (packageRegistryApiForEveryoneEnabled === 'hidden') {
- expect(packageRegistryApiForEveryoneEnabledInput.exists()).toBe(false);
- } else if (packageRegistryApiForEveryoneEnabled === 'disabled') {
- expect(packageRegistryApiForEveryoneEnabledInput.props('disabled')).toBe(true);
- } else {
- expect(packageRegistryApiForEveryoneEnabledInput.props('disabled')).toBe(false);
- await packageRegistryApiForEveryoneEnabledInput.vm.$emit(
- 'change',
- packageRegistryApiForEveryoneEnabled,
- );
- }
-
- expect(wrapper.vm.packageRegistryAccessLevel).toBe(expectedAccessLevel);
- },
- );
+ await findProjectVisibilityLevelInput().setValue(newProjectVisibilityLevel);
- it.each`
- initialProjectVisibilityLevel | newProjectVisibilityLevel | initialAccessLevel | expectedAccessLevel
- ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${featureAccessLevel.NOT_ENABLED} | ${featureAccessLevel.NOT_ENABLED}
- ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${featureAccessLevel.PROJECT_MEMBERS} | ${featureAccessLevel.EVERYONE}
- ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS}
- ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${featureAccessLevel.NOT_ENABLED} | ${featureAccessLevel.NOT_ENABLED}
- ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${featureAccessLevel.PROJECT_MEMBERS} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS}
- ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS}
- ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${featureAccessLevel.NOT_ENABLED} | ${featureAccessLevel.NOT_ENABLED}
- ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${featureAccessLevel.EVERYONE} | ${featureAccessLevel.PROJECT_MEMBERS}
- ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS}
- ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${featureAccessLevel.NOT_ENABLED} | ${featureAccessLevel.NOT_ENABLED}
- ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${featureAccessLevel.EVERYONE} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS}
- ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS}
- ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${featureAccessLevel.NOT_ENABLED} | ${featureAccessLevel.NOT_ENABLED}
- ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS} | ${featureAccessLevel.PROJECT_MEMBERS}
- ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${featureAccessLevel.NOT_ENABLED} | ${featureAccessLevel.NOT_ENABLED}
- ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS} | ${featureAccessLevel.EVERYONE}
- `(
- 'changes access level when project visibility level changed',
- async ({
- initialProjectVisibilityLevel,
- newProjectVisibilityLevel,
- initialAccessLevel,
- expectedAccessLevel,
- }) => {
- wrapper = mountComponent({
- glFeatures: { packageRegistryAccessLevel: true },
- packagesAvailable: true,
- currentSettings: {
- visibilityLevel: initialProjectVisibilityLevel,
- packageRegistryAccessLevel: initialAccessLevel,
- },
- });
-
- await findProjectVisibilityLevelInput().setValue(newProjectVisibilityLevel);
-
- expect(wrapper.vm.packageRegistryAccessLevel).toBe(expectedAccessLevel);
- },
- );
- });
+ expect(wrapper.vm.packageRegistryAccessLevel).toBe(expectedAccessLevel);
+ },
+ );
});
describe('Pages', () => {
diff --git a/spec/frontend/projects/merge_requests/components/report_abuse_dropdown_item_spec.js b/spec/frontend/projects/merge_requests/components/report_abuse_dropdown_item_spec.js
index 35b10375821..11f770fb05e 100644
--- a/spec/frontend/projects/merge_requests/components/report_abuse_dropdown_item_spec.js
+++ b/spec/frontend/projects/merge_requests/components/report_abuse_dropdown_item_spec.js
@@ -10,7 +10,7 @@ describe('ReportAbuseDropdownItem', () => {
let wrapper;
const ACTION_PATH = '/abuse_reports/add_category';
- const USER_ID = '1';
+ const USER_ID = 1;
const REPORTED_FROM_URL = 'http://example.com';
const createComponent = (props) => {
diff --git a/spec/frontend/users/profile/components/report_abuse_button_spec.js b/spec/frontend/users/profile/components/report_abuse_button_spec.js
index 7ad28566f49..1ef856c9849 100644
--- a/spec/frontend/users/profile/components/report_abuse_button_spec.js
+++ b/spec/frontend/users/profile/components/report_abuse_button_spec.js
@@ -9,7 +9,7 @@ describe('ReportAbuseButton', () => {
let wrapper;
const ACTION_PATH = '/abuse_reports/add_category';
- const USER_ID = '1';
+ const USER_ID = 1;
const REPORTED_FROM_URL = 'http://example.com';
const createComponent = (props) => {
diff --git a/spec/frontend/vue_shared/security_reports/store/utils_spec.js b/spec/frontend/vue_shared/security_reports/store/utils_spec.js
new file mode 100644
index 00000000000..c8750cd58a0
--- /dev/null
+++ b/spec/frontend/vue_shared/security_reports/store/utils_spec.js
@@ -0,0 +1,63 @@
+import { enrichVulnerabilityWithFeedback } from '~/vue_shared/security_reports/store/utils';
+import {
+ FEEDBACK_TYPE_DISMISSAL,
+ FEEDBACK_TYPE_ISSUE,
+ FEEDBACK_TYPE_MERGE_REQUEST,
+} from '~/vue_shared/security_reports/constants';
+
+describe('security reports store utils', () => {
+ const vulnerability = { uuid: 1 };
+
+ describe('enrichVulnerabilityWithFeedback', () => {
+ const dismissalFeedback = {
+ feedback_type: FEEDBACK_TYPE_DISMISSAL,
+ finding_uuid: vulnerability.uuid,
+ };
+ const dismissalVuln = { ...vulnerability, isDismissed: true, dismissalFeedback };
+
+ const issueFeedback = {
+ feedback_type: FEEDBACK_TYPE_ISSUE,
+ issue_iid: 1,
+ finding_uuid: vulnerability.uuid,
+ };
+ const issueVuln = { ...vulnerability, hasIssue: true, issue_feedback: issueFeedback };
+ const mrFeedback = {
+ feedback_type: FEEDBACK_TYPE_MERGE_REQUEST,
+ merge_request_iid: 1,
+ finding_uuid: vulnerability.uuid,
+ };
+ const mrVuln = {
+ ...vulnerability,
+ hasMergeRequest: true,
+ merge_request_feedback: mrFeedback,
+ };
+
+ it.each`
+ feedbacks | expected
+ ${[dismissalFeedback]} | ${dismissalVuln}
+ ${[{ ...issueFeedback, issue_iid: null }]} | ${vulnerability}
+ ${[issueFeedback]} | ${issueVuln}
+ ${[{ ...mrFeedback, merge_request_iid: null }]} | ${vulnerability}
+ ${[mrFeedback]} | ${mrVuln}
+ ${[dismissalFeedback, issueFeedback, mrFeedback]} | ${{ ...dismissalVuln, ...issueVuln, ...mrVuln }}
+ `('returns expected enriched vulnerability: $expected', ({ feedbacks, expected }) => {
+ const enrichedVulnerability = enrichVulnerabilityWithFeedback(vulnerability, feedbacks);
+
+ expect(enrichedVulnerability).toEqual(expected);
+ });
+
+ it('matches correct feedback objects to vulnerability', () => {
+ const feedbacks = [
+ dismissalFeedback,
+ issueFeedback,
+ mrFeedback,
+ { ...dismissalFeedback, finding_uuid: 2 },
+ { ...issueFeedback, finding_uuid: 2 },
+ { ...mrFeedback, finding_uuid: 2 },
+ ];
+ const enrichedVulnerability = enrichVulnerabilityWithFeedback(vulnerability, feedbacks);
+
+ expect(enrichedVulnerability).toEqual({ ...dismissalVuln, ...issueVuln, ...mrVuln });
+ });
+ });
+});
diff --git a/spec/models/ci/build_metadata_spec.rb b/spec/models/ci/build_metadata_spec.rb
index 8bf3af44be6..fb50ba89cd3 100644
--- a/spec/models/ci/build_metadata_spec.rb
+++ b/spec/models/ci/build_metadata_spec.rb
@@ -20,6 +20,10 @@ RSpec.describe Ci::BuildMetadata do
it_behaves_like 'having unique enum values'
+ it { is_expected.to belong_to(:build) }
+ it { is_expected.to belong_to(:project) }
+ it { is_expected.to belong_to(:runner_machine) }
+
describe '#update_timeout_state' do
subject { metadata }
diff --git a/spec/models/ci/runner_machine_spec.rb b/spec/models/ci/runner_machine_spec.rb
index e39f987110f..9fc35006233 100644
--- a/spec/models/ci/runner_machine_spec.rb
+++ b/spec/models/ci/runner_machine_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe Ci::RunnerMachine, feature_category: :runner_fleet, type: :model
it_behaves_like 'having unique enum values'
it { is_expected.to belong_to(:runner) }
+ it { is_expected.to have_many(:build_metadata) }
describe 'validation' do
it { is_expected.to validate_presence_of(:runner) }
diff --git a/spec/policies/packages/policies/project_policy_spec.rb b/spec/policies/packages/policies/project_policy_spec.rb
index 5d54ee54572..5c267ff5ac5 100644
--- a/spec/policies/packages/policies/project_policy_spec.rb
+++ b/spec/policies/packages/policies/project_policy_spec.rb
@@ -122,39 +122,6 @@ RSpec.describe Packages::Policies::ProjectPolicy do
end
end
- context 'with feature flag disabled' do
- before do
- stub_feature_flags(package_registry_access_level: false)
- end
-
- where(:project, :current_user, :expect_to_be_allowed) do
- ref(:private_project) | ref(:anonymous) | false
- ref(:private_project) | ref(:non_member) | false
- ref(:private_project) | ref(:guest) | false
- ref(:internal_project) | ref(:anonymous) | false
- ref(:public_project) | ref(:admin) | true
- ref(:public_project) | ref(:owner) | true
- ref(:public_project) | ref(:maintainer) | true
- ref(:public_project) | ref(:developer) | true
- ref(:public_project) | ref(:reporter) | true
- ref(:public_project) | ref(:guest) | true
- ref(:public_project) | ref(:non_member) | true
- ref(:public_project) | ref(:anonymous) | true
- end
-
- with_them do
- it do
- project.project_feature.update!(package_registry_access_level: ProjectFeature::PUBLIC)
-
- if expect_to_be_allowed
- is_expected.to be_allowed(:read_package)
- else
- is_expected.to be_disallowed(:read_package)
- end
- end
- end
- end
-
context 'with admin' do
let(:current_user) { admin }
diff --git a/spec/requests/abuse_reports_controller_spec.rb b/spec/requests/abuse_reports_controller_spec.rb
index 49a80689c65..934f123e45b 100644
--- a/spec/requests/abuse_reports_controller_spec.rb
+++ b/spec/requests/abuse_reports_controller_spec.rb
@@ -5,9 +5,12 @@ require 'spec_helper'
RSpec.describe AbuseReportsController, feature_category: :insider_threat do
let(:reporter) { create(:user) }
let(:user) { create(:user) }
+ let(:abuse_category) { 'spam' }
+
let(:attrs) do
attributes_for(:abuse_report) do |hash|
hash[:user_id] = user.id
+ hash[:category] = abuse_category
end
end
@@ -55,8 +58,6 @@ RSpec.describe AbuseReportsController, feature_category: :insider_threat do
describe 'POST add_category', :aggregate_failures do
subject(:request) { post add_category_abuse_reports_path, params: request_params }
- let(:abuse_category) { 'spam' }
-
context 'when user is reported for abuse' do
let(:ref_url) { 'http://example.com' }
let(:request_params) do
@@ -80,6 +81,17 @@ RSpec.describe AbuseReportsController, feature_category: :insider_threat do
reported_from_url: ref_url
)
end
+
+ it 'tracks the snowplow event' do
+ subject
+
+ expect_snowplow_event(
+ category: 'ReportAbuse',
+ action: 'select_abuse_category',
+ property: abuse_category,
+ user: user
+ )
+ end
end
context 'when abuse_report is missing in params' do
@@ -149,15 +161,35 @@ RSpec.describe AbuseReportsController, feature_category: :insider_threat do
expect(response).to redirect_to root_path
end
+
+ it 'tracks the snowplow event' do
+ post abuse_reports_path(abuse_report: attrs)
+
+ expect_snowplow_event(
+ category: 'ReportAbuse',
+ action: 'submit_form',
+ property: abuse_category,
+ user: user
+ )
+ end
end
context 'with invalid attributes' do
- it 'redirects back to root' do
+ before do
attrs.delete(:user_id)
+ end
+
+ it 'redirects back to root' do
post abuse_reports_path(abuse_report: attrs)
expect(response).to redirect_to root_path
end
+
+ it 'does not track the snowplow event' do
+ post abuse_reports_path(abuse_report: attrs)
+
+ expect_no_snowplow_event
+ end
end
end
end
diff --git a/spec/requests/api/internal/kubernetes_spec.rb b/spec/requests/api/internal/kubernetes_spec.rb
index dc631ad7921..be76e55269a 100644
--- a/spec/requests/api/internal/kubernetes_spec.rb
+++ b/spec/requests/api/internal/kubernetes_spec.rb
@@ -227,7 +227,7 @@ RSpec.describe API::Internal::Kubernetes, feature_category: :kubernetes_manageme
context 'an agent is found' do
let_it_be(:agent_token) { create(:cluster_agent_token) }
- shared_examples 'agent token tracking'
+ include_examples 'agent token tracking'
context 'project is public' do
let(:project) { create(:project, :public) }
diff --git a/spec/support/shared_examples/features/reportable_note_shared_examples.rb b/spec/support/shared_examples/features/reportable_note_shared_examples.rb
index 9d859403465..e9056edbafa 100644
--- a/spec/support/shared_examples/features/reportable_note_shared_examples.rb
+++ b/spec/support/shared_examples/features/reportable_note_shared_examples.rb
@@ -20,10 +20,9 @@ RSpec.shared_examples 'reportable note' do |type|
dropdown = comment.find(more_actions_selector)
open_dropdown(dropdown)
- expect(dropdown).to have_link('Report abuse to administrator', href: abuse_report_path)
-
if type == 'issue' || type == 'merge_request'
expect(dropdown).to have_button('Delete comment')
+ expect(dropdown).to have_button('Report abuse to administrator')
else
expect(dropdown).to have_link('Delete comment', href: note_url(note, project))
end
@@ -33,10 +32,21 @@ RSpec.shared_examples 'reportable note' do |type|
dropdown = comment.find(more_actions_selector)
open_dropdown(dropdown)
- dropdown.click_link('Report abuse to administrator')
+ if type == 'issue' || type == 'merge_request'
+ dropdown.click_button('Report abuse to administrator')
+
+ choose "They're posting spam."
+ click_button "Next"
- expect(find('#user_name')['value']).to match(note.author.username)
- expect(find('#abuse_report_reported_from_url')['value']).to match(noteable_note_url(note))
+ expect(find('#user_name')['value']).to match(note.author.username)
+ expect(find('#abuse_report_reported_from_url')['value']).to match(noteable_note_url(note))
+ expect(find('#abuse_report_category', visible: false)['value']).to match('spam')
+ else
+ dropdown.click_link('Report abuse to administrator')
+
+ expect(find('#user_name')['value']).to match(note.author.username)
+ expect(find('#abuse_report_reported_from_url')['value']).to match(noteable_note_url(note))
+ end
end
def open_dropdown(dropdown)