diff options
Diffstat (limited to 'spec/frontend/runner/components')
6 files changed, 100 insertions, 63 deletions
diff --git a/spec/frontend/runner/components/registration/registration_dropdown_spec.js b/spec/frontend/runner/components/registration/registration_dropdown_spec.js index 5cd93df9967..81c2788f084 100644 --- a/spec/frontend/runner/components/registration/registration_dropdown_spec.js +++ b/spec/frontend/runner/components/registration/registration_dropdown_spec.js @@ -35,6 +35,16 @@ describe('RegistrationDropdown', () => { const findRegistrationTokenInput = () => wrapper.findByTestId('token-value').find('input'); const findTokenResetDropdownItem = () => wrapper.findComponent(RegistrationTokenResetDropdownItem); + const findModalContent = () => + createWrapper(document.body) + .find('[data-testid="runner-instructions-modal"]') + .text() + .replace(/[\n\t\s]+/g, ' '); + + const openModal = async () => { + await findRegistrationInstructionsDropdownItem().trigger('click'); + await waitForPromises(); + }; const createComponent = ({ props = {}, ...options } = {}, mountFn = shallowMount) => { wrapper = extendedWrapper( @@ -49,6 +59,25 @@ describe('RegistrationDropdown', () => { ); }; + const createComponentWithModal = () => { + Vue.use(VueApollo); + + const requestHandlers = [ + [getRunnerPlatformsQuery, jest.fn().mockResolvedValue(mockGraphqlRunnerPlatforms)], + [getRunnerSetupInstructionsQuery, jest.fn().mockResolvedValue(mockGraphqlInstructions)], + ]; + + createComponent( + { + // Mock load modal contents from API + apolloProvider: createMockApollo(requestHandlers), + // Use `attachTo` to find the modal + attachTo: document.body, + }, + mount, + ); + }; + it.each` type | text ${INSTANCE_TYPE} | ${'Register an instance runner'} @@ -76,29 +105,10 @@ describe('RegistrationDropdown', () => { }); describe('When the dropdown item is clicked', () => { - Vue.use(VueApollo); - - const requestHandlers = [ - [getRunnerPlatformsQuery, jest.fn().mockResolvedValue(mockGraphqlRunnerPlatforms)], - [getRunnerSetupInstructionsQuery, jest.fn().mockResolvedValue(mockGraphqlInstructions)], - ]; - - const findModalInBody = () => - createWrapper(document.body).find('[data-testid="runner-instructions-modal"]'); - beforeEach(async () => { - createComponent( - { - // Mock load modal contents from API - apolloProvider: createMockApollo(requestHandlers), - // Use `attachTo` to find the modal - attachTo: document.body, - }, - mount, - ); - - await findRegistrationInstructionsDropdownItem().trigger('click'); - await waitForPromises(); + createComponentWithModal({}, mount); + + await openModal(); }); afterEach(() => { @@ -106,9 +116,7 @@ describe('RegistrationDropdown', () => { }); it('opens the modal with contents', () => { - const modalText = findModalInBody() - .text() - .replace(/[\n\t\s]+/g, ' '); + const modalText = findModalContent(); expect(modalText).toContain('Install a runner'); @@ -153,15 +161,34 @@ describe('RegistrationDropdown', () => { }); }); - it('Updates the token when it gets reset', async () => { + describe('When token is reset', () => { const newToken = 'mock1'; - createComponent({}, mount); - expect(findRegistrationTokenInput().props('value')).not.toBe(newToken); + const resetToken = async () => { + findTokenResetDropdownItem().vm.$emit('tokenReset', newToken); + await nextTick(); + }; + + it('Updates token in input', async () => { + createComponent({}, mount); + + expect(findRegistrationTokenInput().props('value')).not.toBe(newToken); + + await resetToken(); + + expect(findRegistrationToken().props('value')).toBe(newToken); + }); - findTokenResetDropdownItem().vm.$emit('tokenReset', newToken); - await nextTick(); + it('Updates token in modal', async () => { + createComponentWithModal({}, mount); - expect(findRegistrationToken().props('value')).toBe(newToken); + await openModal(); + + expect(findModalContent()).toContain(mockToken); + + await resetToken(); + + expect(findModalContent()).toContain(newToken); + }); }); }); diff --git a/spec/frontend/runner/components/runner_delete_button_spec.js b/spec/frontend/runner/components/runner_delete_button_spec.js index 3eb257607b4..b11c749d0a7 100644 --- a/spec/frontend/runner/components/runner_delete_button_spec.js +++ b/spec/frontend/runner/components/runner_delete_button_spec.js @@ -118,6 +118,12 @@ describe('RunnerDeleteButton', () => { 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); diff --git a/spec/frontend/runner/components/runner_details_spec.js b/spec/frontend/runner/components/runner_details_spec.js index 6bf4a52a799..162d21febfd 100644 --- a/spec/frontend/runner/components/runner_details_spec.js +++ b/spec/frontend/runner/components/runner_details_spec.js @@ -77,6 +77,9 @@ describe('RunnerDetails', () => { ${'Last contact'} | ${{ contactedAt: null }} | ${'Never contacted'} ${'Version'} | ${{ version: '12.3' }} | ${'12.3'} ${'Version'} | ${{ version: null }} | ${'None'} + ${'Executor'} | ${{ executorName: 'shell' }} | ${'shell'} + ${'Architecture'} | ${{ architectureName: 'amd64' }} | ${'amd64'} + ${'Platform'} | ${{ platformName: 'darwin' }} | ${'darwin'} ${'IP Address'} | ${{ ipAddress: '127.0.0.1' }} | ${'127.0.0.1'} ${'IP Address'} | ${{ ipAddress: null }} | ${'None'} ${'Configuration'} | ${{ accessLevel: ACCESS_LEVEL_REF_PROTECTED, runUntagged: true }} | ${'Protected, Runs untagged jobs'} diff --git a/spec/frontend/runner/components/runner_jobs_spec.js b/spec/frontend/runner/components/runner_jobs_spec.js index 9e40e911448..8ac5685a0dd 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 runnerJobsQuery from '~/runner/graphql/details/runner_jobs.query.graphql'; +import runnerJobsQuery from '~/runner/graphql/show/runner_jobs.query.graphql'; import { runnerData, runnerJobsData } from '../mock_data'; diff --git a/spec/frontend/runner/components/runner_projects_spec.js b/spec/frontend/runner/components/runner_projects_spec.js index 62ebc6539e2..04627e2307b 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 runnerProjectsQuery from '~/runner/graphql/details/runner_projects.query.graphql'; +import runnerProjectsQuery from '~/runner/graphql/show/runner_projects.query.graphql'; import { runnerData, runnerProjectsData } from '../mock_data'; diff --git a/spec/frontend/runner/components/runner_update_form_spec.js b/spec/frontend/runner/components/runner_update_form_spec.js index b071791e39f..3037364d941 100644 --- a/spec/frontend/runner/components/runner_update_form_spec.js +++ b/spec/frontend/runner/components/runner_update_form_spec.js @@ -1,10 +1,11 @@ import Vue, { nextTick } from 'vue'; -import { GlForm } from '@gitlab/ui'; +import { GlForm, GlSkeletonLoader } from '@gitlab/ui'; import VueApollo from 'vue-apollo'; import createMockApollo from 'helpers/mock_apollo_helper'; import { mountExtended } from 'helpers/vue_test_utils_helper'; import waitForPromises from 'helpers/wait_for_promises'; import { createAlert, VARIANT_SUCCESS } from '~/flash'; +import { redirectTo } from '~/lib/utils/url_utility'; import RunnerUpdateForm from '~/runner/components/runner_update_form.vue'; import { INSTANCE_TYPE, @@ -13,14 +14,18 @@ import { ACCESS_LEVEL_REF_PROTECTED, ACCESS_LEVEL_NOT_PROTECTED, } from '~/runner/constants'; -import runnerUpdateMutation from '~/runner/graphql/details/runner_update.mutation.graphql'; +import runnerUpdateMutation from '~/runner/graphql/edit/runner_update.mutation.graphql'; import { captureException } from '~/runner/sentry_utils'; -import { runnerData } from '../mock_data'; +import { saveAlertToLocalStorage } from '~/runner/local_storage_alert/save_alert_to_local_storage'; +import { runnerFormData } from '../mock_data'; +jest.mock('~/runner/local_storage_alert/save_alert_to_local_storage'); jest.mock('~/flash'); jest.mock('~/runner/sentry_utils'); +jest.mock('~/lib/utils/url_utility'); -const mockRunner = runnerData.data.runner; +const mockRunner = runnerFormData.data.runner; +const mockRunnerPath = '/admin/runners/1'; Vue.use(VueApollo); @@ -33,8 +38,7 @@ describe('RunnerUpdateForm', () => { const findProtectedCheckbox = () => wrapper.findByTestId('runner-field-protected'); const findRunUntaggedCheckbox = () => wrapper.findByTestId('runner-field-run-untagged'); const findLockedCheckbox = () => wrapper.findByTestId('runner-field-locked'); - - const findIpInput = () => wrapper.findByTestId('runner-field-ip-address').find('input'); + const findFields = () => wrapper.findAll('[data-testid^="runner-field"'); const findDescriptionInput = () => wrapper.findByTestId('runner-field-description').find('input'); const findMaxJobTimeoutInput = () => @@ -53,7 +57,6 @@ describe('RunnerUpdateForm', () => { : ACCESS_LEVEL_NOT_PROTECTED, runUntagged: findRunUntaggedCheckbox().element.checked, locked: findLockedCheckbox().element?.checked || false, - ipAddress: findIpInput().element.value, maximumTimeout: findMaxJobTimeoutInput().element.value || null, tagList: findTagsInput().element.value.split(',').filter(Boolean), }); @@ -62,6 +65,7 @@ describe('RunnerUpdateForm', () => { wrapper = mountExtended(RunnerUpdateForm, { propsData: { runner: mockRunner, + runnerPath: mockRunnerPath, ...props, }, apolloProvider: createMockApollo([[runnerUpdateMutation, runnerUpdateHandler]]), @@ -74,12 +78,13 @@ describe('RunnerUpdateForm', () => { input: expect.objectContaining(submittedRunner), }); - expect(createAlert).toHaveBeenLastCalledWith({ - message: expect.stringContaining('saved'), - variant: VARIANT_SUCCESS, - }); - - expect(findSubmitDisabledAttr()).toBeUndefined(); + expect(saveAlertToLocalStorage).toHaveBeenCalledWith( + expect.objectContaining({ + message: expect.any(String), + variant: VARIANT_SUCCESS, + }), + ); + expect(redirectTo).toHaveBeenCalledWith(mockRunnerPath); }; beforeEach(() => { @@ -122,27 +127,19 @@ describe('RunnerUpdateForm', () => { await submitFormAndWait(); // Some read-only fields are not submitted - const { - __typename, - ipAddress, - runnerType, - createdAt, - status, - editAdminUrl, - contactedAt, - userPermissions, - version, - groups, - jobCount, - ...submitted - } = mockRunner; + const { __typename, shortSha, runnerType, createdAt, status, ...submitted } = mockRunner; expectToHaveSubmittedRunnerContaining(submitted); }); describe('When data is being loaded', () => { beforeEach(() => { - createComponent({ props: { runner: null } }); + createComponent({ props: { loading: true } }); + }); + + it('Form skeleton is shown', () => { + expect(wrapper.find(GlSkeletonLoader).exists()).toBe(true); + expect(findFields()).toHaveLength(0); }); it('Form cannot be submitted', () => { @@ -151,11 +148,12 @@ describe('RunnerUpdateForm', () => { it('Form is updated when data loads', async () => { wrapper.setProps({ - runner: mockRunner, + loading: false, }); await nextTick(); + expect(findFields()).not.toHaveLength(0); expect(mockRunner).toMatchObject(getFieldsModel()); }); }); @@ -273,8 +271,11 @@ describe('RunnerUpdateForm', () => { expect(createAlert).toHaveBeenLastCalledWith({ message: mockErrorMsg, }); - expect(captureException).not.toHaveBeenCalled(); expect(findSubmitDisabledAttr()).toBeUndefined(); + + expect(captureException).not.toHaveBeenCalled(); + expect(saveAlertToLocalStorage).not.toHaveBeenCalled(); + expect(redirectTo).not.toHaveBeenCalled(); }); }); }); |