diff options
Diffstat (limited to 'spec/frontend/runner/components')
8 files changed, 119 insertions, 71 deletions
diff --git a/spec/frontend/runner/components/__snapshots__/runner_status_popover_spec.js.snap b/spec/frontend/runner/components/__snapshots__/runner_status_popover_spec.js.snap index 80a04401760..b27a1adf01b 100644 --- a/spec/frontend/runner/components/__snapshots__/runner_status_popover_spec.js.snap +++ b/spec/frontend/runner/components/__snapshots__/runner_status_popover_spec.js.snap @@ -1,3 +1,3 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`RunnerStatusPopover renders complete text 1`] = `"Never contacted: Runner has never contacted GitLab (when you register a runner, use gitlab-runner run to bring it online) Online: Runner has contacted GitLab within the last 2 hours Offline: Runner has not contacted GitLab in more than 2 hours Stale: Runner has not contacted GitLab in more than 2 months"`; +exports[`RunnerStatusPopover renders complete text 1`] = `"Never contacted: Runner has never contacted GitLab (when you register a runner, use gitlab-runner run to bring it online) Online: Runner has contacted GitLab within the last 2 hours Offline: Runner has not contacted GitLab in more than 2 hours Stale: Runner has not contacted GitLab in more than 3 months"`; diff --git a/spec/frontend/runner/components/cells/runner_status_cell_spec.js b/spec/frontend/runner/components/cells/runner_status_cell_spec.js index 20a1cdf7236..0f5133d0ae2 100644 --- a/spec/frontend/runner/components/cells/runner_status_cell_spec.js +++ b/spec/frontend/runner/components/cells/runner_status_cell_spec.js @@ -1,12 +1,15 @@ -import { GlBadge } from '@gitlab/ui'; import { mount } from '@vue/test-utils'; import RunnerStatusCell from '~/runner/components/cells/runner_status_cell.vue'; + +import RunnerStatusBadge from '~/runner/components/runner_status_badge.vue'; +import RunnerPausedBadge from '~/runner/components/runner_paused_badge.vue'; import { INSTANCE_TYPE, STATUS_ONLINE, STATUS_OFFLINE } from '~/runner/constants'; -describe('RunnerTypeCell', () => { +describe('RunnerStatusCell', () => { let wrapper; - const findBadgeAt = (i) => wrapper.findAllComponents(GlBadge).at(i); + const findStatusBadge = () => wrapper.findComponent(RunnerStatusBadge); + const findPausedBadge = () => wrapper.findComponent(RunnerPausedBadge); const createComponent = ({ runner = {} } = {}) => { wrapper = mount(RunnerStatusCell, { @@ -29,7 +32,7 @@ describe('RunnerTypeCell', () => { createComponent(); expect(wrapper.text()).toMatchInterpolatedText('online'); - expect(findBadgeAt(0).text()).toBe('online'); + expect(findStatusBadge().text()).toBe('online'); }); it('Displays offline status', () => { @@ -40,7 +43,7 @@ describe('RunnerTypeCell', () => { }); expect(wrapper.text()).toMatchInterpolatedText('offline'); - expect(findBadgeAt(0).text()).toBe('offline'); + expect(findStatusBadge().text()).toBe('offline'); }); it('Displays paused status', () => { @@ -52,9 +55,7 @@ describe('RunnerTypeCell', () => { }); expect(wrapper.text()).toMatchInterpolatedText('online paused'); - - expect(findBadgeAt(0).text()).toBe('online'); - expect(findBadgeAt(1).text()).toBe('paused'); + expect(findPausedBadge().text()).toBe('paused'); }); it('Is empty when data is missing', () => { diff --git a/spec/frontend/runner/components/registration/registration_dropdown_spec.js b/spec/frontend/runner/components/registration/registration_dropdown_spec.js index 81c2788f084..d3f38bc1d26 100644 --- a/spec/frontend/runner/components/registration/registration_dropdown_spec.js +++ b/spec/frontend/runner/components/registration/registration_dropdown_spec.js @@ -1,4 +1,4 @@ -import { GlDropdown, GlDropdownItem, GlDropdownForm } from '@gitlab/ui'; +import { GlModal, GlDropdown, GlDropdownItem, GlDropdownForm } from '@gitlab/ui'; import { mount, shallowMount, createWrapper } from '@vue/test-utils'; import Vue, { nextTick } from 'vue'; @@ -24,6 +24,8 @@ import { const mockToken = '0123456789'; const maskToken = '**********'; +Vue.use(VueApollo); + describe('RegistrationDropdown', () => { let wrapper; @@ -32,9 +34,11 @@ describe('RegistrationDropdown', () => { const findRegistrationInstructionsDropdownItem = () => wrapper.findComponent(GlDropdownItem); const findTokenDropdownItem = () => wrapper.findComponent(GlDropdownForm); const findRegistrationToken = () => wrapper.findComponent(RegistrationToken); - const findRegistrationTokenInput = () => wrapper.findByTestId('token-value').find('input'); + const findRegistrationTokenInput = () => + wrapper.findByLabelText(RegistrationToken.i18n.registrationToken); const findTokenResetDropdownItem = () => wrapper.findComponent(RegistrationTokenResetDropdownItem); + const findModal = () => wrapper.findComponent(GlModal); const findModalContent = () => createWrapper(document.body) .find('[data-testid="runner-instructions-modal"]') @@ -43,6 +47,8 @@ describe('RegistrationDropdown', () => { const openModal = async () => { await findRegistrationInstructionsDropdownItem().trigger('click'); + findModal().vm.$emit('shown'); + await waitForPromises(); }; @@ -60,8 +66,6 @@ describe('RegistrationDropdown', () => { }; const createComponentWithModal = () => { - Vue.use(VueApollo); - const requestHandlers = [ [getRunnerPlatformsQuery, jest.fn().mockResolvedValue(mockGraphqlRunnerPlatforms)], [getRunnerSetupInstructionsQuery, jest.fn().mockResolvedValue(mockGraphqlInstructions)], @@ -169,10 +173,10 @@ describe('RegistrationDropdown', () => { await nextTick(); }; - it('Updates token in input', async () => { + it('Updates token input', async () => { createComponent({}, mount); - expect(findRegistrationTokenInput().props('value')).not.toBe(newToken); + expect(findRegistrationToken().props('value')).not.toBe(newToken); await resetToken(); diff --git a/spec/frontend/runner/components/registration/registration_token_spec.js b/spec/frontend/runner/components/registration/registration_token_spec.js index cb42c7c8493..ed1a698d36f 100644 --- a/spec/frontend/runner/components/registration/registration_token_spec.js +++ b/spec/frontend/runner/components/registration/registration_token_spec.js @@ -29,6 +29,7 @@ describe('RegistrationToken', () => { wrapper = mountFn(RegistrationToken, { propsData: { value: mockToken, + inputId: 'token-value', ...props, }, localVue, diff --git a/spec/frontend/runner/components/runner_details_spec.js b/spec/frontend/runner/components/runner_details_spec.js index 162d21febfd..9e0f7014750 100644 --- a/spec/frontend/runner/components/runner_details_spec.js +++ b/spec/frontend/runner/components/runner_details_spec.js @@ -1,14 +1,13 @@ -import { GlSprintf, GlIntersperse, GlTab } from '@gitlab/ui'; -import { createWrapper, ErrorWrapper } from '@vue/test-utils'; +import { GlSprintf, GlIntersperse } from '@gitlab/ui'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue'; import { useFakeDate } from 'helpers/fake_date'; +import { findDd } from 'helpers/dl_locator_helper'; import { ACCESS_LEVEL_REF_PROTECTED, ACCESS_LEVEL_NOT_PROTECTED } from '~/runner/constants'; import RunnerDetails from '~/runner/components/runner_details.vue'; import RunnerDetail from '~/runner/components/runner_detail.vue'; import RunnerGroups from '~/runner/components/runner_groups.vue'; -import RunnersJobs from '~/runner/components/runner_jobs.vue'; import RunnerTags from '~/runner/components/runner_tags.vue'; import RunnerTag from '~/runner/components/runner_tag.vue'; @@ -24,25 +23,14 @@ describe('RunnerDetails', () => { useFakeDate(mockNow); - /** - * Find the definition (<dd>) that corresponds to this term (<dt>) - * @param {string} dtLabel - Label for this value - * @returns Wrapper - */ - const findDd = (dtLabel) => { - const dt = wrapper.findByText(dtLabel).element; - const dd = dt.nextElementSibling; - if (dt.tagName === 'DT' && dd.tagName === 'DD') { - return createWrapper(dd, {}); - } - return ErrorWrapper(dtLabel); - }; - const findDetailGroups = () => wrapper.findComponent(RunnerGroups); - const findRunnersJobs = () => wrapper.findComponent(RunnersJobs); - const findJobCountBadge = () => wrapper.findByTestId('job-count-badge'); - const createComponent = ({ props = {}, mountFn = shallowMountExtended, stubs } = {}) => { + const createComponent = ({ + props = {}, + stubs, + mountFn = shallowMountExtended, + ...options + } = {}) => { wrapper = mountFn(RunnerDetails, { propsData: { ...props, @@ -51,6 +39,7 @@ describe('RunnerDetails', () => { RunnerDetail, ...stubs, }, + ...options, }); }; @@ -108,7 +97,7 @@ describe('RunnerDetails', () => { }); it(`displays expected value "${expectedValue}"`, () => { - expect(findDd(field).text()).toBe(expectedValue); + expect(findDd(field, wrapper).text()).toBe(expectedValue); }); }); @@ -123,7 +112,7 @@ describe('RunnerDetails', () => { stubs, }); - expect(findDd('Tags').text().replace(/\s+/g, ' ')).toBe('tag-1 tag-2'); + expect(findDd('Tags', wrapper).text().replace(/\s+/g, ' ')).toBe('tag-1 tag-2'); }); it('displays "None" when runner has no tags', () => { @@ -134,7 +123,7 @@ describe('RunnerDetails', () => { stubs, }); - expect(findDd('Tags').text().replace(/\s+/g, ' ')).toBe('None'); + expect(findDd('Tags', wrapper).text().replace(/\s+/g, ' ')).toBe('None'); }); }); @@ -153,40 +142,17 @@ describe('RunnerDetails', () => { }); }); - describe('Jobs tab', () => { - const stubs = { GlTab }; - - it('without a runner, shows no jobs', () => { - createComponent({ - props: { runner: null }, - stubs, - }); - - expect(findJobCountBadge().exists()).toBe(false); - expect(findRunnersJobs().exists()).toBe(false); - }); + describe('Jobs tab slot', () => { + it('shows job tab slot', () => { + const JOBS_TAB = '<div>Jobs Tab</div>'; - it('without a job count, shows no jobs count', () => { createComponent({ - props: { - runner: { ...mockRunner, jobCount: undefined }, + slots: { + 'jobs-tab': JOBS_TAB, }, - stubs, - }); - - expect(findJobCountBadge().exists()).toBe(false); - }); - - it('with a job count, shows jobs count', () => { - const runner = { ...mockRunner, jobCount: 3 }; - - createComponent({ - props: { runner }, - stubs, }); - expect(findJobCountBadge().text()).toBe('3'); - expect(findRunnersJobs().props('runner')).toBe(runner); + expect(wrapper.html()).toContain(JOBS_TAB); }); }); }); diff --git a/spec/frontend/runner/components/runner_jobs_spec.js b/spec/frontend/runner/components/runner_jobs_spec.js index 8ac5685a0dd..20582aaaf40 100644 --- a/spec/frontend/runner/components/runner_jobs_spec.js +++ b/spec/frontend/runner/components/runner_jobs_spec.js @@ -1,4 +1,4 @@ -import { GlDeprecatedSkeletonLoading as GlSkeletonLoading } from '@gitlab/ui'; +import { GlSkeletonLoader } from '@gitlab/ui'; import Vue from 'vue'; import VueApollo from 'vue-apollo'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; @@ -28,7 +28,7 @@ describe('RunnerJobs', () => { let wrapper; let mockRunnerJobsQuery; - const findGlSkeletonLoading = () => wrapper.findComponent(GlSkeletonLoading); + const findGlSkeletonLoading = () => wrapper.findComponent(GlSkeletonLoader); const findRunnerJobsTable = () => wrapper.findComponent(RunnerJobsTable); const findRunnerPagination = () => wrapper.findComponent(RunnerPagination); diff --git a/spec/frontend/runner/components/runner_list_empty_state_spec.js b/spec/frontend/runner/components/runner_list_empty_state_spec.js new file mode 100644 index 00000000000..59cff863106 --- /dev/null +++ b/spec/frontend/runner/components/runner_list_empty_state_spec.js @@ -0,0 +1,76 @@ +import { GlEmptyState, GlLink, GlSprintf } from '@gitlab/ui'; +import { s__ } from '~/locale'; +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import { createMockDirective, getBinding } from 'helpers/vue_mock_directive'; +import RunnerInstructionsModal from '~/vue_shared/components/runner_instructions/runner_instructions_modal.vue'; + +import RunnerListEmptyState from '~/runner/components/runner_list_empty_state.vue'; + +const mockSvgPath = 'mock-svg-path.svg'; +const mockFilteredSvgPath = 'mock-filtered-svg-path.svg'; + +describe('RunnerListEmptyState', () => { + let wrapper; + + const findEmptyState = () => wrapper.findComponent(GlEmptyState); + const findLink = () => wrapper.findComponent(GlLink); + const findRunnerInstructionsModal = () => wrapper.findComponent(RunnerInstructionsModal); + + const createComponent = ({ props, mountFn = shallowMountExtended } = {}) => { + wrapper = mountFn(RunnerListEmptyState, { + propsData: { + svgPath: mockSvgPath, + filteredSvgPath: mockFilteredSvgPath, + ...props, + }, + directives: { + GlModal: createMockDirective(), + }, + stubs: { + GlEmptyState, + GlSprintf, + GlLink, + }, + }); + }; + + describe('when search is not filtered', () => { + beforeEach(() => { + createComponent(); + }); + + it('renders an illustration', () => { + expect(findEmptyState().props('svgPath')).toBe(mockSvgPath); + }); + + it('displays "no results" text', () => { + const title = s__('Runners|Get started with runners'); + const desc = s__( + 'Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner.', + ); + + expect(findEmptyState().text()).toMatchInterpolatedText(`${title} ${desc}`); + }); + + it('opens a runner registration instructions modal with a link', () => { + const { value } = getBinding(findLink().element, 'gl-modal'); + + expect(findRunnerInstructionsModal().props('modalId')).toEqual(value); + }); + }); + + describe('when search is filtered', () => { + beforeEach(() => { + createComponent({ props: { isSearchFiltered: true } }); + }); + + it('renders a "filtered search" illustration', () => { + expect(findEmptyState().props('svgPath')).toBe(mockFilteredSvgPath); + }); + + it('displays "no filtered results" text', () => { + expect(findEmptyState().text()).toContain(s__('Runners|No results found')); + expect(findEmptyState().text()).toContain(s__('Runners|Edit your search and try again')); + }); + }); +}); diff --git a/spec/frontend/runner/components/runner_projects_spec.js b/spec/frontend/runner/components/runner_projects_spec.js index 04627e2307b..6932b3b5197 100644 --- a/spec/frontend/runner/components/runner_projects_spec.js +++ b/spec/frontend/runner/components/runner_projects_spec.js @@ -1,4 +1,4 @@ -import { GlDeprecatedSkeletonLoading as GlSkeletonLoading } from '@gitlab/ui'; +import { GlSkeletonLoader } from '@gitlab/ui'; import Vue from 'vue'; import VueApollo from 'vue-apollo'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; @@ -34,7 +34,7 @@ describe('RunnerProjects', () => { let mockRunnerProjectsQuery; const findHeading = () => wrapper.find('h3'); - const findGlSkeletonLoading = () => wrapper.findComponent(GlSkeletonLoading); + const findGlSkeletonLoading = () => wrapper.findComponent(GlSkeletonLoader); const findRunnerAssignedItems = () => wrapper.findAllComponents(RunnerAssignedItem); const findRunnerPagination = () => wrapper.findComponent(RunnerPagination); |