Commit 66bf2de8 authored by Phil Hughes's avatar Phil Hughes

added component specs

parent dd17a484
...@@ -9,13 +9,16 @@ import pipelines from './modules/pipelines'; ...@@ -9,13 +9,16 @@ import pipelines from './modules/pipelines';
Vue.use(Vuex); Vue.use(Vuex);
export default new Vuex.Store({ export const createStore = () =>
state: state(), new Vuex.Store({
actions, state: state(),
mutations, actions,
getters, mutations,
modules: { getters,
commit: commitModule, modules: {
pipelines, commit: commitModule,
}, pipelines,
}); },
});
export default createStore();
...@@ -4,9 +4,9 @@ export const pipelineFailed = state => ...@@ -4,9 +4,9 @@ export const pipelineFailed = state =>
state.latestPipeline && state.latestPipeline.details.status.text === 'failed'; state.latestPipeline && state.latestPipeline.details.status.text === 'failed';
export const failedStages = state => export const failedStages = state =>
state.stages.filter(stage => stage.status.text === 'failed').map(stage => ({ state.stages.filter(stage => stage.status.text.toLowerCase() === 'failed').map(stage => ({
...stage, ...stage,
jobs: stage.jobs.filter(job => job.status.text === 'failed'), jobs: stage.jobs.filter(job => job.status.text.toLowerCase() === 'failed'),
})); }));
export const failedJobsCount = state => export const failedJobsCount = state =>
......
...@@ -38,16 +38,18 @@ export default { ...@@ -38,16 +38,18 @@ export default {
} }
}, },
[types.REQUEST_JOBS](state, id) { [types.REQUEST_JOBS](state, id) {
state.stages = state.stages.map(stage => ({ state.stages = state.stages.map(stage =>
...stage, Object.assign(stage, {
isLoading: id === stage.id ? true : stage.isLoading, isLoading: id === stage.id ? true : stage.isLoading,
})); }),
);
}, },
[types.RECEIVE_JOBS_ERROR](state, id) { [types.RECEIVE_JOBS_ERROR](state, id) {
state.stages = state.stages.map(stage => ({ state.stages = state.stages.map(stage =>
...stage, Object.assign(stage, {
isLoading: id === stage.id ? true : stage.isLoading, isLoading: id === stage.id ? true : stage.isLoading,
})); }),
);
}, },
[types.RECEIVE_JOBS_SUCCESS](state, { id, data }) { [types.RECEIVE_JOBS_SUCCESS](state, { id, data }) {
const normalizeData = job => ({ const normalizeData = job => ({
...@@ -57,16 +59,18 @@ export default { ...@@ -57,16 +59,18 @@ export default {
path: job.build_path, path: job.build_path,
}); });
state.stages = state.stages.map(stage => ({ state.stages = state.stages.map(stage =>
...stage, Object.assign(stage, {
isLoading: id === stage.id ? false : stage.isLoading, isLoading: id === stage.id ? false : stage.isLoading,
jobs: id === stage.id ? data.latest_statuses.map(normalizeData) : stage.jobs, jobs: id === stage.id ? data.latest_statuses.map(normalizeData) : stage.jobs,
})); }),
);
}, },
[types.TOGGLE_STAGE_COLLAPSE](state, id) { [types.TOGGLE_STAGE_COLLAPSE](state, id) {
state.stages = state.stages.map(stage => ({ state.stages = state.stages.map(stage =>
...stage, Object.assign(stage, {
isCollapsed: stage.id === id ? !stage.isCollapsed : stage.isCollapsed, isCollapsed: stage.id === id ? !stage.isCollapsed : stage.isCollapsed,
})); }),
);
}, },
}; };
...@@ -24,4 +24,5 @@ export default () => ({ ...@@ -24,4 +24,5 @@ export default () => ({
unusedSeal: true, unusedSeal: true,
fileFindVisible: false, fileFindVisible: false,
rightPane: null, rightPane: null,
links: {},
}); });
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);
});
});
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,
}).$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();
});
});
});
import Vue from 'vue';
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import { createStore } from '~/ide/stores';
import Stage from '~/ide/components/jobs/stage.vue';
import { createComponentWithStore } from '../../../helpers/vue_mount_component_helper';
import { stages, jobs } from '../../mock_data';
describe('IDE pipeline stage', () => {
const Component = Vue.extend(Stage);
let vm;
let mock;
let stage;
beforeEach(done => {
const store = createStore();
mock = new MockAdapter(axios);
store.state.pipelines.stages = stages.map((mappedState, i) => ({
...mappedState,
id: i,
dropdownPath: mappedState.dropdown_path,
jobs: [],
isLoading: false,
isCollapsed: false,
}));
stage = store.state.pipelines.stages[0];
mock.onGet(stage.dropdownPath).reply(200, {
latest_statuses: jobs,
});
vm = createComponentWithStore(Component, store, {
stage,
}).$mount();
setTimeout(done);
});
afterEach(() => {
vm.$destroy();
mock.restore();
});
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('toggles collapse status when clicking header', done => {
vm.$el.querySelector('.card-header').click();
vm.$nextTick(() => {
expect(vm.$el.querySelector('.card-body').style.display).toBe('none');
done();
});
});
it('sets border bottom class when collapsed', done => {
vm.$el.querySelector('.card-header').click();
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);
});
});
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')
.reply(200, { pipelines: [...pipelines] }, { 'poll-interval': '-1' });
vm = createComponentWithStore(Component, store).$mount();
setTimeout(done);
});
afterEach(() => {
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();
});
});
});
});
import { decorateData } from '~/ide/stores/utils'; import { decorateData } from '~/ide/stores/utils';
import state from '~/ide/stores/state'; import state from '~/ide/stores/state';
import commitState from '~/ide/stores/modules/commit/state'; import commitState from '~/ide/stores/modules/commit/state';
import pipelinesState from '~/ide/stores/modules/pipelines/state';
export const resetStore = store => { export const resetStore = store => {
const newState = { const newState = {
...state(), ...state(),
commit: commitState(), commit: commitState(),
pipelines: pipelinesState(),
}; };
store.replaceState(newState); store.replaceState(newState);
}; };
......
...@@ -19,26 +19,38 @@ export const pipelines = [ ...@@ -19,26 +19,38 @@ export const pipelines = [
id: 1, id: 1,
ref: 'master', ref: 'master',
sha: '123', sha: '123',
status: 'failed', details: {
status: {
icon: 'status_failed',
group: 'failed',
text: 'Failed',
},
},
commit: { id: '123' }, commit: { id: '123' },
}, },
{ {
id: 2, id: 2,
ref: 'master', ref: 'master',
sha: '213', sha: '213',
status: 'success', details: {
status: {
icon: 'status_failed',
group: 'failed',
text: 'Failed',
},
},
commit: { id: '213' }, commit: { id: '213' },
}, },
]; ];
export const stages = [ export const stages = [
{ {
dropdown_path: 'testing', dropdown_path: `${gl.TEST_HOST}/testing`,
name: 'build', name: 'build',
status: { status: {
icon: 'status_failed', icon: 'status_failed',
group: 'failed', group: 'failed',
text: 'Failed', text: 'failed',
}, },
}, },
{ {
...@@ -47,7 +59,7 @@ export const stages = [ ...@@ -47,7 +59,7 @@ export const stages = [
status: { status: {
icon: 'status_failed', icon: 'status_failed',
group: 'failed', group: 'failed',
text: 'Failed', text: 'failed',
}, },
}, },
]; ];
...@@ -56,28 +68,44 @@ export const jobs = [ ...@@ -56,28 +68,44 @@ export const jobs = [
{ {
id: 1, id: 1,
name: 'test', name: 'test',
status: 'failed', path: 'testing',
status: {
icon: 'status_passed',
text: 'passed',
},
stage: 'test', stage: 'test',
duration: 1, duration: 1,
}, },
{ {
id: 2, id: 2,
name: 'test 2', name: 'test 2',
status: 'failed', path: 'testing2',
status: {
icon: 'status_passed',
text: 'passed',
},
stage: 'test', stage: 'test',
duration: 1, duration: 1,
}, },
{ {
id: 3, id: 3,
name: 'test 3', name: 'test 3',
status: 'failed', path: 'testing3',
status: {
icon: 'status_passed',
text: 'passed',
},
stage: 'test', stage: 'test',
duration: 1, duration: 1,
}, },
{ {
id: 4, id: 4,
name: 'test 3', name: 'test 4',
status: 'failed', path: 'testing4',
status: {
icon: 'status_failed',
text: 'failed',
},
stage: 'build', stage: 'build',
duration: 1, duration: 1,
}, },
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment