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-07-24 21:08:45 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-07-24 21:08:45 +0300
commit2ae564d6f59fc939bfdbb155d445efe97b34c1e1 (patch)
tree106ebc2021d84757ca03610747a60c8f47ac9fb0 /spec
parent7308ec9d13fb69018200a40f287e76ef499ed47c (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/factories/keys.rb10
-rw-r--r--spec/features/projects/files/user_browses_files_spec.rb2
-rw-r--r--spec/frontend/contribution_events/components/contribution_event/contribution_event_created_spec.js70
-rw-r--r--spec/frontend/contribution_events/components/contribution_events_spec.js4
-rw-r--r--spec/frontend/contribution_events/components/target_link_spec.js17
-rw-r--r--spec/frontend/contribution_events/utils.js42
-rw-r--r--spec/frontend/fixtures/users.rb9
-rw-r--r--spec/frontend/lib/utils/url_utility_spec.js14
-rw-r--r--spec/frontend/repository/commits_service_spec.js13
-rw-r--r--spec/frontend/repository/components/blob_content_viewer_spec.js8
-rw-r--r--spec/frontend/repository/components/table/parent_row_spec.js17
-rw-r--r--spec/frontend/repository/components/table/row_spec.js11
-rw-r--r--spec/frontend/repository/components/tree_content_spec.js7
-rw-r--r--spec/frontend/repository/pages/index_spec.js6
-rw-r--r--spec/frontend/vue_shared/components/badges/__snapshots__/beta_badge_spec.js.snap53
-rw-r--r--spec/frontend/vue_shared/components/badges/beta_badge_spec.js12
-rw-r--r--spec/frontend/vue_shared/components/blob_viewers/rich_viewer_spec.js6
-rw-r--r--spec/graphql/types/access_levels/deploy_key_type_spec.rb13
-rw-r--r--spec/graphql/types/access_levels/user_type_spec.rb41
-rw-r--r--spec/graphql/types/branch_protections/push_access_level_type_spec.rb2
-rw-r--r--spec/helpers/tree_helper_spec.rb4
-rw-r--r--spec/lib/gitlab/git/repository_spec.rb30
-rw-r--r--spec/lib/gitlab_settings/options_spec.rb16
-rw-r--r--spec/policies/deploy_key_policy_spec.rb100
-rw-r--r--spec/support/shared_contexts/user_contribution_events_shared_context.rb12
25 files changed, 422 insertions, 97 deletions
diff --git a/spec/factories/keys.rb b/spec/factories/keys.rb
index f6f06a99494..4bd41c1faa1 100644
--- a/spec/factories/keys.rb
+++ b/spec/factories/keys.rb
@@ -30,7 +30,15 @@ FactoryBot.define do
key { SSHData::PrivateKey::RSA.generate(3072, unsafe_allow_small_key: true).public_key.openssh }
end
- factory :deploy_key, class: 'DeployKey'
+ factory :deploy_key, class: 'DeployKey' do
+ trait :private do
+ public { false }
+ end
+
+ trait :public do
+ public { true }
+ end
+ end
factory :group_deploy_key, class: 'GroupDeployKey' do
user
diff --git a/spec/features/projects/files/user_browses_files_spec.rb b/spec/features/projects/files/user_browses_files_spec.rb
index 3b30a620257..e93c9427c91 100644
--- a/spec/features/projects/files/user_browses_files_spec.rb
+++ b/spec/features/projects/files/user_browses_files_spec.rb
@@ -155,7 +155,7 @@ RSpec.describe "User browses files", :js, feature_category: :groups_and_projects
click_link("d")
end
- expect(page).to have_link("..", href: project_tree_path(project, "markdown/"))
+ expect(page).to have_link("..", href: project_tree_path(project, "markdown"))
page.within(".tree-table") do
click_link("README.md")
diff --git a/spec/frontend/contribution_events/components/contribution_event/contribution_event_created_spec.js b/spec/frontend/contribution_events/components/contribution_event/contribution_event_created_spec.js
new file mode 100644
index 00000000000..4be4aa50dfc
--- /dev/null
+++ b/spec/frontend/contribution_events/components/contribution_event/contribution_event_created_spec.js
@@ -0,0 +1,70 @@
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import ContributionEventCreated from '~/contribution_events/components/contribution_event/contribution_event_created.vue';
+import ContributionEventBase from '~/contribution_events/components/contribution_event/contribution_event_base.vue';
+import { TARGET_TYPE_WORK_ITEM } from '~/contribution_events/constants';
+import {
+ eventProjectCreated,
+ eventMilestoneCreated,
+ eventIssueCreated,
+ eventMergeRequestCreated,
+ eventWikiPageCreated,
+ eventDesignCreated,
+ eventTaskCreated,
+ eventIncidentCreated,
+} from '../../utils';
+
+describe('ContributionEventCreated', () => {
+ let wrapper;
+
+ const createComponent = ({ propsData }) => {
+ wrapper = shallowMountExtended(ContributionEventCreated, {
+ propsData,
+ });
+ };
+
+ describe.each`
+ event | expectedMessage | expectedIconName | expectedIconClass
+ ${eventProjectCreated()} | ${'Created project %{resourceParentLink}.'} | ${'status_open'} | ${'gl-text-green-500'}
+ ${eventMilestoneCreated()} | ${'Opened milestone %{targetLink} in %{resourceParentLink}.'} | ${'status_open'} | ${'gl-text-green-500'}
+ ${eventIssueCreated()} | ${'Opened issue %{targetLink} in %{resourceParentLink}.'} | ${'status_open'} | ${'gl-text-green-500'}
+ ${eventMergeRequestCreated()} | ${'Opened merge request %{targetLink} in %{resourceParentLink}.'} | ${'status_open'} | ${'gl-text-green-500'}
+ ${eventWikiPageCreated()} | ${'Created wiki page %{targetLink} in %{resourceParentLink}.'} | ${'status_open'} | ${'gl-text-green-500'}
+ ${eventDesignCreated()} | ${'Added design %{targetLink} in %{resourceParentLink}.'} | ${'upload'} | ${null}
+ ${{ resource_parent: { type: 'unsupported type' } }} | ${'Created resource.'} | ${'status_open'} | ${'gl-text-green-500'}
+ ${{ target: { type: 'unsupported type' } }} | ${'Created resource.'} | ${'status_open'} | ${'gl-text-green-500'}
+ `(
+ 'when event target type is $event.target.type',
+ ({ event, expectedMessage, expectedIconName, expectedIconClass }) => {
+ it('renders `ContributionEventBase` with correct props', () => {
+ createComponent({ propsData: { event } });
+
+ expect(wrapper.findComponent(ContributionEventBase).props()).toMatchObject({
+ event,
+ message: expectedMessage,
+ iconName: expectedIconName,
+ iconClass: expectedIconClass,
+ });
+ });
+ },
+ );
+
+ describe(`when event target type is ${TARGET_TYPE_WORK_ITEM}`, () => {
+ describe.each`
+ event | expectedMessage
+ ${eventTaskCreated()} | ${'Opened task %{targetLink} in %{resourceParentLink}.'}
+ ${eventIncidentCreated()} | ${'Opened incident %{targetLink} in %{resourceParentLink}.'}
+ ${{ target: { type: TARGET_TYPE_WORK_ITEM, issue_type: 'unsupported type' } }} | ${'Created resource.'}
+ `('when issue type is $event.target.issue_type', ({ event, expectedMessage }) => {
+ it('renders `ContributionEventBase` with correct props', () => {
+ createComponent({ propsData: { event } });
+
+ expect(wrapper.findComponent(ContributionEventBase).props()).toMatchObject({
+ event,
+ message: expectedMessage,
+ iconName: 'status_open',
+ iconClass: 'gl-text-green-500',
+ });
+ });
+ });
+ });
+});
diff --git a/spec/frontend/contribution_events/components/contribution_events_spec.js b/spec/frontend/contribution_events/components/contribution_events_spec.js
index 31e1bc3e569..8487f6c6ec9 100644
--- a/spec/frontend/contribution_events/components/contribution_events_spec.js
+++ b/spec/frontend/contribution_events/components/contribution_events_spec.js
@@ -7,6 +7,7 @@ import ContributionEventLeft from '~/contribution_events/components/contribution
import ContributionEventPushed from '~/contribution_events/components/contribution_event/contribution_event_pushed.vue';
import ContributionEventPrivate from '~/contribution_events/components/contribution_event/contribution_event_private.vue';
import ContributionEventMerged from '~/contribution_events/components/contribution_event/contribution_event_merged.vue';
+import ContributionEventCreated from '~/contribution_events/components/contribution_event/contribution_event_created.vue';
import {
eventApproved,
eventExpired,
@@ -15,6 +16,7 @@ import {
eventPushedBranch,
eventPrivate,
eventMerged,
+ eventCreated,
} from '../utils';
describe('ContributionEvents', () => {
@@ -31,6 +33,7 @@ describe('ContributionEvents', () => {
eventPushedBranch(),
eventPrivate(),
eventMerged(),
+ eventCreated(),
],
},
});
@@ -45,6 +48,7 @@ describe('ContributionEvents', () => {
${ContributionEventPushed} | ${eventPushedBranch()}
${ContributionEventPrivate} | ${eventPrivate()}
${ContributionEventMerged} | ${eventMerged()}
+ ${ContributionEventCreated} | ${eventCreated()}
`(
'renders `$expectedComponent.name` component and passes expected event',
({ expectedComponent, expectedEvent }) => {
diff --git a/spec/frontend/contribution_events/components/target_link_spec.js b/spec/frontend/contribution_events/components/target_link_spec.js
index b71d6eff432..40650b3585c 100644
--- a/spec/frontend/contribution_events/components/target_link_spec.js
+++ b/spec/frontend/contribution_events/components/target_link_spec.js
@@ -1,7 +1,7 @@
import { GlLink } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import TargetLink from '~/contribution_events/components/target_link.vue';
-import { eventApproved, eventJoined } from '../utils';
+import { eventApproved, eventJoined, eventWikiPageCreated } from '../utils';
describe('TargetLink', () => {
let wrapper;
@@ -19,13 +19,15 @@ describe('TargetLink', () => {
});
};
+ const findLink = () => wrapper.findComponent(GlLink);
+
describe('when target is defined', () => {
beforeEach(() => {
createComponent();
});
it('renders link', () => {
- const link = wrapper.findComponent(GlLink);
+ const link = findLink();
const { web_url: webUrl, title, reference_link_text } = defaultPropsData.event.target;
expect(link.attributes()).toMatchObject({
@@ -34,6 +36,17 @@ describe('TargetLink', () => {
});
expect(link.text()).toBe(reference_link_text);
});
+
+ describe('when target does not have `reference_link_text` defined', () => {
+ const event = eventWikiPageCreated();
+ beforeEach(() => {
+ createComponent({ propsData: { event } });
+ });
+
+ it('uses `title` for the link text', () => {
+ expect(findLink().text()).toBe(event.target.title);
+ });
+ });
});
describe('when target is not defined', () => {
diff --git a/spec/frontend/contribution_events/utils.js b/spec/frontend/contribution_events/utils.js
index 6e97455582d..ba75d39a90f 100644
--- a/spec/frontend/contribution_events/utils.js
+++ b/spec/frontend/contribution_events/utils.js
@@ -9,19 +9,28 @@ import {
EVENT_TYPE_MERGED,
PUSH_EVENT_REF_TYPE_BRANCH,
PUSH_EVENT_REF_TYPE_TAG,
+ EVENT_TYPE_CREATED,
+ TARGET_TYPE_ISSUE,
+ TARGET_TYPE_MILESTONE,
+ TARGET_TYPE_MERGE_REQUEST,
+ TARGET_TYPE_WIKI,
+ TARGET_TYPE_DESIGN,
+ TARGET_TYPE_WORK_ITEM,
+ WORK_ITEM_ISSUE_TYPE_TASK,
+ WORK_ITEM_ISSUE_TYPE_INCIDENT,
} from '~/contribution_events/constants';
-const findEventByAction = (action) => events.find((event) => event.action === action);
+const findEventByAction = (action) => () => events.find((event) => event.action === action);
-export const eventApproved = () => findEventByAction(EVENT_TYPE_APPROVED);
+export const eventApproved = findEventByAction(EVENT_TYPE_APPROVED);
-export const eventExpired = () => findEventByAction(EVENT_TYPE_EXPIRED);
+export const eventExpired = findEventByAction(EVENT_TYPE_EXPIRED);
-export const eventJoined = () => findEventByAction(EVENT_TYPE_JOINED);
+export const eventJoined = findEventByAction(EVENT_TYPE_JOINED);
-export const eventLeft = () => findEventByAction(EVENT_TYPE_LEFT);
+export const eventLeft = findEventByAction(EVENT_TYPE_LEFT);
-export const eventMerged = () => findEventByAction(EVENT_TYPE_MERGED);
+export const eventMerged = findEventByAction(EVENT_TYPE_MERGED);
const findPushEvent = ({
isNew = false,
@@ -50,3 +59,24 @@ export const eventPushedRemovedTag = findPushEvent({
export const eventBulkPushedBranch = findPushEvent({ commitCount: 5 });
export const eventPrivate = () => ({ ...events[0], action: EVENT_TYPE_PRIVATE });
+
+export const eventCreated = findEventByAction(EVENT_TYPE_CREATED);
+
+export const findCreatedEvent = (targetType) => () =>
+ events.find((event) => event.action === EVENT_TYPE_CREATED && event.target?.type === targetType);
+export const findWorkItemCreatedEvent = (issueType) => () =>
+ events.find(
+ (event) =>
+ event.action === EVENT_TYPE_CREATED &&
+ event.target?.type === TARGET_TYPE_WORK_ITEM &&
+ event.target.issue_type === issueType,
+ );
+
+export const eventProjectCreated = findCreatedEvent(undefined);
+export const eventMilestoneCreated = findCreatedEvent(TARGET_TYPE_MILESTONE);
+export const eventIssueCreated = findCreatedEvent(TARGET_TYPE_ISSUE);
+export const eventMergeRequestCreated = findCreatedEvent(TARGET_TYPE_MERGE_REQUEST);
+export const eventWikiPageCreated = findCreatedEvent(TARGET_TYPE_WIKI);
+export const eventDesignCreated = findCreatedEvent(TARGET_TYPE_DESIGN);
+export const eventTaskCreated = findWorkItemCreatedEvent(WORK_ITEM_ISSUE_TYPE_TASK);
+export const eventIncidentCreated = findWorkItemCreatedEvent(WORK_ITEM_ISSUE_TYPE_INCIDENT);
diff --git a/spec/frontend/fixtures/users.rb b/spec/frontend/fixtures/users.rb
index 800a9af194e..24e424b0b72 100644
--- a/spec/frontend/fixtures/users.rb
+++ b/spec/frontend/fixtures/users.rb
@@ -5,6 +5,7 @@ require 'spec_helper'
RSpec.describe 'Users (JavaScript fixtures)', feature_category: :user_profile do
include JavaScriptFixturesHelpers
include ApiHelpers
+ include DesignManagementTestHelpers
let_it_be(:followers) { create_list(:user, 5) }
let_it_be(:followees) { create_list(:user, 5) }
@@ -28,9 +29,15 @@ RSpec.describe 'Users (JavaScript fixtures)', feature_category: :user_profile do
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project_empty_repo, group: group) }
- include_context 'with user contribution events'
+ if Gitlab.ee?
+ include_context '[EE] with user contribution events'
+ else
+ include_context 'with user contribution events'
+ end
before do
+ enable_design_management
+ stub_licensed_features(epics: true)
group.add_owner(user)
project.add_maintainer(user)
sign_in(user)
diff --git a/spec/frontend/lib/utils/url_utility_spec.js b/spec/frontend/lib/utils/url_utility_spec.js
index 0f32eaa4ca6..e54ad674a36 100644
--- a/spec/frontend/lib/utils/url_utility_spec.js
+++ b/spec/frontend/lib/utils/url_utility_spec.js
@@ -1136,4 +1136,18 @@ describe('URL utility', () => {
expect(urlUtils.removeLastSlashInUrlPath(input)).toBe(output);
});
});
+
+ describe('buildURLwithRefType', () => {
+ const base = 'http://gitlab.com/';
+
+ it.each`
+ path | refType | output
+ ${'foo/bar'} | ${'heads'} | ${'/foo/bar?ref_type=heads'}
+ ${'/foo/bar/'} | ${'HEADS'} | ${'/foo/bar/?ref_type=heads'}
+ ${'/foo/bar/'} | ${''} | ${'/foo/bar/'}
+ ${'/'} | ${''} | ${'/'}
+ `('path $path with ref $refType becomes $output', ({ path, refType, output }) => {
+ expect(urlUtils.buildURLwithRefType({ base, path, refType })).toBe(output);
+ });
+ });
});
diff --git a/spec/frontend/repository/commits_service_spec.js b/spec/frontend/repository/commits_service_spec.js
index 22ef552c2f9..5fb683bd370 100644
--- a/spec/frontend/repository/commits_service_spec.js
+++ b/spec/frontend/repository/commits_service_spec.js
@@ -25,8 +25,13 @@ describe('commits service', () => {
resetRequestedCommits();
});
- const requestCommits = (offset, project = 'my-project', path = '', ref = 'main') =>
- loadCommits(project, path, ref, offset);
+ const requestCommits = (
+ offset,
+ project = 'my-project',
+ path = '',
+ ref = 'main',
+ refType = 'heads',
+ ) => loadCommits(project, path, ref, offset, refType);
it('calls axios get', async () => {
const offset = 10;
@@ -37,7 +42,9 @@ describe('commits service', () => {
await requestCommits(offset, project, path, ref);
- expect(axios.get).toHaveBeenCalledWith(testUrl, { params: { format: 'json', offset } });
+ expect(axios.get).toHaveBeenCalledWith(testUrl, {
+ params: { format: 'json', offset, ref_type: 'heads' },
+ });
});
it('encodes the path and ref', async () => {
diff --git a/spec/frontend/repository/components/blob_content_viewer_spec.js b/spec/frontend/repository/components/blob_content_viewer_spec.js
index e2bb7cdb2d7..50727756906 100644
--- a/spec/frontend/repository/components/blob_content_viewer_spec.js
+++ b/spec/frontend/repository/components/blob_content_viewer_spec.js
@@ -64,7 +64,7 @@ const mockRouter = {
push: mockRouterPush,
};
-const legacyViewerUrl = 'some_file.js?format=json&viewer=simple';
+const legacyViewerUrl = '/some_file.js?format=json&viewer=simple';
const createComponent = async (mockData = {}, mountFn = shallowMount, mockRoute = {}) => {
Vue.use(VueApollo);
@@ -255,7 +255,7 @@ describe('Blob content viewer component', () => {
'loads the legacy viewer when a file type is identified as legacy',
async (type) => {
await createComponent({ blob: { ...simpleViewerMock, fileType: type, webPath: type } });
- expect(mockAxios.history.get[0].url).toBe(`${type}?format=json&viewer=simple`);
+ expect(mockAxios.history.get[0].url).toBe(`/${type}?format=json&viewer=simple`);
},
);
@@ -348,7 +348,7 @@ describe('Blob content viewer component', () => {
await createComponent({ blob: { ...richViewerMock, fileType: 'unknown' } });
expect(mockAxios.history.get).toHaveLength(1);
- expect(mockAxios.history.get[0].url).toEqual('some_file.js?format=json&viewer=rich');
+ expect(mockAxios.history.get[0].url).toEqual('/some_file.js?format=json&viewer=rich');
});
});
@@ -371,7 +371,7 @@ describe('Blob content viewer component', () => {
});
it('does not load a CodeIntelligence component when no viewers are loaded', async () => {
- const url = 'some_file.js?format=json&viewer=rich';
+ const url = '/some_file.js?format=json&viewer=rich';
mockAxios.onGet(url).replyOnce(HTTP_STATUS_INTERNAL_SERVER_ERROR);
await createComponent({ blob: { ...richViewerMock, fileType: 'unknown' } });
diff --git a/spec/frontend/repository/components/table/parent_row_spec.js b/spec/frontend/repository/components/table/parent_row_spec.js
index 77822a148b7..daba5a5f63f 100644
--- a/spec/frontend/repository/components/table/parent_row_spec.js
+++ b/spec/frontend/repository/components/table/parent_row_spec.js
@@ -16,6 +16,9 @@ function factory(path, loadingPath) {
path,
loadingPath,
},
+ provide: {
+ refType: 'heads',
+ },
stubs: {
RouterLink: RouterLinkStub,
},
@@ -28,16 +31,14 @@ function factory(path, loadingPath) {
describe('Repository parent row component', () => {
it.each`
path | to
- ${'app'} | ${'/-/tree/main/'}
+ ${'app'} | ${'/-/tree/main'}
${'app/assets'} | ${'/-/tree/main/app'}
${'app/assets#/test'} | ${'/-/tree/main/app/assets%23'}
${'app/assets#/test/world'} | ${'/-/tree/main/app/assets%23/test'}
`('renders link in $path to $to', ({ path, to }) => {
factory(path);
- expect(vm.findComponent(RouterLinkStub).props().to).toEqual({
- path: to,
- });
+ expect(vm.findComponent(RouterLinkStub).props().to).toBe(`${to}?ref_type=heads`);
});
it('pushes new router when clicking row', () => {
@@ -45,9 +46,7 @@ describe('Repository parent row component', () => {
vm.find('td').trigger('click');
- expect($router.push).toHaveBeenCalledWith({
- path: '/-/tree/main/app',
- });
+ expect($router.push).toHaveBeenCalledWith('/-/tree/main/app?ref_type=heads');
});
// We test that it does not get called when clicking any internal
@@ -57,9 +56,7 @@ describe('Repository parent row component', () => {
vm.find('a').trigger('click');
- expect($router.push).not.toHaveBeenCalledWith({
- path: '/-/tree/main/app',
- });
+ expect($router.push).not.toHaveBeenCalled();
});
it('renders loading icon when loading parent', () => {
diff --git a/spec/frontend/repository/components/table/row_spec.js b/spec/frontend/repository/components/table/row_spec.js
index 02b505c828c..80471d8734b 100644
--- a/spec/frontend/repository/components/table/row_spec.js
+++ b/spec/frontend/repository/components/table/row_spec.js
@@ -44,6 +44,9 @@ function factory({ mockData = { ref: 'main', escapedRef: 'main' }, propsData = {
type: 'tree',
...propsData,
},
+ provide: {
+ refType: 'heads',
+ },
directives: {
GlHoverLoad: createMockDirective('gl-hover-load'),
},
@@ -157,9 +160,9 @@ describe('Repository table row component', () => {
},
});
- expect(wrapper.findComponent({ ref: 'link' }).props('to')).toEqual({
- path: `/-/tree/main/${encodeURIComponent(path)}`,
- });
+ expect(wrapper.findComponent({ ref: 'link' }).props('to')).toBe(
+ `/-/tree/main/${encodeURIComponent(path)}?ref_type=heads`,
+ );
});
it('renders link for directory with hash', () => {
@@ -173,7 +176,7 @@ describe('Repository table row component', () => {
},
});
- expect(wrapper.find('.tree-item-link').props('to')).toEqual({ path: '/-/tree/main/test%23' });
+ expect(wrapper.find('.tree-item-link').props('to')).toBe(`/-/tree/main/test%23?ref_type=heads`);
});
it('renders commit ID for submodule', () => {
diff --git a/spec/frontend/repository/components/tree_content_spec.js b/spec/frontend/repository/components/tree_content_spec.js
index 8d45e24e9e6..c0eb65b28fe 100644
--- a/spec/frontend/repository/components/tree_content_spec.js
+++ b/spec/frontend/repository/components/tree_content_spec.js
@@ -51,6 +51,7 @@ describe('Repository table component', () => {
propsData: {
path,
},
+ provide: { refType: 'heads' },
});
};
@@ -170,8 +171,8 @@ describe('Repository table component', () => {
expect(isRequested).toHaveBeenCalledWith(rowNumber);
expect(loadCommits.mock.calls).toEqual([
- ['', path, '', rowNumber],
- ['', path, '', rowNumber - 25],
+ ['', path, '', rowNumber, 'heads'],
+ ['', path, '', rowNumber - 25, 'heads'],
]);
});
@@ -179,7 +180,7 @@ describe('Repository table component', () => {
createComponent({ path });
findFileTable().vm.$emit('row-appear', 0);
- expect(loadCommits.mock.calls).toEqual([['', path, '', 0]]);
+ expect(loadCommits.mock.calls).toEqual([['', path, '', 0, 'heads']]);
});
});
diff --git a/spec/frontend/repository/pages/index_spec.js b/spec/frontend/repository/pages/index_spec.js
index e50557e7d61..a67a472b936 100644
--- a/spec/frontend/repository/pages/index_spec.js
+++ b/spec/frontend/repository/pages/index_spec.js
@@ -9,7 +9,9 @@ describe('Repository index page component', () => {
let wrapper;
function factory() {
- wrapper = shallowMount(IndexPage);
+ wrapper = shallowMount(IndexPage, {
+ propsData: { refType: 'heads' },
+ });
}
afterEach(() => {
@@ -35,6 +37,6 @@ describe('Repository index page component', () => {
const child = wrapper.findComponent(TreePage);
expect(child.exists()).toBe(true);
- expect(child.props()).toEqual({ path: '/' });
+ expect(child.props()).toEqual({ path: '/', refType: 'heads' });
});
});
diff --git a/spec/frontend/vue_shared/components/badges/__snapshots__/beta_badge_spec.js.snap b/spec/frontend/vue_shared/components/badges/__snapshots__/beta_badge_spec.js.snap
new file mode 100644
index 00000000000..5c49ea1b9f4
--- /dev/null
+++ b/spec/frontend/vue_shared/components/badges/__snapshots__/beta_badge_spec.js.snap
@@ -0,0 +1,53 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Beta badge component renders the badge 1`] = `
+<div>
+ <gl-badge-stub
+ class="gl-cursor-pointer"
+ iconsize="md"
+ size="md"
+ variant="muted"
+ >
+ Beta
+ </gl-badge-stub>
+
+ <gl-popover-stub
+ cssclasses=""
+ data-testid="beta-badge"
+ showclosebutton="true"
+ target="[Function]"
+ title="What's Beta?"
+ triggers="hover focus click"
+ >
+ <p>
+ A Beta feature is not production-ready, but is unlikely to change drastically before it's released. We encourage users to try Beta features and provide feedback.
+ </p>
+
+ <p
+ class="gl-mb-0"
+ >
+ A Beta feature:
+ </p>
+
+ <ul
+ class="gl-pl-4"
+ >
+ <li>
+ May have performance or stability issues.
+ </li>
+
+ <li>
+ Should not cause data loss.
+ </li>
+
+ <li>
+ Is supported by a commercially reasonable effort.
+ </li>
+
+ <li>
+ Is complete or near completion.
+ </li>
+ </ul>
+ </gl-popover-stub>
+</div>
+`;
diff --git a/spec/frontend/vue_shared/components/badges/beta_badge_spec.js b/spec/frontend/vue_shared/components/badges/beta_badge_spec.js
new file mode 100644
index 00000000000..6109fad9310
--- /dev/null
+++ b/spec/frontend/vue_shared/components/badges/beta_badge_spec.js
@@ -0,0 +1,12 @@
+import { shallowMount } from '@vue/test-utils';
+import BetaBadge from '~/vue_shared/components/badges/beta_badge.vue';
+
+describe('Beta badge component', () => {
+ let wrapper;
+
+ it('renders the badge', () => {
+ wrapper = shallowMount(BetaBadge);
+
+ expect(wrapper.element).toMatchSnapshot();
+ });
+});
diff --git a/spec/frontend/vue_shared/components/blob_viewers/rich_viewer_spec.js b/spec/frontend/vue_shared/components/blob_viewers/rich_viewer_spec.js
index 1f3029435ee..fc8155bd381 100644
--- a/spec/frontend/vue_shared/components/blob_viewers/rich_viewer_spec.js
+++ b/spec/frontend/vue_shared/components/blob_viewers/rich_viewer_spec.js
@@ -3,8 +3,10 @@ import { shallowMount } from '@vue/test-utils';
import { handleBlobRichViewer } from '~/blob/viewer';
import RichViewer from '~/vue_shared/components/blob_viewers/rich_viewer.vue';
import MarkdownFieldView from '~/vue_shared/components/markdown/field_view.vue';
+import { handleLocationHash } from '~/lib/utils/common_utils';
jest.mock('~/blob/viewer');
+jest.mock('~/lib/utils/common_utils');
describe('Blob Rich Viewer component', () => {
let wrapper;
@@ -50,4 +52,8 @@ describe('Blob Rich Viewer component', () => {
it('is using Markdown View Field', () => {
expect(wrapper.findComponent(MarkdownFieldView).exists()).toBe(true);
});
+
+ it('scrolls to the hash location', () => {
+ expect(handleLocationHash).toHaveBeenCalled();
+ });
});
diff --git a/spec/graphql/types/access_levels/deploy_key_type_spec.rb b/spec/graphql/types/access_levels/deploy_key_type_spec.rb
new file mode 100644
index 00000000000..02f58ec4c15
--- /dev/null
+++ b/spec/graphql/types/access_levels/deploy_key_type_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['AccessLevelDeployKey'], feature_category: :source_code_management do
+ subject { described_class }
+
+ let(:fields) { %i[id title expires_at user] }
+
+ specify { is_expected.to require_graphql_authorizations(:read_deploy_key) }
+
+ specify { is_expected.to have_graphql_fields(fields).at_least }
+end
diff --git a/spec/graphql/types/access_levels/user_type_spec.rb b/spec/graphql/types/access_levels/user_type_spec.rb
new file mode 100644
index 00000000000..7a34f70e166
--- /dev/null
+++ b/spec/graphql/types/access_levels/user_type_spec.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['AccessLevelUser'], feature_category: :source_code_management do
+ include GraphqlHelpers
+
+ describe 'config' do
+ subject { described_class }
+
+ let(:expected_fields) { %w[id username name publicEmail avatarUrl webUrl webPath] }
+
+ it { is_expected.to require_graphql_authorizations(:read_user) }
+ it { is_expected.to have_graphql_fields(expected_fields).only }
+ end
+
+ describe 'fields' do
+ let(:object) { instance_double(User) }
+ let(:current_user) { instance_double(User) }
+
+ before do
+ allow(described_class).to receive(:authorized?).and_return(true)
+ end
+
+ describe '#name' do
+ it 'calls User#redacted_name(current_user)' do
+ allow(object).to receive(:redacted_name).with(current_user)
+ resolve_field(:name, object, current_user: current_user)
+ expect(object).to have_received(:redacted_name).with(current_user).once
+ end
+ end
+
+ describe '#avatar_url' do
+ it 'calls User#avatar_url(only_path: false)' do
+ allow(object).to receive(:avatar_url).with(only_path: false)
+ resolve_field(:avatar_url, object, current_user: current_user)
+ expect(object).to have_received(:avatar_url).with(only_path: false).once
+ end
+ end
+ end
+end
diff --git a/spec/graphql/types/branch_protections/push_access_level_type_spec.rb b/spec/graphql/types/branch_protections/push_access_level_type_spec.rb
index 70944bac9bd..ec5d42ac720 100644
--- a/spec/graphql/types/branch_protections/push_access_level_type_spec.rb
+++ b/spec/graphql/types/branch_protections/push_access_level_type_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe GitlabSchema.types['PushAccessLevel'], feature_category: :source_code_management do
subject { described_class }
- let(:fields) { %i[access_level access_level_description] }
+ let(:fields) { %i[access_level access_level_description deploy_key] }
specify { is_expected.to require_graphql_authorizations(:read_protected_branch) }
diff --git a/spec/helpers/tree_helper_spec.rb b/spec/helpers/tree_helper_spec.rb
index 1ca5b8eb954..c94844eebbc 100644
--- a/spec/helpers/tree_helper_spec.rb
+++ b/spec/helpers/tree_helper_spec.rb
@@ -21,12 +21,14 @@ RSpec.describe TreeHelper do
describe '#vue_file_list_data' do
it 'returns a list of attributes related to the project' do
+ helper.instance_variable_set(:@ref_type, 'heads')
expect(helper.vue_file_list_data(project, sha)).to include(
project_path: project.full_path,
project_short_path: project.path,
ref: sha,
escaped_ref: sha,
- full_name: project.name_with_namespace
+ full_name: project.name_with_namespace,
+ ref_type: 'heads'
)
end
end
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index 9ce8a674146..9c7f393490e 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -306,6 +306,36 @@ RSpec.describe Gitlab::Git::Repository, feature_category: :source_code_managemen
subject
end
+
+ context 'when repository_size does not match repository_info' do
+ before do
+ allow(repository.gitaly_repository_client).to receive(:repository_size).and_return(0)
+ allow(repository.gitaly_repository_client).to receive(:repository_info).and_return(
+ Gitaly::RepositoryInfoResponse.new(size: 1.megabytes)
+ )
+ end
+
+ it 'logs the difference' do
+ expect(Gitlab::AppJsonLogger).to receive(:info).with(
+ message: "Discrepancy between RepositorySize and RepositoryInfo",
+ repository_size_megabytes: 0.0,
+ repository_info_megabytes: 1.0,
+ project_id: project.id
+ ).and_call_original
+ subject
+ end
+
+ context 'when the log_discrepancies_repository_info_for_repository_size flag is disabled' do
+ before do
+ stub_feature_flags(log_discrepancies_repository_info_for_repository_size: false)
+ end
+
+ it 'does not log' do
+ expect(Gitlab::AppJsonLogger).not_to receive(:info)
+ subject
+ end
+ end
+ end
end
end
diff --git a/spec/lib/gitlab_settings/options_spec.rb b/spec/lib/gitlab_settings/options_spec.rb
index abb895032c9..6a53b005025 100644
--- a/spec/lib/gitlab_settings/options_spec.rb
+++ b/spec/lib/gitlab_settings/options_spec.rb
@@ -12,9 +12,11 @@ RSpec.describe GitlabSettings::Options, :aggregate_failures, feature_category: :
it 'returns the unchanged internal hash' do
stub_rails_env('production')
- expect(Gitlab::ErrorTracking)
- .to receive(:track_and_raise_for_dev_exception)
- .with(RuntimeError.new("Warning: Do not mutate GitlabSettings::Options objects: `#{method}`"), method: method)
+ expect(Gitlab::AppJsonLogger)
+ .to receive(:warn)
+ .with(hash_including(
+ message: "Warning: Do not mutate GitlabSettings::Options objects: `#{method}`",
+ method: method))
.and_call_original
expect(options.send(method)).to be_truthy
@@ -234,9 +236,11 @@ RSpec.describe GitlabSettings::Options, :aggregate_failures, feature_category: :
it 'delegates the method to the internal options hash' do
stub_rails_env('production')
- expect(Gitlab::ErrorTracking)
- .to receive(:track_and_raise_for_dev_exception)
- .with(RuntimeError.new('Calling a hash method on GitlabSettings::Options: `delete`'), method: :delete)
+ expect(Gitlab::AppJsonLogger)
+ .to receive(:warn)
+ .with(hash_including(
+ message: 'Calling a hash method on GitlabSettings::Options: `delete`',
+ method: :delete))
.and_call_original
expect { options.foo.delete('bar') }
diff --git a/spec/policies/deploy_key_policy_spec.rb b/spec/policies/deploy_key_policy_spec.rb
index d84b80a8738..754f36ce3b0 100644
--- a/spec/policies/deploy_key_policy_spec.rb
+++ b/spec/policies/deploy_key_policy_spec.rb
@@ -2,69 +2,89 @@
require 'spec_helper'
-RSpec.describe DeployKeyPolicy do
+RSpec.describe DeployKeyPolicy, feature_category: :groups_and_projects do
subject { described_class.new(current_user, deploy_key) }
- describe 'updating a deploy_key' do
- context 'when a regular user' do
- let(:current_user) { create(:user) }
+ let_it_be(:current_user, refind: true) { create(:user) }
+ let_it_be(:admin) { create(:user, :admin) }
- context 'tries to update private deploy key attached to project' do
- let(:deploy_key) { create(:deploy_key, public: false) }
- let(:project) { create(:project_empty_repo) }
+ context 'when deploy key is public' do
+ let_it_be(:deploy_key) { create(:deploy_key, public: true) }
- before do
- project.add_maintainer(current_user)
- project.deploy_keys << deploy_key
- end
+ context 'and current_user is nil' do
+ let(:current_user) { nil }
- it { is_expected.to be_allowed(:update_deploy_key) }
- end
+ it { is_expected.to be_disallowed(:read_deploy_key) }
+
+ it { is_expected.to be_disallowed(:update_deploy_key) }
+ end
- context 'tries to update private deploy key attached to other project' do
- let(:deploy_key) { create(:deploy_key, public: false) }
- let(:other_project) { create(:project_empty_repo) }
+ context 'and current_user is present' do
+ it { is_expected.to be_allowed(:read_deploy_key) }
- before do
- other_project.deploy_keys << deploy_key
- end
+ it { is_expected.to be_disallowed(:update_deploy_key) }
+ end
- it { is_expected.to be_disallowed(:update_deploy_key) }
+ context 'when current_user is admin' do
+ let(:current_user) { admin }
+
+ context 'when admin mode enabled', :enable_admin_mode do
+ it { is_expected.to be_allowed(:read_deploy_key) }
+
+ it { is_expected.to be_allowed(:update_deploy_key) }
end
- context 'tries to update public deploy key' do
- let(:deploy_key) { create(:another_deploy_key, public: true) }
+ context 'when admin mode disabled' do
+ it { is_expected.to be_allowed(:read_deploy_key) }
it { is_expected.to be_disallowed(:update_deploy_key) }
end
end
+ end
+
+ context 'when deploy key is private' do
+ let_it_be(:deploy_key) { create(:deploy_key, :private) }
+
+ context 'and current_user is nil' do
+ let(:current_user) { nil }
- context 'when an admin user' do
- let(:current_user) { create(:user, :admin) }
+ it { is_expected.to be_disallowed(:read_deploy_key) }
- context 'tries to update private deploy key' do
- let(:deploy_key) { create(:deploy_key, public: false) }
+ it { is_expected.to be_disallowed(:update_deploy_key) }
+ end
+
+ context 'when current_user is admin' do
+ let(:current_user) { admin }
- context 'when admin mode enabled', :enable_admin_mode do
- it { is_expected.to be_allowed(:update_deploy_key) }
- end
+ context 'when admin mode enabled', :enable_admin_mode do
+ it { is_expected.to be_allowed(:read_deploy_key) }
- context 'when admin mode disabled' do
- it { is_expected.to be_disallowed(:update_deploy_key) }
- end
+ it { is_expected.to be_allowed(:update_deploy_key) }
end
- context 'when an admin user tries to update public deploy key' do
- let(:deploy_key) { create(:another_deploy_key, public: true) }
+ context 'when admin mode disabled' do
+ it { is_expected.to be_disallowed(:read_deploy_key) }
+
+ it { is_expected.to be_disallowed(:update_deploy_key) }
+ end
+ end
- context 'when admin mode enabled', :enable_admin_mode do
- it { is_expected.to be_allowed(:update_deploy_key) }
- end
+ context 'when assigned to the project' do
+ let_it_be(:deploy_keys_project) { create(:deploy_keys_project, deploy_key: deploy_key) }
- context 'when admin mode disabled' do
- it { is_expected.to be_disallowed(:update_deploy_key) }
- end
+ before_all do
+ deploy_keys_project.project.add_maintainer(current_user)
end
+
+ it { is_expected.to be_allowed(:read_deploy_key) }
+
+ it { is_expected.to be_allowed(:update_deploy_key) }
+ end
+
+ context 'when assigned to another project' do
+ it { is_expected.to be_disallowed(:read_deploy_key) }
+
+ it { is_expected.to be_disallowed(:update_deploy_key) }
end
end
end
diff --git a/spec/support/shared_contexts/user_contribution_events_shared_context.rb b/spec/support/shared_contexts/user_contribution_events_shared_context.rb
index 48f0ac1e4ac..74f25e5f4d1 100644
--- a/spec/support/shared_contexts/user_contribution_events_shared_context.rb
+++ b/spec/support/shared_contexts/user_contribution_events_shared_context.rb
@@ -22,8 +22,6 @@ RSpec.shared_context 'with user contribution events' do
# work item
let_it_be(:incident) { create(:work_item, :incident, author: user, project: project) }
- let_it_be(:test_case) { create(:work_item, :test_case, author: user, project: project) }
- let_it_be(:requirement) { create(:work_item, :requirement, author: user, project: project) }
let_it_be(:task) { create(:work_item, :task, author: user, project: project) }
# events
@@ -37,7 +35,6 @@ RSpec.shared_context 'with user contribution events' do
let_it_be(:closed_issue_event) { create(:event, :closed, author: user, project: project, target: issue) }
let_it_be(:closed_milestone_event) { create(:event, :closed, author: user, project: project, target: milestone) }
let_it_be(:closed_incident_event) { create(:event, :closed, author: user, project: project, target: incident) }
- let_it_be(:closed_test_case_event) { create(:event, :closed, author: user, project: project, target: test_case) }
let_it_be(:closed_merge_request_event) do
create(:event, :closed, author: user, project: project, target: merge_request)
end
@@ -57,14 +54,6 @@ RSpec.shared_context 'with user contribution events' do
create(:event, :created, :for_work_item, author: user, project: project, target: incident)
end
- let_it_be(:created_test_case_event) do
- create(:event, :created, :for_work_item, author: user, project: project, target: test_case)
- end
-
- let_it_be(:created_requirement_event) do
- create(:event, :created, :for_work_item, author: user, project: project, target: requirement)
- end
-
let_it_be(:created_task_event) do
create(:event, :created, :for_work_item, author: user, project: project, target: task)
end
@@ -148,7 +137,6 @@ RSpec.shared_context 'with user contribution events' do
let_it_be(:reopened_issue_event) { create(:event, :reopened, author: user, project: project, target: issue) }
let_it_be(:reopened_milestone_event) { create(:event, :reopened, author: user, project: project, target: milestone) }
let_it_be(:reopened_incident_event) { create(:event, :reopened, author: user, project: project, target: incident) }
- let_it_be(:reopened_test_case_event) { create(:event, :reopened, author: user, project: project, target: test_case) }
let_it_be(:reopened_merge_request_event) do
create(:event, :reopened, author: user, project: project, target: merge_request)
end