diff options
Diffstat (limited to 'spec/frontend/runner/components')
9 files changed, 321 insertions, 229 deletions
diff --git a/spec/frontend/runner/components/cells/runner_actions_cell_spec.js b/spec/frontend/runner/components/cells/runner_actions_cell_spec.js index dcb0af67784..0d579106860 100644 --- a/spec/frontend/runner/components/cells/runner_actions_cell_spec.js +++ b/spec/frontend/runner/components/cells/runner_actions_cell_spec.js @@ -1,84 +1,37 @@ -import Vue from 'vue'; -import VueApollo from 'vue-apollo'; -import createMockApollo from 'helpers/mock_apollo_helper'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; -import waitForPromises from 'helpers/wait_for_promises'; -import { createMockDirective, getBinding } from 'helpers/vue_mock_directive'; -import { createAlert } from '~/flash'; -import { getIdFromGraphQLId } from '~/graphql_shared/utils'; -import { captureException } from '~/runner/sentry_utils'; -import RunnerActionCell from '~/runner/components/cells/runner_actions_cell.vue'; +import RunnerActionsCell from '~/runner/components/cells/runner_actions_cell.vue'; import RunnerPauseButton from '~/runner/components/runner_pause_button.vue'; import RunnerEditButton from '~/runner/components/runner_edit_button.vue'; -import RunnerDeleteModal from '~/runner/components/runner_delete_modal.vue'; -import getGroupRunnersQuery from '~/runner/graphql/get_group_runners.query.graphql'; -import getRunnersQuery from '~/runner/graphql/get_runners.query.graphql'; -import runnerDeleteMutation from '~/runner/graphql/runner_delete.mutation.graphql'; +import RunnerDeleteButton from '~/runner/components/runner_delete_button.vue'; import { runnersData } from '../../mock_data'; const mockRunner = runnersData.data.runners.nodes[0]; -const getRunnersQueryName = getRunnersQuery.definitions[0].name.value; -const getGroupRunnersQueryName = getGroupRunnersQuery.definitions[0].name.value; - -Vue.use(VueApollo); - -jest.mock('~/flash'); -jest.mock('~/runner/sentry_utils'); - -describe('RunnerTypeCell', () => { +describe('RunnerActionsCell', () => { let wrapper; - const mockToastShow = jest.fn(); - const runnerDeleteMutationHandler = jest.fn(); - const findEditBtn = () => wrapper.findComponent(RunnerEditButton); const findRunnerPauseBtn = () => wrapper.findComponent(RunnerPauseButton); - const findRunnerDeleteModal = () => wrapper.findComponent(RunnerDeleteModal); - const findDeleteBtn = () => wrapper.findByTestId('delete-runner'); - const getTooltip = (w) => getBinding(w.element, 'gl-tooltip')?.value; + const findDeleteBtn = () => wrapper.findComponent(RunnerDeleteButton); - const createComponent = (runner = {}, options) => { - wrapper = shallowMountExtended(RunnerActionCell, { + const createComponent = ({ runner = {}, ...props } = {}) => { + wrapper = shallowMountExtended(RunnerActionsCell, { propsData: { + editUrl: mockRunner.editAdminUrl, runner: { id: mockRunner.id, shortSha: mockRunner.shortSha, editAdminUrl: mockRunner.editAdminUrl, userPermissions: mockRunner.userPermissions, - active: mockRunner.active, ...runner, }, + ...props, }, - apolloProvider: createMockApollo([[runnerDeleteMutation, runnerDeleteMutationHandler]]), - directives: { - GlTooltip: createMockDirective(), - GlModal: createMockDirective(), - }, - mocks: { - $toast: { - show: mockToastShow, - }, - }, - ...options, }); }; - beforeEach(() => { - runnerDeleteMutationHandler.mockResolvedValue({ - data: { - runnerDelete: { - errors: [], - }, - }, - }); - }); - afterEach(() => { - mockToastShow.mockReset(); - runnerDeleteMutationHandler.mockReset(); - wrapper.destroy(); }); @@ -91,18 +44,20 @@ describe('RunnerTypeCell', () => { it('Does not render the runner edit link when user cannot update', () => { createComponent({ - userPermissions: { - ...mockRunner.userPermissions, - updateRunner: false, + runner: { + userPermissions: { + ...mockRunner.userPermissions, + updateRunner: false, + }, }, }); expect(findEditBtn().exists()).toBe(false); }); - it('Does not render the runner edit link when editAdminUrl is not provided', () => { + it('Does not render the runner edit link when editUrl is not provided', () => { createComponent({ - editAdminUrl: null, + editUrl: null, }); expect(findEditBtn().exists()).toBe(false); @@ -118,9 +73,11 @@ describe('RunnerTypeCell', () => { it('Does not render the runner pause button when user cannot update', () => { createComponent({ - userPermissions: { - ...mockRunner.userPermissions, - updateRunner: false, + runner: { + userPermissions: { + ...mockRunner.userPermissions, + updateRunner: false, + }, }, }); @@ -129,147 +86,35 @@ describe('RunnerTypeCell', () => { }); describe('Delete action', () => { - beforeEach(() => { - createComponent( - {}, - { - stubs: { RunnerDeleteModal }, - }, - ); - }); + it('Renders a compact delete button', () => { + createComponent(); - it('Renders delete button', () => { - expect(findDeleteBtn().exists()).toBe(true); + expect(findDeleteBtn().props('compact')).toBe(true); }); - it('Delete button opens delete modal', () => { - const modalId = getBinding(findDeleteBtn().element, 'gl-modal').value; + it('Emits delete events', () => { + const value = { name: 'Runner' }; - expect(findRunnerDeleteModal().attributes('modal-id')).toBeDefined(); - expect(findRunnerDeleteModal().attributes('modal-id')).toBe(modalId); - }); - - it('Delete modal shows the runner name', () => { - expect(findRunnerDeleteModal().props('runnerName')).toBe( - `#${getIdFromGraphQLId(mockRunner.id)} (${mockRunner.shortSha})`, - ); - }); - it('The delete button does not have a loading icon', () => { - expect(findDeleteBtn().props('loading')).toBe(false); - expect(getTooltip(findDeleteBtn())).toBe('Delete runner'); - }); + createComponent(); - it('When delete mutation is called, current runners are refetched', () => { - jest.spyOn(wrapper.vm.$apollo, 'mutate'); + expect(wrapper.emitted('deleted')).toBe(undefined); - findRunnerDeleteModal().vm.$emit('primary'); + findDeleteBtn().vm.$emit('deleted', value); - expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({ - mutation: runnerDeleteMutation, - variables: { - input: { - id: mockRunner.id, - }, - }, - awaitRefetchQueries: true, - refetchQueries: [getRunnersQueryName, getGroupRunnersQueryName], - }); + expect(wrapper.emitted('deleted')).toEqual([[value]]); }); it('Does not render the runner delete button when user cannot delete', () => { createComponent({ - userPermissions: { - ...mockRunner.userPermissions, - deleteRunner: false, + runner: { + userPermissions: { + ...mockRunner.userPermissions, + deleteRunner: false, + }, }, }); expect(findDeleteBtn().exists()).toBe(false); - expect(findRunnerDeleteModal().exists()).toBe(false); - }); - - describe('When delete is clicked', () => { - beforeEach(async () => { - findRunnerDeleteModal().vm.$emit('primary'); - await waitForPromises(); - }); - - it('The delete mutation is called correctly', () => { - expect(runnerDeleteMutationHandler).toHaveBeenCalledTimes(1); - expect(runnerDeleteMutationHandler).toHaveBeenCalledWith({ - input: { id: mockRunner.id }, - }); - }); - - it('The delete button has a loading icon', () => { - expect(findDeleteBtn().props('loading')).toBe(true); - expect(getTooltip(findDeleteBtn())).toBe(''); - }); - - it('The toast notification is shown', async () => { - await waitForPromises(); - expect(mockToastShow).toHaveBeenCalledTimes(1); - expect(mockToastShow).toHaveBeenCalledWith( - expect.stringContaining(`#${getIdFromGraphQLId(mockRunner.id)} (${mockRunner.shortSha})`), - ); - }); - }); - - describe('When delete fails', () => { - describe('On a network error', () => { - const mockErrorMsg = 'Delete error!'; - - beforeEach(async () => { - runnerDeleteMutationHandler.mockRejectedValueOnce(new Error(mockErrorMsg)); - - findRunnerDeleteModal().vm.$emit('primary'); - await waitForPromises(); - }); - - it('error is reported to sentry', () => { - expect(captureException).toHaveBeenCalledWith({ - error: new Error(mockErrorMsg), - component: 'RunnerActionsCell', - }); - }); - - it('error is shown to the user', () => { - expect(createAlert).toHaveBeenCalledTimes(1); - }); - - it('toast notification is not shown', () => { - expect(mockToastShow).not.toHaveBeenCalled(); - }); - }); - - describe('On a validation error', () => { - const mockErrorMsg = 'Runner not found!'; - const mockErrorMsg2 = 'User not allowed!'; - - beforeEach(async () => { - runnerDeleteMutationHandler.mockResolvedValue({ - data: { - runnerDelete: { - errors: [mockErrorMsg, mockErrorMsg2], - }, - }, - }); - - findRunnerDeleteModal().vm.$emit('primary'); - await waitForPromises(); - }); - - it('error is reported to sentry', () => { - expect(captureException).toHaveBeenCalledWith({ - error: new Error(`${mockErrorMsg} ${mockErrorMsg2}`), - component: 'RunnerActionsCell', - }); - }); - - it('error is shown to the user', () => { - expect(createAlert).toHaveBeenCalledTimes(1); - }); - }); }); }); }); diff --git a/spec/frontend/runner/components/registration/registration_token_reset_dropdown_item_spec.js b/spec/frontend/runner/components/registration/registration_token_reset_dropdown_item_spec.js index d2deb49a5f7..2510aaf0334 100644 --- a/spec/frontend/runner/components/registration/registration_token_reset_dropdown_item_spec.js +++ b/spec/frontend/runner/components/registration/registration_token_reset_dropdown_item_spec.js @@ -8,7 +8,7 @@ import waitForPromises from 'helpers/wait_for_promises'; import { createAlert } from '~/flash'; import RegistrationTokenResetDropdownItem from '~/runner/components/registration/registration_token_reset_dropdown_item.vue'; import { INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE } from '~/runner/constants'; -import runnersRegistrationTokenResetMutation from '~/runner/graphql/runners_registration_token_reset.mutation.graphql'; +import runnersRegistrationTokenResetMutation from '~/runner/graphql/list/runners_registration_token_reset.mutation.graphql'; import { captureException } from '~/runner/sentry_utils'; import { createMockDirective, getBinding } from 'helpers/vue_mock_directive'; diff --git a/spec/frontend/runner/components/runner_delete_button_spec.js b/spec/frontend/runner/components/runner_delete_button_spec.js new file mode 100644 index 00000000000..81c870f23cf --- /dev/null +++ b/spec/frontend/runner/components/runner_delete_button_spec.js @@ -0,0 +1,233 @@ +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 { runnersData } from '../mock_data'; + +const mockRunner = runnersData.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 runnerDeleteHandler; + + const getTooltip = () => getBinding(wrapper.element, 'gl-tooltip').value; + const getModal = () => getBinding(wrapper.element, 'gl-modal').value; + const findBtn = () => wrapper.findComponent(GlButton); + const findModal = () => wrapper.findComponent(RunnerDeleteModal); + + const createComponent = ({ props = {}, mountFn = shallowMountExtended } = {}) => { + const { runner, ...propsData } = props; + + wrapper = mountFn(RunnerDeleteButton, { + propsData: { + runner: { + id: mockRunner.id, + shortSha: mockRunner.shortSha, + ...runner, + }, + ...propsData, + }, + apolloProvider: createMockApollo([[runnerDeleteMutation, runnerDeleteHandler]]), + 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: [], + }, + }, + }); + }); + + 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('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); + }); + + 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}`); + }); + }); + + 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); + }); + }); + }); + + 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(''); + }); + }); + }); +}); diff --git a/spec/frontend/runner/components/runner_jobs_spec.js b/spec/frontend/runner/components/runner_jobs_spec.js index 97339056370..9abb2861005 100644 --- a/spec/frontend/runner/components/runner_jobs_spec.js +++ b/spec/frontend/runner/components/runner_jobs_spec.js @@ -11,7 +11,7 @@ import RunnerPagination from '~/runner/components/runner_pagination.vue'; import { captureException } from '~/runner/sentry_utils'; import { I18N_NO_JOBS_FOUND, RUNNER_DETAILS_JOBS_PAGE_SIZE } from '~/runner/constants'; -import getRunnerJobsQuery from '~/runner/graphql/get_runner_jobs.query.graphql'; +import runnerJobsQuery from '~/runner/graphql/details/runner_jobs.query.graphql'; import { runnerData, runnerJobsData } from '../mock_data'; @@ -34,7 +34,7 @@ describe('RunnerJobs', () => { const createComponent = ({ mountFn = shallowMountExtended } = {}) => { wrapper = mountFn(RunnerJobs, { - apolloProvider: createMockApollo([[getRunnerJobsQuery, mockRunnerJobsQuery]]), + apolloProvider: createMockApollo([[runnerJobsQuery, mockRunnerJobsQuery]]), propsData: { runner: mockRunner, }, diff --git a/spec/frontend/runner/components/runner_list_spec.js b/spec/frontend/runner/components/runner_list_spec.js index 42d6ecca09e..a0f42738d2c 100644 --- a/spec/frontend/runner/components/runner_list_spec.js +++ b/spec/frontend/runner/components/runner_list_spec.js @@ -1,4 +1,4 @@ -import { GlTable, GlSkeletonLoader } from '@gitlab/ui'; +import { GlTableLite, GlSkeletonLoader } from '@gitlab/ui'; import { extendedWrapper, shallowMountExtended, @@ -6,8 +6,6 @@ import { } from 'helpers/vue_test_utils_helper'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import RunnerList from '~/runner/components/runner_list.vue'; -import RunnerEditButton from '~/runner/components/runner_edit_button.vue'; -import RunnerPauseButton from '~/runner/components/runner_pause_button.vue'; import { runnersData } from '../mock_data'; const mockRunners = runnersData.data.runners.nodes; @@ -17,19 +15,20 @@ describe('RunnerList', () => { let wrapper; const findSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader); - const findTable = () => wrapper.findComponent(GlTable); + const findTable = () => wrapper.findComponent(GlTableLite); const findHeaders = () => wrapper.findAll('th'); const findRows = () => wrapper.findAll('[data-testid^="runner-row-"]'); const findCell = ({ row = 0, fieldKey }) => extendedWrapper(findRows().at(row).find(`[data-testid="td-${fieldKey}"]`)); - const createComponent = ({ props = {} } = {}, mountFn = shallowMountExtended) => { + const createComponent = ({ props = {}, ...options } = {}, mountFn = shallowMountExtended) => { wrapper = mountFn(RunnerList, { propsData: { runners: mockRunners, activeRunnersCount: mockActiveRunnersCount, ...props, }, + ...options, }); }; @@ -90,11 +89,31 @@ describe('RunnerList', () => { expect(findCell({ fieldKey: 'contactedAt' }).text()).toEqual(expect.any(String)); // Actions - const actions = findCell({ fieldKey: 'actions' }); + expect(findCell({ fieldKey: 'actions' }).exists()).toBe(true); + }); + + describe('Scoped cell slots', () => { + it('Render #runner-name slot in "summary" cell', () => { + createComponent( + { + scopedSlots: { 'runner-name': ({ runner }) => `Summary: ${runner.id}` }, + }, + mountExtended, + ); + + expect(findCell({ fieldKey: 'summary' }).text()).toContain(`Summary: ${mockRunners[0].id}`); + }); - expect(actions.findComponent(RunnerEditButton).exists()).toBe(true); - expect(actions.findComponent(RunnerPauseButton).exists()).toBe(true); - expect(actions.findByTestId('delete-runner').exists()).toBe(true); + it('Render #runner-actions-cell slot in "actions" cell', () => { + createComponent( + { + scopedSlots: { 'runner-actions-cell': ({ runner }) => `Actions: ${runner.id}` }, + }, + mountExtended, + ); + + expect(findCell({ fieldKey: 'actions' }).text()).toBe(`Actions: ${mockRunners[0].id}`); + }); }); describe('Table data formatting', () => { @@ -143,7 +162,8 @@ describe('RunnerList', () => { describe('When data is loading', () => { it('shows a busy state', () => { createComponent({ props: { runners: [], loading: true } }); - expect(findTable().attributes('busy')).toBeTruthy(); + + expect(findTable().classes('gl-opacity-6')).toBe(true); }); it('when there are no runners, shows an skeleton loader', () => { diff --git a/spec/frontend/runner/components/runner_pagination_spec.js b/spec/frontend/runner/components/runner_pagination_spec.js index ecd6e6bd7f9..e144b52ceb3 100644 --- a/spec/frontend/runner/components/runner_pagination_spec.js +++ b/spec/frontend/runner/components/runner_pagination_spec.js @@ -45,14 +45,6 @@ describe('RunnerPagination', () => { expect(findPagination().props('nextPage')).toBe(2); }); - it('Shows prev page disabled', () => { - expect(findPagination().find('[aria-disabled]').text()).toBe('Prev'); - }); - - it('Shows next page link', () => { - expect(findPagination().find('a').text()).toBe('Next'); - }); - it('Goes to the second page', () => { findPagination().vm.$emit('input', 2); @@ -84,7 +76,7 @@ describe('RunnerPagination', () => { const links = findPagination().findAll('a'); expect(links).toHaveLength(2); - expect(links.at(0).text()).toBe('Prev'); + expect(links.at(0).text()).toBe('Previous'); expect(links.at(1).text()).toBe('Next'); }); @@ -124,14 +116,6 @@ describe('RunnerPagination', () => { expect(findPagination().props('prevPage')).toBe(2); expect(findPagination().props('nextPage')).toBe(null); }); - - it('Shows next page link', () => { - expect(findPagination().find('a').text()).toBe('Prev'); - }); - - it('Shows next page disabled', () => { - expect(findPagination().find('[aria-disabled]').text()).toBe('Next'); - }); }); describe('When only one page', () => { diff --git a/spec/frontend/runner/components/runner_pause_button_spec.js b/spec/frontend/runner/components/runner_pause_button_spec.js index 278f3dec2ee..3d9df03977e 100644 --- a/spec/frontend/runner/components/runner_pause_button_spec.js +++ b/spec/frontend/runner/components/runner_pause_button_spec.js @@ -4,10 +4,16 @@ 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 runnerToggleActiveMutation from '~/runner/graphql/runner_toggle_active.mutation.graphql'; +import runnerToggleActiveMutation from '~/runner/graphql/shared/runner_toggle_active.mutation.graphql'; import waitForPromises from 'helpers/wait_for_promises'; import { captureException } from '~/runner/sentry_utils'; import { createAlert } from '~/flash'; +import { + I18N_PAUSE, + I18N_PAUSE_TOOLTIP, + I18N_RESUME, + I18N_RESUME_TOOLTIP, +} from '~/runner/constants'; import RunnerPauseButton from '~/runner/components/runner_pause_button.vue'; import { runnersData } from '../mock_data'; @@ -74,10 +80,10 @@ describe('RunnerPauseButton', () => { describe('Pause/Resume action', () => { describe.each` - runnerState | icon | content | isActive | newActiveValue - ${'paused'} | ${'play'} | ${'Resume'} | ${false} | ${true} - ${'active'} | ${'pause'} | ${'Pause'} | ${true} | ${false} - `('When the runner is $runnerState', ({ icon, content, isActive, newActiveValue }) => { + runnerState | icon | content | tooltip | isActive | newActiveValue + ${'paused'} | ${'play'} | ${I18N_RESUME} | ${I18N_RESUME_TOOLTIP} | ${false} | ${true} + ${'active'} | ${'pause'} | ${I18N_PAUSE} | ${I18N_PAUSE_TOOLTIP} | ${true} | ${false} + `('When the runner is $runnerState', ({ icon, content, tooltip, isActive, newActiveValue }) => { beforeEach(() => { createComponent({ props: { @@ -91,7 +97,11 @@ describe('RunnerPauseButton', () => { it(`Displays a ${icon} button`, () => { expect(findBtn().props('loading')).toBe(false); expect(findBtn().props('icon')).toBe(icon); + }); + + it('Displays button content', () => { expect(findBtn().text()).toBe(content); + expect(getTooltip()).toBe(tooltip); }); it('Does not display redundant text for screen readers', () => { @@ -218,8 +228,8 @@ describe('RunnerPauseButton', () => { }); it('Display correctly for screen readers', () => { - expect(findBtn().attributes('aria-label')).toBe('Pause'); - expect(getTooltip()).toBe('Pause'); + expect(findBtn().attributes('aria-label')).toBe(I18N_PAUSE); + expect(getTooltip()).toBe(I18N_PAUSE_TOOLTIP); }); describe('Immediately after the button is clicked', () => { diff --git a/spec/frontend/runner/components/runner_projects_spec.js b/spec/frontend/runner/components/runner_projects_spec.js index 68a2130d6d9..96de8d11bca 100644 --- a/spec/frontend/runner/components/runner_projects_spec.js +++ b/spec/frontend/runner/components/runner_projects_spec.js @@ -16,7 +16,7 @@ import RunnerAssignedItem from '~/runner/components/runner_assigned_item.vue'; import RunnerPagination from '~/runner/components/runner_pagination.vue'; import { captureException } from '~/runner/sentry_utils'; -import getRunnerProjectsQuery from '~/runner/graphql/get_runner_projects.query.graphql'; +import runnerProjectsQuery from '~/runner/graphql/details/runner_projects.query.graphql'; import { runnerData, runnerProjectsData } from '../mock_data'; @@ -40,7 +40,7 @@ describe('RunnerProjects', () => { const createComponent = ({ mountFn = shallowMountExtended } = {}) => { wrapper = mountFn(RunnerProjects, { - apolloProvider: createMockApollo([[getRunnerProjectsQuery, mockRunnerProjectsQuery]]), + apolloProvider: createMockApollo([[runnerProjectsQuery, mockRunnerProjectsQuery]]), propsData: { runner: mockRunner, }, diff --git a/spec/frontend/runner/components/runner_update_form_spec.js b/spec/frontend/runner/components/runner_update_form_spec.js index 8b76be396ef..b071791e39f 100644 --- a/spec/frontend/runner/components/runner_update_form_spec.js +++ b/spec/frontend/runner/components/runner_update_form_spec.js @@ -13,7 +13,7 @@ import { ACCESS_LEVEL_REF_PROTECTED, ACCESS_LEVEL_NOT_PROTECTED, } from '~/runner/constants'; -import runnerUpdateMutation from '~/runner/graphql/runner_update.mutation.graphql'; +import runnerUpdateMutation from '~/runner/graphql/details/runner_update.mutation.graphql'; import { captureException } from '~/runner/sentry_utils'; import { runnerData } from '../mock_data'; |