diff options
author | Filipa Lacerda <filipa@gitlab.com> | 2018-08-20 11:53:43 +0300 |
---|---|---|
committer | Filipa Lacerda <filipa@gitlab.com> | 2018-08-20 11:53:43 +0300 |
commit | e8197c7fe7828b74334a40a2af6469610556e063 (patch) | |
tree | bf75b2c057f5a0896e225631aa5573b951773391 /spec/javascripts/jobs/components | |
parent | 0a630e5e3ac41b95c4ff9045668f006c9fe116c0 (diff) |
Moves job log spec files to the components folder
Diffstat (limited to 'spec/javascripts/jobs/components')
14 files changed, 1083 insertions, 0 deletions
diff --git a/spec/javascripts/jobs/components/artifacts_block_spec.js b/spec/javascripts/jobs/components/artifacts_block_spec.js new file mode 100644 index 00000000000..a06d287b3fa --- /dev/null +++ b/spec/javascripts/jobs/components/artifacts_block_spec.js @@ -0,0 +1,120 @@ +import Vue from 'vue'; +import { getTimeago } from '~/lib/utils/datetime_utility'; +import component from '~/jobs/components/artifacts_block.vue'; +import mountComponent from '../../helpers/vue_mount_component_helper'; + +describe('Artifacts block', () => { + const Component = Vue.extend(component); + let vm; + + const expireAt = '2018-08-14T09:38:49.157Z'; + const timeago = getTimeago(); + const formatedDate = timeago.format(expireAt); + + afterEach(() => { + vm.$destroy(); + }); + + describe('with expired artifacts', () => { + it('renders expired artifact date and info', () => { + vm = mountComponent(Component, { + haveArtifactsExpired: true, + willArtifactsExpire: false, + expireAt, + }); + + expect(vm.$el.querySelector('.js-artifacts-removed')).not.toBeNull(); + expect(vm.$el.querySelector('.js-artifacts-will-be-removed')).toBeNull(); + expect(vm.$el.textContent).toContain(formatedDate); + }); + }); + + describe('with artifacts that will expire', () => { + it('renders will expire artifact date and info', () => { + vm = mountComponent(Component, { + haveArtifactsExpired: false, + willArtifactsExpire: true, + expireAt, + }); + + expect(vm.$el.querySelector('.js-artifacts-removed')).toBeNull(); + expect(vm.$el.querySelector('.js-artifacts-will-be-removed')).not.toBeNull(); + expect(vm.$el.textContent).toContain(formatedDate); + }); + }); + + describe('when the user can keep the artifacts', () => { + it('renders the keep button', () => { + vm = mountComponent(Component, { + haveArtifactsExpired: true, + willArtifactsExpire: false, + expireAt, + keepArtifactsPath: '/keep', + }); + + expect(vm.$el.querySelector('.js-keep-artifacts')).not.toBeNull(); + }); + }); + + describe('when the user can not keep the artifacts', () => { + it('does not render the keep button', () => { + vm = mountComponent(Component, { + haveArtifactsExpired: true, + willArtifactsExpire: false, + expireAt, + }); + + expect(vm.$el.querySelector('.js-keep-artifacts')).toBeNull(); + }); + }); + + describe('when the user can download the artifacts', () => { + it('renders the download button', () => { + vm = mountComponent(Component, { + haveArtifactsExpired: true, + willArtifactsExpire: false, + expireAt, + downloadArtifactsPath: '/download', + }); + + expect(vm.$el.querySelector('.js-download-artifacts')).not.toBeNull(); + }); + }); + + describe('when the user can not download the artifacts', () => { + it('does not render the keep button', () => { + vm = mountComponent(Component, { + haveArtifactsExpired: true, + willArtifactsExpire: false, + expireAt, + }); + + expect(vm.$el.querySelector('.js-download-artifacts')).toBeNull(); + }); + }); + + describe('when the user can browse the artifacts', () => { + it('does not render the browse button', () => { + vm = mountComponent(Component, { + haveArtifactsExpired: true, + willArtifactsExpire: false, + expireAt, + browseArtifactsPath: '/browse', + }); + + expect(vm.$el.querySelector('.js-browse-artifacts')).not.toBeNull(); + }); + }); + + describe('when the user can not browse the artifacts', () => { + it('does not render the browse button', () => { + vm = mountComponent(Component, { + haveArtifactsExpired: true, + willArtifactsExpire: false, + expireAt, + }); + + expect(vm.$el.querySelector('.js-browse-artifacts')).toBeNull(); + }); + }); +}); diff --git a/spec/javascripts/jobs/components/commit_block_spec.js b/spec/javascripts/jobs/components/commit_block_spec.js new file mode 100644 index 00000000000..e21fa9c2874 --- /dev/null +++ b/spec/javascripts/jobs/components/commit_block_spec.js @@ -0,0 +1,73 @@ +import Vue from 'vue'; +import component from '~/jobs/components/commit_block.vue'; +import mountComponent from '../../helpers/vue_mount_component_helper'; + +describe('Commit block', () => { + const Component = Vue.extend(component); + let vm; + + const props = { + pipelineShortSha: '1f0fb84f', + pipelineShaPath: 'commit/1f0fb84fb6770d74d97eee58118fd3909cd4f48c', + mergeRequestReference: '!21244', + mergeRequestPath: 'merge_requests/21244', + gitCommitTitlte: 'Regenerate pot files', + }; + + afterEach(() => { + vm.$destroy(); + }); + + describe('pipeline short sha', () => { + beforeEach(() => { + vm = mountComponent(Component, { + ...props, + }); + }); + + it('renders pipeline short sha link', () => { + expect(vm.$el.querySelector('.js-commit-sha').getAttribute('href')).toEqual(props.pipelineShaPath); + expect(vm.$el.querySelector('.js-commit-sha').textContent.trim()).toEqual(props.pipelineShortSha); + }); + + it('renders clipboard button', () => { + expect(vm.$el.querySelector('button').getAttribute('data-clipboard-text')).toEqual(props.pipelineShortSha); + }); + }); + + 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.mergeRequestPath); + expect(vm.$el.querySelector('.js-link-commit').textContent.trim()).toEqual(props.mergeRequestReference); + + }); + }); + + describe('without merge request', () => { + it('does not render merge request', () => { + const copyProps = Object.assign({}, props); + delete copyProps.mergeRequestPath; + delete copyProps.mergeRequestReference; + + vm = mountComponent(Component, { + ...copyProps, + }); + + expect(vm.$el.querySelector('.js-link-commit')).toBeNull(); + }); + }); + + describe('git commit title', () => { + it('renders git commit title', () => { + vm = mountComponent(Component, { + ...props, + }); + + expect(vm.$el.textContent).toContain(props.gitCommitTitlte); + }); + }); +}); diff --git a/spec/javascripts/jobs/components/empty_state_spec.js b/spec/javascripts/jobs/components/empty_state_spec.js new file mode 100644 index 00000000000..dcc2b3d8a20 --- /dev/null +++ b/spec/javascripts/jobs/components/empty_state_spec.js @@ -0,0 +1,90 @@ +import Vue from 'vue'; +import component from '~/jobs/components/empty_state.vue'; +import mountComponent from '../../helpers/vue_mount_component_helper'; + +describe('Empty State', () => { + const Component = Vue.extend(component); + let vm; + + const props = { + illustrationPath: 'illustrations/pending_job_empty.svg', + illustrationSizeClass: 'svg-430', + title: 'This job has not started yet', + }; + + const content = 'This job is in pending state and is waiting to be picked by a runner'; + + afterEach(() => { + vm.$destroy(); + }); + + describe('renders image and title', () => { + beforeEach(() => { + vm = mountComponent(Component, { + ...props, + content, + }); + }); + + it('renders img with provided path and size', () => { + expect(vm.$el.querySelector('img').getAttribute('src')).toEqual(props.illustrationPath); + expect(vm.$el.querySelector('.svg-content').classList).toContain(props.illustrationSizeClass); + }); + + it('renders provided title', () => { + expect(vm.$el.querySelector('.js-job-empty-state-title').textContent.trim()).toEqual( + props.title, + ); + }); + }); + + describe('with content', () => { + it('renders content', () => { + vm = mountComponent(Component, { + ...props, + content, + }); + + expect(vm.$el.querySelector('.js-job-empty-state-content').textContent.trim()).toEqual( + content, + ); + }); + }); + + describe('without content', () => { + it('does not render content', () => { + vm = mountComponent(Component, { + ...props, + }); + expect(vm.$el.querySelector('.js-job-empty-state-content')).toBeNull(); + }); + }); + + describe('with action', () => { + it('renders action', () => { + vm = mountComponent(Component, { + ...props, + content, + action: { + link: 'runner', + title: 'Check runner', + method: 'post', + }, + }); + + expect(vm.$el.querySelector('.js-job-empty-state-action').getAttribute('href')).toEqual( + 'runner', + ); + }); + }); + + describe('without action', () => { + it('does not render action', () => { + vm = mountComponent(Component, { + ...props, + content, + }); + expect(vm.$el.querySelector('.js-job-empty-state-action')).toBeNull(); + }); + }); +}); diff --git a/spec/javascripts/jobs/components/erased_block_spec.js b/spec/javascripts/jobs/components/erased_block_spec.js new file mode 100644 index 00000000000..a4ae0c7c81e --- /dev/null +++ b/spec/javascripts/jobs/components/erased_block_spec.js @@ -0,0 +1,56 @@ +import Vue from 'vue'; +import { getTimeago } from '~/lib/utils/datetime_utility'; +import component from '~/jobs/components/erased_block.vue'; +import mountComponent from '../../helpers/vue_mount_component_helper'; + +describe('Erased block', () => { + const Component = Vue.extend(component); + let vm; + + const erasedAt = '2016-11-07T11:11:16.525Z'; + const timeago = getTimeago(); + const formatedDate = timeago.format(erasedAt); + + afterEach(() => { + vm.$destroy(); + }); + + describe('with job erased by user', () => { + beforeEach(() => { + vm = mountComponent(Component, { + erasedByUser: true, + username: 'root', + linkToUser: 'gitlab.com/root', + erasedAt, + }); + }); + + it('renders username and link', () => { + expect(vm.$el.querySelector('a').getAttribute('href')).toEqual('gitlab.com/root'); + + expect(vm.$el.textContent).toContain('Job has been erased by'); + expect(vm.$el.textContent).toContain('root'); + }); + + it('renders erasedAt', () => { + expect(vm.$el.textContent).toContain(formatedDate); + }); + }); + + describe('with erased job', () => { + beforeEach(() => { + vm = mountComponent(Component, { + erasedByUser: false, + erasedAt, + }); + }); + + it('renders username and link', () => { + expect(vm.$el.textContent).toContain('Job has been erased'); + }); + + it('renders erasedAt', () => { + expect(vm.$el.textContent).toContain(formatedDate); + }); + }); +}); diff --git a/spec/javascripts/jobs/components/header_spec.js b/spec/javascripts/jobs/components/header_spec.js new file mode 100644 index 00000000000..e21e2c6d6e3 --- /dev/null +++ b/spec/javascripts/jobs/components/header_spec.js @@ -0,0 +1,98 @@ +import Vue from 'vue'; +import headerComponent from '~/jobs/components/header.vue'; +import mountComponent from 'spec/helpers/vue_mount_component_helper'; + +describe('Job details header', () => { + let HeaderComponent; + let vm; + let props; + + beforeEach(() => { + HeaderComponent = Vue.extend(headerComponent); + + const threeWeeksAgo = new Date(); + threeWeeksAgo.setDate(threeWeeksAgo.getDate() - 21); + + const twoDaysAgo = new Date(); + twoDaysAgo.setDate(twoDaysAgo.getDate() - 2); + + props = { + job: { + status: { + group: 'failed', + icon: 'status_failed', + label: 'failed', + text: 'failed', + details_path: 'path', + }, + id: 123, + created_at: threeWeeksAgo.toISOString(), + user: { + web_url: 'path', + name: 'Foo', + username: 'foobar', + email: 'foo@bar.com', + avatar_url: 'link', + }, + started: twoDaysAgo.toISOString(), + new_issue_path: 'path', + }, + isLoading: false, + }; + }); + + afterEach(() => { + vm.$destroy(); + }); + + describe('job reason', () => { + it('should not render the reason when reason is absent', () => { + vm = mountComponent(HeaderComponent, props); + + expect(vm.shouldRenderReason).toBe(false); + }); + + it('should render the reason when reason is present', () => { + props.job.callout_message = 'There is an unknown failure, please try again'; + + vm = mountComponent(HeaderComponent, props); + + expect(vm.shouldRenderReason).toBe(true); + }); + }); + + describe('triggered job', () => { + beforeEach(() => { + vm = mountComponent(HeaderComponent, props); + }); + + it('should render provided job information', () => { + expect( + vm.$el + .querySelector('.header-main-content') + .textContent.replace(/\s+/g, ' ') + .trim(), + ).toEqual('failed Job #123 triggered 2 days ago by Foo'); + }); + + it('should render new issue link', () => { + expect(vm.$el.querySelector('.js-new-issue').getAttribute('href')).toEqual( + props.job.new_issue_path, + ); + }); + }); + + describe('created job', () => { + it('should render created key', () => { + props.job.started = false; + vm = mountComponent(HeaderComponent, props); + + expect( + vm.$el + .querySelector('.header-main-content') + .textContent.replace(/\s+/g, ' ') + .trim(), + ).toEqual('failed Job #123 created 3 weeks ago by Foo'); + }); + }); +}); diff --git a/spec/javascripts/jobs/components/job_details_mediator_spec.js b/spec/javascripts/jobs/components/job_details_mediator_spec.js new file mode 100644 index 00000000000..3e2fb7bfbbb --- /dev/null +++ b/spec/javascripts/jobs/components/job_details_mediator_spec.js @@ -0,0 +1,39 @@ +import MockAdapter from 'axios-mock-adapter'; +import axios from '~/lib/utils/axios_utils'; +import JobMediator from '~/jobs/job_details_mediator'; +import job from '../mock_data'; + +describe('JobMediator', () => { + let mediator; + let mock; + + beforeEach(() => { + mediator = new JobMediator({ endpoint: 'jobs/40291672.json' }); + mock = new MockAdapter(axios); + }); + + afterEach(() => { + mock.restore(); + }); + + it('should set defaults', () => { + expect(mediator.store).toBeDefined(); + expect(mediator.service).toBeDefined(); + expect(mediator.options).toEqual({ endpoint: 'jobs/40291672.json' }); + expect(mediator.state.isLoading).toEqual(false); + }); + + describe('request and store data', () => { + beforeEach(() => { + mock.onGet().reply(200, job, {}); + }); + + it('should store received data', (done) => { + mediator.fetchJob(); + setTimeout(() => { + expect(mediator.store.state.job).toEqual(job); + done(); + }, 0); + }); + }); +}); diff --git a/spec/javascripts/jobs/components/job_log_spec.js b/spec/javascripts/jobs/components/job_log_spec.js new file mode 100644 index 00000000000..6a5b375a26c --- /dev/null +++ b/spec/javascripts/jobs/components/job_log_spec.js @@ -0,0 +1,45 @@ +import Vue from 'vue'; +import component from '~/jobs/components/job_log.vue'; +import mountComponent from '../../helpers/vue_mount_component_helper'; + +describe('Job Log', () => { + const Component = Vue.extend(component); + let vm; + + const trace = 'Running with gitlab-runner 11.1.0 (081978aa)<br> on docker-auto-scale-com d5ae8d25<br>Using Docker executor with image dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.4.4-golang-1.9-git-2.18-chrome-67.0-node-8.x-yarn-1.2-postgresql-9.6-graphicsmagick-1.3.29 ...<br>'; + + afterEach(() => { + vm.$destroy(); + }); + + it('renders provided trace', () => { + vm = mountComponent(Component, { + trace, + isReceivingBuildTrace: true, + }); + + expect(vm.$el.querySelector('code').textContent).toContain('Running with gitlab-runner 11.1.0 (081978aa)'); + }); + + describe('while receiving trace', () => { + it('renders animation', () => { + vm = mountComponent(Component, { + trace, + isReceivingBuildTrace: true, + }); + + expect(vm.$el.querySelector('.js-log-animation')).not.toBeNull(); + }); + }); + + describe('when build trace has finishes', () => { + it('does not render animation', () => { + vm = mountComponent(Component, { + trace, + isReceivingBuildTrace: false, + }); + + expect(vm.$el.querySelector('.js-log-animation')).toBeNull(); + }); + }); +}); diff --git a/spec/javascripts/jobs/components/job_store_spec.js b/spec/javascripts/jobs/components/job_store_spec.js new file mode 100644 index 00000000000..0dad5111b32 --- /dev/null +++ b/spec/javascripts/jobs/components/job_store_spec.js @@ -0,0 +1,26 @@ +import JobStore from '~/jobs/stores/job_store'; +import job from '../mock_data'; + +describe('Job Store', () => { + let store; + + beforeEach(() => { + store = new JobStore(); + }); + + it('should set defaults', () => { + expect(store.state.job).toEqual({}); + }); + + describe('storeJob', () => { + it('should store empty object if none is provided', () => { + store.storeJob(); + expect(store.state.job).toEqual({}); + }); + + it('should store provided argument', () => { + store.storeJob(job); + expect(store.state.job).toEqual(job); + }); + }); +}); diff --git a/spec/javascripts/jobs/components/jobs_container_spec.js b/spec/javascripts/jobs/components/jobs_container_spec.js new file mode 100644 index 00000000000..f3f8ff0d031 --- /dev/null +++ b/spec/javascripts/jobs/components/jobs_container_spec.js @@ -0,0 +1,126 @@ +import Vue from 'vue'; +import component from '~/jobs/components/jobs_container.vue'; +import mountComponent from '../../helpers/vue_mount_component_helper'; + +describe('Artifacts block', () => { + const Component = Vue.extend(component); + let vm; + + const retried = { + status: { + details_path: '/gitlab-org/gitlab-ce/pipelines/28029444', + group: 'success', + has_details: true, + icon: 'status_success', + label: 'passed', + text: 'passed', + tooltip: 'passed', + }, + path: 'job/233432756', + id: '233432756', + tooltip: 'build - passed', + retried: true, + }; + + const active = { + name: 'test', + status: { + details_path: '/gitlab-org/gitlab-ce/pipelines/28029444', + group: 'success', + has_details: true, + icon: 'status_success', + label: 'passed', + text: 'passed', + tooltip: 'passed', + }, + path: 'job/2322756', + id: '2322756', + tooltip: 'build - passed', + active: true, + }; + + const job = { + name: 'build', + status: { + details_path: '/gitlab-org/gitlab-ce/pipelines/28029444', + group: 'success', + has_details: true, + icon: 'status_success', + label: 'passed', + text: 'passed', + tooltip: 'passed', + }, + path: 'job/232153', + id: '232153', + tooltip: 'build - passed', + }; + + afterEach(() => { + vm.$destroy(); + }); + + it('renders list of jobs', () => { + vm = mountComponent(Component, { + jobs: [job, retried, active], + }); + + expect(vm.$el.querySelectorAll('a').length).toEqual(3); + }); + + it('renders arrow right when job is active', () => { + vm = mountComponent(Component, { + jobs: [active], + }); + + expect(vm.$el.querySelector('a .js-arrow-right')).not.toBeNull(); + }); + + it('does not render arrow right when job is not active', () => { + vm = mountComponent(Component, { + jobs: [job], + }); + + expect(vm.$el.querySelector('a .js-arrow-right')).toBeNull(); + }); + + it('renders job name when present', () => { + vm = mountComponent(Component, { + jobs: [job], + }); + + expect(vm.$el.querySelector('a').textContent.trim()).toContain(job.name); + expect(vm.$el.querySelector('a').textContent.trim()).not.toContain(job.id); + }); + + it('renders job id when job name is not available', () => { + vm = mountComponent(Component, { + jobs: [retried], + }); + + expect(vm.$el.querySelector('a').textContent.trim()).toContain(retried.id); + }); + + it('links to the job page', () => { + vm = mountComponent(Component, { + jobs: [job], + }); + + expect(vm.$el.querySelector('a').getAttribute('href')).toEqual(job.path); + }); + + it('renders retry icon when job was retried', () => { + vm = mountComponent(Component, { + jobs: [retried], + }); + + expect(vm.$el.querySelector('.js-retry-icon')).not.toBeNull(); + }); + + it('does not render retry icon when job was not retried', () => { + vm = mountComponent(Component, { + jobs: [job], + }); + + expect(vm.$el.querySelector('.js-retry-icon')).toBeNull(); + }); +}); diff --git a/spec/javascripts/jobs/components/sidebar_detail_row_spec.js b/spec/javascripts/jobs/components/sidebar_detail_row_spec.js new file mode 100644 index 00000000000..e6bfb0c4adc --- /dev/null +++ b/spec/javascripts/jobs/components/sidebar_detail_row_spec.js @@ -0,0 +1,61 @@ +import Vue from 'vue'; +import sidebarDetailRow from '~/jobs/components/sidebar_detail_row.vue'; + +describe('Sidebar detail row', () => { + let SidebarDetailRow; + let vm; + + beforeEach(() => { + SidebarDetailRow = Vue.extend(sidebarDetailRow); + }); + + afterEach(() => { + vm.$destroy(); + }); + + it('should render no title', () => { + vm = new SidebarDetailRow({ + propsData: { + value: 'this is the value', + }, + }).$mount(); + + expect(vm.$el.textContent.replace(/\s+/g, ' ').trim()).toEqual('this is the value'); + }); + + beforeEach(() => { + vm = new SidebarDetailRow({ + propsData: { + title: 'this is the title', + value: 'this is the value', + }, + }).$mount(); + }); + + it('should render provided title and value', () => { + expect( + vm.$el.textContent.replace(/\s+/g, ' ').trim(), + ).toEqual('this is the title: this is the value'); + }); + + describe('when helpUrl not provided', () => { + it('should not render help', () => { + expect(vm.$el.querySelector('.help-button')).toBeNull(); + }); + }); + + describe('when helpUrl provided', () => { + beforeEach(() => { + vm = new SidebarDetailRow({ + propsData: { + helpUrl: 'help url', + value: 'foo', + }, + }).$mount(); + }); + + it('should render help', () => { + expect(vm.$el.querySelector('.help-button a').getAttribute('href')).toEqual('help url'); + }); + }); +}); diff --git a/spec/javascripts/jobs/components/sidebar_details_block_spec.js b/spec/javascripts/jobs/components/sidebar_details_block_spec.js new file mode 100644 index 00000000000..ba19534dac2 --- /dev/null +++ b/spec/javascripts/jobs/components/sidebar_details_block_spec.js @@ -0,0 +1,139 @@ +import Vue from 'vue'; +import sidebarDetailsBlock from '~/jobs/components/sidebar_details_block.vue'; +import job from '../mock_data'; +import mountComponent from '../../helpers/vue_mount_component_helper'; + +describe('Sidebar details block', () => { + let SidebarComponent; + let vm; + + function trimWhitespace(element) { + return element.textContent.replace(/\s+/g, ' ').trim(); + } + + beforeEach(() => { + SidebarComponent = Vue.extend(sidebarDetailsBlock); + }); + + afterEach(() => { + vm.$destroy(); + }); + + describe('when it is loading', () => { + it('should render a loading spinner', () => { + vm = mountComponent(SidebarComponent, { + job: {}, + isLoading: true, + }); + expect(vm.$el.querySelector('.fa-spinner')).toBeDefined(); + }); + }); + + describe('when there is no retry path retry', () => { + it('should not render a retry button', () => { + vm = mountComponent(SidebarComponent, { + job: {}, + isLoading: false, + }); + + expect(vm.$el.querySelector('.js-retry-job')).toBeNull(); + }); + }); + + describe('without terminal path', () => { + it('does not render terminal link', () => { + vm = mountComponent(SidebarComponent, { + job, + isLoading: false, + }); + + expect(vm.$el.querySelector('.js-terminal-link')).toBeNull(); + }); + }); + + describe('with terminal path', () => { + it('renders terminal link', () => { + vm = mountComponent(SidebarComponent, { + job, + isLoading: false, + terminalPath: 'job/43123/terminal', + }); + + expect(vm.$el.querySelector('.js-terminal-link')).not.toBeNull(); + }); + }); + + beforeEach(() => { + vm = mountComponent(SidebarComponent, { + job, + isLoading: false, + }); + }); + + describe('actions', () => { + it('should render link to new issue', () => { + expect(vm.$el.querySelector('.js-new-issue').getAttribute('href')).toEqual( + job.new_issue_path, + ); + expect(vm.$el.querySelector('.js-new-issue').textContent.trim()).toEqual('New issue'); + }); + + it('should render link to retry job', () => { + expect(vm.$el.querySelector('.js-retry-job').getAttribute('href')).toEqual(job.retry_path); + }); + + it('should render link to cancel job', () => { + expect(vm.$el.querySelector('.js-cancel-job').getAttribute('href')).toEqual(job.cancel_path); + }); + }); + + describe('information', () => { + it('should render merge request link', () => { + expect(trimWhitespace(vm.$el.querySelector('.js-job-mr'))).toEqual('Merge Request: !2'); + + expect(vm.$el.querySelector('.js-job-mr a').getAttribute('href')).toEqual( + job.merge_request.path, + ); + }); + + it('should render job duration', () => { + expect(trimWhitespace(vm.$el.querySelector('.js-job-duration'))).toEqual( + 'Duration: 6 seconds', + ); + }); + + it('should render erased date', () => { + expect(trimWhitespace(vm.$el.querySelector('.js-job-erased'))).toEqual('Erased: 3 weeks ago'); + }); + + it('should render finished date', () => { + expect(trimWhitespace(vm.$el.querySelector('.js-job-finished'))).toEqual( + 'Finished: 3 weeks ago', + ); + }); + + it('should render queued date', () => { + expect(trimWhitespace(vm.$el.querySelector('.js-job-queued'))).toEqual('Queued: 9 seconds'); + }); + + it('should render runner ID', () => { + expect(trimWhitespace(vm.$el.querySelector('.js-job-runner'))).toEqual( + 'Runner: local ci runner (#1)', + ); + }); + + it('should render timeout information', () => { + expect(trimWhitespace(vm.$el.querySelector('.js-job-timeout'))).toEqual( + 'Timeout: 1m 40s (from runner)', + ); + }); + + it('should render coverage', () => { + expect(trimWhitespace(vm.$el.querySelector('.js-job-coverage'))).toEqual('Coverage: 20%'); + }); + + it('should render tags', () => { + expect(trimWhitespace(vm.$el.querySelector('.js-job-tags'))).toEqual('Tags: tag'); + }); + }); +}); diff --git a/spec/javascripts/jobs/components/stages_dropdown_spec.js b/spec/javascripts/jobs/components/stages_dropdown_spec.js new file mode 100644 index 00000000000..402289345aa --- /dev/null +++ b/spec/javascripts/jobs/components/stages_dropdown_spec.js @@ -0,0 +1,63 @@ +import Vue from 'vue'; +import component from '~/jobs/components/stages_dropdown.vue'; +import mountComponent from '../../helpers/vue_mount_component_helper'; + +describe('Artifacts block', () => { + const Component = Vue.extend(component); + let vm; + + beforeEach(() => { + vm = mountComponent(Component, { + pipelineId: 28029444, + pipelinePath: 'pipeline/28029444', + pipelineRef: '50101-truncated-job-information', + pipelineRefPath: 'commits/50101-truncated-job-information', + stages: [ + { + name: 'build', + }, + { + name: 'test', + }, + ], + pipelineStatus: { + details_path: '/gitlab-org/gitlab-ce/pipelines/28029444', + group: 'success', + has_details: true, + icon: 'status_success', + label: 'passed', + text: 'passed', + tooltip: 'passed', + }, + }); + }); + + afterEach(() => { + vm.$destroy(); + }); + + it('renders pipeline status', () => { + expect(vm.$el.querySelector('.js-ci-status-icon-success')).not.toBeNull(); + }); + + it('renders pipeline link', () => { + expect(vm.$el.querySelector('.js-pipeline-path').getAttribute('href')).toEqual( + 'pipeline/28029444', + ); + }); + + it('renders dropdown with stages', () => { + expect(vm.$el.querySelector('.dropdown button').textContent).toContain('build'); + }); + + it('updates selected stage on click', done => { + vm.$el.querySelectorAll('.stage-item')[1].click(); + vm + .$nextTick() + .then(() => { + expect(vm.$el.querySelector('.dropdown button').textContent).toContain('test'); + }) + .then(done) + .catch(done.fail); + }); +}); diff --git a/spec/javascripts/jobs/components/stuck_block_spec.js b/spec/javascripts/jobs/components/stuck_block_spec.js new file mode 100644 index 00000000000..c320793b2be --- /dev/null +++ b/spec/javascripts/jobs/components/stuck_block_spec.js @@ -0,0 +1,81 @@ +import Vue from 'vue'; +import component from '~/jobs/components/stuck_block.vue'; +import mountComponent from '../../helpers/vue_mount_component_helper'; + +describe('Stuck Block Job component', () => { + const Component = Vue.extend(component); + let vm; + + afterEach(() => { + vm.$destroy(); + }); + + describe('with no runners for project', () => { + beforeEach(() => { + vm = mountComponent(Component, { + hasNoRunnersForProject: true, + runnersPath: '/root/project/runners#js-runners-settings', + }); + }); + + it('renders only information about project not having runners', () => { + expect(vm.$el.querySelector('.js-stuck-no-runners')).not.toBeNull(); + expect(vm.$el.querySelector('.js-stuck-with-tags')).toBeNull(); + expect(vm.$el.querySelector('.js-stuck-no-active-runner')).toBeNull(); + }); + + it('renders link to runners page', () => { + expect(vm.$el.querySelector('.js-runners-path').getAttribute('href')).toEqual( + '/root/project/runners#js-runners-settings', + ); + }); + }); + + describe('with tags', () => { + beforeEach(() => { + vm = mountComponent(Component, { + hasNoRunnersForProject: false, + tags: ['docker', 'gitlab-org'], + runnersPath: '/root/project/runners#js-runners-settings', + }); + }); + + it('renders information about the tags not being set', () => { + expect(vm.$el.querySelector('.js-stuck-no-runners')).toBeNull(); + expect(vm.$el.querySelector('.js-stuck-with-tags')).not.toBeNull(); + expect(vm.$el.querySelector('.js-stuck-no-active-runner')).toBeNull(); + }); + + it('renders tags', () => { + expect(vm.$el.textContent).toContain('docker'); + expect(vm.$el.textContent).toContain('gitlab-org'); + }); + + it('renders link to runners page', () => { + expect(vm.$el.querySelector('.js-runners-path').getAttribute('href')).toEqual( + '/root/project/runners#js-runners-settings', + ); + }); + }); + + describe('without active runners', () => { + beforeEach(() => { + vm = mountComponent(Component, { + hasNoRunnersForProject: false, + runnersPath: '/root/project/runners#js-runners-settings', + }); + }); + + it('renders information about project not having runners', () => { + expect(vm.$el.querySelector('.js-stuck-no-runners')).toBeNull(); + expect(vm.$el.querySelector('.js-stuck-with-tags')).toBeNull(); + expect(vm.$el.querySelector('.js-stuck-no-active-runner')).not.toBeNull(); + }); + + it('renders link to runners page', () => { + expect(vm.$el.querySelector('.js-runners-path').getAttribute('href')).toEqual( + '/root/project/runners#js-runners-settings', + ); + }); + }); +}); diff --git a/spec/javascripts/jobs/components/trigger_value_spec.js b/spec/javascripts/jobs/components/trigger_value_spec.js new file mode 100644 index 00000000000..3d41a3cfac1 --- /dev/null +++ b/spec/javascripts/jobs/components/trigger_value_spec.js @@ -0,0 +1,66 @@ +import Vue from 'vue'; +import component from '~/jobs/components/trigger_block.vue'; +import mountComponent from '../../helpers/vue_mount_component_helper'; + +describe('Trigger block', () => { + const Component = Vue.extend(component); + let vm; + + afterEach(() => { + vm.$destroy(); + }); + + describe('with short token', () => { + it('renders short token', () => { + vm = mountComponent(Component, { + shortToken: '0a666b2', + }); + + expect(vm.$el.querySelector('.js-short-token').textContent).toContain('0a666b2'); + }); + }); + + describe('without short token', () => { + it('does not render short token', () => { + vm = mountComponent(Component, {}); + + expect(vm.$el.querySelector('.js-short-token')).toBeNull(); + }); + }); + + describe('with variables', () => { + describe('reveal variables', () => { + it('reveals variables on click', done => { + vm = mountComponent(Component, { + variables: { + key: 'value', + variable: 'foo', + }, + }); + + vm.$el.querySelector('.js-reveal-variables').click(); + + vm + .$nextTick() + .then(() => { + expect(vm.$el.querySelector('.js-build-variables')).not.toBeNull(); + expect(vm.$el.querySelector('.js-build-variables').textContent).toContain('key'); + expect(vm.$el.querySelector('.js-build-variables').textContent).toContain('value'); + expect(vm.$el.querySelector('.js-build-variables').textContent).toContain('variable'); + expect(vm.$el.querySelector('.js-build-variables').textContent).toContain('foo'); + }) + .then(done) + .catch(done.fail); + }); + }); + }); + + describe('without variables', () => { + it('does not render variables', () => { + vm = mountComponent(Component); + + expect(vm.$el.querySelector('.js-reveal-variables')).toBeNull(); + expect(vm.$el.querySelector('.js-build-variables')).toBeNull(); + }); + }); +}); |