summaryrefslogtreecommitdiff
path: root/spec/javascripts/ide
diff options
context:
space:
mode:
authorFilipa Lacerda <filipa@gitlab.com>2018-06-01 08:45:35 +0000
committerFilipa Lacerda <filipa@gitlab.com>2018-06-01 08:45:35 +0000
commit5b9e4d986a70b0dd4088598c500fd0cd9e85f25e (patch)
tree5a89d79a60b547835bda6451deaca2bb434343a6 /spec/javascripts/ide
parente12471862bd2c29d4e63dc4cbeece9d9008ef4a0 (diff)
parent745d353801ce8a961c010edc02925fa8470158fd (diff)
downloadgitlab-ce-5b9e4d986a70b0dd4088598c500fd0cd9e85f25e.tar.gz
Merge branch 'ide-jobs-list-components' into 'master'
Show CI jobs in IDE Closes #44604 See merge request gitlab-org/gitlab-ce!19106
Diffstat (limited to 'spec/javascripts/ide')
-rw-r--r--spec/javascripts/ide/components/jobs/item_spec.js29
-rw-r--r--spec/javascripts/ide/components/jobs/list_spec.js67
-rw-r--r--spec/javascripts/ide/components/jobs/stage_spec.js95
-rw-r--r--spec/javascripts/ide/components/pipelines/list_spec.js117
-rw-r--r--spec/javascripts/ide/helpers.js2
-rw-r--r--spec/javascripts/ide/mock_data.js70
-rw-r--r--spec/javascripts/ide/stores/actions/project_spec.js111
-rw-r--r--spec/javascripts/ide/stores/modules/pipelines/actions_spec.js265
-rw-r--r--spec/javascripts/ide/stores/modules/pipelines/getters_spec.js31
-rw-r--r--spec/javascripts/ide/stores/modules/pipelines/mutations_spec.js162
-rw-r--r--spec/javascripts/ide/stores/mutations/branch_spec.js36
11 files changed, 611 insertions, 374 deletions
diff --git a/spec/javascripts/ide/components/jobs/item_spec.js b/spec/javascripts/ide/components/jobs/item_spec.js
new file mode 100644
index 00000000000..7c1dd4e475c
--- /dev/null
+++ b/spec/javascripts/ide/components/jobs/item_spec.js
@@ -0,0 +1,29 @@
+import Vue from 'vue';
+import JobItem from '~/ide/components/jobs/item.vue';
+import mountComponent from '../../../helpers/vue_mount_component_helper';
+import { jobs } from '../../mock_data';
+
+describe('IDE jobs item', () => {
+ const Component = Vue.extend(JobItem);
+ const job = jobs[0];
+ let vm;
+
+ beforeEach(() => {
+ vm = mountComponent(Component, {
+ job,
+ });
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('renders job details', () => {
+ expect(vm.$el.textContent).toContain(job.name);
+ expect(vm.$el.textContent).toContain(`#${job.id}`);
+ });
+
+ it('renders CI icon', () => {
+ expect(vm.$el.querySelector('.ic-status_passed_borderless')).not.toBe(null);
+ });
+});
diff --git a/spec/javascripts/ide/components/jobs/list_spec.js b/spec/javascripts/ide/components/jobs/list_spec.js
new file mode 100644
index 00000000000..b24853c56fa
--- /dev/null
+++ b/spec/javascripts/ide/components/jobs/list_spec.js
@@ -0,0 +1,67 @@
+import Vue from 'vue';
+import StageList from '~/ide/components/jobs/list.vue';
+import { createStore } from '~/ide/stores';
+import { createComponentWithStore } from '../../../helpers/vue_mount_component_helper';
+import { stages, jobs } from '../../mock_data';
+
+describe('IDE stages list', () => {
+ const Component = Vue.extend(StageList);
+ let vm;
+
+ beforeEach(() => {
+ const store = createStore();
+
+ vm = createComponentWithStore(Component, store, {
+ stages: stages.map((mappedState, i) => ({
+ ...mappedState,
+ id: i,
+ dropdownPath: mappedState.dropdown_path,
+ jobs: [...jobs],
+ isLoading: false,
+ isCollapsed: false,
+ })),
+ loading: false,
+ });
+
+ spyOn(vm, 'fetchJobs');
+ spyOn(vm, 'toggleStageCollapsed');
+
+ vm.$mount();
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('renders list of stages', () => {
+ expect(vm.$el.querySelectorAll('.card').length).toBe(2);
+ });
+
+ it('renders loading icon when no stages & is loading', done => {
+ vm.stages = [];
+ vm.loading = true;
+
+ vm.$nextTick(() => {
+ expect(vm.$el.querySelector('.loading-container')).not.toBe(null);
+
+ done();
+ });
+ });
+
+ it('calls toggleStageCollapsed when clicking stage header', done => {
+ vm.$el.querySelector('.card-header').click();
+
+ vm.$nextTick(() => {
+ expect(vm.toggleStageCollapsed).toHaveBeenCalledWith(0);
+
+ done();
+ });
+ });
+
+ it('calls fetchJobs when stage is mounted', () => {
+ expect(vm.fetchJobs.calls.count()).toBe(stages.length);
+
+ expect(vm.fetchJobs.calls.argsFor(0)).toEqual([vm.stages[0]]);
+ expect(vm.fetchJobs.calls.argsFor(1)).toEqual([vm.stages[1]]);
+ });
+});
diff --git a/spec/javascripts/ide/components/jobs/stage_spec.js b/spec/javascripts/ide/components/jobs/stage_spec.js
new file mode 100644
index 00000000000..fc3831f2d05
--- /dev/null
+++ b/spec/javascripts/ide/components/jobs/stage_spec.js
@@ -0,0 +1,95 @@
+import Vue from 'vue';
+import Stage from '~/ide/components/jobs/stage.vue';
+import { stages, jobs } from '../../mock_data';
+
+describe('IDE pipeline stage', () => {
+ const Component = Vue.extend(Stage);
+ let vm;
+ let stage;
+
+ beforeEach(() => {
+ stage = {
+ ...stages[0],
+ id: 0,
+ dropdownPath: stages[0].dropdown_path,
+ jobs: [...jobs],
+ isLoading: false,
+ isCollapsed: false,
+ };
+
+ vm = new Component({
+ propsData: { stage },
+ });
+
+ spyOn(vm, '$emit');
+
+ vm.$mount();
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('emits fetch event when mounted', () => {
+ expect(vm.$emit).toHaveBeenCalledWith('fetch', vm.stage);
+ });
+
+ it('renders stages details', () => {
+ expect(vm.$el.textContent).toContain(vm.stage.name);
+ });
+
+ it('renders CI icon', () => {
+ expect(vm.$el.querySelector('.ic-status_failed')).not.toBe(null);
+ });
+
+ describe('collapsed', () => {
+ it('emits event when clicking header', done => {
+ vm.$el.querySelector('.card-header').click();
+
+ vm.$nextTick(() => {
+ expect(vm.$emit).toHaveBeenCalledWith('toggleCollapsed', vm.stage.id);
+
+ done();
+ });
+ });
+
+ it('toggles collapse status when collapsed', done => {
+ vm.stage.isCollapsed = true;
+
+ vm.$nextTick(() => {
+ expect(vm.$el.querySelector('.card-body').style.display).toBe('none');
+
+ done();
+ });
+ });
+
+ it('sets border bottom class when collapsed', done => {
+ vm.stage.isCollapsed = true;
+
+ vm.$nextTick(() => {
+ expect(vm.$el.querySelector('.card-header').classList).toContain('border-bottom-0');
+
+ done();
+ });
+ });
+ });
+
+ it('renders jobs count', () => {
+ expect(vm.$el.querySelector('.badge').textContent).toContain('4');
+ });
+
+ it('renders loading icon when no jobs and isLoading is true', done => {
+ vm.stage.isLoading = true;
+ vm.stage.jobs = [];
+
+ vm.$nextTick(() => {
+ expect(vm.$el.querySelector('.loading-container')).not.toBe(null);
+
+ done();
+ });
+ });
+
+ it('renders list of jobs', () => {
+ expect(vm.$el.querySelectorAll('.ide-job-item').length).toBe(4);
+ });
+});
diff --git a/spec/javascripts/ide/components/pipelines/list_spec.js b/spec/javascripts/ide/components/pipelines/list_spec.js
new file mode 100644
index 00000000000..2bb5aa08c3b
--- /dev/null
+++ b/spec/javascripts/ide/components/pipelines/list_spec.js
@@ -0,0 +1,117 @@
+import Vue from 'vue';
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
+import { createStore } from '~/ide/stores';
+import List from '~/ide/components/pipelines/list.vue';
+import { createComponentWithStore } from '../../../helpers/vue_mount_component_helper';
+import { pipelines, projectData, stages, jobs } from '../../mock_data';
+
+describe('IDE pipelines list', () => {
+ const Component = Vue.extend(List);
+ let vm;
+ let mock;
+
+ beforeEach(done => {
+ const store = createStore();
+
+ mock = new MockAdapter(axios);
+
+ store.state.currentProjectId = 'abc/def';
+ store.state.currentBranchId = 'master';
+ store.state.projects['abc/def'] = {
+ ...projectData,
+ path_with_namespace: 'abc/def',
+ branches: {
+ master: { commit: { id: '123' } },
+ },
+ };
+ store.state.links = { ciHelpPagePath: gl.TEST_HOST };
+ store.state.pipelinesEmptyStateSvgPath = gl.TEST_HOST;
+ store.state.pipelines.stages = stages.map((mappedState, i) => ({
+ ...mappedState,
+ id: i,
+ dropdownPath: mappedState.dropdown_path,
+ jobs: [...jobs],
+ isLoading: false,
+ isCollapsed: false,
+ }));
+
+ mock
+ .onGet('/abc/def/commit/123/pipelines')
+ .replyOnce(200, { pipelines: [...pipelines] }, { 'poll-interval': '-1' });
+
+ vm = createComponentWithStore(Component, store).$mount();
+
+ setTimeout(done);
+ });
+
+ afterEach(() => {
+ vm.$store.dispatch('pipelines/stopPipelinePolling');
+ vm.$store.dispatch('pipelines/clearEtagPoll');
+
+ vm.$destroy();
+ mock.restore();
+ });
+
+ it('renders pipeline data', () => {
+ expect(vm.$el.textContent).toContain('#1');
+ });
+
+ it('renders CI icon', () => {
+ expect(vm.$el.querySelector('.ci-status-icon-failed')).not.toBe(null);
+ });
+
+ it('renders list of jobs', () => {
+ expect(vm.$el.querySelectorAll('.tab-pane:first-child .ide-job-item').length).toBe(
+ jobs.length * stages.length,
+ );
+ });
+
+ it('renders list of failed jobs on failed jobs tab', done => {
+ vm.$el.querySelectorAll('.tab-links a')[1].click();
+
+ vm.$nextTick(() => {
+ expect(vm.$el.querySelectorAll('.tab-pane.active .ide-job-item').length).toBe(2);
+
+ done();
+ });
+ });
+
+ describe('YAML error', () => {
+ it('renders YAML error', done => {
+ vm.$store.state.pipelines.latestPipeline.yamlError = 'test yaml error';
+
+ vm.$nextTick(() => {
+ expect(vm.$el.textContent).toContain('Found errors in your .gitlab-ci.yml:');
+ expect(vm.$el.textContent).toContain('test yaml error');
+
+ done();
+ });
+ });
+ });
+
+ describe('empty state', () => {
+ it('renders pipelines empty state', done => {
+ vm.$store.state.pipelines.latestPipeline = false;
+
+ vm.$nextTick(() => {
+ expect(vm.$el.querySelector('.empty-state')).not.toBe(null);
+
+ done();
+ });
+ });
+ });
+
+ describe('loading state', () => {
+ it('renders loading state when there is no latest pipeline', done => {
+ vm.$store.state.pipelines.latestPipeline = null;
+ vm.$store.state.pipelines.isLoadingPipeline = true;
+
+ vm.$nextTick(() => {
+ expect(vm.$el.querySelector('.loading-container')).not.toBe(null);
+
+ done();
+ });
+ });
+ });
+});
diff --git a/spec/javascripts/ide/helpers.js b/spec/javascripts/ide/helpers.js
index 98db6defc7a..5c7e2db0e96 100644
--- a/spec/javascripts/ide/helpers.js
+++ b/spec/javascripts/ide/helpers.js
@@ -1,11 +1,13 @@
import { decorateData } from '~/ide/stores/utils';
import state from '~/ide/stores/state';
import commitState from '~/ide/stores/modules/commit/state';
+import pipelinesState from '~/ide/stores/modules/pipelines/state';
export const resetStore = store => {
const newState = {
...state(),
commit: commitState(),
+ pipelines: pipelinesState(),
};
store.replaceState(newState);
};
diff --git a/spec/javascripts/ide/mock_data.js b/spec/javascripts/ide/mock_data.js
index c68ae050641..8ad51e122b6 100644
--- a/spec/javascripts/ide/mock_data.js
+++ b/spec/javascripts/ide/mock_data.js
@@ -19,13 +19,48 @@ export const pipelines = [
id: 1,
ref: 'master',
sha: '123',
- status: 'failed',
+ details: {
+ status: {
+ icon: 'status_failed',
+ group: 'failed',
+ text: 'Failed',
+ },
+ },
+ commit: { id: '123' },
},
{
id: 2,
ref: 'master',
sha: '213',
- status: 'success',
+ details: {
+ status: {
+ icon: 'status_failed',
+ group: 'failed',
+ text: 'Failed',
+ },
+ },
+ commit: { id: '213' },
+ },
+];
+
+export const stages = [
+ {
+ dropdown_path: `${gl.TEST_HOST}/testing`,
+ name: 'build',
+ status: {
+ icon: 'status_failed',
+ group: 'failed',
+ text: 'failed',
+ },
+ },
+ {
+ dropdown_path: 'testing',
+ name: 'test',
+ status: {
+ icon: 'status_failed',
+ group: 'failed',
+ text: 'failed',
+ },
},
];
@@ -33,28 +68,44 @@ export const jobs = [
{
id: 1,
name: 'test',
- status: 'failed',
+ path: 'testing',
+ status: {
+ icon: 'status_passed',
+ text: 'passed',
+ },
stage: 'test',
duration: 1,
},
{
id: 2,
name: 'test 2',
- status: 'failed',
+ path: 'testing2',
+ status: {
+ icon: 'status_passed',
+ text: 'passed',
+ },
stage: 'test',
duration: 1,
},
{
id: 3,
name: 'test 3',
- status: 'failed',
+ path: 'testing3',
+ status: {
+ icon: 'status_passed',
+ text: 'passed',
+ },
stage: 'test',
duration: 1,
},
{
id: 4,
- name: 'test 3',
- status: 'failed',
+ name: 'test 4',
+ path: 'testing4',
+ status: {
+ icon: 'status_failed',
+ text: 'failed',
+ },
stage: 'build',
duration: 1,
},
@@ -68,14 +119,16 @@ export const fullPipelinesResponse = {
pipelines: [
{
id: '51',
+ path: 'test',
commit: {
- id: 'xxxxxxxxxxxxxxxxxxxx',
+ id: '123',
},
details: {
status: {
icon: 'status_failed',
text: 'failed',
},
+ stages: [...stages],
},
},
{
@@ -88,6 +141,7 @@ export const fullPipelinesResponse = {
icon: 'status_passed',
text: 'passed',
},
+ stages: [...stages],
},
},
],
diff --git a/spec/javascripts/ide/stores/actions/project_spec.js b/spec/javascripts/ide/stores/actions/project_spec.js
index 8e078ae7138..d71fc0e035e 100644
--- a/spec/javascripts/ide/stores/actions/project_spec.js
+++ b/spec/javascripts/ide/stores/actions/project_spec.js
@@ -1,31 +1,10 @@
-import Visibility from 'visibilityjs';
-import MockAdapter from 'axios-mock-adapter';
-import { refreshLastCommitData, pollSuccessCallBack } from '~/ide/stores/actions';
+import { refreshLastCommitData } from '~/ide/stores/actions';
import store from '~/ide/stores';
import service from '~/ide/services';
-import axios from '~/lib/utils/axios_utils';
-import { fullPipelinesResponse } from '../../mock_data';
import { resetStore } from '../../helpers';
import testAction from '../../../helpers/vuex_action_helper';
describe('IDE store project actions', () => {
- const setProjectState = () => {
- store.state.currentProjectId = 'abc/def';
- store.state.currentBranchId = 'master';
- store.state.projects['abc/def'] = {
- id: 4,
- path_with_namespace: 'abc/def',
- branches: {
- master: {
- commit: {
- id: 'abc123def456ghi789jkl',
- title: 'example',
- },
- },
- },
- };
- };
-
beforeEach(() => {
store.state.projects['abc/def'] = {};
});
@@ -101,92 +80,4 @@ describe('IDE store project actions', () => {
);
});
});
-
- describe('pipelinePoll', () => {
- let mock;
-
- beforeEach(() => {
- setProjectState();
- jasmine.clock().install();
- mock = new MockAdapter(axios);
- mock
- .onGet('/abc/def/commit/abc123def456ghi789jkl/pipelines')
- .reply(200, { data: { foo: 'bar' } }, { 'poll-interval': '10000' });
- });
-
- afterEach(() => {
- jasmine.clock().uninstall();
- mock.restore();
- store.dispatch('stopPipelinePolling');
- });
-
- it('calls service periodically', done => {
- spyOn(axios, 'get').and.callThrough();
- spyOn(Visibility, 'hidden').and.returnValue(false);
-
- store
- .dispatch('pipelinePoll')
- .then(() => {
- jasmine.clock().tick(1000);
-
- expect(axios.get).toHaveBeenCalled();
- expect(axios.get.calls.count()).toBe(1);
- })
- .then(() => new Promise(resolve => requestAnimationFrame(resolve)))
- .then(() => {
- jasmine.clock().tick(10000);
- expect(axios.get.calls.count()).toBe(2);
- })
- .then(() => new Promise(resolve => requestAnimationFrame(resolve)))
- .then(() => {
- jasmine.clock().tick(10000);
- expect(axios.get.calls.count()).toBe(3);
- })
- .then(() => new Promise(resolve => requestAnimationFrame(resolve)))
- .then(() => {
- jasmine.clock().tick(10000);
- expect(axios.get.calls.count()).toBe(4);
- })
-
- .then(done)
- .catch(done.fail);
- });
- });
-
- describe('pollSuccessCallBack', () => {
- beforeEach(() => {
- setProjectState();
- });
-
- it('commits correct pipeline', done => {
- testAction(
- pollSuccessCallBack,
- fullPipelinesResponse,
- store.state,
- [
- {
- type: 'SET_LAST_COMMIT_PIPELINE',
- payload: {
- projectId: 'abc/def',
- branchId: 'master',
- pipeline: {
- id: '50',
- commit: {
- id: 'abc123def456ghi789jkl',
- },
- details: {
- status: {
- icon: 'status_passed',
- text: 'passed',
- },
- },
- },
- },
- },
- ], // mutations
- [], // action
- done,
- );
- });
- });
});
diff --git a/spec/javascripts/ide/stores/modules/pipelines/actions_spec.js b/spec/javascripts/ide/stores/modules/pipelines/actions_spec.js
index 85fbcf8084b..f26eaf9c81f 100644
--- a/spec/javascripts/ide/stores/modules/pipelines/actions_spec.js
+++ b/spec/javascripts/ide/stores/modules/pipelines/actions_spec.js
@@ -1,3 +1,4 @@
+import Visibility from 'visibilityjs';
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import actions, {
@@ -5,10 +6,13 @@ import actions, {
receiveLatestPipelineError,
receiveLatestPipelineSuccess,
fetchLatestPipeline,
+ stopPipelinePolling,
+ clearEtagPoll,
requestJobs,
receiveJobsError,
receiveJobsSuccess,
fetchJobs,
+ toggleStageCollapsed,
} from '~/ide/stores/modules/pipelines/actions';
import state from '~/ide/stores/modules/pipelines/state';
import * as types from '~/ide/stores/modules/pipelines/mutation_types';
@@ -51,7 +55,7 @@ describe('IDE pipelines actions', () => {
null,
mockedState,
[{ type: types.RECEIVE_LASTEST_PIPELINE_ERROR }],
- [],
+ [{ type: 'stopPipelinePolling' }],
done,
);
});
@@ -59,91 +63,128 @@ describe('IDE pipelines actions', () => {
it('creates flash message', () => {
const flashSpy = spyOnDependency(actions, 'flash');
- receiveLatestPipelineError({ commit() {} });
+ receiveLatestPipelineError({ commit() {}, dispatch() {} });
expect(flashSpy).toHaveBeenCalled();
});
});
describe('receiveLatestPipelineSuccess', () => {
- it('commits pipeline', done => {
- testAction(
- receiveLatestPipelineSuccess,
+ const rootGetters = {
+ lastCommit: { id: '123' },
+ };
+ let commit;
+
+ beforeEach(() => {
+ commit = jasmine.createSpy('commit');
+ });
+
+ it('commits pipeline', () => {
+ receiveLatestPipelineSuccess({ rootGetters, commit }, { pipelines });
+
+ expect(commit.calls.argsFor(0)).toEqual([
+ types.RECEIVE_LASTEST_PIPELINE_SUCCESS,
pipelines[0],
- mockedState,
- [{ type: types.RECEIVE_LASTEST_PIPELINE_SUCCESS, payload: pipelines[0] }],
- [],
- done,
- );
+ ]);
+ });
+
+ it('commits false when there are no pipelines', () => {
+ receiveLatestPipelineSuccess({ rootGetters, commit }, { pipelines: [] });
+
+ expect(commit.calls.argsFor(0)).toEqual([types.RECEIVE_LASTEST_PIPELINE_SUCCESS, false]);
});
});
describe('fetchLatestPipeline', () => {
+ beforeEach(() => {
+ jasmine.clock().install();
+ });
+
+ afterEach(() => {
+ jasmine.clock().uninstall();
+ stopPipelinePolling();
+ clearEtagPoll();
+ });
+
describe('success', () => {
beforeEach(() => {
- mock.onGet(/\/api\/v4\/projects\/(.*)\/pipelines(.*)/).replyOnce(200, pipelines);
+ mock
+ .onGet('/abc/def/commit/abc123def456ghi789jkl/pipelines')
+ .reply(200, { data: { foo: 'bar' } }, { 'poll-interval': '10000' });
});
it('dispatches request', done => {
- testAction(
- fetchLatestPipeline,
- '123',
- mockedState,
- [],
- [{ type: 'requestLatestPipeline' }, { type: 'receiveLatestPipelineSuccess' }],
- done,
- );
- });
-
- it('dispatches success with latest pipeline', done => {
- testAction(
- fetchLatestPipeline,
- '123',
- mockedState,
- [],
- [
- { type: 'requestLatestPipeline' },
- { type: 'receiveLatestPipelineSuccess', payload: pipelines[0] },
- ],
- done,
- );
- });
-
- it('calls axios with correct params', () => {
- const apiSpy = spyOn(axios, 'get').and.callThrough();
-
- fetchLatestPipeline({ dispatch() {}, rootState: state }, '123');
-
- expect(apiSpy).toHaveBeenCalledWith(jasmine.anything(), {
- params: {
- sha: '123',
- per_page: '1',
- },
- });
+ spyOn(axios, 'get').and.callThrough();
+ spyOn(Visibility, 'hidden').and.returnValue(false);
+
+ const dispatch = jasmine.createSpy('dispatch');
+ const rootGetters = {
+ lastCommit: { id: 'abc123def456ghi789jkl' },
+ currentProject: { path_with_namespace: 'abc/def' },
+ };
+
+ fetchLatestPipeline({ dispatch, rootGetters });
+
+ expect(dispatch.calls.argsFor(0)).toEqual(['requestLatestPipeline']);
+
+ jasmine.clock().tick(1000);
+
+ new Promise(resolve => requestAnimationFrame(resolve))
+ .then(() => {
+ expect(axios.get).toHaveBeenCalled();
+ expect(axios.get.calls.count()).toBe(1);
+
+ expect(dispatch.calls.argsFor(1)).toEqual([
+ 'receiveLatestPipelineSuccess',
+ jasmine.anything(),
+ ]);
+
+ jasmine.clock().tick(10000);
+ })
+ .then(() => new Promise(resolve => requestAnimationFrame(resolve)))
+ .then(() => {
+ expect(axios.get).toHaveBeenCalled();
+ expect(axios.get.calls.count()).toBe(2);
+
+ expect(dispatch.calls.argsFor(2)).toEqual([
+ 'receiveLatestPipelineSuccess',
+ jasmine.anything(),
+ ]);
+ })
+ .then(done)
+ .catch(done.fail);
});
});
describe('error', () => {
beforeEach(() => {
- mock.onGet(/\/api\/v4\/projects\/(.*)\/pipelines(.*)/).replyOnce(500);
+ mock.onGet('/abc/def/commit/abc123def456ghi789jkl/pipelines').reply(500);
});
it('dispatches error', done => {
- testAction(
- fetchLatestPipeline,
- '123',
- mockedState,
- [],
- [{ type: 'requestLatestPipeline' }, { type: 'receiveLatestPipelineError' }],
- done,
- );
+ const dispatch = jasmine.createSpy('dispatch');
+ const rootGetters = {
+ lastCommit: { id: 'abc123def456ghi789jkl' },
+ currentProject: { path_with_namespace: 'abc/def' },
+ };
+
+ fetchLatestPipeline({ dispatch, rootGetters });
+
+ jasmine.clock().tick(1500);
+
+ new Promise(resolve => requestAnimationFrame(resolve))
+ .then(() => {
+ expect(dispatch.calls.argsFor(1)).toEqual(['receiveLatestPipelineError']);
+ })
+ .then(done)
+ .catch(done.fail);
});
});
});
describe('requestJobs', () => {
it('commits request', done => {
- testAction(requestJobs, null, mockedState, [{ type: types.REQUEST_JOBS }], [], done);
+ testAction(requestJobs, 1, mockedState, [{ type: types.REQUEST_JOBS, payload: 1 }], [], done);
});
});
@@ -151,9 +192,9 @@ describe('IDE pipelines actions', () => {
it('commits error', done => {
testAction(
receiveJobsError,
- null,
+ 1,
mockedState,
- [{ type: types.RECEIVE_JOBS_ERROR }],
+ [{ type: types.RECEIVE_JOBS_ERROR, payload: 1 }],
[],
done,
);
@@ -162,19 +203,19 @@ describe('IDE pipelines actions', () => {
it('creates flash message', () => {
const flashSpy = spyOnDependency(actions, 'flash');
- receiveJobsError({ commit() {} });
+ receiveJobsError({ commit() {} }, 1);
expect(flashSpy).toHaveBeenCalled();
});
});
describe('receiveJobsSuccess', () => {
- it('commits jobs', done => {
+ it('commits data', done => {
testAction(
receiveJobsSuccess,
- jobs,
+ { id: 1, data: jobs },
mockedState,
- [{ type: types.RECEIVE_JOBS_SUCCESS, payload: jobs }],
+ [{ type: types.RECEIVE_JOBS_SUCCESS, payload: { id: 1, data: jobs } }],
[],
done,
);
@@ -182,108 +223,62 @@ describe('IDE pipelines actions', () => {
});
describe('fetchJobs', () => {
- let page = '';
-
- beforeEach(() => {
- mockedState.latestPipeline = pipelines[0];
- });
+ const stage = {
+ id: 1,
+ dropdownPath: `${gl.TEST_HOST}/jobs`,
+ };
describe('success', () => {
beforeEach(() => {
- mock.onGet(/\/api\/v4\/projects\/(.*)\/pipelines\/(.*)\/jobs/).replyOnce(() => [
- 200,
- jobs,
- {
- 'x-next-page': page,
- },
- ]);
+ mock.onGet(stage.dropdownPath).replyOnce(200, jobs);
});
it('dispatches request', done => {
testAction(
fetchJobs,
- null,
- mockedState,
- [],
- [{ type: 'requestJobs' }, { type: 'receiveJobsSuccess' }],
- done,
- );
- });
-
- it('dispatches success with latest pipeline', done => {
- testAction(
- fetchJobs,
- null,
- mockedState,
- [],
- [{ type: 'requestJobs' }, { type: 'receiveJobsSuccess', payload: jobs }],
- done,
- );
- });
-
- it('dispatches twice for both pages', done => {
- page = '2';
-
- testAction(
- fetchJobs,
- null,
+ stage,
mockedState,
[],
[
- { type: 'requestJobs' },
- { type: 'receiveJobsSuccess', payload: jobs },
- { type: 'fetchJobs', payload: '2' },
- { type: 'requestJobs' },
- { type: 'receiveJobsSuccess', payload: jobs },
+ { type: 'requestJobs', payload: stage.id },
+ { type: 'receiveJobsSuccess', payload: { id: stage.id, data: jobs } },
],
done,
);
});
-
- it('calls axios with correct URL', () => {
- const apiSpy = spyOn(axios, 'get').and.callThrough();
-
- fetchJobs({ dispatch() {}, state: mockedState, rootState: mockedState });
-
- expect(apiSpy).toHaveBeenCalledWith('/api/v4/projects/test%2Fproject/pipelines/1/jobs', {
- params: { page: '1' },
- });
- });
-
- it('calls axios with page next page', () => {
- const apiSpy = spyOn(axios, 'get').and.callThrough();
-
- fetchJobs({ dispatch() {}, state: mockedState, rootState: mockedState });
-
- expect(apiSpy).toHaveBeenCalledWith('/api/v4/projects/test%2Fproject/pipelines/1/jobs', {
- params: { page: '1' },
- });
-
- page = '2';
-
- fetchJobs({ dispatch() {}, state: mockedState, rootState: mockedState }, page);
-
- expect(apiSpy).toHaveBeenCalledWith('/api/v4/projects/test%2Fproject/pipelines/1/jobs', {
- params: { page: '2' },
- });
- });
});
describe('error', () => {
beforeEach(() => {
- mock.onGet(/\/api\/v4\/projects\/(.*)\/pipelines(.*)/).replyOnce(500);
+ mock.onGet(stage.dropdownPath).replyOnce(500);
});
it('dispatches error', done => {
testAction(
fetchJobs,
- null,
+ stage,
mockedState,
[],
- [{ type: 'requestJobs' }, { type: 'receiveJobsError' }],
+ [
+ { type: 'requestJobs', payload: stage.id },
+ { type: 'receiveJobsError', payload: stage.id },
+ ],
done,
);
});
});
});
+
+ describe('toggleStageCollapsed', () => {
+ it('commits collapse', done => {
+ testAction(
+ toggleStageCollapsed,
+ 1,
+ mockedState,
+ [{ type: types.TOGGLE_STAGE_COLLAPSE, payload: 1 }],
+ [],
+ done,
+ );
+ });
+ });
});
diff --git a/spec/javascripts/ide/stores/modules/pipelines/getters_spec.js b/spec/javascripts/ide/stores/modules/pipelines/getters_spec.js
index b2a7e8a9025..4514896b5ea 100644
--- a/spec/javascripts/ide/stores/modules/pipelines/getters_spec.js
+++ b/spec/javascripts/ide/stores/modules/pipelines/getters_spec.js
@@ -37,35 +37,4 @@ describe('IDE pipeline getters', () => {
expect(getters.hasLatestPipeline(mockedState)).toBe(true);
});
});
-
- describe('failedJobs', () => {
- it('returns array of failed jobs', () => {
- mockedState.stages = [
- {
- title: 'test',
- jobs: [{ id: 1, status: 'failed' }, { id: 2, status: 'success' }],
- },
- {
- title: 'build',
- jobs: [{ id: 3, status: 'failed' }, { id: 4, status: 'failed' }],
- },
- ];
-
- expect(getters.failedJobs(mockedState).length).toBe(3);
- expect(getters.failedJobs(mockedState)).toEqual([
- {
- id: 1,
- status: jasmine.anything(),
- },
- {
- id: 3,
- status: jasmine.anything(),
- },
- {
- id: 4,
- status: jasmine.anything(),
- },
- ]);
- });
- });
});
diff --git a/spec/javascripts/ide/stores/modules/pipelines/mutations_spec.js b/spec/javascripts/ide/stores/modules/pipelines/mutations_spec.js
index 8262e916243..6285c01d483 100644
--- a/spec/javascripts/ide/stores/modules/pipelines/mutations_spec.js
+++ b/spec/javascripts/ide/stores/modules/pipelines/mutations_spec.js
@@ -1,7 +1,7 @@
import mutations from '~/ide/stores/modules/pipelines/mutations';
import state from '~/ide/stores/modules/pipelines/state';
import * as types from '~/ide/stores/modules/pipelines/mutation_types';
-import { pipelines, jobs } from '../../../mock_data';
+import { fullPipelinesResponse, stages, jobs } from '../../../mock_data';
describe('IDE pipelines mutations', () => {
let mockedState;
@@ -28,93 +28,147 @@ describe('IDE pipelines mutations', () => {
describe(types.RECEIVE_LASTEST_PIPELINE_SUCCESS, () => {
it('sets loading to false on success', () => {
- mutations[types.RECEIVE_LASTEST_PIPELINE_SUCCESS](mockedState, pipelines[0]);
+ mutations[types.RECEIVE_LASTEST_PIPELINE_SUCCESS](
+ mockedState,
+ fullPipelinesResponse.data.pipelines[0],
+ );
expect(mockedState.isLoadingPipeline).toBe(false);
});
it('sets latestPipeline', () => {
- mutations[types.RECEIVE_LASTEST_PIPELINE_SUCCESS](mockedState, pipelines[0]);
+ mutations[types.RECEIVE_LASTEST_PIPELINE_SUCCESS](
+ mockedState,
+ fullPipelinesResponse.data.pipelines[0],
+ );
expect(mockedState.latestPipeline).toEqual({
- id: pipelines[0].id,
- status: pipelines[0].status,
+ id: '51',
+ path: 'test',
+ commit: { id: '123' },
+ details: { status: jasmine.any(Object) },
+ yamlError: undefined,
});
});
it('does not set latest pipeline if pipeline is null', () => {
mutations[types.RECEIVE_LASTEST_PIPELINE_SUCCESS](mockedState, null);
- expect(mockedState.latestPipeline).toEqual(null);
+ expect(mockedState.latestPipeline).toEqual(false);
+ });
+
+ it('sets stages', () => {
+ mutations[types.RECEIVE_LASTEST_PIPELINE_SUCCESS](
+ mockedState,
+ fullPipelinesResponse.data.pipelines[0],
+ );
+
+ expect(mockedState.stages.length).toBe(2);
+ expect(mockedState.stages).toEqual([
+ {
+ id: 0,
+ dropdownPath: stages[0].dropdown_path,
+ name: stages[0].name,
+ status: stages[0].status,
+ isCollapsed: false,
+ isLoading: false,
+ jobs: [],
+ },
+ {
+ id: 1,
+ dropdownPath: stages[1].dropdown_path,
+ name: stages[1].name,
+ status: stages[1].status,
+ isCollapsed: false,
+ isLoading: false,
+ jobs: [],
+ },
+ ]);
});
});
describe(types.REQUEST_JOBS, () => {
- it('sets jobs loading to true', () => {
- mutations[types.REQUEST_JOBS](mockedState);
+ beforeEach(() => {
+ mockedState.stages = stages.map((stage, i) => ({
+ ...stage,
+ id: i,
+ }));
+ });
+
+ it('sets isLoading on stage', () => {
+ mutations[types.REQUEST_JOBS](mockedState, mockedState.stages[0].id);
- expect(mockedState.isLoadingJobs).toBe(true);
+ expect(mockedState.stages[0].isLoading).toBe(true);
});
});
describe(types.RECEIVE_JOBS_ERROR, () => {
- it('sets jobs loading to false', () => {
- mutations[types.RECEIVE_JOBS_ERROR](mockedState);
+ beforeEach(() => {
+ mockedState.stages = stages.map((stage, i) => ({
+ ...stage,
+ id: i,
+ }));
+ });
+
+ it('sets isLoading on stage after error', () => {
+ mutations[types.RECEIVE_JOBS_ERROR](mockedState, mockedState.stages[0].id);
- expect(mockedState.isLoadingJobs).toBe(false);
+ expect(mockedState.stages[0].isLoading).toBe(false);
});
});
describe(types.RECEIVE_JOBS_SUCCESS, () => {
- it('sets jobs loading to false on success', () => {
- mutations[types.RECEIVE_JOBS_SUCCESS](mockedState, jobs);
+ let data;
- expect(mockedState.isLoadingJobs).toBe(false);
+ beforeEach(() => {
+ mockedState.stages = stages.map((stage, i) => ({
+ ...stage,
+ id: i,
+ }));
+
+ data = {
+ latest_statuses: [...jobs],
+ };
});
- it('sets stages', () => {
- mutations[types.RECEIVE_JOBS_SUCCESS](mockedState, jobs);
+ it('updates loading', () => {
+ mutations[types.RECEIVE_JOBS_SUCCESS](mockedState, { id: mockedState.stages[0].id, data });
- expect(mockedState.stages.length).toBe(2);
- expect(mockedState.stages).toEqual([
- {
- title: 'test',
- jobs: jasmine.anything(),
- },
- {
- title: 'build',
- jobs: jasmine.anything(),
- },
- ]);
+ expect(mockedState.stages[0].isLoading).toBe(false);
});
- it('sets jobs in stages', () => {
- mutations[types.RECEIVE_JOBS_SUCCESS](mockedState, jobs);
+ it('sets jobs on stage', () => {
+ mutations[types.RECEIVE_JOBS_SUCCESS](mockedState, { id: mockedState.stages[0].id, data });
+
+ expect(mockedState.stages[0].jobs.length).toBe(jobs.length);
+ expect(mockedState.stages[0].jobs).toEqual(
+ jobs.map(job => ({
+ id: job.id,
+ name: job.name,
+ status: job.status,
+ path: job.build_path,
+ })),
+ );
+ });
+ });
- expect(mockedState.stages[0].jobs.length).toBe(3);
- expect(mockedState.stages[1].jobs.length).toBe(1);
- expect(mockedState.stages).toEqual([
- {
- title: jasmine.anything(),
- jobs: jobs.filter(job => job.stage === 'test').map(job => ({
- id: job.id,
- name: job.name,
- status: job.status,
- stage: job.stage,
- duration: job.duration,
- })),
- },
- {
- title: jasmine.anything(),
- jobs: jobs.filter(job => job.stage === 'build').map(job => ({
- id: job.id,
- name: job.name,
- status: job.status,
- stage: job.stage,
- duration: job.duration,
- })),
- },
- ]);
+ describe(types.TOGGLE_STAGE_COLLAPSE, () => {
+ beforeEach(() => {
+ mockedState.stages = stages.map((stage, i) => ({
+ ...stage,
+ id: i,
+ isCollapsed: false,
+ }));
+ });
+
+ it('toggles collapsed state', () => {
+ mutations[types.TOGGLE_STAGE_COLLAPSE](mockedState, mockedState.stages[0].id);
+
+ expect(mockedState.stages[0].isCollapsed).toBe(true);
+
+ mutations[types.TOGGLE_STAGE_COLLAPSE](mockedState, mockedState.stages[0].id);
+
+ expect(mockedState.stages[0].isCollapsed).toBe(false);
});
});
});
diff --git a/spec/javascripts/ide/stores/mutations/branch_spec.js b/spec/javascripts/ide/stores/mutations/branch_spec.js
index f2f1f2a9a2e..29eb859ddaf 100644
--- a/spec/javascripts/ide/stores/mutations/branch_spec.js
+++ b/spec/javascripts/ide/stores/mutations/branch_spec.js
@@ -37,40 +37,4 @@ describe('Multi-file store branch mutations', () => {
expect(localState.projects.Example.branches.master.commit.title).toBe('Example commit');
});
});
-
- describe('SET_LAST_COMMIT_PIPELINE', () => {
- it('sets the pipeline for the last commit on current project', () => {
- localState.projects = {
- Example: {
- branches: {
- master: {
- commit: {},
- },
- },
- },
- };
-
- mutations.SET_LAST_COMMIT_PIPELINE(localState, {
- projectId: 'Example',
- branchId: 'master',
- pipeline: {
- id: '50',
- details: {
- status: {
- icon: 'status_passed',
- text: 'passed',
- },
- },
- },
- });
-
- expect(localState.projects.Example.branches.master.commit.pipeline.id).toBe('50');
- expect(localState.projects.Example.branches.master.commit.pipeline.details.status.text).toBe(
- 'passed',
- );
- expect(localState.projects.Example.branches.master.commit.pipeline.details.status.icon).toBe(
- 'status_passed',
- );
- });
- });
});