diff options
author | Bryce Johnson <bryce@gitlab.com> | 2017-05-15 15:01:46 -0400 |
---|---|---|
committer | Bryce Johnson <bryce@gitlab.com> | 2017-05-23 21:37:36 -0400 |
commit | dbf9736a90dfecb839726305d93e4c0c29e334e8 (patch) | |
tree | f419eedb3925f8f8369adb49f8a31182221ab4c8 | |
parent | 18a6d9c5326bc2b90a1f0cc8664d638a39885924 (diff) | |
download | gitlab-ce-bpj-related-project-pipelines.tar.gz |
Stub out data, specs, and components for linked pipelines.bpj-related-project-pipelines
6 files changed, 283 insertions, 15 deletions
diff --git a/app/assets/javascripts/pipelines/components/graph/graph_component.vue b/app/assets/javascripts/pipelines/components/graph/graph_component.vue index 14c98847d93..e028cd09fec 100644 --- a/app/assets/javascripts/pipelines/components/graph/graph_component.vue +++ b/app/assets/javascripts/pipelines/components/graph/graph_component.vue @@ -4,12 +4,14 @@ import Poll from '../../../lib/utils/poll'; import PipelineService from '../../services/pipeline_service'; import PipelineStore from '../../stores/pipeline_store'; + import linkedPipelinesColumn from './linked_pipelines_column.vue'; import stageColumnComponent from './stage_column_component.vue'; import loadingIcon from '../../../vue_shared/components/loading_icon.vue'; import '../../../flash'; export default { components: { + linkedPipelinesColumn, stageColumnComponent, loadingIcon, }, @@ -17,12 +19,23 @@ data() { const DOMdata = document.getElementById('js-pipeline-graph-vue').dataset; const store = new PipelineStore(); + const upstreamPipelines = [ + { id: '111', path: 'hello/world/tho', project_name: 'My Project Name', status: 'success' }, + ]; + + const downstreamPipelines = [ + { id: '111', path: 'hello/world/tho', project_name: 'My Project Name', status: 'success' }, + { id: '111', path: 'hello/world/tho', project_name: 'My Project Name', status: 'success' }, + { id: '111', path: 'hello/world/tho', project_name: 'My Project Name', status: 'success' }, + ]; return { isLoading: false, endpoint: DOMdata.endpoint, store, state: store.state, + upstreamPipelines, + downstreamPipelines, }; }, @@ -75,7 +88,7 @@ let className; // If it's the first stage column and only has one job - if (index === 0 && stage.groups.length === 1) { + if (this.isFirstColumn(index) && stage.groups.length === 1) { className = 'no-margin'; } else if (index > 0) { // If it is not the first column @@ -97,6 +110,12 @@ /> </div> + <linked-pipelines-column + v-if="upstreamPipelines" + :linked-pipelines="upstreamPipelines" + linked-pipeline-orientation="Upstream" + /> + <ul v-if="!isLoading" class="stage-column-list"> @@ -108,6 +127,12 @@ :stage-connector-class="stageConnectorClass(index, stage)" :is-first-column="isFirstColumn(index)"/> </ul> + + <linked-pipelines-column + v-if="downstreamPipelines" + :linked-pipelines="downstreamPipelines" + linked-pipeline-orientation="Downstream" + /> </div> </div> </template> diff --git a/app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue b/app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue new file mode 100644 index 00000000000..0a20297afab --- /dev/null +++ b/app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue @@ -0,0 +1,33 @@ +<script> +export default { + props: { + pipelineId: { + type: String, + required: true, + }, + pipelinePath: { + type: String, + required: true, + }, + pipelineStatus: { + type: String, + required: true, + }, + projectName: { + type: String, + required: true, + }, + }, +}; + +</script> + +<template> + <li class="build"> + <a :href="pipelinePath" class="build-content"> + <span class="linked-pipeline-status"> {{ pipelineStatus }} </span> + <span class="linked-pipeline-project-name"> {{ projectName }}</span> + <span class="linked-pipeline-id"> #{{ pipelineId }}</span> + </a> + </li> +</template> diff --git a/app/assets/javascripts/pipelines/components/graph/linked_pipelines_column.vue b/app/assets/javascripts/pipelines/components/graph/linked_pipelines_column.vue new file mode 100644 index 00000000000..5189c226126 --- /dev/null +++ b/app/assets/javascripts/pipelines/components/graph/linked_pipelines_column.vue @@ -0,0 +1,35 @@ +<script> +import relatedProjectPipelineComponent from './linked_pipeline.vue'; + +export default { + props: { + linkedPipelineOrientation: { + type: String, + required: true, + }, + linkedPipelines: { + type: Array, + required: true, + }, + }, + components: { + linkedPipeline, + }, +}; +</script> + +<template> + <div class="stage-column linked-pipelines-column"> + <span class="stage-name linked-pipeline-title"> {{ linkedPipelineOrientation }} </span> + <ul> + <linked-pipeline + v-for="(pipeline, index) in linkedPipelines" + :pipeline-id="pipeline.id" + :project-name="pipeline.project_name" + :pipeline-status="pipeline.status" + :pipeline-path="pipeline.path" + /> + </ul> + <span> arrow graphic </span> + </div> +</template> diff --git a/spec/javascripts/pipelines/graph/graph_component_spec.js b/spec/javascripts/pipelines/graph/graph_component_spec.js index 6bd0eb86263..ec6ec45ce8c 100644 --- a/spec/javascripts/pipelines/graph/graph_component_spec.js +++ b/spec/javascripts/pipelines/graph/graph_component_spec.js @@ -19,7 +19,7 @@ describe('graph component', () => { }); }); - describe('with a successfull response', () => { + describe('with a successful response', () => { const interceptor = (request, next) => { next(request.respondWith(JSON.stringify(graphJSON), { status: 200, @@ -34,29 +34,103 @@ describe('graph component', () => { Vue.http.interceptors = _.without(Vue.http.interceptors, interceptor); }); - it('should render the graph', (done) => { + describe('rendered output', () => { const component = new GraphComponent().$mount('#js-pipeline-graph-vue'); - setTimeout(() => { + it('should include the pipelines graph', () => { expect(component.$el.classList.contains('js-pipeline-graph')).toEqual(true); + }); - expect( - component.$el.querySelector('.stage-column:first-child').classList.contains('no-margin'), - ).toEqual(true); + it('should include the first column with no margin', () => { + const firstColumn = component.$el.querySelector('.stage-column:first-child'); + expect(firstColumn.classList.contains('no-margin')).toEqual(true); + }); - expect( - component.$el.querySelector('.stage-column:nth-child(2)').classList.contains('left-margin'), - ).toEqual(true); + it('should include the second column with a left margin', () => { + const secondColumn = component.$el.querySelector('.stage-column:nth-child(2)'); + expect(secondColumn.classList.contains('left-margin')).toEqual(true); + }); - expect( - component.$el.querySelector('.stage-column:nth-child(2) .build:nth-child(1)').classList.contains('left-connector'), - ).toEqual(true); + it('should include the second column first build with a left connector', () => { + const firstBuild = component.$el.querySelector('.stage-column:nth-child(2) .build:nth-child(1)'); + expect(firstBuild.classList.contains('left-connector')).toEqual(true); + }); + it('should not include the loading icon', () => { expect(component.$el.querySelector('loading-icon')).toBe(null); + }); + it('should include the stage column list', () => { expect(component.$el.querySelector('.stage-column-list')).toBeDefined(); - done(); - }, 0); + }); + }); + + describe('methods', () => { + describe('stageConnectorClass', () => { + it('returns no-margin when it is the first stage column and only has one job', () => { + + }); + + it('returns whatttt when it is the first stage column but multiple jobs', () => { + + }); + + it('returns left-margin when it is not the first column', () => { + + }); + }); + + describe('capitalizeStageName', () => { + it('returns a capitalized stage name', () => { + + }); + }); + }); + + describe('setup', () => { + it('polling is started when the component is created', () => { + + }); + + it('polling is stopped when visibility is hidden', () => { + + }); + + it('polling is restarted when visibility is shown', () => { + + }); + }); + }); + + describe('Linked Pipelines', () => { + describe('when upstream pipelines are defined', () => { + it('should render an upstream pipelines column', () => { + + }); + + it('should render the upstream column with no margin', () => { + + }); + + it('should render the first stage column with left-margin', () => { + + }); + }); + + describe('when downstream pipelines are defined', () => { + it('should render a downstream pipelines column', () => { + + }); + }); + + describe('when neither upstream nor downstream pipelines are defined', () => { + it('should not render an upstream pipelines column', () => { + + }); + + it('should not render a downstream pipelines column', () => { + + }); }); }); }); diff --git a/spec/javascripts/pipelines/graph/linked_pipeline_spec.js b/spec/javascripts/pipelines/graph/linked_pipeline_spec.js new file mode 100644 index 00000000000..62fc336b402 --- /dev/null +++ b/spec/javascripts/pipelines/graph/linked_pipeline_spec.js @@ -0,0 +1,66 @@ +import Vue from 'vue'; +import LinkedPipelineComponent from '~/pipelines/components/graph/linked_pipeline.vue'; + +const LinkedPipeline = Vue.extend(LinkedPipelineComponent); + +describe('Linked pipeline', () => { + beforeEach(() => { + this.propsData = { + pipelineId: 12345, + pipelinePath: 'my/pipeline/path', + pipelineStatus: 'cancelled', + projectName: 'GitLab CE', + }; + + this.linkedPipeline = new LinkedPipeline({ + propsData: this.propsData, + }).$mount(); + }); + + it('should return a defined Vue component', () => { + expect(this.linkedPipeline).toBeDefined(); + }); + + it('should render a list item as the containing element', () => { + expect(this.linkedPipeline.$el.tagName).toBe('LI'); + }); + + it('should render a link', () => { + const linkElement = this.linkedPipeline.$el.querySelector('.linked-pipeline-link'); + expect(linkElement).not.toBeNull(); + }); + + it('should link to the correct path', () => { + const linkElement = this.linkedPipeline.$el.querySelector('.linked-pipeline-link'); + expect(linkElement.getAttribute('href')).toBe(this.propsData.pipelinePath); + }); + + it('should render the project name', () => { + const projectNameElement = this.linkedPipeline.$el.querySelector('.linked-project-pipeline-name'); + expect(projectNameElement).toContain(this.propsData.projectName); + }); + + it('should render an svg within the status container', () => { + const pipelineStatusElement = this.linkedPipeline.$el.querySelector('.linked-pipeline-status'); + expect(pipelineStatusElement.querySelector('svg')).not.toBeNull(); + }); + + it('should render the correct pipeline status icon', () => { + const pipelineStatusElement = this.linkedPipeline.$el.querySelector('.linked-pipeline-status'); + + }); + + it('should render the correct pipeline status icon style selector', () => { + const pipelineStatusElement = this.linkedPipeline.$el.querySelector('.linked-pipeline-status'); + + }); + + it('should have a ci-status child component', () => { + + }); + + it('should render the pipeline id', () => { + const pipelineIdElement = this.linkedPipeline.$el.querySelector('.linked-pipeline-id'); + expect(pipelineIdElement).toContain(`${this.propsData.pipelineId}`); + }); +});
\ No newline at end of file diff --git a/spec/javascripts/pipelines/graph/linked_pipelines_column_spec.js b/spec/javascripts/pipelines/graph/linked_pipelines_column_spec.js new file mode 100644 index 00000000000..9b3c4737d1c --- /dev/null +++ b/spec/javascripts/pipelines/graph/linked_pipelines_column_spec.js @@ -0,0 +1,35 @@ +import Vue from 'vue'; +import LinkedPipelinesColumn from '~/pipelines/components/graph/linked_pipelines_column.vue'; + +const LinkedPipelinesColumnComponent = Vue.extend(LinkedPipelinesColumn); + +describe('Linked Pipelines Column', () => { + beforeEach(() => { + this.propsData = { + linkedPipelinesOrientation: 'Upstream', + linkedPipelines: [{}], + }; + this.linkedPipelinesColumn = new LinkedPipelinesColumnComponent({ + propsData: this.propsData, + }); + }); + + it('instantiates a defined Vue component', () => { + expect(this.linkedPipelinesColumn).toBeDefined(); + }); + + it('renders the pipeline orientation', () => { + const titleElement = this.linkedPipelinesColumn.$el.querySelector('.linked-pipelines-column-title'); + expect(titleElement).toContain(this.propsData.linkedPipelinesOrientation); + }); + + it('has the correct number of linked pipeline child components', () => { + + }); + + it('renders the correct number of linked pipelines', () => { + const linkedPipelineElements = this.linkedPipelinesColumn.$el.querySelectorAll('.linked-pipeline'); + expect(linkedPipelineElements.length).toBe(this.propsData.linkedPipelines.length); + }); +}); + |