2017-08-17 22:00:37 +05:30
|
|
|
import Vue from 'vue';
|
2018-10-15 14:42:47 +05:30
|
|
|
import mountComponent from 'spec/helpers/vue_mount_component_helper';
|
2019-12-21 20:55:43 +05:30
|
|
|
import PipelineStore from '~/pipelines/stores/pipeline_store';
|
2017-08-17 22:00:37 +05:30
|
|
|
import graphComponent from '~/pipelines/components/graph/graph_component.vue';
|
|
|
|
import graphJSON from './mock_data';
|
2019-12-21 20:55:43 +05:30
|
|
|
import linkedPipelineJSON from '../linked_pipelines_mock.json';
|
|
|
|
import PipelinesMediator from '~/pipelines/pipeline_details_mediator';
|
2017-08-17 22:00:37 +05:30
|
|
|
|
|
|
|
describe('graph component', () => {
|
2018-10-15 14:42:47 +05:30
|
|
|
const GraphComponent = Vue.extend(graphComponent);
|
2019-12-21 20:55:43 +05:30
|
|
|
const store = new PipelineStore();
|
|
|
|
store.storePipeline(linkedPipelineJSON);
|
|
|
|
const mediator = new PipelinesMediator({ endpoint: '' });
|
|
|
|
|
2018-10-15 14:42:47 +05:30
|
|
|
let component;
|
2017-08-17 22:00:37 +05:30
|
|
|
|
2019-12-04 20:38:33 +05:30
|
|
|
beforeEach(() => {
|
|
|
|
setFixtures(`
|
|
|
|
<div class="layout-page"></div>
|
|
|
|
`);
|
|
|
|
});
|
|
|
|
|
2018-10-15 14:42:47 +05:30
|
|
|
afterEach(() => {
|
|
|
|
component.$destroy();
|
2017-08-17 22:00:37 +05:30
|
|
|
});
|
|
|
|
|
|
|
|
describe('while is loading', () => {
|
|
|
|
it('should render a loading icon', () => {
|
2018-10-15 14:42:47 +05:30
|
|
|
component = mountComponent(GraphComponent, {
|
|
|
|
isLoading: true,
|
|
|
|
pipeline: {},
|
2019-12-21 20:55:43 +05:30
|
|
|
mediator,
|
2018-10-15 14:42:47 +05:30
|
|
|
});
|
|
|
|
|
2017-08-17 22:00:37 +05:30
|
|
|
expect(component.$el.querySelector('.loading-icon')).toBeDefined();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2017-09-10 17:25:29 +05:30
|
|
|
describe('with data', () => {
|
|
|
|
it('should render the graph', () => {
|
2018-10-15 14:42:47 +05:30
|
|
|
component = mountComponent(GraphComponent, {
|
|
|
|
isLoading: false,
|
|
|
|
pipeline: graphJSON,
|
2019-12-21 20:55:43 +05:30
|
|
|
mediator,
|
2018-10-15 14:42:47 +05:30
|
|
|
});
|
2017-08-17 22:00:37 +05:30
|
|
|
|
2017-09-10 17:25:29 +05:30
|
|
|
expect(component.$el.classList.contains('js-pipeline-graph')).toEqual(true);
|
2017-08-17 22:00:37 +05:30
|
|
|
|
2017-09-10 17:25:29 +05:30
|
|
|
expect(
|
|
|
|
component.$el.querySelector('.stage-column:first-child').classList.contains('no-margin'),
|
|
|
|
).toEqual(true);
|
2017-08-17 22:00:37 +05:30
|
|
|
|
2017-09-10 17:25:29 +05:30
|
|
|
expect(
|
|
|
|
component.$el.querySelector('.stage-column:nth-child(2)').classList.contains('left-margin'),
|
|
|
|
).toEqual(true);
|
2017-08-17 22:00:37 +05:30
|
|
|
|
2017-09-10 17:25:29 +05:30
|
|
|
expect(
|
2018-12-13 13:39:08 +05:30
|
|
|
component.$el
|
|
|
|
.querySelector('.stage-column:nth-child(2) .build:nth-child(1)')
|
|
|
|
.classList.contains('left-connector'),
|
2017-09-10 17:25:29 +05:30
|
|
|
).toEqual(true);
|
2017-08-17 22:00:37 +05:30
|
|
|
|
2017-09-10 17:25:29 +05:30
|
|
|
expect(component.$el.querySelector('loading-icon')).toBe(null);
|
2017-08-17 22:00:37 +05:30
|
|
|
|
2017-09-10 17:25:29 +05:30
|
|
|
expect(component.$el.querySelector('.stage-column-list')).toBeDefined();
|
2017-08-17 22:00:37 +05:30
|
|
|
});
|
|
|
|
});
|
2018-10-15 14:42:47 +05:30
|
|
|
|
2019-12-21 20:55:43 +05:30
|
|
|
describe('when linked pipelines are present', () => {
|
|
|
|
beforeEach(() => {
|
|
|
|
component = mountComponent(GraphComponent, {
|
|
|
|
isLoading: false,
|
|
|
|
pipeline: store.state.pipeline,
|
|
|
|
mediator,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('rendered output', () => {
|
|
|
|
it('should include the pipelines graph', () => {
|
|
|
|
expect(component.$el.classList.contains('js-pipeline-graph')).toEqual(true);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should not include the loading icon', () => {
|
|
|
|
expect(component.$el.querySelector('.fa-spinner')).toBeNull();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should include the stage column list', () => {
|
|
|
|
expect(component.$el.querySelector('.stage-column-list')).not.toBeNull();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should include the no-margin class on the first child', () => {
|
|
|
|
const firstStageColumnElement = component.$el.querySelector(
|
|
|
|
'.stage-column-list .stage-column',
|
|
|
|
);
|
|
|
|
|
|
|
|
expect(firstStageColumnElement.classList.contains('no-margin')).toEqual(true);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should include the has-only-one-job class on the first child', () => {
|
|
|
|
const firstStageColumnElement = component.$el.querySelector(
|
|
|
|
'.stage-column-list .stage-column',
|
|
|
|
);
|
|
|
|
|
|
|
|
expect(firstStageColumnElement.classList.contains('has-only-one-job')).toEqual(true);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should include the left-margin class on the second child', () => {
|
|
|
|
const firstStageColumnElement = component.$el.querySelector(
|
|
|
|
'.stage-column-list .stage-column:last-child',
|
|
|
|
);
|
|
|
|
|
|
|
|
expect(firstStageColumnElement.classList.contains('left-margin')).toEqual(true);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should include the js-has-linked-pipelines flag', () => {
|
|
|
|
expect(component.$el.querySelector('.js-has-linked-pipelines')).not.toBeNull();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('computeds and methods', () => {
|
|
|
|
describe('capitalizeStageName', () => {
|
|
|
|
it('it capitalizes the stage name', () => {
|
|
|
|
expect(component.capitalizeStageName('mystage')).toBe('Mystage');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('stageConnectorClass', () => {
|
|
|
|
it('it returns left-margin when there is a triggerer', () => {
|
|
|
|
expect(component.stageConnectorClass(0, { groups: ['job'] })).toBe('no-margin');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('linked pipelines components', () => {
|
|
|
|
beforeEach(() => {
|
|
|
|
component = mountComponent(GraphComponent, {
|
|
|
|
isLoading: false,
|
|
|
|
pipeline: store.state.pipeline,
|
|
|
|
mediator,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should render an upstream pipelines column', () => {
|
|
|
|
expect(component.$el.querySelector('.linked-pipelines-column')).not.toBeNull();
|
|
|
|
expect(component.$el.innerHTML).toContain('Upstream');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should render a downstream pipelines column', () => {
|
|
|
|
expect(component.$el.querySelector('.linked-pipelines-column')).not.toBeNull();
|
|
|
|
expect(component.$el.innerHTML).toContain('Downstream');
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('triggered by', () => {
|
|
|
|
describe('on click', () => {
|
|
|
|
it('should emit `onClickTriggeredBy` when triggered by linked pipeline is clicked', () => {
|
|
|
|
spyOn(component, '$emit');
|
|
|
|
|
|
|
|
component.$el.querySelector('#js-linked-pipeline-12').click();
|
|
|
|
|
|
|
|
expect(component.$emit).toHaveBeenCalledWith(
|
|
|
|
'onClickTriggeredBy',
|
|
|
|
component.pipeline,
|
|
|
|
component.pipeline.triggered_by[0],
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('with expanded pipeline', () => {
|
|
|
|
it('should render expanded pipeline', done => {
|
|
|
|
// expand the pipeline
|
|
|
|
store.state.pipeline.triggered_by[0].isExpanded = true;
|
|
|
|
|
|
|
|
component = mountComponent(GraphComponent, {
|
|
|
|
isLoading: false,
|
|
|
|
pipeline: store.state.pipeline,
|
|
|
|
mediator,
|
|
|
|
});
|
|
|
|
|
|
|
|
Vue.nextTick()
|
|
|
|
.then(() => {
|
|
|
|
expect(component.$el.querySelector('.js-upstream-pipeline-12')).not.toBeNull();
|
|
|
|
})
|
|
|
|
.then(done)
|
|
|
|
.catch(done.fail);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('triggered', () => {
|
|
|
|
describe('on click', () => {
|
|
|
|
it('should emit `onClickTriggered`', () => {
|
|
|
|
spyOn(component, '$emit');
|
|
|
|
|
|
|
|
component.$el.querySelector('#js-linked-pipeline-34993051').click();
|
|
|
|
|
|
|
|
expect(component.$emit).toHaveBeenCalledWith(
|
|
|
|
'onClickTriggered',
|
|
|
|
component.pipeline,
|
|
|
|
component.pipeline.triggered[0],
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('with expanded pipeline', () => {
|
|
|
|
it('should render expanded pipeline', done => {
|
|
|
|
// expand the pipeline
|
|
|
|
store.state.pipeline.triggered[0].isExpanded = true;
|
|
|
|
|
|
|
|
component = mountComponent(GraphComponent, {
|
|
|
|
isLoading: false,
|
|
|
|
pipeline: store.state.pipeline,
|
|
|
|
mediator,
|
|
|
|
});
|
|
|
|
|
|
|
|
Vue.nextTick()
|
|
|
|
.then(() => {
|
|
|
|
expect(
|
|
|
|
component.$el.querySelector('.js-downstream-pipeline-34993051'),
|
|
|
|
).not.toBeNull();
|
|
|
|
})
|
|
|
|
.then(done)
|
|
|
|
.catch(done.fail);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('when linked pipelines are not present', () => {
|
|
|
|
beforeEach(() => {
|
|
|
|
const pipeline = Object.assign(linkedPipelineJSON, { triggered: null, triggered_by: null });
|
|
|
|
component = mountComponent(GraphComponent, {
|
|
|
|
isLoading: false,
|
|
|
|
pipeline,
|
|
|
|
mediator,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('rendered output', () => {
|
|
|
|
it('should include the first column with a no margin', () => {
|
|
|
|
const firstColumn = component.$el.querySelector('.stage-column:first-child');
|
|
|
|
|
|
|
|
expect(firstColumn.classList.contains('no-margin')).toEqual(true);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should not render a linked pipelines column', () => {
|
|
|
|
expect(component.$el.querySelector('.linked-pipelines-column')).toBeNull();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('stageConnectorClass', () => {
|
|
|
|
it('it returns left-margin when no triggerer and there is one job', () => {
|
|
|
|
expect(component.stageConnectorClass(0, { groups: ['job'] })).toBe('no-margin');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('it returns left-margin when no triggerer and not the first stage', () => {
|
|
|
|
expect(component.stageConnectorClass(99, { groups: ['job'] })).toBe('left-margin');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2018-10-15 14:42:47 +05:30
|
|
|
describe('capitalizeStageName', () => {
|
|
|
|
it('capitalizes and escapes stage name', () => {
|
|
|
|
component = mountComponent(GraphComponent, {
|
|
|
|
isLoading: false,
|
|
|
|
pipeline: graphJSON,
|
2019-12-21 20:55:43 +05:30
|
|
|
mediator,
|
2018-10-15 14:42:47 +05:30
|
|
|
});
|
|
|
|
|
2018-12-13 13:39:08 +05:30
|
|
|
expect(
|
|
|
|
component.$el.querySelector('.stage-column:nth-child(2) .stage-name').textContent.trim(),
|
|
|
|
).toEqual('Deploy <img src=x onerror=alert(document.domain)>');
|
2018-10-15 14:42:47 +05:30
|
|
|
});
|
|
|
|
});
|
2017-08-17 22:00:37 +05:30
|
|
|
});
|