diff options
Diffstat (limited to 'spec/frontend/runner/components/runner_delete_button_spec.js')
-rw-r--r-- | spec/frontend/runner/components/runner_delete_button_spec.js | 266 |
1 files changed, 0 insertions, 266 deletions
diff --git a/spec/frontend/runner/components/runner_delete_button_spec.js b/spec/frontend/runner/components/runner_delete_button_spec.js deleted file mode 100644 index c8fb7a69379..00000000000 --- a/spec/frontend/runner/components/runner_delete_button_spec.js +++ /dev/null @@ -1,266 +0,0 @@ -import Vue from 'vue'; -import { GlButton } from '@gitlab/ui'; -import VueApollo from 'vue-apollo'; -import createMockApollo from 'helpers/mock_apollo_helper'; -import { createMockDirective, getBinding } from 'helpers/vue_mock_directive'; -import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper'; -import runnerDeleteMutation from '~/runner/graphql/shared/runner_delete.mutation.graphql'; -import waitForPromises from 'helpers/wait_for_promises'; -import { captureException } from '~/runner/sentry_utils'; -import { getIdFromGraphQLId } from '~/graphql_shared/utils'; -import { createAlert } from '~/flash'; -import { I18N_DELETE_RUNNER } from '~/runner/constants'; - -import RunnerDeleteButton from '~/runner/components/runner_delete_button.vue'; -import RunnerDeleteModal from '~/runner/components/runner_delete_modal.vue'; -import { allRunnersData } from '../mock_data'; - -const mockRunner = allRunnersData.data.runners.nodes[0]; -const mockRunnerId = getIdFromGraphQLId(mockRunner.id); - -Vue.use(VueApollo); - -jest.mock('~/flash'); -jest.mock('~/runner/sentry_utils'); - -describe('RunnerDeleteButton', () => { - let wrapper; - let apolloProvider; - let apolloCache; - let runnerDeleteHandler; - - const findBtn = () => wrapper.findComponent(GlButton); - const findModal = () => wrapper.findComponent(RunnerDeleteModal); - - const getTooltip = () => getBinding(wrapper.element, 'gl-tooltip').value; - const getModal = () => getBinding(findBtn().element, 'gl-modal').value; - - const createComponent = ({ props = {}, mountFn = shallowMountExtended } = {}) => { - const { runner, ...propsData } = props; - - wrapper = mountFn(RunnerDeleteButton, { - propsData: { - runner: { - // We need typename so that cache.identify works - // eslint-disable-next-line no-underscore-dangle - __typename: mockRunner.__typename, - id: mockRunner.id, - shortSha: mockRunner.shortSha, - ...runner, - }, - ...propsData, - }, - apolloProvider, - directives: { - GlTooltip: createMockDirective(), - GlModal: createMockDirective(), - }, - }); - }; - - const clickOkAndWait = async () => { - findModal().vm.$emit('primary'); - await waitForPromises(); - }; - - beforeEach(() => { - runnerDeleteHandler = jest.fn().mockImplementation(() => { - return Promise.resolve({ - data: { - runnerDelete: { - errors: [], - }, - }, - }); - }); - apolloProvider = createMockApollo([[runnerDeleteMutation, runnerDeleteHandler]]); - apolloCache = apolloProvider.defaultClient.cache; - - jest.spyOn(apolloCache, 'evict'); - jest.spyOn(apolloCache, 'gc'); - - createComponent(); - }); - - afterEach(() => { - wrapper.destroy(); - }); - - it('Displays a delete button without an icon', () => { - expect(findBtn().props()).toMatchObject({ - loading: false, - icon: '', - }); - expect(findBtn().classes('btn-icon')).toBe(false); - expect(findBtn().text()).toBe(I18N_DELETE_RUNNER); - }); - - it('Displays a modal with the runner name', () => { - expect(findModal().props('runnerName')).toBe(`#${mockRunnerId} (${mockRunner.shortSha})`); - }); - - it('Does not have tabindex when button is enabled', () => { - expect(wrapper.attributes('tabindex')).toBeUndefined(); - }); - - it('Displays a modal when clicked', () => { - const modalId = `delete-runner-modal-${mockRunnerId}`; - - expect(getModal()).toBe(modalId); - expect(findModal().attributes('modal-id')).toBe(modalId); - }); - - it('Does not display redundant text for screen readers', () => { - expect(findBtn().attributes('aria-label')).toBe(undefined); - }); - - it('Passes other attributes to the button', () => { - createComponent({ props: { category: 'secondary' } }); - - expect(findBtn().props('category')).toBe('secondary'); - }); - - describe(`Before the delete button is clicked`, () => { - it('The mutation has not been called', () => { - expect(runnerDeleteHandler).toHaveBeenCalledTimes(0); - }); - }); - - describe('Immediately after the delete button is clicked', () => { - beforeEach(async () => { - findModal().vm.$emit('primary'); - }); - - it('The button has a loading state', async () => { - expect(findBtn().props('loading')).toBe(true); - }); - - it('The stale tooltip is removed', async () => { - expect(getTooltip()).toBe(''); - }); - }); - - describe('After clicking on the delete button', () => { - beforeEach(async () => { - await clickOkAndWait(); - }); - - it('The mutation to delete is called', () => { - expect(runnerDeleteHandler).toHaveBeenCalledTimes(1); - expect(runnerDeleteHandler).toHaveBeenCalledWith({ - input: { - id: mockRunner.id, - }, - }); - }); - - it('The user can be notified with an event', () => { - const deleted = wrapper.emitted('deleted'); - - expect(deleted).toHaveLength(1); - expect(deleted[0][0].message).toMatch(`#${mockRunnerId}`); - expect(deleted[0][0].message).toMatch(`${mockRunner.shortSha}`); - }); - - it('evicts runner from apollo cache', () => { - expect(apolloCache.evict).toHaveBeenCalledWith({ - id: apolloCache.identify(mockRunner), - }); - expect(apolloCache.gc).toHaveBeenCalled(); - }); - }); - - describe('When update fails', () => { - describe('On a network error', () => { - const mockErrorMsg = 'Update error!'; - - beforeEach(async () => { - runnerDeleteHandler.mockRejectedValueOnce(new Error(mockErrorMsg)); - - await clickOkAndWait(); - }); - - it('error is reported to sentry', () => { - expect(captureException).toHaveBeenCalledWith({ - error: new Error(mockErrorMsg), - component: 'RunnerDeleteButton', - }); - }); - - it('error is shown to the user', () => { - expect(createAlert).toHaveBeenCalledTimes(1); - }); - }); - - describe('On a validation error', () => { - const mockErrorMsg = 'Runner not found!'; - const mockErrorMsg2 = 'User not allowed!'; - - beforeEach(async () => { - runnerDeleteHandler.mockResolvedValueOnce({ - data: { - runnerDelete: { - errors: [mockErrorMsg, mockErrorMsg2], - }, - }, - }); - - await clickOkAndWait(); - }); - - it('error is reported to sentry', () => { - expect(captureException).toHaveBeenCalledWith({ - error: new Error(`${mockErrorMsg} ${mockErrorMsg2}`), - component: 'RunnerDeleteButton', - }); - }); - - it('error is shown to the user', () => { - expect(createAlert).toHaveBeenCalledTimes(1); - }); - - it('does not evict runner from apollo cache', () => { - expect(apolloCache.evict).not.toHaveBeenCalled(); - expect(apolloCache.gc).not.toHaveBeenCalled(); - }); - }); - }); - - describe('When displaying a compact button for an active runner', () => { - beforeEach(() => { - createComponent({ - props: { - runner: { - active: true, - }, - compact: true, - }, - mountFn: mountExtended, - }); - }); - - it('Displays no text', () => { - expect(findBtn().text()).toBe(''); - expect(findBtn().classes('btn-icon')).toBe(true); - }); - - it('Display correctly for screen readers', () => { - expect(findBtn().attributes('aria-label')).toBe(I18N_DELETE_RUNNER); - expect(getTooltip()).toBe(I18N_DELETE_RUNNER); - }); - - describe('Immediately after the button is clicked', () => { - beforeEach(async () => { - findModal().vm.$emit('primary'); - }); - - it('The button has a loading state', async () => { - expect(findBtn().props('loading')).toBe(true); - }); - - it('The stale tooltip is removed', async () => { - expect(getTooltip()).toBe(''); - }); - }); - }); -}); |