diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-07-24 21:08:45 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-07-24 21:08:45 +0300 |
commit | 2ae564d6f59fc939bfdbb155d445efe97b34c1e1 (patch) | |
tree | 106ebc2021d84757ca03610747a60c8f47ac9fb0 /spec | |
parent | 7308ec9d13fb69018200a40f287e76ef499ed47c (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
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 |