diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-09-28 09:09:28 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-09-28 09:09:28 +0000 |
commit | f3cfb235c76426ce5a18003bb80ba625097bf1d0 (patch) | |
tree | 01705538824afb4ef6651d3e013c9e2411c08891 /spec | |
parent | f8184e504b8aa6f77b42583a9fd08daebbdcc8ab (diff) | |
download | gitlab-ce-f3cfb235c76426ce5a18003bb80ba625097bf1d0.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
49 files changed, 362 insertions, 209 deletions
diff --git a/spec/factories/bulk_import/entities.rb b/spec/factories/bulk_import/entities.rb index cf31ffec4f6..eeb4f8325ae 100644 --- a/spec/factories/bulk_import/entities.rb +++ b/spec/factories/bulk_import/entities.rb @@ -9,6 +9,7 @@ FactoryBot.define do sequence(:destination_namespace) { |n| "destination-path-#{n}" } destination_name { 'Imported Entity' } + sequence(:source_xid) trait(:group_entity) do source_type { :group_entity } diff --git a/spec/frontend/commit/commit_pipeline_status_component_spec.js b/spec/frontend/commit/commit_pipeline_status_component_spec.js index 73720c1cc88..e75fb697a7b 100644 --- a/spec/frontend/commit/commit_pipeline_status_component_spec.js +++ b/spec/frontend/commit/commit_pipeline_status_component_spec.js @@ -3,7 +3,7 @@ import { shallowMount } from '@vue/test-utils'; import Visibility from 'visibilityjs'; import { nextTick } from 'vue'; import fixture from 'test_fixtures/pipelines/pipelines.json'; -import createFlash from '~/flash'; +import { createAlert } from '~/flash'; import Poll from '~/lib/utils/poll'; import CommitPipelineStatus from '~/projects/tree/components/commit_pipeline_status_component.vue'; import CiIcon from '~/vue_shared/components/ci_icon.vue'; @@ -170,7 +170,7 @@ describe('Commit pipeline status component', () => { }); it('displays flash error message', () => { - expect(createFlash).toHaveBeenCalled(); + expect(createAlert).toHaveBeenCalled(); }); }); }); diff --git a/spec/frontend/error_tracking/components/error_details_spec.js b/spec/frontend/error_tracking/components/error_details_spec.js index 732eff65495..9d6e46be8c4 100644 --- a/spec/frontend/error_tracking/components/error_details_spec.js +++ b/spec/frontend/error_tracking/components/error_details_spec.js @@ -18,7 +18,7 @@ import { trackErrorDetailsViewsOptions, trackErrorStatusUpdateOptions, } from '~/error_tracking/utils'; -import createFlash from '~/flash'; +import { createAlert, VARIANT_WARNING } from '~/flash'; import { __ } from '~/locale'; import Tracking from '~/tracking'; @@ -144,7 +144,7 @@ describe('ErrorDetails', () => { await nextTick(); expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true); - expect(createFlash).not.toHaveBeenCalled(); + expect(createAlert).not.toHaveBeenCalled(); expect(mocks.$apollo.queries.error.stopPolling).not.toHaveBeenCalled(); }); @@ -156,9 +156,9 @@ describe('ErrorDetails', () => { await nextTick(); expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(false); expect(wrapper.findComponent(GlLink).exists()).toBe(false); - expect(createFlash).toHaveBeenCalledWith({ + expect(createAlert).toHaveBeenCalledWith({ message: 'Could not connect to Sentry. Refresh the page to try again.', - type: 'warning', + variant: VARIANT_WARNING, }); expect(mocks.$apollo.queries.error.stopPolling).toHaveBeenCalled(); }); diff --git a/spec/frontend/error_tracking/store/actions_spec.js b/spec/frontend/error_tracking/store/actions_spec.js index 6bac21341a7..8f085282f80 100644 --- a/spec/frontend/error_tracking/store/actions_spec.js +++ b/spec/frontend/error_tracking/store/actions_spec.js @@ -2,7 +2,7 @@ import MockAdapter from 'axios-mock-adapter'; import testAction from 'helpers/vuex_action_helper'; import * as actions from '~/error_tracking/store/actions'; import * as types from '~/error_tracking/store/mutation_types'; -import createFlash from '~/flash'; +import { createAlert } from '~/flash'; import axios from '~/lib/utils/axios_utils'; import { visitUrl } from '~/lib/utils/url_utility'; @@ -20,7 +20,7 @@ describe('Sentry common store actions', () => { afterEach(() => { mock.restore(); - createFlash.mockClear(); + createAlert.mockClear(); }); const endpoint = '123/stacktrace'; const redirectUrl = '/list'; @@ -49,7 +49,7 @@ describe('Sentry common store actions', () => { mock.onPut().reply(400, {}); await testAction(actions.updateStatus, params, {}, [], []); expect(visitUrl).not.toHaveBeenCalled(); - expect(createFlash).toHaveBeenCalledTimes(1); + expect(createAlert).toHaveBeenCalledTimes(1); }); }); diff --git a/spec/frontend/error_tracking/store/details/actions_spec.js b/spec/frontend/error_tracking/store/details/actions_spec.js index a3a6f7cc309..1893d226270 100644 --- a/spec/frontend/error_tracking/store/details/actions_spec.js +++ b/spec/frontend/error_tracking/store/details/actions_spec.js @@ -2,7 +2,7 @@ import MockAdapter from 'axios-mock-adapter'; import testAction from 'helpers/vuex_action_helper'; import * as actions from '~/error_tracking/store/details/actions'; import * as types from '~/error_tracking/store/details/mutation_types'; -import createFlash from '~/flash'; +import { createAlert } from '~/flash'; import axios from '~/lib/utils/axios_utils'; import Poll from '~/lib/utils/poll'; @@ -19,7 +19,7 @@ describe('Sentry error details store actions', () => { afterEach(() => { mockedAdapter.restore(); - createFlash.mockClear(); + createAlert.mockClear(); if (mockedRestart) { mockedRestart.mockRestore(); mockedRestart = null; @@ -53,7 +53,7 @@ describe('Sentry error details store actions', () => { [{ type: types.SET_LOADING_STACKTRACE, payload: false }], [], ); - expect(createFlash).toHaveBeenCalledTimes(1); + expect(createAlert).toHaveBeenCalledTimes(1); }); it('should not restart polling when receiving an empty 204 response', async () => { diff --git a/spec/frontend/error_tracking/store/list/actions_spec.js b/spec/frontend/error_tracking/store/list/actions_spec.js index 7173f68bb96..2809bbe834e 100644 --- a/spec/frontend/error_tracking/store/list/actions_spec.js +++ b/spec/frontend/error_tracking/store/list/actions_spec.js @@ -2,7 +2,7 @@ import MockAdapter from 'axios-mock-adapter'; import testAction from 'helpers/vuex_action_helper'; import * as actions from '~/error_tracking/store/list/actions'; import * as types from '~/error_tracking/store/list/mutation_types'; -import createFlash from '~/flash'; +import { createAlert } from '~/flash'; import axios from '~/lib/utils/axios_utils'; import httpStatusCodes from '~/lib/utils/http_status'; @@ -51,7 +51,7 @@ describe('error tracking actions', () => { ], [], ); - expect(createFlash).toHaveBeenCalledTimes(1); + expect(createAlert).toHaveBeenCalledTimes(1); }); }); diff --git a/spec/frontend/feature_highlight/feature_highlight_helper_spec.js b/spec/frontend/feature_highlight/feature_highlight_helper_spec.js index b87571830ca..22bac3fca15 100644 --- a/spec/frontend/feature_highlight/feature_highlight_helper_spec.js +++ b/spec/frontend/feature_highlight/feature_highlight_helper_spec.js @@ -1,6 +1,6 @@ import MockAdapter from 'axios-mock-adapter'; import { dismiss } from '~/feature_highlight/feature_highlight_helper'; -import createFlash from '~/flash'; +import { createAlert } from '~/flash'; import axios from '~/lib/utils/axios_utils'; import httpStatusCodes from '~/lib/utils/http_status'; @@ -32,7 +32,7 @@ describe('feature highlight helper', () => { await dismiss(endpoint, highlightId); - expect(createFlash).toHaveBeenCalledWith({ + expect(createAlert).toHaveBeenCalledWith({ message: 'An error occurred while dismissing the feature highlight. Refresh the page and try dismissing again.', }); diff --git a/spec/frontend/grafana_integration/components/grafana_integration_spec.js b/spec/frontend/grafana_integration/components/grafana_integration_spec.js index d2111194097..021a3aa41ed 100644 --- a/spec/frontend/grafana_integration/components/grafana_integration_spec.js +++ b/spec/frontend/grafana_integration/components/grafana_integration_spec.js @@ -3,7 +3,7 @@ import { shallowMount } from '@vue/test-utils'; import { nextTick } from 'vue'; import { TEST_HOST } from 'helpers/test_constants'; import { mountExtended } from 'helpers/vue_test_utils_helper'; -import createFlash from '~/flash'; +import { createAlert } from '~/flash'; import GrafanaIntegration from '~/grafana_integration/components/grafana_integration.vue'; import { createStore } from '~/grafana_integration/store'; import axios from '~/lib/utils/axios_utils'; @@ -30,7 +30,7 @@ describe('grafana integration component', () => { afterEach(() => { if (wrapper.destroy) { wrapper.destroy(); - createFlash.mockReset(); + createAlert.mockReset(); refreshCurrentPage.mockReset(); } }); @@ -113,7 +113,7 @@ describe('grafana integration component', () => { await nextTick(); await jest.runAllTicks(); - expect(createFlash).toHaveBeenCalledWith({ + expect(createAlert).toHaveBeenCalledWith({ message: `There was an error saving your changes. ${message}`, }); }); diff --git a/spec/frontend/groups/components/app_spec.js b/spec/frontend/groups/components/app_spec.js index a4a7530184d..33d76a8571d 100644 --- a/spec/frontend/groups/components/app_spec.js +++ b/spec/frontend/groups/components/app_spec.js @@ -3,7 +3,7 @@ import { shallowMount } from '@vue/test-utils'; import AxiosMockAdapter from 'axios-mock-adapter'; import Vue, { nextTick } from 'vue'; import waitForPromises from 'helpers/wait_for_promises'; -import createFlash from '~/flash'; +import { createAlert } from '~/flash'; import appComponent from '~/groups/components/app.vue'; import groupFolderComponent from '~/groups/components/group_folder.vue'; import groupItemComponent from '~/groups/components/group_item.vue'; @@ -115,7 +115,7 @@ describe('AppComponent', () => { return vm.fetchGroups({}).then(() => { expect(vm.isLoading).toBe(false); expect(window.scrollTo).toHaveBeenCalledWith({ behavior: 'smooth', top: 0 }); - expect(createFlash).toHaveBeenCalledWith({ + expect(createAlert).toHaveBeenCalledWith({ message: 'An error occurred. Please try again.', }); }); @@ -326,7 +326,7 @@ describe('AppComponent', () => { expect(vm.service.leaveGroup).toHaveBeenCalledWith(childGroupItem.leavePath); return waitForPromises().then(() => { expect(vm.store.removeGroup).not.toHaveBeenCalled(); - expect(createFlash).toHaveBeenCalledWith({ message }); + expect(createAlert).toHaveBeenCalledWith({ message }); expect(vm.targetGroup.isBeingRemoved).toBe(false); }); }); @@ -341,7 +341,7 @@ describe('AppComponent', () => { expect(vm.service.leaveGroup).toHaveBeenCalledWith(childGroupItem.leavePath); return waitForPromises().then(() => { expect(vm.store.removeGroup).not.toHaveBeenCalled(); - expect(createFlash).toHaveBeenCalledWith({ message }); + expect(createAlert).toHaveBeenCalledWith({ message }); expect(vm.targetGroup.isBeingRemoved).toBe(false); }); }); diff --git a/spec/frontend/ide/components/new_dropdown/modal_spec.js b/spec/frontend/ide/components/new_dropdown/modal_spec.js index 68cc08d2ebc..c6f9fd0c4ea 100644 --- a/spec/frontend/ide/components/new_dropdown/modal_spec.js +++ b/spec/frontend/ide/components/new_dropdown/modal_spec.js @@ -1,6 +1,6 @@ import { GlButton, GlModal } from '@gitlab/ui'; import { nextTick } from 'vue'; -import createFlash from '~/flash'; +import { createAlert } from '~/flash'; import Modal from '~/ide/components/new_dropdown/modal.vue'; import { createStore } from '~/ide/stores'; import { stubComponent } from 'helpers/stub_component'; @@ -341,7 +341,7 @@ describe('new file modal component', () => { }); it('does not trigger flash', () => { - expect(createFlash).not.toHaveBeenCalled(); + expect(createAlert).not.toHaveBeenCalled(); }); }); @@ -360,7 +360,7 @@ describe('new file modal component', () => { }); it('does not trigger flash', () => { - expect(createFlash).not.toHaveBeenCalled(); + expect(createAlert).not.toHaveBeenCalled(); }); }); }); @@ -380,7 +380,7 @@ describe('new file modal component', () => { }); it('creates flash', () => { - expect(createFlash).toHaveBeenCalledWith({ + expect(createAlert).toHaveBeenCalledWith({ message: 'The name "src" is already taken in this directory.', fadeTransition: false, addBodyClass: true, @@ -405,7 +405,7 @@ describe('new file modal component', () => { }); it('does not create flash', () => { - expect(createFlash).not.toHaveBeenCalled(); + expect(createAlert).not.toHaveBeenCalled(); }); it('dispatches event', () => { diff --git a/spec/frontend/ide/stores/actions/merge_request_spec.js b/spec/frontend/ide/stores/actions/merge_request_spec.js index abc3ba5b0a2..f1b2a7b881a 100644 --- a/spec/frontend/ide/stores/actions/merge_request_spec.js +++ b/spec/frontend/ide/stores/actions/merge_request_spec.js @@ -3,7 +3,7 @@ import { range } from 'lodash'; import { stubPerformanceWebAPI } from 'helpers/performance'; import { TEST_HOST } from 'helpers/test_constants'; import testAction from 'helpers/vuex_action_helper'; -import createFlash from '~/flash'; +import { createAlert } from '~/flash'; import { leftSidebarViews, PERMISSION_READ_MR, MAX_MR_FILES_AUTO_OPEN } from '~/ide/constants'; import service from '~/ide/services'; import { createStore } from '~/ide/stores'; @@ -139,8 +139,8 @@ describe('IDE store merge request actions', () => { branchId: 'bar', }) .catch(() => { - expect(createFlash).toHaveBeenCalled(); - expect(createFlash.mock.calls[0][0].message).toBe( + expect(createAlert).toHaveBeenCalled(); + expect(createAlert.mock.calls[0][0].message).toBe( 'Error fetching merge requests for bar', ); }); @@ -520,7 +520,7 @@ describe('IDE store merge request actions', () => { store.dispatch.mockRejectedValue(); return openMergeRequest(store, mr).catch(() => { - expect(createFlash).toHaveBeenCalledWith({ + expect(createAlert).toHaveBeenCalledWith({ message: expect.any(String), }); }); diff --git a/spec/frontend/ide/stores/actions/project_spec.js b/spec/frontend/ide/stores/actions/project_spec.js index cc7d39b4d43..5a5ead4c544 100644 --- a/spec/frontend/ide/stores/actions/project_spec.js +++ b/spec/frontend/ide/stores/actions/project_spec.js @@ -2,7 +2,7 @@ import MockAdapter from 'axios-mock-adapter'; import { useMockLocationHelper } from 'helpers/mock_window_location_helper'; import testAction from 'helpers/vuex_action_helper'; import api from '~/api'; -import createFlash from '~/flash'; +import { createAlert } from '~/flash'; import service from '~/ide/services'; import { createStore } from '~/ide/stores'; import { @@ -97,7 +97,7 @@ describe('IDE store project actions', () => { }); afterEach(() => { - createFlash.mockRestore(); + createAlert.mockRestore(); }); it.each` @@ -122,7 +122,7 @@ describe('IDE store project actions', () => { if (!responseSuccess) { expect(logError).toHaveBeenCalled(); - expect(createFlash).toHaveBeenCalled(); + expect(createAlert).toHaveBeenCalled(); } }); }); diff --git a/spec/frontend/ide/stores/actions_spec.js b/spec/frontend/ide/stores/actions_spec.js index 21480ef873f..fd2c3d18813 100644 --- a/spec/frontend/ide/stores/actions_spec.js +++ b/spec/frontend/ide/stores/actions_spec.js @@ -4,6 +4,7 @@ import testAction from 'helpers/vuex_action_helper'; import eventHub from '~/ide/eventhub'; import { createRouter } from '~/ide/ide_router'; import { createStore } from '~/ide/stores'; +import { createAlert } from '~/flash'; import { init, stageAllChanges, @@ -29,6 +30,7 @@ jest.mock('~/lib/utils/url_utility', () => ({ visitUrl: jest.fn(), joinPaths: jest.requireActual('~/lib/utils/url_utility').joinPaths, })); +jest.mock('~/flash'); describe('Multi-file store actions', () => { let store; @@ -158,7 +160,7 @@ describe('Multi-file store actions', () => { type: 'tree', }); expect(store.state.entries[tree.path].tempFile).toEqual(false); - expect(document.querySelector('.flash-alert')).not.toBeNull(); + expect(createAlert).toHaveBeenCalled(); }); }); @@ -216,8 +218,10 @@ describe('Multi-file store actions', () => { name: 'test', type: 'blob', }); - expect(document.querySelector('.flash-alert')?.textContent.trim()).toEqual( - `The name "${f.name}" is already taken in this directory.`, + expect(createAlert).toHaveBeenCalledWith( + expect.objectContaining({ + message: `The name "${f.name}" is already taken in this directory.`, + }), ); }); }); @@ -930,7 +934,7 @@ describe('Multi-file store actions', () => { ); expect(dispatch.mock.calls).toHaveLength(0); - expect(document.querySelector('.flash-alert')).not.toBeNull(); + expect(createAlert).toHaveBeenCalled(); }); }); }); diff --git a/spec/frontend/ide/stores/modules/terminal/actions/session_controls_spec.js b/spec/frontend/ide/stores/modules/terminal/actions/session_controls_spec.js index ecda7f304ba..f48797415df 100644 --- a/spec/frontend/ide/stores/modules/terminal/actions/session_controls_spec.js +++ b/spec/frontend/ide/stores/modules/terminal/actions/session_controls_spec.js @@ -1,6 +1,6 @@ import MockAdapter from 'axios-mock-adapter'; import testAction from 'helpers/vuex_action_helper'; -import createFlash from '~/flash'; +import { createAlert } from '~/flash'; import * as actions from '~/ide/stores/modules/terminal/actions/session_controls'; import { STARTING, PENDING, STOPPING, STOPPED } from '~/ide/stores/modules/terminal/constants'; import * as messages from '~/ide/stores/modules/terminal/messages'; @@ -89,7 +89,7 @@ describe('IDE store terminal session controls actions', () => { it('flashes message', () => { actions.receiveStartSessionError({ dispatch }); - expect(createFlash).toHaveBeenCalledWith({ + expect(createAlert).toHaveBeenCalledWith({ message: messages.UNEXPECTED_ERROR_STARTING, }); }); @@ -163,7 +163,7 @@ describe('IDE store terminal session controls actions', () => { it('flashes message', () => { actions.receiveStopSessionError({ dispatch }); - expect(createFlash).toHaveBeenCalledWith({ + expect(createAlert).toHaveBeenCalledWith({ message: messages.UNEXPECTED_ERROR_STOPPING, }); }); diff --git a/spec/frontend/ide/stores/modules/terminal/actions/session_status_spec.js b/spec/frontend/ide/stores/modules/terminal/actions/session_status_spec.js index eabc69b23aa..fe2328f25c2 100644 --- a/spec/frontend/ide/stores/modules/terminal/actions/session_status_spec.js +++ b/spec/frontend/ide/stores/modules/terminal/actions/session_status_spec.js @@ -1,6 +1,6 @@ import MockAdapter from 'axios-mock-adapter'; import testAction from 'helpers/vuex_action_helper'; -import createFlash from '~/flash'; +import { createAlert } from '~/flash'; import * as actions from '~/ide/stores/modules/terminal/actions/session_status'; import { PENDING, RUNNING, STOPPING, STOPPED } from '~/ide/stores/modules/terminal/constants'; import * as messages from '~/ide/stores/modules/terminal/messages'; @@ -115,7 +115,7 @@ describe('IDE store terminal session controls actions', () => { it('flashes message', () => { actions.receiveSessionStatusError({ dispatch }); - expect(createFlash).toHaveBeenCalledWith({ + expect(createAlert).toHaveBeenCalledWith({ message: messages.UNEXPECTED_ERROR_STATUS, }); }); diff --git a/spec/frontend/import_entities/import_groups/components/import_table_spec.js b/spec/frontend/import_entities/import_groups/components/import_table_spec.js index f97ea046cbe..cb967267b7f 100644 --- a/spec/frontend/import_entities/import_groups/components/import_table_spec.js +++ b/spec/frontend/import_entities/import_groups/components/import_table_spec.js @@ -5,7 +5,7 @@ import VueApollo from 'vue-apollo'; import MockAdapter from 'axios-mock-adapter'; import createMockApollo from 'helpers/mock_apollo_helper'; import waitForPromises from 'helpers/wait_for_promises'; -import createFlash from '~/flash'; +import { createAlert } from '~/flash'; import httpStatus from '~/lib/utils/http_status'; import axios from '~/lib/utils/axios_utils'; import { STATUSES } from '~/import_entities/constants'; @@ -246,7 +246,7 @@ describe('import table', () => { await findImportButtons()[0].trigger('click'); await waitForPromises(); - expect(createFlash).toHaveBeenCalledWith( + expect(createAlert).toHaveBeenCalledWith( expect.objectContaining({ message: i18n.ERROR_IMPORT, }), diff --git a/spec/frontend/import_entities/import_groups/services/status_poller_spec.js b/spec/frontend/import_entities/import_groups/services/status_poller_spec.js index 01f976562c6..13d2a95ca14 100644 --- a/spec/frontend/import_entities/import_groups/services/status_poller_spec.js +++ b/spec/frontend/import_entities/import_groups/services/status_poller_spec.js @@ -1,6 +1,6 @@ import MockAdapter from 'axios-mock-adapter'; import Visibility from 'visibilityjs'; -import createFlash from '~/flash'; +import { createAlert } from '~/flash'; import { STATUSES } from '~/import_entities/constants'; import { StatusPoller } from '~/import_entities/import_groups/services/status_poller'; import axios from '~/lib/utils/axios_utils'; @@ -83,7 +83,7 @@ describe('Bulk import status poller', () => { it('when error occurs shows flash with error', () => { const [[pollConfig]] = Poll.mock.calls; pollConfig.errorCallback(); - expect(createFlash).toHaveBeenCalled(); + expect(createAlert).toHaveBeenCalled(); }); it('when success response arrives updates relevant group status', () => { diff --git a/spec/frontend/import_entities/import_projects/store/actions_spec.js b/spec/frontend/import_entities/import_projects/store/actions_spec.js index 0ebe8525b5a..f6b34f4e4ca 100644 --- a/spec/frontend/import_entities/import_projects/store/actions_spec.js +++ b/spec/frontend/import_entities/import_projects/store/actions_spec.js @@ -1,7 +1,7 @@ import MockAdapter from 'axios-mock-adapter'; import { TEST_HOST } from 'helpers/test_constants'; import testAction from 'helpers/vuex_action_helper'; -import createFlash from '~/flash'; +import { createAlert } from '~/flash'; import { STATUSES } from '~/import_entities/constants'; import actionsFactory from '~/import_entities/import_projects/store/actions'; import { getImportTarget } from '~/import_entities/import_projects/store/getters'; @@ -155,7 +155,7 @@ describe('import_projects store actions', () => { [], ); - expect(createFlash).toHaveBeenCalledWith({ + expect(createAlert).toHaveBeenCalledWith({ message: 'Provider rate limit exceeded. Try again later', }); }); @@ -234,7 +234,7 @@ describe('import_projects store actions', () => { [], ); - expect(createFlash).toHaveBeenCalledWith({ + expect(createAlert).toHaveBeenCalledWith({ message: 'Importing the project failed', }); }); @@ -257,7 +257,7 @@ describe('import_projects store actions', () => { [], ); - expect(createFlash).toHaveBeenCalledWith({ + expect(createAlert).toHaveBeenCalledWith({ message: `Importing the project failed: ${ERROR_MESSAGE}`, }); }); @@ -358,7 +358,7 @@ describe('import_projects store actions', () => { [], ); - expect(createFlash).toHaveBeenCalledWith({ + expect(createAlert).toHaveBeenCalledWith({ message: 'Requesting namespaces failed', }); }); diff --git a/spec/frontend/issuable/related_issues/components/related_issues_root_spec.js b/spec/frontend/issuable/related_issues/components/related_issues_root_spec.js index b518d2fbdec..680dbd68493 100644 --- a/spec/frontend/issuable/related_issues/components/related_issues_root_spec.js +++ b/spec/frontend/issuable/related_issues/components/related_issues_root_spec.js @@ -7,7 +7,7 @@ import { issuable1, issuable2, } from 'jest/issuable/components/related_issuable_mock_data'; -import createFlash from '~/flash'; +import { createAlert } from '~/flash'; import axios from '~/lib/utils/axios_utils'; import { linkedIssueTypesMap } from '~/related_issues/constants'; import RelatedIssuesBlock from '~/related_issues/components/related_issues_block.vue'; @@ -136,7 +136,7 @@ describe('RelatedIssuesRoot', () => { await createComponent(); jest.spyOn(wrapper.vm, 'processAllReferences'); jest.spyOn(wrapper.vm.service, 'addRelatedIssues'); - createFlash.mockClear(); + createAlert.mockClear(); }); it('processes references before submitting', () => { @@ -207,12 +207,12 @@ describe('RelatedIssuesRoot', () => { mock.onPost(defaultProps.endpoint).reply(409, { message }); wrapper.vm.store.setPendingReferences([issuable1.reference, issuable2.reference]); - expect(createFlash).not.toHaveBeenCalled(); + expect(createAlert).not.toHaveBeenCalled(); findRelatedIssuesBlock().vm.$emit('addIssuableFormSubmit', input); await waitForPromises(); - expect(createFlash).toHaveBeenCalledWith({ message }); + expect(createAlert).toHaveBeenCalledWith({ message }); }); }); diff --git a/spec/frontend/milestones/components/promote_milestone_modal_spec.js b/spec/frontend/milestones/components/promote_milestone_modal_spec.js index 11eaa92f2b0..60657fbc9b8 100644 --- a/spec/frontend/milestones/components/promote_milestone_modal_spec.js +++ b/spec/frontend/milestones/components/promote_milestone_modal_spec.js @@ -3,7 +3,7 @@ import { shallowMount } from '@vue/test-utils'; import { setHTMLFixture } from 'helpers/fixtures'; import { TEST_HOST } from 'helpers/test_constants'; import waitForPromises from 'helpers/wait_for_promises'; -import createFlash from '~/flash'; +import { createAlert } from '~/flash'; import axios from '~/lib/utils/axios_utils'; import * as urlUtils from '~/lib/utils/url_utility'; import PromoteMilestoneModal from '~/milestones/components/promote_milestone_modal.vue'; @@ -103,7 +103,7 @@ describe('Promote milestone modal', () => { wrapper.findComponent(GlModal).vm.$emit('primary'); await waitForPromises(); - expect(createFlash).toHaveBeenCalledWith({ message: dummyError }); + expect(createAlert).toHaveBeenCalledWith({ message: dummyError }); }); }); }); diff --git a/spec/frontend/monitoring/components/dashboard_spec.js b/spec/frontend/monitoring/components/dashboard_spec.js index 1de6b6e3e98..1d17a9116df 100644 --- a/spec/frontend/monitoring/components/dashboard_spec.js +++ b/spec/frontend/monitoring/components/dashboard_spec.js @@ -4,7 +4,7 @@ import { nextTick } from 'vue'; import setWindowLocation from 'helpers/set_window_location_helper'; import { TEST_HOST } from 'helpers/test_constants'; import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper'; -import createFlash from '~/flash'; +import { createAlert } from '~/flash'; import axios from '~/lib/utils/axios_utils'; import { ESC_KEY } from '~/lib/utils/keys'; import { objectToQuery } from '~/lib/utils/url_utility'; @@ -198,7 +198,7 @@ describe('Dashboard', () => { ); await nextTick(); - expect(createFlash).toHaveBeenCalled(); + expect(createAlert).toHaveBeenCalled(); }); it('does not display a warning if there are no validation warnings', async () => { @@ -210,7 +210,7 @@ describe('Dashboard', () => { ); await nextTick(); - expect(createFlash).not.toHaveBeenCalled(); + expect(createAlert).not.toHaveBeenCalled(); }); }); @@ -275,7 +275,7 @@ describe('Dashboard', () => { setupStoreWithData(store); await nextTick(); - expect(createFlash).toHaveBeenCalled(); + expect(createAlert).toHaveBeenCalled(); expect(store.dispatch).not.toHaveBeenCalledWith( 'monitoringDashboard/setExpandedPanel', expect.anything(), diff --git a/spec/frontend/monitoring/components/dashboard_url_time_spec.js b/spec/frontend/monitoring/components/dashboard_url_time_spec.js index a327e234581..9873654bdda 100644 --- a/spec/frontend/monitoring/components/dashboard_url_time_spec.js +++ b/spec/frontend/monitoring/components/dashboard_url_time_spec.js @@ -1,7 +1,7 @@ import { mount } from '@vue/test-utils'; import MockAdapter from 'axios-mock-adapter'; import { nextTick } from 'vue'; -import createFlash from '~/flash'; +import { createAlert } from '~/flash'; import axios from '~/lib/utils/axios_utils'; import { queryToObject, @@ -115,7 +115,7 @@ describe('dashboard invalid url parameters', () => { createMountedWrapper(); await nextTick(); - expect(createFlash).toHaveBeenCalled(); + expect(createAlert).toHaveBeenCalled(); expect(findDateTimePicker().props('value')).toEqual(defaultTimeRange); diff --git a/spec/frontend/monitoring/store/actions_spec.js b/spec/frontend/monitoring/store/actions_spec.js index a872a7780eb..ca66768c3cc 100644 --- a/spec/frontend/monitoring/store/actions_spec.js +++ b/spec/frontend/monitoring/store/actions_spec.js @@ -1,7 +1,7 @@ import MockAdapter from 'axios-mock-adapter'; import { backoffMockImplementation } from 'helpers/backoff_helper'; import testAction from 'helpers/vuex_action_helper'; -import createFlash from '~/flash'; +import { createAlert } from '~/flash'; import axios from '~/lib/utils/axios_utils'; import * as commonUtils from '~/lib/utils/common_utils'; import statusCodes from '~/lib/utils/http_status'; @@ -82,7 +82,7 @@ describe('Monitoring store actions', () => { mock.reset(); commonUtils.backOff.mockReset(); - createFlash.mockReset(); + createAlert.mockReset(); }); // Setup @@ -241,7 +241,7 @@ describe('Monitoring store actions', () => { 'receiveMetricsDashboardFailure', new Error('Request failed with status code 500'), ); - expect(createFlash).toHaveBeenCalled(); + expect(createAlert).toHaveBeenCalled(); }); it('dispatches a failure action when a message is returned', async () => { @@ -250,7 +250,7 @@ describe('Monitoring store actions', () => { 'receiveMetricsDashboardFailure', new Error('Request failed with status code 500'), ); - expect(createFlash).toHaveBeenCalledWith({ + expect(createAlert).toHaveBeenCalledWith({ message: expect.stringContaining(mockDashboardsErrorResponse.message), }); }); @@ -263,7 +263,7 @@ describe('Monitoring store actions', () => { 'receiveMetricsDashboardFailure', new Error('Request failed with status code 500'), ); - expect(createFlash).not.toHaveBeenCalled(); + expect(createAlert).not.toHaveBeenCalled(); }); }); }); @@ -328,7 +328,7 @@ describe('Monitoring store actions', () => { }, }); - expect(createFlash).not.toHaveBeenCalled(); + expect(createAlert).not.toHaveBeenCalled(); }); it('dispatches fetchPrometheusMetric for each panel query', async () => { @@ -385,7 +385,7 @@ describe('Monitoring store actions', () => { defaultQueryParams, }); - expect(createFlash).toHaveBeenCalledTimes(1); + expect(createAlert).toHaveBeenCalledTimes(1); }); }); @@ -570,7 +570,7 @@ describe('Monitoring store actions', () => { [], [{ type: 'receiveDeploymentsDataFailure' }], () => { - expect(createFlash).toHaveBeenCalled(); + expect(createAlert).toHaveBeenCalled(); }, ); }); @@ -1084,8 +1084,8 @@ describe('Monitoring store actions', () => { return testAction(fetchVariableMetricLabelValues, { defaultQueryParams }, state, [], []).then( () => { - expect(createFlash).toHaveBeenCalledTimes(1); - expect(createFlash).toHaveBeenCalledWith({ + expect(createAlert).toHaveBeenCalledTimes(1); + expect(createAlert).toHaveBeenCalledWith({ message: expect.stringContaining('error getting options for variable "label1"'), }); }, diff --git a/spec/frontend/pages/projects/forks/new/components/project_namespace_spec.js b/spec/frontend/pages/projects/forks/new/components/project_namespace_spec.js index 1a88aebae32..f6d3957115f 100644 --- a/spec/frontend/pages/projects/forks/new/components/project_namespace_spec.js +++ b/spec/frontend/pages/projects/forks/new/components/project_namespace_spec.js @@ -10,7 +10,7 @@ import { mount, shallowMount } from '@vue/test-utils'; import Vue, { nextTick } from 'vue'; import VueApollo from 'vue-apollo'; import createMockApollo from 'helpers/mock_apollo_helper'; -import createFlash from '~/flash'; +import { createAlert } from '~/flash'; import searchQuery from '~/pages/projects/forks/new/queries/search_forkable_namespaces.query.graphql'; import ProjectNamespace from '~/pages/projects/forks/new/components/project_namespace.vue'; @@ -167,7 +167,7 @@ describe('ProjectNamespace component', () => { }); it('creates a flash message and captures the error', () => { - expect(createFlash).toHaveBeenCalledWith({ + expect(createAlert).toHaveBeenCalledWith({ message: 'Something went wrong while loading data. Please refresh the page to try again.', captureError: true, error: expect.any(Error), diff --git a/spec/frontend/persistent_user_callout_spec.js b/spec/frontend/persistent_user_callout_spec.js index 9cd5bb9e9a1..c9574208900 100644 --- a/spec/frontend/persistent_user_callout_spec.js +++ b/spec/frontend/persistent_user_callout_spec.js @@ -1,7 +1,7 @@ import MockAdapter from 'axios-mock-adapter'; import { useMockLocationHelper } from 'helpers/mock_window_location_helper'; import waitForPromises from 'helpers/wait_for_promises'; -import createFlash from '~/flash'; +import { createAlert } from '~/flash'; import axios from '~/lib/utils/axios_utils'; import PersistentUserCallout from '~/persistent_user_callout'; @@ -108,7 +108,7 @@ describe('PersistentUserCallout', () => { await waitForPromises(); expect(persistentUserCallout.container.remove).not.toHaveBeenCalled(); - expect(createFlash).toHaveBeenCalledWith({ + expect(createAlert).toHaveBeenCalledWith({ message: 'An error occurred while dismissing the alert. Refresh the page and try again.', }); }); @@ -214,7 +214,7 @@ describe('PersistentUserCallout', () => { await waitForPromises(); expect(window.location.assign).not.toHaveBeenCalled(); - expect(createFlash).toHaveBeenCalledWith({ + expect(createAlert).toHaveBeenCalledWith({ message: 'An error occurred while acknowledging the notification. Refresh the page and try again.', }); diff --git a/spec/frontend/projects/settings/repository/branch_rules/app_spec.js b/spec/frontend/projects/settings/repository/branch_rules/app_spec.js index e920cd48163..117e106e15b 100644 --- a/spec/frontend/projects/settings/repository/branch_rules/app_spec.js +++ b/spec/frontend/projects/settings/repository/branch_rules/app_spec.js @@ -6,7 +6,7 @@ import { mountExtended } from 'helpers/vue_test_utils_helper'; import BranchRules, { i18n } from '~/projects/settings/repository/branch_rules/app.vue'; import BranchRule from '~/projects/settings/repository/branch_rules/components/branch_rule.vue'; import branchRulesQuery from '~/projects/settings/repository/branch_rules/graphql/queries/branch_rules.query.graphql'; -import createFlash from '~/flash'; +import { createAlert } from '~/flash'; import { branchRulesMockResponse, propsDataMock } from './mock_data'; jest.mock('~/flash'); @@ -39,7 +39,7 @@ describe('Branch rules app', () => { it('displays an error if branch rules query fails', async () => { await createComponent({ queryHandler: jest.fn().mockRejectedValue() }); - expect(createFlash).toHaveBeenCalledWith({ message: i18n.queryError }); + expect(createAlert).toHaveBeenCalledWith({ message: i18n.queryError }); }); it('displays an empty state if no branch rules are present', async () => { diff --git a/spec/frontend/protected_branches/protected_branch_edit_spec.js b/spec/frontend/protected_branches/protected_branch_edit_spec.js index 6ef1b58a956..0aec4fbc037 100644 --- a/spec/frontend/protected_branches/protected_branch_edit_spec.js +++ b/spec/frontend/protected_branches/protected_branch_edit_spec.js @@ -2,7 +2,7 @@ import MockAdapter from 'axios-mock-adapter'; import $ from 'jquery'; import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures'; import { TEST_HOST } from 'helpers/test_constants'; -import createFlash from '~/flash'; +import { createAlert } from '~/flash'; import axios from '~/lib/utils/axios_utils'; import ProtectedBranchEdit from '~/protected_branches/protected_branch_edit'; @@ -136,7 +136,7 @@ describe('ProtectedBranchEdit', () => { expect(toggle).not.toHaveClass(IS_DISABLED_CLASS); expect(toggle.querySelector(IS_LOADING_SELECTOR)).toBe(null); - expect(createFlash).not.toHaveBeenCalled(); + expect(createAlert).not.toHaveBeenCalled(); }); }); @@ -149,7 +149,7 @@ describe('ProtectedBranchEdit', () => { it('flashes error', async () => { await axios.waitForAll(); - expect(createFlash).toHaveBeenCalled(); + expect(createAlert).toHaveBeenCalled(); }); }); }); diff --git a/spec/frontend/releases/components/app_index_spec.js b/spec/frontend/releases/components/app_index_spec.js index f64f07de90e..48589a54ec4 100644 --- a/spec/frontend/releases/components/app_index_spec.js +++ b/spec/frontend/releases/components/app_index_spec.js @@ -6,7 +6,7 @@ import createMockApollo from 'helpers/mock_apollo_helper'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import waitForPromises from 'helpers/wait_for_promises'; import allReleasesQuery from '~/releases/graphql/queries/all_releases.query.graphql'; -import createFlash from '~/flash'; +import { createAlert } from '~/flash'; import { historyPushState } from '~/lib/utils/common_utils'; import { sprintf, __ } from '~/locale'; import ReleasesIndexApp from '~/releases/components/app_index.vue'; @@ -161,13 +161,13 @@ describe('app_index.vue', () => { it(`${toDescription(flashMessage)} show a flash message`, async () => { await waitForPromises(); if (flashMessage) { - expect(createFlash).toHaveBeenCalledWith({ + expect(createAlert).toHaveBeenCalledWith({ message: ReleasesIndexApp.i18n.errorMessage, captureError: true, error: expect.any(Error), }); } else { - expect(createFlash).not.toHaveBeenCalled(); + expect(createAlert).not.toHaveBeenCalled(); } }); diff --git a/spec/frontend/releases/components/app_show_spec.js b/spec/frontend/releases/components/app_show_spec.js index 9ca25b3b69a..c5cb8589ee8 100644 --- a/spec/frontend/releases/components/app_show_spec.js +++ b/spec/frontend/releases/components/app_show_spec.js @@ -4,7 +4,7 @@ import VueApollo from 'vue-apollo'; import oneReleaseQueryResponse from 'test_fixtures/graphql/releases/graphql/queries/one_release.query.graphql.json'; import createMockApollo from 'helpers/mock_apollo_helper'; import waitForPromises from 'helpers/wait_for_promises'; -import createFlash from '~/flash'; +import { createAlert } from '~/flash'; import ReleaseShowApp from '~/releases/components/app_show.vue'; import ReleaseBlock from '~/releases/components/release_block.vue'; import ReleaseSkeletonLoader from '~/releases/components/release_skeleton_loader.vue'; @@ -53,13 +53,13 @@ describe('Release show component', () => { const expectNoFlash = () => { it('does not show a flash message', () => { - expect(createFlash).not.toHaveBeenCalled(); + expect(createAlert).not.toHaveBeenCalled(); }); }; const expectFlashWithMessage = (message) => { it(`shows a flash message that reads "${message}"`, () => { - expect(createFlash).toHaveBeenCalledWith({ + expect(createAlert).toHaveBeenCalledWith({ message, captureError: true, error: expect.any(Error), diff --git a/spec/frontend/releases/stores/modules/detail/actions_spec.js b/spec/frontend/releases/stores/modules/detail/actions_spec.js index 67a07e82532..eeee6747349 100644 --- a/spec/frontend/releases/stores/modules/detail/actions_spec.js +++ b/spec/frontend/releases/stores/modules/detail/actions_spec.js @@ -2,7 +2,7 @@ import { cloneDeep } from 'lodash'; import originalOneReleaseForEditingQueryResponse from 'test_fixtures/graphql/releases/graphql/queries/one_release_for_editing.query.graphql.json'; import testAction from 'helpers/vuex_action_helper'; import { getTag } from '~/api/tags_api'; -import createFlash from '~/flash'; +import { createAlert } from '~/flash'; import { redirectTo } from '~/lib/utils/url_utility'; import { s__ } from '~/locale'; import { ASSET_LINK_TYPE } from '~/releases/constants'; @@ -59,7 +59,7 @@ describe('Release edit/new actions', () => { releaseResponse = cloneDeep(originalOneReleaseForEditingQueryResponse); gon.api_version = 'v4'; error = new Error('Yikes!'); - createFlash.mockClear(); + createAlert.mockClear(); }); describe('when creating a new release', () => { @@ -151,8 +151,8 @@ describe('Release edit/new actions', () => { it(`shows a flash message`, () => { return actions.fetchRelease({ commit: jest.fn(), state, rootState: state }).then(() => { - expect(createFlash).toHaveBeenCalledTimes(1); - expect(createFlash).toHaveBeenCalledWith({ + expect(createAlert).toHaveBeenCalledTimes(1); + expect(createAlert).toHaveBeenCalledWith({ message: 'Something went wrong while getting the release details.', }); }); @@ -379,8 +379,8 @@ describe('Release edit/new actions', () => { return actions .createRelease({ commit: jest.fn(), dispatch: jest.fn(), state, getters: {} }) .then(() => { - expect(createFlash).toHaveBeenCalledTimes(1); - expect(createFlash).toHaveBeenCalledWith({ + expect(createAlert).toHaveBeenCalledTimes(1); + expect(createAlert).toHaveBeenCalledWith({ message: 'Yikes!', }); }); @@ -405,8 +405,8 @@ describe('Release edit/new actions', () => { return actions .createRelease({ commit: jest.fn(), dispatch: jest.fn(), state, getters: {} }) .then(() => { - expect(createFlash).toHaveBeenCalledTimes(1); - expect(createFlash).toHaveBeenCalledWith({ + expect(createAlert).toHaveBeenCalledTimes(1); + expect(createAlert).toHaveBeenCalledWith({ message: 'Something went wrong while creating a new release.', }); }); @@ -536,8 +536,8 @@ describe('Release edit/new actions', () => { it('shows a flash message', async () => { await actions.updateRelease({ commit, dispatch, state, getters }); - expect(createFlash).toHaveBeenCalledTimes(1); - expect(createFlash).toHaveBeenCalledWith({ + expect(createAlert).toHaveBeenCalledTimes(1); + expect(createAlert).toHaveBeenCalledWith({ message: 'Something went wrong while saving the release details.', }); }); @@ -556,8 +556,8 @@ describe('Release edit/new actions', () => { it('shows a flash message', async () => { await actions.updateRelease({ commit, dispatch, state, getters }); - expect(createFlash).toHaveBeenCalledTimes(1); - expect(createFlash).toHaveBeenCalledWith({ + expect(createAlert).toHaveBeenCalledTimes(1); + expect(createAlert).toHaveBeenCalledWith({ message: 'Something went wrong while saving the release details.', }); }); @@ -709,8 +709,8 @@ describe('Release edit/new actions', () => { it('shows a flash message', async () => { await actions.deleteRelease({ commit, dispatch, state, getters }); - expect(createFlash).toHaveBeenCalledTimes(1); - expect(createFlash).toHaveBeenCalledWith({ + expect(createAlert).toHaveBeenCalledTimes(1); + expect(createAlert).toHaveBeenCalledWith({ message: 'Something went wrong while deleting the release.', }); }); @@ -745,8 +745,8 @@ describe('Release edit/new actions', () => { it('shows a flash message', async () => { await actions.deleteRelease({ commit, dispatch, state, getters }); - expect(createFlash).toHaveBeenCalledTimes(1); - expect(createFlash).toHaveBeenCalledWith({ + expect(createAlert).toHaveBeenCalledTimes(1); + expect(createAlert).toHaveBeenCalledWith({ message: 'Something went wrong while deleting the release.', }); }); @@ -788,7 +788,7 @@ describe('Release edit/new actions', () => { [], ); - expect(createFlash).toHaveBeenCalledWith({ + expect(createAlert).toHaveBeenCalledWith({ message: s__('Release|Unable to fetch the tag notes.'), }); expect(getTag).toHaveBeenCalledWith(state.projectId, tagName); diff --git a/spec/frontend/work_items/components/work_item_assignees_spec.js b/spec/frontend/work_items/components/work_item_assignees_spec.js index 901b2ba63c6..1b204b6fd60 100644 --- a/spec/frontend/work_items/components/work_item_assignees_spec.js +++ b/spec/frontend/work_items/components/work_item_assignees_spec.js @@ -160,7 +160,9 @@ describe('WorkItemAssignees component', () => { it('has a label', () => { createComponent(); - expect(findTokenSelector().props('ariaLabelledby')).toContain('assignees-title-'); + expect(findTokenSelector().props('ariaLabelledby')).toEqual( + findAssigneesTitle().attributes('id'), + ); }); describe('when clicking outside the token selector', () => { diff --git a/spec/frontend/work_items/components/work_item_labels_spec.js b/spec/frontend/work_items/components/work_item_labels_spec.js index f59d512d610..e8173997ac1 100644 --- a/spec/frontend/work_items/components/work_item_labels_spec.js +++ b/spec/frontend/work_items/components/work_item_labels_spec.js @@ -21,8 +21,8 @@ describe('WorkItemLabels component', () => { const findTokenSelector = () => wrapper.findComponent(GlTokenSelector); const findSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader); - const findEmptyState = () => wrapper.findByTestId('empty-state'); + const findLabelsTitle = () => wrapper.findByTestId('labels-title'); const successSearchQueryHandler = jest.fn().mockResolvedValue(projectLabelsResponse); const errorHandler = jest.fn().mockRejectedValue('Houston, we have a problem'); @@ -63,7 +63,7 @@ describe('WorkItemLabels component', () => { it('has a label', () => { createComponent(); - expect(findTokenSelector().props('ariaLabelledby')).toContain('labels-title-'); + expect(findTokenSelector().props('ariaLabelledby')).toEqual(findLabelsTitle().attributes('id')); }); it('focuses token selector on token selector input event', async () => { diff --git a/spec/lib/bulk_imports/common/pipelines/lfs_objects_pipeline_spec.rb b/spec/lib/bulk_imports/common/pipelines/lfs_objects_pipeline_spec.rb index f0b461e518e..5220b9d37e5 100644 --- a/spec/lib/bulk_imports/common/pipelines/lfs_objects_pipeline_spec.rb +++ b/spec/lib/bulk_imports/common/pipelines/lfs_objects_pipeline_spec.rb @@ -7,7 +7,7 @@ RSpec.describe BulkImports::Common::Pipelines::LfsObjectsPipeline do let_it_be(:oid) { 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' } let(:tmpdir) { Dir.mktmpdir } - let(:entity) { create(:bulk_import_entity, :project_entity, project: portable, source_full_path: 'test') } + let(:entity) { create(:bulk_import_entity, :project_entity, project: portable, source_full_path: 'test', source_xid: nil) } let(:tracker) { create(:bulk_import_tracker, entity: entity) } let(:context) { BulkImports::Pipeline::Context.new(tracker) } let(:lfs_dir_path) { tmpdir } diff --git a/spec/lib/bulk_imports/common/pipelines/uploads_pipeline_spec.rb b/spec/lib/bulk_imports/common/pipelines/uploads_pipeline_spec.rb index f650e931dc7..7a93365d098 100644 --- a/spec/lib/bulk_imports/common/pipelines/uploads_pipeline_spec.rb +++ b/spec/lib/bulk_imports/common/pipelines/uploads_pipeline_spec.rb @@ -152,14 +152,14 @@ RSpec.describe BulkImports::Common::Pipelines::UploadsPipeline do context 'when importing to group' do let(:portable) { group } - let(:entity) { create(:bulk_import_entity, :group_entity, group: group, source_full_path: 'test') } + let(:entity) { create(:bulk_import_entity, :group_entity, group: group, source_full_path: 'test', source_xid: nil) } include_examples 'uploads import' end context 'when importing to project' do let(:portable) { project } - let(:entity) { create(:bulk_import_entity, :project_entity, project: project, source_full_path: 'test') } + let(:entity) { create(:bulk_import_entity, :project_entity, project: project, source_full_path: 'test', source_xid: nil) } include_examples 'uploads import' end diff --git a/spec/lib/bulk_imports/common/rest/get_badges_query_spec.rb b/spec/lib/bulk_imports/common/rest/get_badges_query_spec.rb index 0a04c0a2243..fabef50af8b 100644 --- a/spec/lib/bulk_imports/common/rest/get_badges_query_spec.rb +++ b/spec/lib/bulk_imports/common/rest/get_badges_query_spec.rb @@ -9,15 +9,32 @@ RSpec.describe BulkImports::Common::Rest::GetBadgesQuery do let(:context) { BulkImports::Pipeline::Context.new(tracker) } let(:encoded_full_path) { ERB::Util.url_encode(entity.source_full_path) } - it 'returns correct query and page info' do - expected = { - resource: [entity.pluralized_name, encoded_full_path, 'badges'].join('/'), - query: { - page: context.tracker.next_page + context 'when source id is present' do + it 'returns correct query using source id and page info' do + expected = { + resource: [entity.base_resource_path, 'badges'].join('/'), + query: { + page: context.tracker.next_page + } } - } - expect(described_class.to_h(context)).to eq(expected) + expect(described_class.to_h(context)).to eq(expected) + end + end + + context 'when source id is missing' do + it 'returns correct query using source full path' do + entity.update!(source_xid: nil) + + expected = { + resource: ["/#{entity.pluralized_name}", encoded_full_path, 'badges'].join('/'), + query: { + page: context.tracker.next_page + } + } + + expect(described_class.to_h(context)).to eq(expected) + end end end diff --git a/spec/lib/bulk_imports/groups/pipelines/group_pipeline_spec.rb b/spec/lib/bulk_imports/groups/pipelines/group_pipeline_spec.rb index 441a34b0c74..36b425f4f12 100644 --- a/spec/lib/bulk_imports/groups/pipelines/group_pipeline_spec.rb +++ b/spec/lib/bulk_imports/groups/pipelines/group_pipeline_spec.rb @@ -13,7 +13,7 @@ RSpec.describe BulkImports::Groups::Pipelines::GroupPipeline do :bulk_import_entity, bulk_import: bulk_import, source_full_path: 'source/full/path', - destination_name: 'My Destination Group', + destination_slug: 'my-destination-group', destination_namespace: parent.full_path ) end diff --git a/spec/lib/bulk_imports/groups/pipelines/project_entities_pipeline_spec.rb b/spec/lib/bulk_imports/groups/pipelines/project_entities_pipeline_spec.rb index 5b6c93e695f..c07d27e973f 100644 --- a/spec/lib/bulk_imports/groups/pipelines/project_entities_pipeline_spec.rb +++ b/spec/lib/bulk_imports/groups/pipelines/project_entities_pipeline_spec.rb @@ -19,6 +19,7 @@ RSpec.describe BulkImports::Groups::Pipelines::ProjectEntitiesPipeline do let(:extracted_data) do BulkImports::Pipeline::ExtractedData.new(data: { + 'id' => 'gid://gitlab/Project/1234567', 'name' => 'project', 'full_path' => 'group/project' }) @@ -44,6 +45,7 @@ RSpec.describe BulkImports::Groups::Pipelines::ProjectEntitiesPipeline do expect(project_entity.source_full_path).to eq('group/project') expect(project_entity.destination_name).to eq('project') expect(project_entity.destination_namespace).to eq(destination_group.full_path) + expect(project_entity.source_xid).to eq(1234567) end end diff --git a/spec/lib/bulk_imports/groups/transformers/group_attributes_transformer_spec.rb b/spec/lib/bulk_imports/groups/transformers/group_attributes_transformer_spec.rb index 896af865c56..32d8dc8e207 100644 --- a/spec/lib/bulk_imports/groups/transformers/group_attributes_transformer_spec.rb +++ b/spec/lib/bulk_imports/groups/transformers/group_attributes_transformer_spec.rb @@ -24,59 +24,67 @@ RSpec.describe BulkImports::Groups::Transformers::GroupAttributesTransformer do let(:data) do { 'name' => 'Source Group Name', + 'description' => 'Source Group Description', 'path' => 'source-group-path', 'full_path' => 'source/full/path', 'visibility' => 'private', 'project_creation_level' => 'developer', - 'subgroup_creation_level' => 'maintainer' + 'subgroup_creation_level' => 'maintainer', + 'emails_disabled' => true, + 'lfs_enabled' => false, + 'mentions_disabled' => true, + 'share_with_group_lock' => false, + 'require_two_factor_authentication' => false, + 'two_factor_grace_period' => 100, + 'request_access_enabled' => false } end subject { described_class.new } it 'returns original data with some keys transformed' do - transformed_data = subject.transform(context, { 'name' => 'Name', 'description' => 'Description' }) + transformed_data = subject.transform(context, data) expect(transformed_data).to eq({ - 'name' => 'Name', - 'description' => 'Description', + 'name' => 'Source Group Name', + 'description' => 'Source Group Description', 'parent_id' => parent.id, - 'path' => 'destination-slug-path' + 'path' => entity.destination_slug, + 'visibility_level' => Gitlab::VisibilityLevel.string_options[data['visibility']], + 'project_creation_level' => Gitlab::Access.project_creation_string_options[data['project_creation_level']], + 'subgroup_creation_level' => Gitlab::Access.subgroup_creation_string_options[data['subgroup_creation_level']], + 'emails_disabled' => true, + 'lfs_enabled' => false, + 'mentions_disabled' => true, + 'share_with_group_lock' => false, + 'require_two_factor_authentication' => false, + 'two_factor_grace_period' => 100, + 'request_access_enabled' => false }) end - it 'transforms path from destination_slug' do - transformed_data = subject.transform(context, data) - - expect(transformed_data['path']).to eq(entity.destination_slug) - end - - it 'removes full path' do - transformed_data = subject.transform(context, data) - - expect(transformed_data).not_to have_key('full_path') - end - - it 'transforms visibility level' do - visibility = data['visibility'] - transformed_data = subject.transform(context, data) - - expect(transformed_data).not_to have_key('visibility') - expect(transformed_data['visibility_level']).to eq(Gitlab::VisibilityLevel.string_options[visibility]) - end - - it 'transforms project creation level' do - level = data['project_creation_level'] - transformed_data = subject.transform(context, data) + context 'when some fields are not present' do + it 'does not include those fields' do + data = { + 'name' => 'Source Group Name', + 'description' => 'Source Group Description', + 'path' => 'source-group-path', + 'full_path' => 'source/full/path' + } - expect(transformed_data['project_creation_level']).to eq(Gitlab::Access.project_creation_string_options[level]) - end - - it 'transforms subgroup creation level' do - level = data['subgroup_creation_level'] - transformed_data = subject.transform(context, data) + transformed_data = subject.transform(context, data) - expect(transformed_data['subgroup_creation_level']).to eq(Gitlab::Access.subgroup_creation_string_options[level]) + expect(transformed_data).to eq({ + 'name' => 'Source Group Name', + 'path' => 'destination-slug-path', + 'description' => 'Source Group Description', + 'parent_id' => parent.id, + 'share_with_group_lock' => nil, + 'emails_disabled' => nil, + 'lfs_enabled' => nil, + 'mentions_disabled' => nil + }) + end end describe 'parent group transformation' do diff --git a/spec/lib/bulk_imports/projects/pipelines/design_bundle_pipeline_spec.rb b/spec/lib/bulk_imports/projects/pipelines/design_bundle_pipeline_spec.rb index 39b539ece21..6a509ca7f14 100644 --- a/spec/lib/bulk_imports/projects/pipelines/design_bundle_pipeline_spec.rb +++ b/spec/lib/bulk_imports/projects/pipelines/design_bundle_pipeline_spec.rb @@ -8,7 +8,10 @@ RSpec.describe BulkImports::Projects::Pipelines::DesignBundlePipeline do let(:portable) { create(:project) } let(:tmpdir) { Dir.mktmpdir } let(:design_bundle_path) { File.join(tmpdir, 'design.bundle') } - let(:entity) { create(:bulk_import_entity, :project_entity, project: portable, source_full_path: 'test') } + let(:entity) do + create(:bulk_import_entity, :project_entity, project: portable, source_full_path: 'test', source_xid: nil) + end + let(:tracker) { create(:bulk_import_tracker, entity: entity) } let(:context) { BulkImports::Pipeline::Context.new(tracker) } diff --git a/spec/lib/bulk_imports/projects/pipelines/repository_bundle_pipeline_spec.rb b/spec/lib/bulk_imports/projects/pipelines/repository_bundle_pipeline_spec.rb index 712c37ee578..b8c21feb05d 100644 --- a/spec/lib/bulk_imports/projects/pipelines/repository_bundle_pipeline_spec.rb +++ b/spec/lib/bulk_imports/projects/pipelines/repository_bundle_pipeline_spec.rb @@ -8,7 +8,10 @@ RSpec.describe BulkImports::Projects::Pipelines::RepositoryBundlePipeline do let(:portable) { create(:project) } let(:tmpdir) { Dir.mktmpdir } let(:bundle_path) { File.join(tmpdir, 'repository.bundle') } - let(:entity) { create(:bulk_import_entity, :project_entity, project: portable, source_full_path: 'test') } + let(:entity) do + create(:bulk_import_entity, :project_entity, project: portable, source_full_path: 'test', source_xid: nil) + end + let(:tracker) { create(:bulk_import_tracker, entity: entity) } let(:context) { BulkImports::Pipeline::Context.new(tracker) } diff --git a/spec/models/bulk_imports/entity_spec.rb b/spec/models/bulk_imports/entity_spec.rb index 47d355de1d8..fab32af5bd4 100644 --- a/spec/models/bulk_imports/entity_spec.rb +++ b/spec/models/bulk_imports/entity_spec.rb @@ -236,7 +236,7 @@ RSpec.describe BulkImports::Entity, type: :model do it 'returns group export relations url' do entity = build(:bulk_import_entity, :group_entity) - expect(entity.export_relations_url_path).to eq("/groups/#{entity.encoded_source_full_path}/export_relations") + expect(entity.export_relations_url_path).to eq("/groups/#{entity.source_xid}/export_relations") end end @@ -244,7 +244,7 @@ RSpec.describe BulkImports::Entity, type: :model do it 'returns project export relations url' do entity = build(:bulk_import_entity, :project_entity) - expect(entity.export_relations_url_path).to eq("/projects/#{entity.encoded_source_full_path}/export_relations") + expect(entity.export_relations_url_path).to eq("/projects/#{entity.source_xid}/export_relations") end end end @@ -254,7 +254,7 @@ RSpec.describe BulkImports::Entity, type: :model do entity = build(:bulk_import_entity) expect(entity.relation_download_url_path('test')) - .to eq("/groups/#{entity.encoded_source_full_path}/export_relations/download?relation=test") + .to eq("/groups/#{entity.source_xid}/export_relations/download?relation=test") end end @@ -290,15 +290,15 @@ RSpec.describe BulkImports::Entity, type: :model do describe '#base_resource_url_path' do it 'returns base entity url path' do - entity = build(:bulk_import_entity) + entity = build(:bulk_import_entity, source_xid: nil) - expect(entity.base_resource_url_path).to eq("/groups/#{entity.encoded_source_full_path}") + expect(entity.base_resource_path).to eq("/groups/#{entity.encoded_source_full_path}") end end describe '#wiki_url_path' do it 'returns entity wiki url path' do - entity = build(:bulk_import_entity) + entity = build(:bulk_import_entity, source_xid: nil) expect(entity.wikis_url_path).to eq("/groups/#{entity.encoded_source_full_path}/wikis") end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 0128b32aadb..6f659b3a41d 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -181,6 +181,8 @@ RSpec.configure do |config| config.include RSpec::Benchmark::Matchers, type: :benchmark config.include DetailedErrorHelpers + config.include_context 'when rendered has no HTML escapes', type: :view + include StubFeatureFlags include StubSnowplow include StubMember diff --git a/spec/support/helpers/html_escaped_helpers.rb b/spec/support/helpers/html_escaped_helpers.rb index 7f6825e9598..7cbea7e7428 100644 --- a/spec/support/helpers/html_escaped_helpers.rb +++ b/spec/support/helpers/html_escaped_helpers.rb @@ -21,4 +21,35 @@ module HtmlEscapedHelpers match_data end + + # Checks if +content+ contains HTML escaped tags and raises an exception + # if it does. + # + # See #match_html_escaped_tags for details. + def ensure_no_html_escaped_tags!(content, example) + match_data = match_html_escaped_tags(content) + return unless match_data + + # Truncate + pre_match = match_data.pre_match.last(50) + match = match_data[0] + post_match = match_data.post_match.first(50) + + string = "#{pre_match}«#{match}»#{post_match}" + + raise <<~MESSAGE + The following string contains HTML escaped tags: + + #{string} + + Please consider using `.html_safe`. + + This check can be disabled via: + + it #{example.description.inspect}, :skip_html_escaped_tags_check do + ... + end + + MESSAGE + end end diff --git a/spec/support/shared_contexts/html_safe_shared_context.rb b/spec/support/shared_contexts/html_safe_shared_context.rb new file mode 100644 index 00000000000..9bdaea9fe64 --- /dev/null +++ b/spec/support/shared_contexts/html_safe_shared_context.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +RSpec.shared_context 'when rendered has no HTML escapes' do + # Check once per example if `rendered` contains HTML escapes. + let(:rendered) do |example| + super().tap do |rendered| + next if example.metadata[:skip_html_escaped_tags_check] + + HtmlEscapedHelpers.ensure_no_html_escaped_tags!(rendered, example) + end + end +end + +RSpec.shared_context 'when page has no HTML escapes' do + # Check once per example if `page` contains HTML escapes. + let(:page) do |example| + super().tap do |page| + next if example.metadata[:skip_html_escaped_tags_check] + + HtmlEscapedHelpers.ensure_no_html_escaped_tags!(page.native.to_s, example) + end + end +end diff --git a/spec/support/shared_contexts/views/html_safe_render_shared_context.rb b/spec/support/shared_contexts/views/html_safe_render_shared_context.rb deleted file mode 100644 index 3acca60c901..00000000000 --- a/spec/support/shared_contexts/views/html_safe_render_shared_context.rb +++ /dev/null @@ -1,39 +0,0 @@ -# frozen_string_literal: true - -RSpec.shared_context 'when rendered view has no HTML escapes', type: :view do - # Check once per example if `rendered` contains HTML escapes. - let(:rendered) do |example| - super().tap do |rendered| - next if example.metadata[:skip_html_escaped_tags_check] - - ensure_no_html_escaped_tags!(rendered, example) - end - end - - def ensure_no_html_escaped_tags!(content, example) - match_data = HtmlEscapedHelpers.match_html_escaped_tags(content) - return unless match_data - - # Truncate - pre_match = match_data.pre_match.last(50) - match = match_data[0] - post_match = match_data.post_match.first(50) - - string = "#{pre_match}«#{match}»#{post_match}" - - raise <<~MESSAGE - The following string contains HTML escaped tags: - - #{string} - - Please consider using `.html_safe`. - - This check can be disabled via: - - it #{example.description.inspect}, :skip_html_escaped_tags_check do - ... - end - - MESSAGE - end -end diff --git a/spec/support/view_component.rb b/spec/support/view_component.rb index 9166a06fc8c..912bfda6d33 100644 --- a/spec/support/view_component.rb +++ b/spec/support/view_component.rb @@ -4,4 +4,11 @@ require 'view_component/test_helpers' RSpec.configure do |config| config.include ViewComponent::TestHelpers, type: :component config.include Capybara::RSpecMatchers, type: :component + config.include Devise::Test::ControllerHelpers, type: :component + + config.before(:each, type: :component) do + @request = controller.request + end + + config.include_context 'when page has no HTML escapes', type: :component end diff --git a/spec/support_specs/helpers/html_escaped_helpers_spec.rb b/spec/support_specs/helpers/html_escaped_helpers_spec.rb index 337f7ecc659..77ca6231881 100644 --- a/spec/support_specs/helpers/html_escaped_helpers_spec.rb +++ b/spec/support_specs/helpers/html_escaped_helpers_spec.rb @@ -40,4 +40,33 @@ RSpec.describe HtmlEscapedHelpers do specify { expect(actual_match).to eq(expected_match) } end end + + describe '#ensure_no_html_escaped_tags!' do + subject { |example| described_class.ensure_no_html_escaped_tags!(content, example) } + + context 'when content contains HTML escaped chars' do + let(:content) { 'See <a href="">Link</a>' } + + it 'raises an exception' do + parts = [ + 'The following string contains HTML escaped tags:', + 'See «<a» href="">Link</a>', + 'This check can be disabled via:', + %(it "raises an exception", :skip_html_escaped_tags_check do) + ] + + regexp = Regexp.new(parts.join('.*'), Regexp::MULTILINE) + + expect { subject }.to raise_error(regexp) + end + end + + context 'when content does not contain HTML escaped tags' do + let(:content) { 'See <a href="">Link</a>' } + + it 'does not raise anything' do + expect(subject).to be_nil + end + end + end end diff --git a/spec/workers/bulk_import_worker_spec.rb b/spec/workers/bulk_import_worker_spec.rb index 7e301efe708..0d0b81d2ec0 100644 --- a/spec/workers/bulk_import_worker_spec.rb +++ b/spec/workers/bulk_import_worker_spec.rb @@ -87,7 +87,6 @@ RSpec.describe BulkImportWorker do create(:bulk_import_entity, :created, bulk_import: bulk_import) expect(described_class).to receive(:perform_in).with(described_class::PERFORM_DELAY, bulk_import.id) - expect(BulkImports::EntityWorker).to receive(:perform_async).twice expect(BulkImports::ExportRequestWorker).to receive(:perform_async).twice subject.perform(bulk_import.id) @@ -111,7 +110,7 @@ RSpec.describe BulkImportWorker do bulk_import = create(:bulk_import, :created) create(:bulk_import_entity, :created, bulk_import: bulk_import) - allow(BulkImports::EntityWorker).to receive(:perform_async).and_raise(StandardError) + allow(BulkImports::ExportRequestWorker).to receive(:perform_async).and_raise(StandardError) expect(Gitlab::ErrorTracking).to receive(:track_exception).with(kind_of(StandardError), bulk_import_id: bulk_import.id) diff --git a/spec/workers/bulk_imports/export_request_worker_spec.rb b/spec/workers/bulk_imports/export_request_worker_spec.rb index a7f7aaa7dba..8d78c2ca35c 100644 --- a/spec/workers/bulk_imports/export_request_worker_spec.rb +++ b/spec/workers/bulk_imports/export_request_worker_spec.rb @@ -21,11 +21,13 @@ RSpec.describe BulkImports::ExportRequestWorker do shared_examples 'requests relations export for api resource' do include_examples 'an idempotent worker' do - it 'requests relations export' do + it 'requests relations export & schedules entity worker' do expect_next_instance_of(BulkImports::Clients::HTTP) do |client| expect(client).to receive(:post).with(expected).twice end + expect(BulkImports::EntityWorker).to receive(:perform_async).twice + perform_multiple(job_args) end @@ -55,19 +57,78 @@ RSpec.describe BulkImports::ExportRequestWorker do expect(failure.exception_message).to eq('Export error') end end + + context 'when source id is nil' do + let(:entity_source_id) { 'gid://gitlab/Model/1234567' } + + before do + graphql_client = instance_double(BulkImports::Clients::Graphql) + response = double(original_hash: { 'data' => { entity.entity_type => { 'id' => entity_source_id } } }) + + allow(BulkImports::Clients::Graphql).to receive(:new).and_return(graphql_client) + allow(graphql_client).to receive(:parse) + allow(graphql_client).to receive(:execute).and_return(response) + end + + it 'updates entity source id & requests export using source id' do + expect_next_instance_of(BulkImports::Clients::HTTP) do |client| + expect(client) + .to receive(:post) + .with("/#{entity.pluralized_name}/1234567/export_relations") + .twice + end + + entity.update!(source_xid: nil) + + perform_multiple(job_args) + + expect(entity.reload.source_xid).to eq(1234567) + end + + context 'when something goes wrong during source id fetch' do + let(:entity_source_id) { 'invalid' } + + it 'logs the error & requests relations export using full path url' do + expect_next_instance_of(BulkImports::Clients::HTTP) do |client| + expect(client).to receive(:post).with(full_path_url).twice + end + + entity.update!(source_xid: nil) + + expect(Gitlab::Import::Logger).to receive(:error).with( + a_hash_including( + 'message' => 'Failed to fetch source entity id', + 'bulk_import_entity_id' => entity.id, + 'pipeline_class' => 'ExportRequestWorker', + 'exception_class' => 'NoMethodError', + 'exception_message' => "undefined method `model_id' for nil:NilClass", + 'correlation_id_value' => anything, + 'bulk_import_id' => bulk_import.id, + 'bulk_import_entity_type' => entity.source_type + ) + ).twice + + perform_multiple(job_args) + + expect(entity.source_xid).to be_nil + end + end + end end end context 'when entity is group' do let(:entity) { create(:bulk_import_entity, :group_entity, source_full_path: 'foo/bar', bulk_import: bulk_import) } - let(:expected) { '/groups/foo%2Fbar/export_relations' } + let(:expected) { "/groups/#{entity.source_xid}/export_relations" } + let(:full_path_url) { '/groups/foo%2Fbar/export_relations' } include_examples 'requests relations export for api resource' end context 'when entity is project' do let(:entity) { create(:bulk_import_entity, :project_entity, source_full_path: 'foo/bar', bulk_import: bulk_import) } - let(:expected) { '/projects/foo%2Fbar/export_relations' } + let(:expected) { "/projects/#{entity.source_xid}/export_relations" } + let(:full_path_url) { '/projects/foo%2Fbar/export_relations' } include_examples 'requests relations export for api resource' end |