Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilipa Lacerda <filipa@gitlab.com>2018-08-20 11:53:43 +0300
committerFilipa Lacerda <filipa@gitlab.com>2018-08-20 11:53:43 +0300
commite8197c7fe7828b74334a40a2af6469610556e063 (patch)
treebf75b2c057f5a0896e225631aa5573b951773391 /spec/javascripts/jobs/components
parent0a630e5e3ac41b95c4ff9045668f006c9fe116c0 (diff)
Moves job log spec files to the components folder
Diffstat (limited to 'spec/javascripts/jobs/components')
-rw-r--r--spec/javascripts/jobs/components/artifacts_block_spec.js120
-rw-r--r--spec/javascripts/jobs/components/commit_block_spec.js73
-rw-r--r--spec/javascripts/jobs/components/empty_state_spec.js90
-rw-r--r--spec/javascripts/jobs/components/erased_block_spec.js56
-rw-r--r--spec/javascripts/jobs/components/header_spec.js98
-rw-r--r--spec/javascripts/jobs/components/job_details_mediator_spec.js39
-rw-r--r--spec/javascripts/jobs/components/job_log_spec.js45
-rw-r--r--spec/javascripts/jobs/components/job_store_spec.js26
-rw-r--r--spec/javascripts/jobs/components/jobs_container_spec.js126
-rw-r--r--spec/javascripts/jobs/components/sidebar_detail_row_spec.js61
-rw-r--r--spec/javascripts/jobs/components/sidebar_details_block_spec.js139
-rw-r--r--spec/javascripts/jobs/components/stages_dropdown_spec.js63
-rw-r--r--spec/javascripts/jobs/components/stuck_block_spec.js81
-rw-r--r--spec/javascripts/jobs/components/trigger_value_spec.js66
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();
+ });
+ });
+});