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:
authorKamil Trzcinski <ayufan@ayufan.eu>2017-05-06 20:02:06 +0300
committerKamil Trzcinski <ayufan@ayufan.eu>2017-05-06 20:04:48 +0300
commitaa440eb1c0947d2dc551c61abbd9d271b9002050 (patch)
tree907f60233034d904edd1b5d8ea4c9d6df9278ec5 /spec/javascripts
parentc17e6a6c68b0412b3433632802b852db474a7b30 (diff)
Single commit squash of all changes for https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/10878
It's needed due to https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/10777 being merged with squash.
Diffstat (limited to 'spec/javascripts')
-rw-r--r--spec/javascripts/bootstrap_linked_tabs_spec.js8
-rw-r--r--spec/javascripts/ci_status_icon_spec.js44
-rw-r--r--spec/javascripts/fixtures/graph.html.haml1
-rw-r--r--spec/javascripts/pipelines/graph/action_component_spec.js40
-rw-r--r--spec/javascripts/pipelines/graph/dropdown_action_component_spec.js30
-rw-r--r--spec/javascripts/pipelines/graph/graph_component_spec.js83
-rw-r--r--spec/javascripts/pipelines/graph/job_component_spec.js117
-rw-r--r--spec/javascripts/pipelines/graph/job_name_component_spec.js27
-rw-r--r--spec/javascripts/pipelines/graph/stage_column_component_spec.js42
-rw-r--r--spec/javascripts/pipelines_spec.js32
-rw-r--r--spec/javascripts/vue_shared/ci_action_icons_spec.js22
-rw-r--r--spec/javascripts/vue_shared/ci_status_icon_spec.js27
-rw-r--r--spec/javascripts/vue_shared/components/ci_icon_spec.js130
13 files changed, 535 insertions, 68 deletions
diff --git a/spec/javascripts/bootstrap_linked_tabs_spec.js b/spec/javascripts/bootstrap_linked_tabs_spec.js
index fa9f95e16cd..a27dc48b3fd 100644
--- a/spec/javascripts/bootstrap_linked_tabs_spec.js
+++ b/spec/javascripts/bootstrap_linked_tabs_spec.js
@@ -1,4 +1,4 @@
-require('~/lib/utils/bootstrap_linked_tabs');
+import LinkedTabs from '~/lib/utils/bootstrap_linked_tabs';
(() => {
// TODO: remove this hack!
@@ -25,7 +25,7 @@ require('~/lib/utils/bootstrap_linked_tabs');
});
it('should activate the tab correspondent to the given action', () => {
- const linkedTabs = new window.gl.LinkedTabs({ // eslint-disable-line
+ const linkedTabs = new LinkedTabs({ // eslint-disable-line
action: 'tab1',
defaultAction: 'tab1',
parentEl: '.linked-tabs',
@@ -35,7 +35,7 @@ require('~/lib/utils/bootstrap_linked_tabs');
});
it('should active the default tab action when the action is show', () => {
- const linkedTabs = new window.gl.LinkedTabs({ // eslint-disable-line
+ const linkedTabs = new LinkedTabs({ // eslint-disable-line
action: 'show',
defaultAction: 'tab1',
parentEl: '.linked-tabs',
@@ -49,7 +49,7 @@ require('~/lib/utils/bootstrap_linked_tabs');
it('should change the url according to the clicked tab', () => {
const historySpy = !phantomjs && spyOn(history, 'replaceState').and.callFake(() => {});
- const linkedTabs = new window.gl.LinkedTabs({ // eslint-disable-line
+ const linkedTabs = new LinkedTabs({
action: 'show',
defaultAction: 'tab1',
parentEl: '.linked-tabs',
diff --git a/spec/javascripts/ci_status_icon_spec.js b/spec/javascripts/ci_status_icon_spec.js
deleted file mode 100644
index c83416c15ef..00000000000
--- a/spec/javascripts/ci_status_icon_spec.js
+++ /dev/null
@@ -1,44 +0,0 @@
-import * as icons from '~/ci_status_icons';
-
-describe('CI status icons', () => {
- const statuses = [
- 'canceled',
- 'created',
- 'failed',
- 'manual',
- 'pending',
- 'running',
- 'skipped',
- 'success',
- 'warning',
- ];
-
- statuses.forEach((status) => {
- it(`should export a ${status} svg`, () => {
- const key = `${status.toUpperCase()}_SVG`;
-
- expect(Object.hasOwnProperty.call(icons, key)).toBe(true);
- expect(icons[key]).toMatch(/^<svg/);
- });
- });
-
- describe('default export map', () => {
- const entityIconNames = [
- 'icon_status_canceled',
- 'icon_status_created',
- 'icon_status_failed',
- 'icon_status_manual',
- 'icon_status_pending',
- 'icon_status_running',
- 'icon_status_skipped',
- 'icon_status_success',
- 'icon_status_warning',
- ];
-
- entityIconNames.forEach((iconName) => {
- it(`should have a '${iconName}' key`, () => {
- expect(Object.hasOwnProperty.call(icons.default, iconName)).toBe(true);
- });
- });
- });
-});
diff --git a/spec/javascripts/fixtures/graph.html.haml b/spec/javascripts/fixtures/graph.html.haml
new file mode 100644
index 00000000000..4fedb0f1ded
--- /dev/null
+++ b/spec/javascripts/fixtures/graph.html.haml
@@ -0,0 +1 @@
+#js-pipeline-graph-vue{ data: { endpoint: "foo" } }
diff --git a/spec/javascripts/pipelines/graph/action_component_spec.js b/spec/javascripts/pipelines/graph/action_component_spec.js
new file mode 100644
index 00000000000..f033956c071
--- /dev/null
+++ b/spec/javascripts/pipelines/graph/action_component_spec.js
@@ -0,0 +1,40 @@
+import Vue from 'vue';
+import actionComponent from '~/pipelines/components/graph/action_component.vue';
+
+describe('pipeline graph action component', () => {
+ let component;
+
+ beforeEach(() => {
+ const ActionComponent = Vue.extend(actionComponent);
+ component = new ActionComponent({
+ propsData: {
+ tooltipText: 'bar',
+ link: 'foo',
+ actionMethod: 'post',
+ actionIcon: 'icon_action_cancel',
+ },
+ }).$mount();
+ });
+
+ it('should render a link', () => {
+ expect(component.$el.getAttribute('href')).toEqual('foo');
+ });
+
+ it('should render the provided title as a bootstrap tooltip', () => {
+ expect(component.$el.getAttribute('data-original-title')).toEqual('bar');
+ });
+
+ it('should update bootstrap tooltip when title changes', (done) => {
+ component.tooltipText = 'changed';
+
+ Vue.nextTick(() => {
+ expect(component.$el.getAttribute('data-original-title')).toBe('changed');
+ done();
+ });
+ });
+
+ it('should render an svg', () => {
+ expect(component.$el.querySelector('.ci-action-icon-wrapper')).toBeDefined();
+ expect(component.$el.querySelector('svg')).toBeDefined();
+ });
+});
diff --git a/spec/javascripts/pipelines/graph/dropdown_action_component_spec.js b/spec/javascripts/pipelines/graph/dropdown_action_component_spec.js
new file mode 100644
index 00000000000..14ff1b0d25c
--- /dev/null
+++ b/spec/javascripts/pipelines/graph/dropdown_action_component_spec.js
@@ -0,0 +1,30 @@
+import Vue from 'vue';
+import dropdownActionComponent from '~/pipelines/components/graph/dropdown_action_component.vue';
+
+describe('action component', () => {
+ let component;
+
+ beforeEach(() => {
+ const DropdownActionComponent = Vue.extend(dropdownActionComponent);
+ component = new DropdownActionComponent({
+ propsData: {
+ tooltipText: 'bar',
+ link: 'foo',
+ actionMethod: 'post',
+ actionIcon: 'icon_action_cancel',
+ },
+ }).$mount();
+ });
+
+ it('should render a link', () => {
+ expect(component.$el.getAttribute('href')).toEqual('foo');
+ });
+
+ it('should render the provided title as a bootstrap tooltip', () => {
+ expect(component.$el.getAttribute('data-original-title')).toEqual('bar');
+ });
+
+ it('should render an svg', () => {
+ expect(component.$el.querySelector('svg')).toBeDefined();
+ });
+});
diff --git a/spec/javascripts/pipelines/graph/graph_component_spec.js b/spec/javascripts/pipelines/graph/graph_component_spec.js
new file mode 100644
index 00000000000..a756617e65e
--- /dev/null
+++ b/spec/javascripts/pipelines/graph/graph_component_spec.js
@@ -0,0 +1,83 @@
+import Vue from 'vue';
+import graphComponent from '~/pipelines/components/graph/graph_component.vue';
+
+describe('graph component', () => {
+ preloadFixtures('static/graph.html.raw');
+
+ let GraphComponent;
+
+ beforeEach(() => {
+ loadFixtures('static/graph.html.raw');
+ GraphComponent = Vue.extend(graphComponent);
+ });
+
+ describe('while is loading', () => {
+ it('should render a loading icon', () => {
+ const component = new GraphComponent().$mount('#js-pipeline-graph-vue');
+ expect(component.$el.querySelector('.loading-icon')).toBeDefined();
+ });
+ });
+
+ describe('with a successfull response', () => {
+ const interceptor = (request, next) => {
+ next(request.respondWith(JSON.stringify({
+ details: {
+ stages: [{
+ name: 'test',
+ title: 'test: passed',
+ status: {
+ icon: 'icon_status_success',
+ text: 'passed',
+ label: 'passed',
+ details_path: '/root/ci-mock/pipelines/123#test',
+ },
+ path: '/root/ci-mock/pipelines/123#test',
+ groups: [{
+ name: 'test',
+ size: 1,
+ jobs: [{
+ id: 4153,
+ name: 'test',
+ status: {
+ icon: 'icon_status_success',
+ text: 'passed',
+ label: 'passed',
+ details_path: '/root/ci-mock/builds/4153',
+ action: {
+ icon: 'icon_action_retry',
+ title: 'Retry',
+ path: '/root/ci-mock/builds/4153/retry',
+ method: 'post',
+ },
+ },
+ }],
+ }],
+ }],
+ },
+ }), {
+ status: 200,
+ }));
+ };
+
+ beforeEach(() => {
+ Vue.http.interceptors.push(interceptor);
+ });
+
+ afterEach(() => {
+ Vue.http.interceptors = _.without(Vue.http.interceptors, interceptor);
+ });
+
+ it('should render the graph', (done) => {
+ const component = new GraphComponent().$mount('#js-pipeline-graph-vue');
+
+ setTimeout(() => {
+ expect(component.$el.classList.contains('js-pipeline-graph')).toEqual(true);
+
+ expect(component.$el.querySelector('loading-icon')).toBe(null);
+
+ expect(component.$el.querySelector('.stage-column-list')).toBeDefined();
+ done();
+ }, 0);
+ });
+ });
+});
diff --git a/spec/javascripts/pipelines/graph/job_component_spec.js b/spec/javascripts/pipelines/graph/job_component_spec.js
new file mode 100644
index 00000000000..63986b6c0db
--- /dev/null
+++ b/spec/javascripts/pipelines/graph/job_component_spec.js
@@ -0,0 +1,117 @@
+import Vue from 'vue';
+import jobComponent from '~/pipelines/components/graph/job_component.vue';
+
+describe('pipeline graph job component', () => {
+ let JobComponent;
+
+ const mockJob = {
+ id: 4256,
+ name: 'test',
+ status: {
+ icon: 'icon_status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ details_path: '/root/ci-mock/builds/4256',
+ action: {
+ icon: 'icon_action_retry',
+ title: 'Retry',
+ path: '/root/ci-mock/builds/4256/retry',
+ method: 'post',
+ },
+ },
+ };
+
+ beforeEach(() => {
+ JobComponent = Vue.extend(jobComponent);
+ });
+
+ describe('name with link', () => {
+ it('should render the job name and status with a link', () => {
+ const component = new JobComponent({
+ propsData: {
+ job: mockJob,
+ },
+ }).$mount();
+
+ const link = component.$el.querySelector('a');
+
+ expect(link.getAttribute('href')).toEqual(mockJob.status.details_path);
+
+ expect(
+ link.getAttribute('data-original-title'),
+ ).toEqual(`${mockJob.name} - ${mockJob.status.label}`);
+
+ expect(component.$el.querySelector('.js-status-icon-success')).toBeDefined();
+
+ expect(
+ component.$el.querySelector('.ci-status-text').textContent.trim(),
+ ).toEqual(mockJob.name);
+ });
+ });
+
+ describe('name without link', () => {
+ it('it should render status and name', () => {
+ const component = new JobComponent({
+ propsData: {
+ job: {
+ id: 4256,
+ name: 'test',
+ status: {
+ icon: 'icon_status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ details_path: '/root/ci-mock/builds/4256',
+ },
+ },
+ },
+ }).$mount();
+
+ expect(component.$el.querySelector('.js-status-icon-success')).toBeDefined();
+
+ expect(
+ component.$el.querySelector('.ci-status-text').textContent.trim(),
+ ).toEqual(mockJob.name);
+ });
+ });
+
+ describe('action icon', () => {
+ it('it should render the action icon', () => {
+ const component = new JobComponent({
+ propsData: {
+ job: mockJob,
+ },
+ }).$mount();
+
+ expect(component.$el.querySelector('a.ci-action-icon-container')).toBeDefined();
+ expect(component.$el.querySelector('i.ci-action-icon-wrapper')).toBeDefined();
+ });
+ });
+
+ describe('dropdown', () => {
+ it('should render the dropdown action icon', () => {
+ const component = new JobComponent({
+ propsData: {
+ job: mockJob,
+ isDropdown: true,
+ },
+ }).$mount();
+
+ expect(component.$el.querySelector('a.ci-action-icon-wrapper')).toBeDefined();
+ });
+ });
+
+ it('should render provided class name', () => {
+ const component = new JobComponent({
+ propsData: {
+ job: mockJob,
+ cssClassJobName: 'css-class-job-name',
+ },
+ }).$mount();
+
+ expect(
+ component.$el.querySelector('a').classList.contains('css-class-job-name'),
+ ).toBe(true);
+ });
+});
diff --git a/spec/javascripts/pipelines/graph/job_name_component_spec.js b/spec/javascripts/pipelines/graph/job_name_component_spec.js
new file mode 100644
index 00000000000..8e2071ba0b3
--- /dev/null
+++ b/spec/javascripts/pipelines/graph/job_name_component_spec.js
@@ -0,0 +1,27 @@
+import Vue from 'vue';
+import jobNameComponent from '~/pipelines/components/graph/job_name_component.vue';
+
+describe('job name component', () => {
+ let component;
+
+ beforeEach(() => {
+ const JobNameComponent = Vue.extend(jobNameComponent);
+ component = new JobNameComponent({
+ propsData: {
+ name: 'foo',
+ status: {
+ icon: 'icon_status_success',
+ },
+ },
+ }).$mount();
+ });
+
+ it('should render the provided name', () => {
+ expect(component.$el.querySelector('.ci-status-text').textContent.trim()).toEqual('foo');
+ });
+
+ it('should render an icon with the provided status', () => {
+ expect(component.$el.querySelector('.ci-status-icon-success')).toBeDefined();
+ expect(component.$el.querySelector('.ci-status-icon-success svg')).toBeDefined();
+ });
+});
diff --git a/spec/javascripts/pipelines/graph/stage_column_component_spec.js b/spec/javascripts/pipelines/graph/stage_column_component_spec.js
new file mode 100644
index 00000000000..aa4d6eedaf4
--- /dev/null
+++ b/spec/javascripts/pipelines/graph/stage_column_component_spec.js
@@ -0,0 +1,42 @@
+import Vue from 'vue';
+import stageColumnComponent from '~/pipelines/components/graph/stage_column_component.vue';
+
+describe('stage column component', () => {
+ let component;
+ const mockJob = {
+ id: 4256,
+ name: 'test',
+ status: {
+ icon: 'icon_status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ details_path: '/root/ci-mock/builds/4256',
+ action: {
+ icon: 'icon_action_retry',
+ title: 'Retry',
+ path: '/root/ci-mock/builds/4256/retry',
+ method: 'post',
+ },
+ },
+ };
+
+ beforeEach(() => {
+ const StageColumnComponent = Vue.extend(stageColumnComponent);
+
+ component = new StageColumnComponent({
+ propsData: {
+ title: 'foo',
+ jobs: [mockJob, mockJob, mockJob],
+ },
+ }).$mount();
+ });
+
+ it('should render provided title', () => {
+ expect(component.$el.querySelector('.stage-name').textContent.trim()).toEqual('foo');
+ });
+
+ it('should render the provided jobs', () => {
+ expect(component.$el.querySelectorAll('.builds-container > ul > li').length).toEqual(3);
+ });
+});
diff --git a/spec/javascripts/pipelines_spec.js b/spec/javascripts/pipelines_spec.js
index 72770a702d3..81ac589f4e6 100644
--- a/spec/javascripts/pipelines_spec.js
+++ b/spec/javascripts/pipelines_spec.js
@@ -1,30 +1,22 @@
-require('~/pipelines');
+import Pipelines from '~/pipelines';
// Fix for phantomJS
if (!Element.prototype.matches && Element.prototype.webkitMatchesSelector) {
Element.prototype.matches = Element.prototype.webkitMatchesSelector;
}
-(() => {
- describe('Pipelines', () => {
- preloadFixtures('static/pipeline_graph.html.raw');
+describe('Pipelines', () => {
+ preloadFixtures('static/pipeline_graph.html.raw');
- beforeEach(() => {
- loadFixtures('static/pipeline_graph.html.raw');
- });
-
- it('should be defined', () => {
- expect(window.gl.Pipelines).toBeDefined();
- });
-
- it('should create a `Pipelines` instance without options', () => {
- expect(() => { new window.gl.Pipelines(); }).not.toThrow(); //eslint-disable-line
- });
+ beforeEach(() => {
+ loadFixtures('static/pipeline_graph.html.raw');
+ });
- it('should create a `Pipelines` instance with options', () => {
- const pipelines = new window.gl.Pipelines({ foo: 'bar' });
+ it('should be defined', () => {
+ expect(Pipelines).toBeDefined();
+ });
- expect(pipelines.pipelineGraph).toBeDefined();
- });
+ it('should create a `Pipelines` instance without options', () => {
+ expect(() => { new Pipelines(); }).not.toThrow(); //eslint-disable-line
});
-})();
+});
diff --git a/spec/javascripts/vue_shared/ci_action_icons_spec.js b/spec/javascripts/vue_shared/ci_action_icons_spec.js
new file mode 100644
index 00000000000..2e89a07e76e
--- /dev/null
+++ b/spec/javascripts/vue_shared/ci_action_icons_spec.js
@@ -0,0 +1,22 @@
+import getActionIcon from '~/vue_shared/ci_action_icons';
+import cancelSVG from 'icons/_icon_action_cancel.svg';
+import retrySVG from 'icons/_icon_action_retry.svg';
+import playSVG from 'icons/_icon_action_play.svg';
+
+describe('getActionIcon', () => {
+ it('should return an empty string', () => {
+ expect(getActionIcon()).toEqual('');
+ });
+
+ it('should return cancel svg', () => {
+ expect(getActionIcon('icon_action_cancel')).toEqual(cancelSVG);
+ });
+
+ it('should return retry svg', () => {
+ expect(getActionIcon('icon_action_retry')).toEqual(retrySVG);
+ });
+
+ it('should return play svg', () => {
+ expect(getActionIcon('icon_action_play')).toEqual(playSVG);
+ });
+});
diff --git a/spec/javascripts/vue_shared/ci_status_icon_spec.js b/spec/javascripts/vue_shared/ci_status_icon_spec.js
new file mode 100644
index 00000000000..b6621d6054d
--- /dev/null
+++ b/spec/javascripts/vue_shared/ci_status_icon_spec.js
@@ -0,0 +1,27 @@
+import { borderlessStatusIconEntityMap, statusIconEntityMap } from '~/vue_shared/ci_status_icons';
+
+describe('CI status icons', () => {
+ const statuses = [
+ 'icon_status_canceled',
+ 'icon_status_created',
+ 'icon_status_failed',
+ 'icon_status_manual',
+ 'icon_status_pending',
+ 'icon_status_running',
+ 'icon_status_skipped',
+ 'icon_status_success',
+ 'icon_status_warning',
+ ];
+
+ it('should have a dictionary for borderless icons', () => {
+ statuses.forEach((status) => {
+ expect(borderlessStatusIconEntityMap[status]).toBeDefined();
+ });
+ });
+
+ it('should have a dictionary for icons', () => {
+ statuses.forEach((status) => {
+ expect(statusIconEntityMap[status]).toBeDefined();
+ });
+ });
+});
diff --git a/spec/javascripts/vue_shared/components/ci_icon_spec.js b/spec/javascripts/vue_shared/components/ci_icon_spec.js
new file mode 100644
index 00000000000..98dc6caa622
--- /dev/null
+++ b/spec/javascripts/vue_shared/components/ci_icon_spec.js
@@ -0,0 +1,130 @@
+import Vue from 'vue';
+import ciIcon from '~/vue_shared/components/ci_icon.vue';
+
+describe('CI Icon component', () => {
+ let CiIcon;
+ beforeEach(() => {
+ CiIcon = Vue.extend(ciIcon);
+ });
+
+ it('should render a span element with an svg', () => {
+ const component = new CiIcon({
+ propsData: {
+ status: {
+ icon: 'icon_status_success',
+ },
+ },
+ }).$mount();
+
+ expect(component.$el.tagName).toEqual('SPAN');
+ expect(component.$el.querySelector('span > svg')).toBeDefined();
+ });
+
+ it('should render a success status', () => {
+ const component = new CiIcon({
+ propsData: {
+ status: {
+ icon: 'icon_status_success',
+ },
+ },
+ }).$mount();
+
+ expect(component.$el.classList.contains('ci-status-icon-success')).toEqual(true);
+ });
+
+ it('should render a failed status', () => {
+ const component = new CiIcon({
+ propsData: {
+ status: {
+ icon: 'icon_status_failed',
+ },
+ },
+ }).$mount();
+
+ expect(component.$el.classList.contains('ci-status-icon-failed')).toEqual(true);
+ });
+
+ it('should render success with warnings status', () => {
+ const component = new CiIcon({
+ propsData: {
+ status: {
+ icon: 'icon_status_warning',
+ },
+ },
+ }).$mount();
+
+ expect(component.$el.classList.contains('ci-status-icon-warning')).toEqual(true);
+ });
+
+ it('should render pending status', () => {
+ const component = new CiIcon({
+ propsData: {
+ status: {
+ icon: 'icon_status_pending',
+ },
+ },
+ }).$mount();
+
+ expect(component.$el.classList.contains('ci-status-icon-pending')).toEqual(true);
+ });
+
+ it('should render running status', () => {
+ const component = new CiIcon({
+ propsData: {
+ status: {
+ icon: 'icon_status_running',
+ },
+ },
+ }).$mount();
+
+ expect(component.$el.classList.contains('ci-status-icon-running')).toEqual(true);
+ });
+
+ it('should render created status', () => {
+ const component = new CiIcon({
+ propsData: {
+ status: {
+ icon: 'icon_status_created',
+ },
+ },
+ }).$mount();
+
+ expect(component.$el.classList.contains('ci-status-icon-created')).toEqual(true);
+ });
+
+ it('should render skipped status', () => {
+ const component = new CiIcon({
+ propsData: {
+ status: {
+ icon: 'icon_status_skipped',
+ },
+ },
+ }).$mount();
+
+ expect(component.$el.classList.contains('ci-status-icon-skipped')).toEqual(true);
+ });
+
+ it('should render canceled status', () => {
+ const component = new CiIcon({
+ propsData: {
+ status: {
+ icon: 'icon_status_canceled',
+ },
+ },
+ }).$mount();
+
+ expect(component.$el.classList.contains('ci-status-icon-canceled')).toEqual(true);
+ });
+
+ it('should render status for manual action', () => {
+ const component = new CiIcon({
+ propsData: {
+ status: {
+ icon: 'icon_status_manual',
+ },
+ },
+ }).$mount();
+
+ expect(component.$el.classList.contains('ci-status-icon-manual')).toEqual(true);
+ });
+});