diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-06-25 00:08:34 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-06-25 00:08:34 +0000 |
commit | 1e6730a4e32f6cbf4b84aa9fc13204778783f33c (patch) | |
tree | 6dd6c9ed98ec836432cf431397a4ef45dd78deb8 /spec | |
parent | 95a48f11db963bc55ab918e3eb24f8576dca4a81 (diff) | |
download | gitlab-ce-1e6730a4e32f6cbf4b84aa9fc13204778783f33c.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
20 files changed, 256 insertions, 62 deletions
diff --git a/spec/frontend/batch_comments/components/draft_note_spec.js b/spec/frontend/batch_comments/components/draft_note_spec.js index c2d488a465e..5d22823e974 100644 --- a/spec/frontend/batch_comments/components/draft_note_spec.js +++ b/spec/frontend/batch_comments/components/draft_note_spec.js @@ -1,5 +1,6 @@ import { getByRole } from '@testing-library/dom'; import { shallowMount, createLocalVue } from '@vue/test-utils'; +import { stubComponent } from 'helpers/stub_component'; import DraftNote from '~/batch_comments/components/draft_note.vue'; import { createStore } from '~/batch_comments/stores'; import NoteableNote from '~/notes/components/noteable_note.vue'; @@ -8,6 +9,14 @@ import { createDraft } from '../mock_data'; const localVue = createLocalVue(); +const NoteableNoteStub = stubComponent(NoteableNote, { + template: ` + <div> + <slot name="note-header-info">Test</slot> + </div> + `, +}); + describe('Batch comments draft note component', () => { let store; let wrapper; @@ -26,6 +35,9 @@ describe('Batch comments draft note component', () => { store, propsData, localVue, + stubs: { + NoteableNote: NoteableNoteStub, + }, }); jest.spyOn(wrapper.vm.$store, 'dispatch').mockImplementation(); diff --git a/spec/frontend/frequent_items/utils_spec.js b/spec/frontend/frequent_items/utils_spec.js index a7ab18b0d10..8c3841558f4 100644 --- a/spec/frontend/frequent_items/utils_spec.js +++ b/spec/frontend/frequent_items/utils_spec.js @@ -66,35 +66,36 @@ describe('Frequent Items utils spec', () => { }); describe('updateExistingFrequentItem', () => { - let mockedProject; - - beforeEach(() => { - mockedProject = { - ...mockProject, - frequency: 1, - lastAccessedOn: 1497979281815, - }; + const LAST_ACCESSED = 1497979281815; + const WITHIN_AN_HOUR = LAST_ACCESSED + HOUR_IN_MS; + const OVER_AN_HOUR = WITHIN_AN_HOUR + 1; + const EXISTING_ITEM = Object.freeze({ + ...mockProject, + frequency: 1, + lastAccessedOn: 1497979281815, }); - it('updates item if accessed over an hour ago', () => { - const newTimestamp = Date.now() + HOUR_IN_MS + 1; + it.each` + desc | existingProps | newProps | expected + ${'updates item if accessed over an hour ago'} | ${{}} | ${{ lastAccessedOn: OVER_AN_HOUR }} | ${{ lastAccessedOn: Date.now(), frequency: 2 }} + ${'does not update is accessed with an hour'} | ${{}} | ${{ lastAccessedOn: WITHIN_AN_HOUR }} | ${{ lastAccessedOn: EXISTING_ITEM.lastAccessedOn, frequency: 1 }} + ${'updates if lastAccessedOn not found'} | ${{ lastAccessedOn: undefined }} | ${{ lastAccessedOn: WITHIN_AN_HOUR }} | ${{ lastAccessedOn: Date.now(), frequency: 2 }} + `('$desc', ({ existingProps, newProps, expected }) => { const newItem = { - ...mockedProject, - lastAccessedOn: newTimestamp, + ...EXISTING_ITEM, + ...newProps, }; - const result = updateExistingFrequentItem(mockedProject, newItem); - - expect(result.frequency).toBe(mockedProject.frequency + 1); - }); - - it('does not update item if accessed within the hour', () => { - const newItem = { - ...mockedProject, - lastAccessedOn: mockedProject.lastAccessedOn + HOUR_IN_MS, + const existingItem = { + ...EXISTING_ITEM, + ...existingProps, }; - const result = updateExistingFrequentItem(mockedProject, newItem); - expect(result.frequency).toBe(mockedProject.frequency); + const result = updateExistingFrequentItem(existingItem, newItem); + + expect(result).toEqual({ + ...newItem, + ...expected, + }); }); }); diff --git a/spec/frontend/issuable_create/components/issuable_form_spec.js b/spec/frontend/issuable_create/components/issuable_form_spec.js index a074fddf091..30b116bc35c 100644 --- a/spec/frontend/issuable_create/components/issuable_form_spec.js +++ b/spec/frontend/issuable_create/components/issuable_form_spec.js @@ -23,6 +23,9 @@ const createComponent = ({ <button class="js-issuable-save">Submit issuable</button> `, }, + stubs: { + MarkdownField, + }, }); }; diff --git a/spec/frontend/monitoring/components/charts/time_series_spec.js b/spec/frontend/monitoring/components/charts/time_series_spec.js index 754ddd96c9b..ea6e4f4a5ed 100644 --- a/spec/frontend/monitoring/components/charts/time_series_spec.js +++ b/spec/frontend/monitoring/components/charts/time_series_spec.js @@ -51,6 +51,8 @@ describe('Time series component', () => { }, stubs: { GlPopover: true, + GlLineChart, + GlAreaChart, }, attachTo: document.body, }); @@ -202,7 +204,7 @@ describe('Time series component', () => { describe('when series is of line type', () => { beforeEach(() => { - createWrapper(); + createWrapper({}, mount); wrapper.vm.formatTooltipText(mockLineSeriesData()); return wrapper.vm.$nextTick(); }); diff --git a/spec/frontend/monitoring/components/dashboard_actions_menu_spec.js b/spec/frontend/monitoring/components/dashboard_actions_menu_spec.js index 6e98ca28071..dbb9fd5f603 100644 --- a/spec/frontend/monitoring/components/dashboard_actions_menu_spec.js +++ b/spec/frontend/monitoring/components/dashboard_actions_menu_spec.js @@ -1,4 +1,4 @@ -import { GlDropdownItem } from '@gitlab/ui'; +import { GlDropdownItem, GlModal } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; import CustomMetricsFormFields from '~/custom_metrics/components/custom_metrics_form_fields.vue'; import { redirectTo } from '~/lib/utils/url_utility'; @@ -43,6 +43,9 @@ describe('Actions menu', () => { wrapper = shallowMount(ActionsMenu, { propsData: { ...dashboardActionsMenuProps, ...props }, store, + stubs: { + GlModal, + }, ...options, }); }; @@ -82,7 +85,7 @@ describe('Actions menu', () => { it('modal for custom metrics form is rendered', () => { expect(findAddMetricModal().exists()).toBe(true); - expect(findAddMetricModal().attributes().modalid).toBe('addMetric'); + expect(findAddMetricModal().props('modalId')).toBe('addMetric'); }); it('add metric modal submit button exists', () => { diff --git a/spec/frontend/nav/components/responsive_app_spec.js b/spec/frontend/nav/components/responsive_app_spec.js index 7221ea2c5cd..e1b443745e3 100644 --- a/spec/frontend/nav/components/responsive_app_spec.js +++ b/spec/frontend/nav/components/responsive_app_spec.js @@ -111,6 +111,7 @@ describe('~/nav/components/responsive_app.vue', () => { containerClass: 'gl-px-3', frequentItemsDropdownType: ResponsiveApp.FREQUENT_ITEMS_PROJECTS.namespace, frequentItemsVuexModule: ResponsiveApp.FREQUENT_ITEMS_PROJECTS.vuexModule, + currentItem: {}, linksPrimary: TEST_NAV_DATA.views.projects.linksPrimary, linksSecondary: TEST_NAV_DATA.views.projects.linksSecondary, }; @@ -118,6 +119,7 @@ describe('~/nav/components/responsive_app.vue', () => { containerClass: 'gl-px-3', frequentItemsDropdownType: ResponsiveApp.FREQUENT_ITEMS_GROUPS.namespace, frequentItemsVuexModule: ResponsiveApp.FREQUENT_ITEMS_GROUPS.vuexModule, + currentItem: {}, linksPrimary: TEST_NAV_DATA.views.groups.linksPrimary, linksSecondary: TEST_NAV_DATA.views.groups.linksSecondary, }; diff --git a/spec/frontend/nav/components/top_nav_container_view_spec.js b/spec/frontend/nav/components/top_nav_container_view_spec.js index 06d2179b859..0218f09af0a 100644 --- a/spec/frontend/nav/components/top_nav_container_view_spec.js +++ b/spec/frontend/nav/components/top_nav_container_view_spec.js @@ -1,4 +1,5 @@ import { shallowMount } from '@vue/test-utils'; +import { merge } from 'lodash'; import { nextTick } from 'vue'; import FrequentItemsApp from '~/frequent_items/components/app.vue'; import { FREQUENT_ITEMS_PROJECTS } from '~/frequent_items/constants'; @@ -82,7 +83,9 @@ describe('~/nav/components/top_nav_container_view.vue', () => { it('renders frequent items app', () => { expect(findFrequentItemsApp()).toEqual({ vuexModule: DEFAULT_PROPS.frequentItemsVuexModule, - props: expect.objectContaining(TEST_OTHER_PROPS), + props: expect.objectContaining( + merge({ currentItem: { lastAccessedOn: Date.now() } }, TEST_OTHER_PROPS), + ), attributes: expect.objectContaining(EXTRA_ATTRS), }); }); diff --git a/spec/frontend/notes/components/discussion_notes_spec.js b/spec/frontend/notes/components/discussion_notes_spec.js index cd24b9afbdf..59ac75f00e6 100644 --- a/spec/frontend/notes/components/discussion_notes_spec.js +++ b/spec/frontend/notes/components/discussion_notes_spec.js @@ -1,5 +1,5 @@ import { getByRole } from '@testing-library/dom'; -import { shallowMount } from '@vue/test-utils'; +import { shallowMount, mount } from '@vue/test-utils'; import '~/behaviors/markdown/render_gfm'; import DiscussionNotes from '~/notes/components/discussion_notes.vue'; import NoteableNote from '~/notes/components/noteable_note.vue'; @@ -23,8 +23,8 @@ describe('DiscussionNotes', () => { let wrapper; const getList = () => getByRole(wrapper.element, 'list'); - const createComponent = (props) => { - wrapper = shallowMount(DiscussionNotes, { + const createComponent = (props, mountingMethod = shallowMount) => { + wrapper = mountingMethod(DiscussionNotes, { store, propsData: { discussion: discussionMock, @@ -33,7 +33,11 @@ describe('DiscussionNotes', () => { ...props, }, scopedSlots: { - footer: '<p slot-scope="{ showReplies }">showReplies:{{showReplies}}</p>', + footer: ` + <template #default="{ showReplies }"> + <p>showReplies:{{ showReplies }}</p>, + </template> + `, }, slots: { 'avatar-badge': '<span class="avatar-badge-slot-content" />', @@ -112,7 +116,7 @@ describe('DiscussionNotes', () => { }); it('passes down avatar-badge slot content', () => { - createComponent(); + createComponent({}, mount); expect(wrapper.find('.avatar-badge-slot-content').exists()).toBe(true); }); }); diff --git a/spec/frontend/pages/projects/forks/new/components/fork_form_spec.js b/spec/frontend/pages/projects/forks/new/components/fork_form_spec.js index c80ccfa8256..f9be0796546 100644 --- a/spec/frontend/pages/projects/forks/new/components/fork_form_spec.js +++ b/spec/frontend/pages/projects/forks/new/components/fork_form_spec.js @@ -155,7 +155,7 @@ describe('ForkForm component', () => { describe('forks namespaces', () => { beforeEach(() => { mockGetRequest({ namespaces: MOCK_NAMESPACES_RESPONSE }); - createComponent(); + createFullComponent(); }); it('make GET request from endpoint', async () => { diff --git a/spec/frontend/projects/pipelines/charts/components/__snapshots__/ci_cd_analytics_area_chart_spec.js.snap b/spec/frontend/projects/pipelines/charts/components/__snapshots__/ci_cd_analytics_area_chart_spec.js.snap index c37f6415898..fc51825f15b 100644 --- a/spec/frontend/projects/pipelines/charts/components/__snapshots__/ci_cd_analytics_area_chart_spec.js.snap +++ b/spec/frontend/projects/pipelines/charts/components/__snapshots__/ci_cd_analytics_area_chart_spec.js.snap @@ -21,11 +21,7 @@ exports[`CiCdAnalyticsAreaChart matches the snapshot 1`] = ` option="[object Object]" thresholds="" width="0" - > - <template /> - - <template /> - </glareachart-stub> + /> </div> </div> `; diff --git a/spec/frontend/terraform/components/terraform_list_spec.js b/spec/frontend/terraform/components/terraform_list_spec.js index 882b7b55b3e..c622f86072d 100644 --- a/spec/frontend/terraform/components/terraform_list_spec.js +++ b/spec/frontend/terraform/components/terraform_list_spec.js @@ -47,6 +47,9 @@ describe('TerraformList', () => { localVue, apolloProvider, propsData, + stubs: { + GlTab, + }, }); }; diff --git a/spec/frontend/vue_mr_widget/components/states/commit_edit_spec.js b/spec/frontend/vue_mr_widget/components/states/commit_edit_spec.js index 5d09af50420..8214cedc4a1 100644 --- a/spec/frontend/vue_mr_widget/components/states/commit_edit_spec.js +++ b/spec/frontend/vue_mr_widget/components/states/commit_edit_spec.js @@ -63,7 +63,7 @@ describe('Commits edit component', () => { beforeEach(() => { createComponent({ header: `<div class="test-header">${testCommitMessage}</div>`, - checkbox: `<label slot="checkbox" class="test-checkbox">${testLabel}</label >`, + checkbox: `<label class="test-checkbox">${testLabel}</label >`, }); }); diff --git a/spec/frontend/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js b/spec/frontend/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js index 2d00cd8e8d4..cd77d442cbf 100644 --- a/spec/frontend/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js +++ b/spec/frontend/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js @@ -70,6 +70,9 @@ const createComponent = (customConfig = {}, mergeRequestWidgetGraphql = false) = mergeRequestWidgetGraphql, }, }, + stubs: { + CommitEdit, + }, }); }; diff --git a/spec/frontend/vue_shared/components/diff_viewer/viewers/image_diff_viewer_spec.js b/spec/frontend/vue_shared/components/diff_viewer/viewers/image_diff_viewer_spec.js index eacc41ccdad..01fc6210d3f 100644 --- a/spec/frontend/vue_shared/components/diff_viewer/viewers/image_diff_viewer_spec.js +++ b/spec/frontend/vue_shared/components/diff_viewer/viewers/image_diff_viewer_spec.js @@ -121,7 +121,9 @@ describe('ImageDiffViewer', () => { :new-size="newSize" :old-size="oldSize" > - <span slot="image-overlay" class="overlay">test</span> + <template #image-overlay> + <span class="overlay">test</span> + </template> </image-diff-viewer> `), }).$mount(); diff --git a/spec/frontend/vue_shared/components/paginated_list_spec.js b/spec/frontend/vue_shared/components/paginated_list_spec.js index c0ee49f194f..9f819cc4e94 100644 --- a/spec/frontend/vue_shared/components/paginated_list_spec.js +++ b/spec/frontend/vue_shared/components/paginated_list_spec.js @@ -7,9 +7,11 @@ describe('Pagination links component', () => { let glPaginatedList; const template = ` - <div class="slot" slot-scope="{ listItem }"> - <span class="item">Item Name: {{listItem.id}}</span> - </div> + <template #default="{ listItem }"> + <div class="slot"> + <span class="item">Item Name: {{ listItem.id }}</span> + </div> + </template> `; const props = { diff --git a/spec/frontend/vue_shared/components/resizable_chart/__snapshots__/resizable_chart_container_spec.js.snap b/spec/frontend/vue_shared/components/resizable_chart/__snapshots__/resizable_chart_container_spec.js.snap index add0c36a120..cdfe311acd9 100644 --- a/spec/frontend/vue_shared/components/resizable_chart/__snapshots__/resizable_chart_container_spec.js.snap +++ b/spec/frontend/vue_shared/components/resizable_chart/__snapshots__/resizable_chart_container_spec.js.snap @@ -2,20 +2,22 @@ exports[`Resizable Chart Container renders the component 1`] = ` <div> - <div - class="slot" - > - <span - class="width" + <template> + <div + class="slot" > - 0 - </span> - - <span - class="height" - > - 0 - </span> - </div> + <span + class="width" + > + 0 + </span> + + <span + class="height" + > + 0 + </span> + </div> + </template> </div> `; diff --git a/spec/frontend/vue_shared/components/resizable_chart/resizable_chart_container_spec.js b/spec/frontend/vue_shared/components/resizable_chart/resizable_chart_container_spec.js index 1fce3c5d0b0..40f0c0f29f2 100644 --- a/spec/frontend/vue_shared/components/resizable_chart/resizable_chart_container_spec.js +++ b/spec/frontend/vue_shared/components/resizable_chart/resizable_chart_container_spec.js @@ -16,10 +16,12 @@ describe('Resizable Chart Container', () => { wrapper = mount(ResizableChartContainer, { scopedSlots: { default: ` - <div class="slot" slot-scope="{ width, height }"> - <span class="width">{{width}}</span> - <span class="height">{{height}}</span> - </div> + <template #default="{ width, height }"> + <div class="slot"> + <span class="width">{{width}}</span> + <span class="height">{{height}}</span> + </div> + </template> `, }, }); diff --git a/spec/models/service_desk_setting_spec.rb b/spec/models/service_desk_setting_spec.rb index 8ccbd983ba1..f99ac84175c 100644 --- a/spec/models/service_desk_setting_spec.rb +++ b/spec/models/service_desk_setting_spec.rb @@ -10,7 +10,7 @@ RSpec.describe ServiceDeskSetting do it { is_expected.to validate_length_of(:outgoing_name).is_at_most(255) } it { is_expected.to validate_length_of(:project_key).is_at_most(255) } it { is_expected.to allow_value('abc123_').for(:project_key) } - it { is_expected.not_to allow_value('abc 12').for(:project_key) } + it { is_expected.not_to allow_value('abc 12').for(:project_key).with_message("can contain only lowercase letters, digits, and '_'.") } it { is_expected.not_to allow_value('Big val').for(:project_key) } describe '.valid_issue_template' do diff --git a/spec/requests/api/graphql/mutations/packages/destroy_package_spec.rb b/spec/requests/api/graphql/mutations/packages/destroy_package_spec.rb new file mode 100644 index 00000000000..e5ced419ecf --- /dev/null +++ b/spec/requests/api/graphql/mutations/packages/destroy_package_spec.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Destroying a package' do + using RSpec::Parameterized::TableSyntax + + include GraphqlHelpers + + let_it_be_with_reload(:package) { create(:package) } + let_it_be(:user) { create(:user) } + + let(:project) { package.project } + let(:id) { package.to_global_id.to_s } + + let(:query) do + <<~GQL + errors + GQL + end + + let(:params) { { id: id } } + let(:mutation) { graphql_mutation(:destroy_package, params, query) } + let(:mutation_response) { graphql_mutation_response(:destroyPackage) } + + shared_examples 'destroying the package' do + it 'destroy the package' do + expect(::Packages::DestroyPackageService) + .to receive(:new).with(container: package, current_user: user).and_call_original + + expect { mutation_request }.to change { ::Packages::Package.count }.by(-1) + end + + it_behaves_like 'returning response status', :success + end + + shared_examples 'denying the mutation request' do + it 'does not destroy the package' do + expect(::Packages::DestroyPackageService) + .not_to receive(:new).with(container: package, current_user: user) + + expect { mutation_request }.not_to change { ::Packages::Package.count } + + expect(mutation_response).to be_nil + end + + it_behaves_like 'returning response status', :success + end + + describe 'post graphql mutation' do + subject(:mutation_request) { post_graphql_mutation(mutation, current_user: user) } + + context 'with valid id' do + where(:user_role, :shared_examples_name) do + :maintainer | 'destroying the package' + :developer | 'denying the mutation request' + :reporter | 'denying the mutation request' + :guest | 'denying the mutation request' + :anonymous | 'denying the mutation request' + end + + with_them do + before do + project.send("add_#{user_role}", user) unless user_role == :anonymous + end + + it_behaves_like params[:shared_examples_name] + end + end + + context 'with invalid id' do + let(:params) { { id: 'gid://gitlab/Packages::Package/5555' } } + + it_behaves_like 'denying the mutation request' + end + + context 'when an error occures' do + before do + project.add_maintainer(user) + end + + it 'returns the errors in the response' do + allow_next_found_instance_of(::Packages::Package) do |package| + allow(package).to receive(:destroy!).and_raise(StandardError) + end + + mutation_request + + expect(mutation_response['errors']).to eq(['Failed to remove the package']) + end + end + end +end diff --git a/spec/services/packages/destroy_package_service_spec.rb b/spec/services/packages/destroy_package_service_spec.rb new file mode 100644 index 00000000000..92db8da968c --- /dev/null +++ b/spec/services/packages/destroy_package_service_spec.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Packages::DestroyPackageService do + let_it_be(:user) { create(:user) } + + let!(:package) { create(:npm_package) } + + describe '#execute' do + subject(:service) { described_class.new(container: package, current_user: user) } + + context 'when the user is authorized' do + before do + package.project.add_maintainer(user) + end + + context 'when the destroy is successfull' do + it 'destroy the package' do + expect(package).to receive(:sync_maven_metadata).and_call_original + expect { service.execute }.to change { Packages::Package.count }.by(-1) + end + + it 'returns a success ServiceResponse' do + response = service.execute + + expect(response).to be_a(ServiceResponse) + expect(response).to be_success + expect(response.message).to eq("Package was successfully deleted") + end + end + + context 'when the destroy is not successful' do + before do + allow(package).to receive(:destroy!).and_raise(StandardError, "test") + end + + it 'returns an error ServiceResponse' do + response = service.execute + + expect(package).not_to receive(:sync_maven_metadata) + expect(response).to be_a(ServiceResponse) + expect(response).to be_error + expect(response.message).to eq("Failed to remove the package") + expect(response.status).to eq(:error) + end + end + end + + context 'when the user is not authorized' do + it 'returns an error ServiceResponse' do + response = service.execute + + expect(response).to be_a(ServiceResponse) + expect(response).to be_error + expect(response.message).to eq("You don't have access to this package") + expect(response.status).to eq(:error) + end + end + end +end |