diff options
Diffstat (limited to 'spec/frontend/jobs')
-rw-r--r-- | spec/frontend/jobs/components/commit_block_spec.js | 105 | ||||
-rw-r--r-- | spec/frontend/jobs/components/job_sidebar_details_container_spec.js | 15 | ||||
-rw-r--r-- | spec/frontend/jobs/components/manual_variables_form_spec.js | 153 | ||||
-rw-r--r-- | spec/frontend/jobs/components/sidebar_spec.js | 30 | ||||
-rw-r--r-- | spec/frontend/jobs/components/stages_dropdown_spec.js | 155 | ||||
-rw-r--r-- | spec/frontend/jobs/components/table/jobs_table_spec.js | 31 | ||||
-rw-r--r-- | spec/frontend/jobs/components/table/jobs_table_tabs_spec.js | 42 | ||||
-rw-r--r-- | spec/frontend/jobs/mock_data.js | 215 |
8 files changed, 524 insertions, 222 deletions
diff --git a/spec/frontend/jobs/components/commit_block_spec.js b/spec/frontend/jobs/components/commit_block_spec.js index 13261317b48..8a6d48cecb8 100644 --- a/spec/frontend/jobs/components/commit_block_spec.js +++ b/spec/frontend/jobs/components/commit_block_spec.js @@ -1,89 +1,70 @@ -import Vue from 'vue'; -import mountComponent from 'helpers/vue_mount_component_helper'; -import component from '~/jobs/components/commit_block.vue'; +import { shallowMount } from '@vue/test-utils'; +import { extendedWrapper } from 'helpers/vue_test_utils_helper'; +import CommitBlock from '~/jobs/components/commit_block.vue'; +import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; describe('Commit block', () => { - const Component = Vue.extend(component); - let vm; + let wrapper; - const props = { - commit: { - short_id: '1f0fb84f', - id: '1f0fb84fb6770d74d97eee58118fd3909cd4f48c', - commit_path: 'commit/1f0fb84fb6770d74d97eee58118fd3909cd4f48c', - title: 'Update README.md', - }, - mergeRequest: { - iid: '!21244', - path: 'merge_requests/21244', - }, - isLastBlock: true, + const commit = { + short_id: '1f0fb84f', + id: '1f0fb84fb6770d74d97eee58118fd3909cd4f48c', + commit_path: 'commit/1f0fb84fb6770d74d97eee58118fd3909cd4f48c', + title: 'Update README.md', + }; + + const mergeRequest = { + iid: '!21244', + path: 'merge_requests/21244', + }; + + const findCommitSha = () => wrapper.findByTestId('commit-sha'); + const findLinkSha = () => wrapper.findByTestId('link-commit'); + + const mountComponent = (props) => { + wrapper = extendedWrapper( + shallowMount(CommitBlock, { + propsData: { + commit, + ...props, + }, + }), + ); }; afterEach(() => { - vm.$destroy(); + wrapper.destroy(); }); - describe('pipeline short sha', () => { + describe('without merge request', () => { beforeEach(() => { - vm = mountComponent(Component, { - ...props, - }); + mountComponent(); }); it('renders pipeline short sha link', () => { - expect(vm.$el.querySelector('.js-commit-sha').getAttribute('href')).toEqual( - props.commit.commit_path, - ); - - expect(vm.$el.querySelector('.js-commit-sha').textContent.trim()).toEqual( - props.commit.short_id, - ); + expect(findCommitSha().attributes('href')).toBe(commit.commit_path); + expect(findCommitSha().text()).toBe(commit.short_id); }); it('renders clipboard button', () => { - expect(vm.$el.querySelector('button').getAttribute('data-clipboard-text')).toEqual( - props.commit.id, - ); + expect(wrapper.findComponent(ClipboardButton).attributes('text')).toBe(commit.id); }); - }); - - describe('with merge request', () => { - it('renders merge request link and reference', () => { - vm = mountComponent(Component, { - ...props, - }); - - expect(vm.$el.querySelector('.js-link-commit').getAttribute('href')).toEqual( - props.mergeRequest.path, - ); - expect(vm.$el.querySelector('.js-link-commit').textContent.trim()).toEqual( - `!${props.mergeRequest.iid}`, - ); + it('renders git commit title', () => { + expect(wrapper.text()).toContain(commit.title); }); - }); - describe('without merge request', () => { it('does not render merge request', () => { - const copyProps = { ...props }; - delete copyProps.mergeRequest; - - vm = mountComponent(Component, { - ...copyProps, - }); - - expect(vm.$el.querySelector('.js-link-commit')).toBeNull(); + expect(findLinkSha().exists()).toBe(false); }); }); - describe('git commit title', () => { - it('renders git commit title', () => { - vm = mountComponent(Component, { - ...props, - }); + describe('with merge request', () => { + it('renders merge request link and reference', () => { + mountComponent({ mergeRequest }); - expect(vm.$el.textContent).toContain(props.commit.title); + expect(findLinkSha().attributes('href')).toBe(mergeRequest.path); + expect(findLinkSha().text()).toBe(`!${mergeRequest.iid}`); }); }); }); diff --git a/spec/frontend/jobs/components/job_sidebar_details_container_spec.js b/spec/frontend/jobs/components/job_sidebar_details_container_spec.js index 2b56bd2d558..ad0368555fa 100644 --- a/spec/frontend/jobs/components/job_sidebar_details_container_spec.js +++ b/spec/frontend/jobs/components/job_sidebar_details_container_spec.js @@ -34,11 +34,22 @@ describe('Job Sidebar Details Container', () => { }); describe('when no details are available', () => { - it('should render an empty container', () => { + beforeEach(() => { createWrapper(); + }); + it('should render an empty container', () => { expect(wrapper.html()).toBe(''); }); + + it.each(['duration', 'erased_at', 'finished_at', 'queued', 'runner', 'coverage'])( + 'should not render %s details when missing', + async (detail) => { + await store.dispatch('receiveJobSuccess', { [detail]: undefined }); + + expect(findAllDetailsRow()).toHaveLength(0); + }, + ); }); describe('when some of the details are available', () => { @@ -49,7 +60,7 @@ describe('Job Sidebar Details Container', () => { ['erased_at', 'Erased: 3 weeks ago'], ['finished_at', 'Finished: 3 weeks ago'], ['queued', 'Queued: 9 seconds'], - ['runner', 'Runner: local ci runner (#1)'], + ['runner', 'Runner: #1 (ABCDEFGH) local ci runner'], ['coverage', 'Coverage: 20%'], ])('uses %s to render job-%s', async (detail, value) => { await store.dispatch('receiveJobSuccess', { [detail]: job[detail] }); diff --git a/spec/frontend/jobs/components/manual_variables_form_spec.js b/spec/frontend/jobs/components/manual_variables_form_spec.js index 7172a319876..376a822dde5 100644 --- a/spec/frontend/jobs/components/manual_variables_form_spec.js +++ b/spec/frontend/jobs/components/manual_variables_form_spec.js @@ -1,11 +1,16 @@ -import { GlButton } from '@gitlab/ui'; -import { shallowMount, createLocalVue } from '@vue/test-utils'; +import { createLocalVue, mount, shallowMount } from '@vue/test-utils'; +import Vue from 'vue'; +import Vuex from 'vuex'; +import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import Form from '~/jobs/components/manual_variables_form.vue'; const localVue = createLocalVue(); +Vue.use(Vuex); + describe('Manual Variables Form', () => { let wrapper; + let store; const requiredProps = { action: { @@ -16,88 +21,104 @@ describe('Manual Variables Form', () => { variablesSettingsUrl: '/settings', }; - const factory = (props = {}) => { - wrapper = shallowMount(localVue.extend(Form), { - propsData: props, - localVue, + const createComponent = ({ props = {}, mountFn = shallowMount } = {}) => { + store = new Vuex.Store({ + actions: { + triggerManualJob: jest.fn(), + }, }); + + wrapper = extendedWrapper( + mountFn(localVue.extend(Form), { + propsData: { ...requiredProps, ...props }, + localVue, + store, + }), + ); }; - beforeEach(() => { - factory(requiredProps); - }); + const findInputKey = () => wrapper.findComponent({ ref: 'inputKey' }); + const findInputValue = () => wrapper.findComponent({ ref: 'inputSecretValue' }); - afterEach((done) => { - // The component has a `nextTick` callback after some events so we need - // to wait for those to finish before destroying. - setImmediate(() => { - wrapper.destroy(); - wrapper = null; + const findTriggerBtn = () => wrapper.findByTestId('trigger-manual-job-btn'); + const findHelpText = () => wrapper.findByTestId('form-help-text'); + const findDeleteVarBtn = () => wrapper.findByTestId('delete-variable-btn'); + const findCiVariableKey = () => wrapper.findByTestId('ci-variable-key'); + const findCiVariableValue = () => wrapper.findByTestId('ci-variable-value'); + const findAllVariables = () => wrapper.findAllByTestId('ci-variable-row'); - done(); - }); + afterEach(() => { + wrapper.destroy(); }); - it('renders empty form with correct placeholders', () => { - expect(wrapper.find({ ref: 'inputKey' }).attributes('placeholder')).toBe('Input variable key'); - expect(wrapper.find({ ref: 'inputSecretValue' }).attributes('placeholder')).toBe( - 'Input variable value', - ); - }); + describe('shallowMount', () => { + beforeEach(() => { + createComponent(); + }); - it('renders help text with provided link', () => { - expect(wrapper.find('p').text()).toBe( - 'Specify variable values to be used in this run. The values specified in CI/CD settings will be used as default', - ); + it('renders empty form with correct placeholders', () => { + expect(findInputKey().attributes('placeholder')).toBe('Input variable key'); + expect(findInputValue().attributes('placeholder')).toBe('Input variable value'); + }); - expect(wrapper.find('a').attributes('href')).toBe(requiredProps.variablesSettingsUrl); - }); + it('renders help text with provided link', () => { + expect(findHelpText().text()).toBe( + 'Specify variable values to be used in this run. The values specified in CI/CD settings will be used as default', + ); - describe('when adding a new variable', () => { - it('creates a new variable when user types a new key and resets the form', (done) => { - wrapper.vm - .$nextTick() - .then(() => wrapper.find({ ref: 'inputKey' }).setValue('new key')) - .then(() => { - expect(wrapper.vm.variables.length).toBe(1); - expect(wrapper.vm.variables[0].key).toBe('new key'); - expect(wrapper.find({ ref: 'inputKey' }).attributes('value')).toBe(undefined); - }) - .then(done) - .catch(done.fail); + expect(wrapper.find('a').attributes('href')).toBe(requiredProps.variablesSettingsUrl); }); - it('creates a new variable when user types a new value and resets the form', (done) => { - wrapper.vm - .$nextTick() - .then(() => wrapper.find({ ref: 'inputSecretValue' }).setValue('new value')) - .then(() => { - expect(wrapper.vm.variables.length).toBe(1); - expect(wrapper.vm.variables[0].secret_value).toBe('new value'); - expect(wrapper.find({ ref: 'inputSecretValue' }).attributes('value')).toBe(undefined); - }) - .then(done) - .catch(done.fail); + describe('when adding a new variable', () => { + it('creates a new variable when user types a new key and resets the form', async () => { + await findInputKey().setValue('new key'); + + expect(findAllVariables()).toHaveLength(1); + expect(findCiVariableKey().element.value).toBe('new key'); + expect(findInputKey().attributes('value')).toBe(undefined); + }); + + it('creates a new variable when user types a new value and resets the form', async () => { + await findInputValue().setValue('new value'); + + expect(findAllVariables()).toHaveLength(1); + expect(findCiVariableValue().element.value).toBe('new value'); + expect(findInputValue().attributes('value')).toBe(undefined); + }); }); }); - describe('when deleting a variable', () => { - beforeEach((done) => { - wrapper.vm.variables = [ - { - key: 'new key', - secret_value: 'value', - id: '1', - }, - ]; - - wrapper.vm.$nextTick(done); + describe('mount', () => { + beforeEach(() => { + createComponent({ mountFn: mount }); + }); + + describe('when deleting a variable', () => { + it('removes the variable row', async () => { + await wrapper.setData({ + variables: [ + { + key: 'new key', + secret_value: 'value', + id: '1', + }, + ], + }); + + findDeleteVarBtn().trigger('click'); + + await wrapper.vm.$nextTick(); + + expect(findAllVariables()).toHaveLength(0); + }); }); - it('removes the variable row', () => { - wrapper.find(GlButton).vm.$emit('click'); + it('trigger button is disabled after trigger action', async () => { + expect(findTriggerBtn().props('disabled')).toBe(false); + + await findTriggerBtn().trigger('click'); - expect(wrapper.vm.variables.length).toBe(0); + expect(findTriggerBtn().props('disabled')).toBe(true); }); }); }); diff --git a/spec/frontend/jobs/components/sidebar_spec.js b/spec/frontend/jobs/components/sidebar_spec.js index 5a2e699137d..500a1b48950 100644 --- a/spec/frontend/jobs/components/sidebar_spec.js +++ b/spec/frontend/jobs/components/sidebar_spec.js @@ -1,5 +1,6 @@ import { shallowMount } from '@vue/test-utils'; import { extendedWrapper } from 'helpers/vue_test_utils_helper'; +import ArtifactsBlock from '~/jobs/components/artifacts_block.vue'; import JobRetryForwardDeploymentModal from '~/jobs/components/job_retry_forward_deployment_modal.vue'; import JobRetryButton from '~/jobs/components/job_sidebar_retry_button.vue'; import JobsContainer from '~/jobs/components/jobs_container.vue'; @@ -14,6 +15,7 @@ describe('Sidebar details block', () => { const forwardDeploymentFailure = 'forward_deployment_failure'; const findModal = () => wrapper.find(JobRetryForwardDeploymentModal); + const findArtifactsBlock = () => wrapper.findComponent(ArtifactsBlock); const findCancelButton = () => wrapper.findByTestId('cancel-button'); const findNewIssueButton = () => wrapper.findByTestId('job-new-issue'); const findRetryButton = () => wrapper.find(JobRetryButton); @@ -21,6 +23,9 @@ describe('Sidebar details block', () => { const createWrapper = ({ props = {} } = {}) => { store = createStore(); + + store.state.job = job; + wrapper = extendedWrapper( shallowMount(Sidebar, { ...props, @@ -164,4 +169,29 @@ describe('Sidebar details block', () => { }); }); }); + + describe('artifacts', () => { + beforeEach(() => { + createWrapper(); + }); + + it('artifacts are not shown if there are no properties other than locked', () => { + expect(findArtifactsBlock().exists()).toBe(false); + }); + + it('artifacts are shown if present', async () => { + store.state.job.artifact = { + download_path: '/root/ci-project/-/jobs/1960/artifacts/download', + browse_path: '/root/ci-project/-/jobs/1960/artifacts/browse', + keep_path: '/root/ci-project/-/jobs/1960/artifacts/keep', + expire_at: '2021-03-23T17:57:11.211Z', + expired: false, + locked: false, + }; + + await wrapper.vm.$nextTick(); + + expect(findArtifactsBlock().exists()).toBe(true); + }); + }); }); diff --git a/spec/frontend/jobs/components/stages_dropdown_spec.js b/spec/frontend/jobs/components/stages_dropdown_spec.js index 72d5d0f9d44..b75d1707a8d 100644 --- a/spec/frontend/jobs/components/stages_dropdown_spec.js +++ b/spec/frontend/jobs/components/stages_dropdown_spec.js @@ -1,163 +1,134 @@ -import Vue from 'vue'; +import { GlDropdown, GlDropdownItem } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; import { trimText } from 'helpers/text_helper'; -import mountComponent from 'helpers/vue_mount_component_helper'; -import component from '~/jobs/components/stages_dropdown.vue'; +import { extendedWrapper } from 'helpers/vue_test_utils_helper'; +import StagesDropdown from '~/jobs/components/stages_dropdown.vue'; +import CiIcon from '~/vue_shared/components/ci_icon.vue'; +import { + mockPipelineWithoutMR, + mockPipelineWithAttachedMR, + mockPipelineDetached, +} from '../mock_data'; describe('Stages Dropdown', () => { - const Component = Vue.extend(component); - let vm; - - const mockPipelineData = { - id: 28029444, - details: { - status: { - details_path: '/gitlab-org/gitlab-foss/pipelines/28029444', - group: 'success', - has_details: true, - icon: 'status_success', - label: 'passed', - text: 'passed', - tooltip: 'passed', - }, - }, - path: 'pipeline/28029444', - flags: { - merge_request_pipeline: true, - detached_merge_request_pipeline: false, - }, - merge_request: { - iid: 1234, - path: '/root/detached-merge-request-pipelines/-/merge_requests/1', - title: 'Update README.md', - source_branch: 'feature-1234', - source_branch_path: '/root/detached-merge-request-pipelines/branches/feature-1234', - target_branch: 'master', - target_branch_path: '/root/detached-merge-request-pipelines/branches/master', - }, - ref: { - name: 'test-branch', - }, + let wrapper; + + const findStatus = () => wrapper.findComponent(CiIcon); + const findSelectedStageText = () => wrapper.findComponent(GlDropdown).props('text'); + const findStageItem = (index) => wrapper.findAllComponents(GlDropdownItem).at(index); + + const findPipelineInfoText = () => wrapper.findByTestId('pipeline-info').text(); + const findPipelinePath = () => wrapper.findByTestId('pipeline-path').attributes('href'); + const findMRLinkPath = () => wrapper.findByTestId('mr-link').attributes('href'); + const findSourceBranchLinkPath = () => + wrapper.findByTestId('source-branch-link').attributes('href'); + const findTargetBranchLinkPath = () => + wrapper.findByTestId('target-branch-link').attributes('href'); + + const createComponent = (props) => { + wrapper = extendedWrapper( + shallowMount(StagesDropdown, { + propsData: { + ...props, + }, + }), + ); }; - describe('without a merge request pipeline', () => { - let pipeline; + afterEach(() => { + wrapper.destroy(); + }); + describe('without a merge request pipeline', () => { beforeEach(() => { - pipeline = JSON.parse(JSON.stringify(mockPipelineData)); - delete pipeline.merge_request; - delete pipeline.flags.merge_request_pipeline; - delete pipeline.flags.detached_merge_request_pipeline; - - vm = mountComponent(Component, { - pipeline, + createComponent({ + pipeline: mockPipelineWithoutMR, stages: [{ name: 'build' }, { name: 'test' }], selectedStage: 'deploy', }); }); - afterEach(() => { - vm.$destroy(); - }); - it('renders pipeline status', () => { - expect(vm.$el.querySelector('.js-ci-status-icon-success')).not.toBeNull(); + expect(findStatus().exists()).toBe(true); }); it('renders pipeline link', () => { - expect(vm.$el.querySelector('.js-pipeline-path').getAttribute('href')).toEqual( - 'pipeline/28029444', - ); + expect(findPipelinePath()).toBe('pipeline/28029444'); }); it('renders dropdown with stages', () => { - expect(vm.$el.querySelector('.dropdown .js-stage-item').textContent).toContain('build'); + expect(findStageItem(0).text()).toBe('build'); }); it('rendes selected stage', () => { - expect(vm.$el.querySelector('.dropdown .js-selected-stage').textContent).toContain('deploy'); + expect(findSelectedStageText()).toBe('deploy'); }); it(`renders the pipeline info text like "Pipeline #123 for source_branch"`, () => { - const expected = `Pipeline #${pipeline.id} for ${pipeline.ref.name}`; - const actual = trimText(vm.$el.querySelector('.js-pipeline-info').innerText); + const expected = `Pipeline #${mockPipelineWithoutMR.id} for ${mockPipelineWithoutMR.ref.name}`; + const actual = trimText(findPipelineInfoText()); expect(actual).toBe(expected); }); }); describe('with an "attached" merge request pipeline', () => { - let pipeline; - beforeEach(() => { - pipeline = JSON.parse(JSON.stringify(mockPipelineData)); - pipeline.flags.merge_request_pipeline = true; - pipeline.flags.detached_merge_request_pipeline = false; - - vm = mountComponent(Component, { - pipeline, + createComponent({ + pipeline: mockPipelineWithAttachedMR, stages: [], selectedStage: 'deploy', }); }); it(`renders the pipeline info text like "Pipeline #123 for !456 with source_branch into target_branch"`, () => { - const expected = `Pipeline #${pipeline.id} for !${pipeline.merge_request.iid} with ${pipeline.merge_request.source_branch} into ${pipeline.merge_request.target_branch}`; - const actual = trimText(vm.$el.querySelector('.js-pipeline-info').innerText); + const expected = `Pipeline #${mockPipelineWithAttachedMR.id} for !${mockPipelineWithAttachedMR.merge_request.iid} with ${mockPipelineWithAttachedMR.merge_request.source_branch} into ${mockPipelineWithAttachedMR.merge_request.target_branch}`; + const actual = trimText(findPipelineInfoText()); expect(actual).toBe(expected); }); it(`renders the correct merge request link`, () => { - const actual = vm.$el.querySelector('.js-mr-link').href; - - expect(actual).toContain(pipeline.merge_request.path); + expect(findMRLinkPath()).toBe(mockPipelineWithAttachedMR.merge_request.path); }); it(`renders the correct source branch link`, () => { - const actual = vm.$el.querySelector('.js-source-branch-link').href; - - expect(actual).toContain(pipeline.merge_request.source_branch_path); + expect(findSourceBranchLinkPath()).toBe( + mockPipelineWithAttachedMR.merge_request.source_branch_path, + ); }); it(`renders the correct target branch link`, () => { - const actual = vm.$el.querySelector('.js-target-branch-link').href; - - expect(actual).toContain(pipeline.merge_request.target_branch_path); + expect(findTargetBranchLinkPath()).toBe( + mockPipelineWithAttachedMR.merge_request.target_branch_path, + ); }); }); describe('with a detached merge request pipeline', () => { - let pipeline; - beforeEach(() => { - pipeline = JSON.parse(JSON.stringify(mockPipelineData)); - pipeline.flags.merge_request_pipeline = false; - pipeline.flags.detached_merge_request_pipeline = true; - - vm = mountComponent(Component, { - pipeline, + createComponent({ + pipeline: mockPipelineDetached, stages: [], selectedStage: 'deploy', }); }); it(`renders the pipeline info like "Pipeline #123 for !456 with source_branch"`, () => { - const expected = `Pipeline #${pipeline.id} for !${pipeline.merge_request.iid} with ${pipeline.merge_request.source_branch}`; - const actual = trimText(vm.$el.querySelector('.js-pipeline-info').innerText); + const expected = `Pipeline #${mockPipelineDetached.id} for !${mockPipelineDetached.merge_request.iid} with ${mockPipelineDetached.merge_request.source_branch}`; + const actual = trimText(findPipelineInfoText()); expect(actual).toBe(expected); }); it(`renders the correct merge request link`, () => { - const actual = vm.$el.querySelector('.js-mr-link').href; - - expect(actual).toContain(pipeline.merge_request.path); + expect(findMRLinkPath()).toBe(mockPipelineDetached.merge_request.path); }); it(`renders the correct source branch link`, () => { - const actual = vm.$el.querySelector('.js-source-branch-link').href; - - expect(actual).toContain(pipeline.merge_request.source_branch_path); + expect(findSourceBranchLinkPath()).toBe( + mockPipelineDetached.merge_request.source_branch_path, + ); }); }); }); diff --git a/spec/frontend/jobs/components/table/jobs_table_spec.js b/spec/frontend/jobs/components/table/jobs_table_spec.js new file mode 100644 index 00000000000..db057efbfb4 --- /dev/null +++ b/spec/frontend/jobs/components/table/jobs_table_spec.js @@ -0,0 +1,31 @@ +import { GlTable } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; +import JobsTable from '~/jobs/components/table/jobs_table.vue'; +import { mockJobsInTable } from '../../mock_data'; + +describe('Jobs Table', () => { + let wrapper; + + const findTable = () => wrapper.findComponent(GlTable); + + const createComponent = (props = {}) => { + wrapper = shallowMount(JobsTable, { + propsData: { + jobs: mockJobsInTable, + ...props, + }, + }); + }; + + beforeEach(() => { + createComponent(); + }); + + afterEach(() => { + wrapper.destroy(); + }); + + it('displays a table', () => { + expect(findTable().exists()).toBe(true); + }); +}); diff --git a/spec/frontend/jobs/components/table/jobs_table_tabs_spec.js b/spec/frontend/jobs/components/table/jobs_table_tabs_spec.js new file mode 100644 index 00000000000..ac9b45be932 --- /dev/null +++ b/spec/frontend/jobs/components/table/jobs_table_tabs_spec.js @@ -0,0 +1,42 @@ +import { mount } from '@vue/test-utils'; +import { trimText } from 'helpers/text_helper'; +import { extendedWrapper } from 'helpers/vue_test_utils_helper'; +import JobsTableTabs from '~/jobs/components/table/jobs_table_tabs.vue'; + +describe('Jobs Table Tabs', () => { + let wrapper; + + const defaultProps = { + jobCounts: { all: 848, pending: 0, running: 0, finished: 704 }, + }; + + const findTab = (testId) => wrapper.findByTestId(testId); + + const createComponent = () => { + wrapper = extendedWrapper( + mount(JobsTableTabs, { + provide: { + ...defaultProps, + }, + }), + ); + }; + + beforeEach(() => { + createComponent(); + }); + + afterEach(() => { + wrapper.destroy(); + }); + + it.each` + tabId | text | count + ${'jobs-all-tab'} | ${'All'} | ${defaultProps.jobCounts.all} + ${'jobs-pending-tab'} | ${'Pending'} | ${defaultProps.jobCounts.pending} + ${'jobs-running-tab'} | ${'Running'} | ${defaultProps.jobCounts.running} + ${'jobs-finished-tab'} | ${'Finished'} | ${defaultProps.jobCounts.finished} + `('displays the right tab text and badge count', ({ tabId, text, count }) => { + expect(trimText(findTab(tabId).text())).toBe(`${text} ${count}`); + }); +}); diff --git a/spec/frontend/jobs/mock_data.js b/spec/frontend/jobs/mock_data.js index 3d40e94d219..1432c6d7e9b 100644 --- a/spec/frontend/jobs/mock_data.js +++ b/spec/frontend/jobs/mock_data.js @@ -911,6 +911,9 @@ export const stages = [ export default { id: 4757, + artifact: { + locked: false, + }, name: 'test', build_path: '/root/ci-mock/-/jobs/4757', retry_path: '/root/ci-mock/-/jobs/4757/retry', @@ -955,6 +958,7 @@ export default { artifacts: [null], runner: { id: 1, + short_sha: 'ABCDEFGH', description: 'local ci runner', edit_path: '/root/ci-mock/runners/1/edit', }, @@ -1189,3 +1193,214 @@ export const jobsInStage = { path: '/gitlab-org/gitlab-shell/pipelines/27#build', dropdown_path: '/gitlab-org/gitlab-shell/pipelines/27/stage.json?stage=build', }; + +export const mockPipelineWithoutMR = { + id: 28029444, + details: { + status: { + details_path: '/gitlab-org/gitlab-foss/pipelines/28029444', + group: 'success', + has_details: true, + icon: 'status_success', + label: 'passed', + text: 'passed', + tooltip: 'passed', + }, + }, + path: 'pipeline/28029444', + ref: { + name: 'test-branch', + }, +}; + +export const mockPipelineWithAttachedMR = { + id: 28029444, + details: { + status: { + details_path: '/gitlab-org/gitlab-foss/pipelines/28029444', + group: 'success', + has_details: true, + icon: 'status_success', + label: 'passed', + text: 'passed', + tooltip: 'passed', + }, + }, + path: 'pipeline/28029444', + flags: { + merge_request_pipeline: true, + detached_merge_request_pipeline: false, + }, + merge_request: { + iid: 1234, + path: '/root/detached-merge-request-pipelines/-/merge_requests/1', + title: 'Update README.md', + source_branch: 'feature-1234', + source_branch_path: '/root/detached-merge-request-pipelines/branches/feature-1234', + target_branch: 'master', + target_branch_path: '/root/detached-merge-request-pipelines/branches/master', + }, + ref: { + name: 'test-branch', + }, +}; + +export const mockPipelineDetached = { + id: 28029444, + details: { + status: { + details_path: '/gitlab-org/gitlab-foss/pipelines/28029444', + group: 'success', + has_details: true, + icon: 'status_success', + label: 'passed', + text: 'passed', + tooltip: 'passed', + }, + }, + path: 'pipeline/28029444', + flags: { + merge_request_pipeline: false, + detached_merge_request_pipeline: true, + }, + merge_request: { + iid: 1234, + path: '/root/detached-merge-request-pipelines/-/merge_requests/1', + title: 'Update README.md', + source_branch: 'feature-1234', + source_branch_path: '/root/detached-merge-request-pipelines/branches/feature-1234', + target_branch: 'master', + target_branch_path: '/root/detached-merge-request-pipelines/branches/master', + }, + ref: { + name: 'test-branch', + }, +}; + +export const mockJobsInTable = [ + { + detailedStatus: { + icon: 'status_manual', + label: 'manual play action', + text: 'manual', + tooltip: 'manual action', + action: { + buttonTitle: 'Trigger this manual action', + icon: 'play', + method: 'post', + path: '/root/ci-project/-/jobs/2004/play', + title: 'Play', + __typename: 'StatusAction', + }, + __typename: 'DetailedStatus', + }, + id: 'gid://gitlab/Ci::Build/2004', + refName: 'master', + refPath: '/root/ci-project/-/commits/master', + tags: [], + shortSha: '2d5d8323', + commitPath: '/root/ci-project/-/commit/2d5d83230bdea0e003d83ef4c16d2bf9a8808ebe', + pipeline: { + id: 'gid://gitlab/Ci::Pipeline/423', + path: '/root/ci-project/-/pipelines/423', + user: { + webPath: '/root', + avatarUrl: + 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', + __typename: 'User', + }, + __typename: 'Pipeline', + }, + stage: { name: 'test', __typename: 'CiStage' }, + name: 'test_manual_job', + duration: null, + finishedAt: null, + coverage: null, + retryable: false, + playable: true, + cancelable: false, + active: false, + __typename: 'CiJob', + }, + { + detailedStatus: { + icon: 'status_skipped', + label: 'skipped', + text: 'skipped', + tooltip: 'skipped', + action: null, + __typename: 'DetailedStatus', + }, + id: 'gid://gitlab/Ci::Build/2021', + refName: 'master', + refPath: '/root/ci-project/-/commits/master', + tags: [], + shortSha: '2d5d8323', + commitPath: '/root/ci-project/-/commit/2d5d83230bdea0e003d83ef4c16d2bf9a8808ebe', + pipeline: { + id: 'gid://gitlab/Ci::Pipeline/425', + path: '/root/ci-project/-/pipelines/425', + user: { + webPath: '/root', + avatarUrl: + 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', + __typename: 'User', + }, + __typename: 'Pipeline', + }, + stage: { name: 'test', __typename: 'CiStage' }, + name: 'coverage_job', + duration: null, + finishedAt: null, + coverage: null, + retryable: false, + playable: false, + cancelable: false, + active: false, + __typename: 'CiJob', + }, + { + detailedStatus: { + icon: 'status_success', + label: 'passed', + text: 'passed', + tooltip: 'passed', + action: { + buttonTitle: 'Retry this job', + icon: 'retry', + method: 'post', + path: '/root/ci-project/-/jobs/2015/retry', + title: 'Retry', + __typename: 'StatusAction', + }, + __typename: 'DetailedStatus', + }, + id: 'gid://gitlab/Ci::Build/2015', + refName: 'master', + refPath: '/root/ci-project/-/commits/master', + tags: [], + shortSha: '2d5d8323', + commitPath: '/root/ci-project/-/commit/2d5d83230bdea0e003d83ef4c16d2bf9a8808ebe', + pipeline: { + id: 'gid://gitlab/Ci::Pipeline/424', + path: '/root/ci-project/-/pipelines/424', + user: { + webPath: '/root', + avatarUrl: + 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', + __typename: 'User', + }, + __typename: 'Pipeline', + }, + stage: { name: 'deploy', __typename: 'CiStage' }, + name: 'artifact_job', + duration: 2, + finishedAt: '2021-04-01T17:36:18Z', + coverage: null, + retryable: true, + playable: false, + cancelable: false, + active: false, + __typename: 'CiJob', + }, +]; |