diff options
Diffstat (limited to 'spec/frontend/ci/pipeline_schedules/components')
11 files changed, 696 insertions, 0 deletions
diff --git a/spec/frontend/ci/pipeline_schedules/components/delete_pipeline_schedule_modal_spec.js b/spec/frontend/ci/pipeline_schedules/components/delete_pipeline_schedule_modal_spec.js new file mode 100644 index 00000000000..ba948f12b33 --- /dev/null +++ b/spec/frontend/ci/pipeline_schedules/components/delete_pipeline_schedule_modal_spec.js @@ -0,0 +1,38 @@ +import { shallowMount } from '@vue/test-utils'; +import { GlModal } from '@gitlab/ui'; +import DeletePipelineScheduleModal from '~/ci/pipeline_schedules/components/delete_pipeline_schedule_modal.vue'; + +describe('Delete pipeline schedule modal', () => { + let wrapper; + + const createComponent = (props = {}) => { + wrapper = shallowMount(DeletePipelineScheduleModal, { + propsData: { + visible: true, + ...props, + }, + }); + }; + + const findModal = () => wrapper.findComponent(GlModal); + + beforeEach(() => { + createComponent(); + }); + + afterEach(() => { + wrapper.destroy(); + }); + + it('emits the deleteSchedule event', async () => { + findModal().vm.$emit('primary'); + + expect(wrapper.emitted()).toEqual({ deleteSchedule: [[]] }); + }); + + it('emits the hideModal event', async () => { + findModal().vm.$emit('hide'); + + expect(wrapper.emitted()).toEqual({ hideModal: [[]] }); + }); +}); diff --git a/spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_form_spec.js b/spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_form_spec.js new file mode 100644 index 00000000000..e5d9b378a42 --- /dev/null +++ b/spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_form_spec.js @@ -0,0 +1,25 @@ +import { shallowMount } from '@vue/test-utils'; +import { GlForm } from '@gitlab/ui'; +import PipelineSchedulesForm from '~/ci/pipeline_schedules/components/pipeline_schedules_form.vue'; + +describe('Pipeline schedules form', () => { + let wrapper; + + const createComponent = () => { + wrapper = shallowMount(PipelineSchedulesForm); + }; + + const findForm = () => wrapper.findComponent(GlForm); + + beforeEach(() => { + createComponent(); + }); + + afterEach(() => { + wrapper.destroy(); + }); + + it('displays form', () => { + expect(findForm().exists()).toBe(true); + }); +}); diff --git a/spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_spec.js b/spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_spec.js new file mode 100644 index 00000000000..4aa4cdf89a1 --- /dev/null +++ b/spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_spec.js @@ -0,0 +1,280 @@ +import { GlAlert, GlLoadingIcon, GlTabs } from '@gitlab/ui'; +import Vue, { nextTick } from 'vue'; +import VueApollo from 'vue-apollo'; +import { trimText } from 'helpers/text_helper'; +import createMockApollo from 'helpers/mock_apollo_helper'; +import waitForPromises from 'helpers/wait_for_promises'; +import { mountExtended } from 'helpers/vue_test_utils_helper'; +import PipelineSchedules from '~/ci/pipeline_schedules/components/pipeline_schedules.vue'; +import DeletePipelineScheduleModal from '~/ci/pipeline_schedules/components/delete_pipeline_schedule_modal.vue'; +import TakeOwnershipModal from '~/ci/pipeline_schedules/components/take_ownership_modal.vue'; +import PipelineSchedulesTable from '~/ci/pipeline_schedules/components/table/pipeline_schedules_table.vue'; +import deletePipelineScheduleMutation from '~/ci/pipeline_schedules/graphql/mutations/delete_pipeline_schedule.mutation.graphql'; +import takeOwnershipMutation from '~/ci/pipeline_schedules/graphql/mutations/take_ownership.mutation.graphql'; +import getPipelineSchedulesQuery from '~/ci/pipeline_schedules/graphql/queries/get_pipeline_schedules.query.graphql'; +import { + mockGetPipelineSchedulesGraphQLResponse, + mockPipelineScheduleNodes, + deleteMutationResponse, + takeOwnershipMutationResponse, +} from '../mock_data'; + +Vue.use(VueApollo); + +const $toast = { + show: jest.fn(), +}; + +describe('Pipeline schedules app', () => { + let wrapper; + + const successHandler = jest.fn().mockResolvedValue(mockGetPipelineSchedulesGraphQLResponse); + const failedHandler = jest.fn().mockRejectedValue(new Error('GraphQL error')); + + const deleteMutationHandlerSuccess = jest.fn().mockResolvedValue(deleteMutationResponse); + const deleteMutationHandlerFailed = jest.fn().mockRejectedValue(new Error('GraphQL error')); + const takeOwnershipMutationHandlerSuccess = jest + .fn() + .mockResolvedValue(takeOwnershipMutationResponse); + const takeOwnershipMutationHandlerFailed = jest + .fn() + .mockRejectedValue(new Error('GraphQL error')); + + const createMockApolloProvider = ( + requestHandlers = [[getPipelineSchedulesQuery, successHandler]], + ) => { + return createMockApollo(requestHandlers); + }; + + const createComponent = (requestHandlers) => { + wrapper = mountExtended(PipelineSchedules, { + provide: { + fullPath: 'gitlab-org/gitlab', + }, + mocks: { + $toast, + }, + apolloProvider: createMockApolloProvider(requestHandlers), + }); + }; + + const findTable = () => wrapper.findComponent(PipelineSchedulesTable); + const findAlert = () => wrapper.findComponent(GlAlert); + const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); + const findDeleteModal = () => wrapper.findComponent(DeletePipelineScheduleModal); + const findTakeOwnershipModal = () => wrapper.findComponent(TakeOwnershipModal); + const findTabs = () => wrapper.findComponent(GlTabs); + const findNewButton = () => wrapper.findByTestId('new-schedule-button'); + const findAllTab = () => wrapper.findByTestId('pipeline-schedules-all-tab'); + const findActiveTab = () => wrapper.findByTestId('pipeline-schedules-active-tab'); + const findInactiveTab = () => wrapper.findByTestId('pipeline-schedules-inactive-tab'); + + afterEach(() => { + wrapper.destroy(); + }); + + describe('default', () => { + beforeEach(() => { + createComponent(); + }); + + it('displays table, tabs and new button', async () => { + await waitForPromises(); + + expect(findTable().exists()).toBe(true); + expect(findNewButton().exists()).toBe(true); + expect(findTabs().exists()).toBe(true); + expect(findAlert().exists()).toBe(false); + }); + + it('handles loading state', async () => { + expect(findLoadingIcon().exists()).toBe(true); + + await waitForPromises(); + + expect(findLoadingIcon().exists()).toBe(false); + }); + }); + + describe('fetching pipeline schedules', () => { + it('fetches query and passes an array of pipeline schedules', async () => { + createComponent(); + + expect(successHandler).toHaveBeenCalled(); + + await waitForPromises(); + + expect(findTable().props('schedules')).toEqual(mockPipelineScheduleNodes); + }); + + it('shows query error alert', async () => { + createComponent([[getPipelineSchedulesQuery, failedHandler]]); + + await waitForPromises(); + + expect(findAlert().text()).toBe('There was a problem fetching pipeline schedules.'); + }); + }); + + describe('deleting a pipeline schedule', () => { + it('shows delete mutation error alert', async () => { + createComponent([ + [getPipelineSchedulesQuery, successHandler], + [deletePipelineScheduleMutation, deleteMutationHandlerFailed], + ]); + + await waitForPromises(); + + findDeleteModal().vm.$emit('deleteSchedule'); + + await waitForPromises(); + + expect(findAlert().text()).toBe('There was a problem deleting the pipeline schedule.'); + }); + + it('deletes pipeline schedule and refetches query', async () => { + createComponent([ + [getPipelineSchedulesQuery, successHandler], + [deletePipelineScheduleMutation, deleteMutationHandlerSuccess], + ]); + + jest.spyOn(wrapper.vm.$apollo.queries.schedules, 'refetch'); + + await waitForPromises(); + + const scheduleId = mockPipelineScheduleNodes[0].id; + + findTable().vm.$emit('showDeleteModal', scheduleId); + + expect(wrapper.vm.$apollo.queries.schedules.refetch).not.toHaveBeenCalled(); + + findDeleteModal().vm.$emit('deleteSchedule'); + + await waitForPromises(); + + expect(deleteMutationHandlerSuccess).toHaveBeenCalledWith({ + id: scheduleId, + }); + expect(wrapper.vm.$apollo.queries.schedules.refetch).toHaveBeenCalled(); + expect($toast.show).toHaveBeenCalledWith('Pipeline schedule successfully deleted.'); + }); + + it('handles delete modal visibility correctly', async () => { + createComponent(); + + await waitForPromises(); + + expect(findDeleteModal().props('visible')).toBe(false); + + findTable().vm.$emit('showDeleteModal', mockPipelineScheduleNodes[0].id); + + await nextTick(); + + expect(findDeleteModal().props('visible')).toBe(true); + expect(findTakeOwnershipModal().props('visible')).toBe(false); + + findDeleteModal().vm.$emit('hideModal'); + + await nextTick(); + + expect(findDeleteModal().props('visible')).toBe(false); + }); + }); + + describe('taking ownership of a pipeline schedule', () => { + it('shows take ownership mutation error alert', async () => { + createComponent([ + [getPipelineSchedulesQuery, successHandler], + [takeOwnershipMutation, takeOwnershipMutationHandlerFailed], + ]); + + await waitForPromises(); + + findTakeOwnershipModal().vm.$emit('takeOwnership'); + + await waitForPromises(); + + expect(findAlert().text()).toBe( + 'There was a problem taking ownership of the pipeline schedule.', + ); + }); + + it('takes ownership of pipeline schedule and refetches query', async () => { + createComponent([ + [getPipelineSchedulesQuery, successHandler], + [takeOwnershipMutation, takeOwnershipMutationHandlerSuccess], + ]); + + jest.spyOn(wrapper.vm.$apollo.queries.schedules, 'refetch'); + + await waitForPromises(); + + const scheduleId = mockPipelineScheduleNodes[1].id; + + findTable().vm.$emit('showTakeOwnershipModal', scheduleId); + + expect(wrapper.vm.$apollo.queries.schedules.refetch).not.toHaveBeenCalled(); + + findTakeOwnershipModal().vm.$emit('takeOwnership'); + + await waitForPromises(); + + expect(takeOwnershipMutationHandlerSuccess).toHaveBeenCalledWith({ + id: scheduleId, + }); + expect(wrapper.vm.$apollo.queries.schedules.refetch).toHaveBeenCalled(); + expect($toast.show).toHaveBeenCalledWith('Successfully taken ownership from Admin.'); + }); + + it('handles take ownership modal visibility correctly', async () => { + createComponent(); + + await waitForPromises(); + + expect(findTakeOwnershipModal().props('visible')).toBe(false); + + findTable().vm.$emit('showTakeOwnershipModal', mockPipelineScheduleNodes[0].id); + + await nextTick(); + + expect(findTakeOwnershipModal().props('visible')).toBe(true); + expect(findDeleteModal().props('visible')).toBe(false); + + findTakeOwnershipModal().vm.$emit('hideModal'); + + await nextTick(); + + expect(findTakeOwnershipModal().props('visible')).toBe(false); + }); + }); + + describe('pipeline schedule tabs', () => { + beforeEach(async () => { + createComponent(); + + await waitForPromises(); + }); + + it('displays All tab with count', () => { + expect(trimText(findAllTab().text())).toBe(`All ${mockPipelineScheduleNodes.length}`); + }); + + it('displays Active tab with no count', () => { + expect(findActiveTab().text()).toBe('Active'); + }); + + it('displays Inactive tab with no count', () => { + expect(findInactiveTab().text()).toBe('Inactive'); + }); + + it('should refetch the schedules query on a tab click', async () => { + jest.spyOn(wrapper.vm.$apollo.queries.schedules, 'refetch').mockImplementation(jest.fn()); + + expect(wrapper.vm.$apollo.queries.schedules.refetch).toHaveBeenCalledTimes(0); + + await findAllTab().trigger('click'); + + expect(wrapper.vm.$apollo.queries.schedules.refetch).toHaveBeenCalledTimes(1); + }); + }); +}); diff --git a/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_actions_spec.js b/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_actions_spec.js new file mode 100644 index 00000000000..3364c61d155 --- /dev/null +++ b/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_actions_spec.js @@ -0,0 +1,64 @@ +import { GlButton } from '@gitlab/ui'; +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import PipelineScheduleActions from '~/ci/pipeline_schedules/components/table/cells/pipeline_schedule_actions.vue'; +import { + mockPipelineScheduleNodes, + mockPipelineScheduleAsGuestNodes, + mockTakeOwnershipNodes, +} from '../../../mock_data'; + +describe('Pipeline schedule actions', () => { + let wrapper; + + const defaultProps = { + schedule: mockPipelineScheduleNodes[0], + }; + + const createComponent = (props = defaultProps) => { + wrapper = shallowMountExtended(PipelineScheduleActions, { + propsData: { + ...props, + }, + }); + }; + + const findAllButtons = () => wrapper.findAllComponents(GlButton); + const findDeleteBtn = () => wrapper.findByTestId('delete-pipeline-schedule-btn'); + const findTakeOwnershipBtn = () => wrapper.findByTestId('take-ownership-pipeline-schedule-btn'); + + afterEach(() => { + wrapper.destroy(); + }); + + it('displays action buttons', () => { + createComponent(); + + expect(findAllButtons()).toHaveLength(3); + }); + + it('does not display action buttons', () => { + createComponent({ schedule: mockPipelineScheduleAsGuestNodes[0] }); + + expect(findAllButtons()).toHaveLength(0); + }); + + it('delete button emits showDeleteModal event and schedule id', () => { + createComponent(); + + findDeleteBtn().vm.$emit('click'); + + expect(wrapper.emitted()).toEqual({ + showDeleteModal: [[mockPipelineScheduleNodes[0].id]], + }); + }); + + it('take ownership button emits showTakeOwnershipModal event and schedule id', () => { + createComponent({ schedule: mockTakeOwnershipNodes[0] }); + + findTakeOwnershipBtn().vm.$emit('click'); + + expect(wrapper.emitted()).toEqual({ + showTakeOwnershipModal: [[mockTakeOwnershipNodes[0].id]], + }); + }); +}); diff --git a/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline_spec.js b/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline_spec.js new file mode 100644 index 00000000000..17bf465baf3 --- /dev/null +++ b/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline_spec.js @@ -0,0 +1,42 @@ +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import CiBadge from '~/vue_shared/components/ci_badge_link.vue'; +import PipelineScheduleLastPipeline from '~/ci/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline.vue'; +import { mockPipelineScheduleNodes } from '../../../mock_data'; + +describe('Pipeline schedule last pipeline', () => { + let wrapper; + + const defaultProps = { + schedule: mockPipelineScheduleNodes[2], + }; + + const createComponent = (props = defaultProps) => { + wrapper = shallowMountExtended(PipelineScheduleLastPipeline, { + propsData: { + ...props, + }, + }); + }; + + const findCIBadge = () => wrapper.findComponent(CiBadge); + const findStatusText = () => wrapper.findByTestId('pipeline-schedule-status-text'); + + afterEach(() => { + wrapper.destroy(); + }); + + it('displays pipeline status', () => { + createComponent(); + + expect(findCIBadge().exists()).toBe(true); + expect(findCIBadge().props('status')).toBe(defaultProps.schedule.lastPipeline.detailedStatus); + expect(findStatusText().exists()).toBe(false); + }); + + it('displays "none" status text', () => { + createComponent({ schedule: mockPipelineScheduleNodes[0] }); + + expect(findStatusText().text()).toBe('None'); + expect(findCIBadge().exists()).toBe(false); + }); +}); diff --git a/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_next_run_spec.js b/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_next_run_spec.js new file mode 100644 index 00000000000..1c06c411097 --- /dev/null +++ b/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_next_run_spec.js @@ -0,0 +1,43 @@ +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import PipelineScheduleNextRun from '~/ci/pipeline_schedules/components/table/cells/pipeline_schedule_next_run.vue'; +import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; +import { mockPipelineScheduleNodes } from '../../../mock_data'; + +describe('Pipeline schedule next run', () => { + let wrapper; + + const defaultProps = { + schedule: mockPipelineScheduleNodes[0], + }; + + const createComponent = (props = defaultProps) => { + wrapper = shallowMountExtended(PipelineScheduleNextRun, { + propsData: { + ...props, + }, + }); + }; + + const findTimeAgo = () => wrapper.findComponent(TimeAgoTooltip); + const findInactive = () => wrapper.findByTestId('pipeline-schedule-inactive'); + + afterEach(() => { + wrapper.destroy(); + }); + + it('displays time ago', () => { + createComponent(); + + expect(findTimeAgo().exists()).toBe(true); + expect(findInactive().exists()).toBe(false); + expect(findTimeAgo().props('time')).toBe(defaultProps.schedule.realNextRun); + }); + + it('displays inactive state', () => { + const inactiveSchedule = mockPipelineScheduleNodes[1]; + createComponent({ schedule: inactiveSchedule }); + + expect(findInactive().text()).toBe('Inactive'); + expect(findTimeAgo().exists()).toBe(false); + }); +}); diff --git a/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_owner_spec.js b/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_owner_spec.js new file mode 100644 index 00000000000..6c1991cb4ac --- /dev/null +++ b/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_owner_spec.js @@ -0,0 +1,40 @@ +import { GlAvatar, GlAvatarLink } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; +import PipelineScheduleOwner from '~/ci/pipeline_schedules/components/table/cells/pipeline_schedule_owner.vue'; +import { mockPipelineScheduleNodes } from '../../../mock_data'; + +describe('Pipeline schedule owner', () => { + let wrapper; + + const defaultProps = { + schedule: mockPipelineScheduleNodes[0], + }; + + const createComponent = (props = defaultProps) => { + wrapper = shallowMount(PipelineScheduleOwner, { + propsData: { + ...props, + }, + }); + }; + + const findAvatar = () => wrapper.findComponent(GlAvatar); + const findAvatarLink = () => wrapper.findComponent(GlAvatarLink); + + beforeEach(() => { + createComponent(); + }); + + afterEach(() => { + wrapper.destroy(); + }); + + it('displays avatar', () => { + expect(findAvatar().exists()).toBe(true); + expect(findAvatar().props('src')).toBe(defaultProps.schedule.owner.avatarUrl); + }); + + it('avatar links to user', () => { + expect(findAvatarLink().attributes('href')).toBe(defaultProps.schedule.owner.webPath); + }); +}); diff --git a/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_target_spec.js b/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_target_spec.js new file mode 100644 index 00000000000..f531f04a736 --- /dev/null +++ b/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_target_spec.js @@ -0,0 +1,41 @@ +import { GlIcon, GlLink } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; +import PipelineScheduleTarget from '~/ci/pipeline_schedules/components/table/cells/pipeline_schedule_target.vue'; +import { mockPipelineScheduleNodes } from '../../../mock_data'; + +describe('Pipeline schedule target', () => { + let wrapper; + + const defaultProps = { + schedule: mockPipelineScheduleNodes[0], + }; + + const createComponent = (props = defaultProps) => { + wrapper = shallowMount(PipelineScheduleTarget, { + propsData: { + ...props, + }, + }); + }; + + const findIcon = () => wrapper.findComponent(GlIcon); + const findLink = () => wrapper.findComponent(GlLink); + + beforeEach(() => { + createComponent(); + }); + + afterEach(() => { + wrapper.destroy(); + }); + + it('displays icon', () => { + expect(findIcon().exists()).toBe(true); + expect(findIcon().props('name')).toBe('fork'); + }); + + it('displays ref link', () => { + expect(findLink().attributes('href')).toBe(defaultProps.schedule.refPath); + expect(findLink().text()).toBe(defaultProps.schedule.refForDisplay); + }); +}); diff --git a/spec/frontend/ci/pipeline_schedules/components/table/pipeline_schedules_table_spec.js b/spec/frontend/ci/pipeline_schedules/components/table/pipeline_schedules_table_spec.js new file mode 100644 index 00000000000..316b3bcf926 --- /dev/null +++ b/spec/frontend/ci/pipeline_schedules/components/table/pipeline_schedules_table_spec.js @@ -0,0 +1,39 @@ +import { GlTableLite } from '@gitlab/ui'; +import { mountExtended } from 'helpers/vue_test_utils_helper'; +import PipelineSchedulesTable from '~/ci/pipeline_schedules/components/table/pipeline_schedules_table.vue'; +import { mockPipelineScheduleNodes } from '../../mock_data'; + +describe('Pipeline schedules table', () => { + let wrapper; + + const defaultProps = { + schedules: mockPipelineScheduleNodes, + }; + + const createComponent = (props = defaultProps) => { + wrapper = mountExtended(PipelineSchedulesTable, { + propsData: { + ...props, + }, + }); + }; + + const findTable = () => wrapper.findComponent(GlTableLite); + const findScheduleDescription = () => wrapper.findByTestId('pipeline-schedule-description'); + + beforeEach(() => { + createComponent(); + }); + + afterEach(() => { + wrapper.destroy(); + }); + + it('displays table', () => { + expect(findTable().exists()).toBe(true); + }); + + it('displays schedule description', () => { + expect(findScheduleDescription().text()).toBe('pipeline schedule'); + }); +}); diff --git a/spec/frontend/ci/pipeline_schedules/components/take_ownership_modal_legacy_spec.js b/spec/frontend/ci/pipeline_schedules/components/take_ownership_modal_legacy_spec.js new file mode 100644 index 00000000000..7e6d4ec4bf8 --- /dev/null +++ b/spec/frontend/ci/pipeline_schedules/components/take_ownership_modal_legacy_spec.js @@ -0,0 +1,44 @@ +import { GlModal } from '@gitlab/ui'; +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import TakeOwnershipModalLegacy from '~/ci/pipeline_schedules/components/take_ownership_modal_legacy.vue'; + +describe('Take ownership modal', () => { + let wrapper; + const url = `/root/job-log-tester/-/pipeline_schedules/3/take_ownership`; + + const createComponent = (props = {}) => { + wrapper = shallowMountExtended(TakeOwnershipModalLegacy, { + propsData: { + ownershipUrl: url, + ...props, + }, + }); + }; + + const findModal = () => wrapper.findComponent(GlModal); + + beforeEach(() => { + createComponent(); + }); + + it('has a primary action set to a url and a post data-method', () => { + const actionPrimary = findModal().props('actionPrimary'); + + expect(actionPrimary.attributes).toEqual( + expect.objectContaining([ + { + category: 'primary', + variant: 'confirm', + href: url, + 'data-method': 'post', + }, + ]), + ); + }); + + it('shows a take ownership message', () => { + expect(findModal().text()).toBe( + 'Only the owner of a pipeline schedule can make changes to it. Do you want to take ownership of this schedule?', + ); + }); +}); diff --git a/spec/frontend/ci/pipeline_schedules/components/take_ownership_modal_spec.js b/spec/frontend/ci/pipeline_schedules/components/take_ownership_modal_spec.js new file mode 100644 index 00000000000..e3965d13c19 --- /dev/null +++ b/spec/frontend/ci/pipeline_schedules/components/take_ownership_modal_spec.js @@ -0,0 +1,40 @@ +import { shallowMount } from '@vue/test-utils'; +import { GlModal } from '@gitlab/ui'; +import TakeOwnershipModal from '~/ci/pipeline_schedules/components/take_ownership_modal.vue'; + +describe('Take ownership modal', () => { + let wrapper; + + const createComponent = (props = {}) => { + wrapper = shallowMount(TakeOwnershipModal, { + propsData: { + visible: true, + ...props, + }, + }); + }; + + const findModal = () => wrapper.findComponent(GlModal); + + beforeEach(() => { + createComponent(); + }); + + it('shows a take ownership message', () => { + expect(findModal().text()).toBe( + 'Only the owner of a pipeline schedule can make changes to it. Do you want to take ownership of this schedule?', + ); + }); + + it('emits the takeOwnership event', async () => { + findModal().vm.$emit('primary'); + + expect(wrapper.emitted()).toEqual({ takeOwnership: [[]] }); + }); + + it('emits the hideModal event', async () => { + findModal().vm.$emit('hide'); + + expect(wrapper.emitted()).toEqual({ hideModal: [[]] }); + }); +}); |