Commit 5b07495e authored by Sarah Groff Hennigh-Palermo's avatar Sarah Groff Hennigh-Palermo Committed by Mark Florian

Add wrapper and GraphQL query

Adjusts mounting funcs, adds query, specs
parent 55b92a6b
<script>
import { GlAlert, GlLoadingIcon } from '@gitlab/ui';
import { __ } from '~/locale';
import { DEFAULT, LOAD_FAILURE } from '../../constants';
import getPipelineDetails from '../../graphql/queries/get_pipeline_details.query.graphql';
import PipelineGraph from './graph_component.vue';
import { unwrapPipelineData } from './utils';
export default {
name: 'PipelineGraphWrapper',
components: {
GlAlert,
GlLoadingIcon,
PipelineGraph,
},
inject: {
pipelineIid: {
default: '',
},
pipelineProjectPath: {
default: '',
},
},
data() {
return {
pipeline: null,
alertType: null,
showAlert: false,
};
},
errorTexts: {
[LOAD_FAILURE]: __('We are currently unable to fetch data for this pipeline.'),
[DEFAULT]: __('An unknown error occurred while loading this graph.'),
},
apollo: {
pipeline: {
query: getPipelineDetails,
variables() {
return {
projectPath: this.pipelineProjectPath,
iid: this.pipelineIid,
};
},
update(data) {
return unwrapPipelineData(this.pipelineIid, data);
},
error() {
this.reportFailure(LOAD_FAILURE);
},
},
},
computed: {
alert() {
switch (this.alertType) {
case LOAD_FAILURE:
return {
text: this.$options.errorTexts[LOAD_FAILURE],
variant: 'danger',
};
default:
return {
text: this.$options.errorTexts[DEFAULT],
variant: 'danger',
};
}
},
},
methods: {
hideAlert() {
this.showAlert = false;
},
reportFailure(type) {
this.showAlert = true;
this.failureType = type;
},
},
};
</script>
<template>
<gl-alert v-if="showAlert" :variant="alert.variant" @dismiss="hideAlert">
{{ alert.text }}
</gl-alert>
<gl-loading-icon
v-else-if="$apollo.queries.pipeline.loading"
class="gl-mx-auto gl-my-4"
size="lg"
/>
<pipeline-graph v-else :pipeline="pipeline" />
</template>
query getPipelineDetails($projectPath: ID!, $iid: ID!) {
project(fullPath: $projectPath) {
pipeline(iid: $iid) {
id: iid
stages {
nodes {
name
status: detailedStatus {
action {
icon
path
title
}
}
groups {
nodes {
status: detailedStatus {
label
group
icon
}
name
size
jobs {
nodes {
name
scheduledAt
needs {
nodes {
name
}
}
status: detailedStatus {
icon
tooltip
hasDetails
detailsPath
group
action {
buttonTitle
icon
path
title
}
}
}
}
}
}
}
}
}
}
}
...@@ -149,7 +149,9 @@ export default async function() { ...@@ -149,7 +149,9 @@ export default async function() {
const { createPipelinesDetailApp } = await import( const { createPipelinesDetailApp } = await import(
/* webpackChunkName: 'createPipelinesDetailApp' */ './pipeline_details_graph' /* webpackChunkName: 'createPipelinesDetailApp' */ './pipeline_details_graph'
); );
createPipelinesDetailApp();
const { pipelineProjectPath, pipelineIid } = dataset;
createPipelinesDetailApp(SELECTORS.PIPELINE_DETAILS, pipelineProjectPath, pipelineIid);
} catch { } catch {
Flash(__('An error occurred while loading the pipeline.')); Flash(__('An error occurred while loading the pipeline.'));
} }
......
const createPipelinesDetailApp = () => { import Vue from 'vue';
// Placeholder. See: https://gitlab.com/gitlab-org/gitlab/-/issues/223262 import VueApollo from 'vue-apollo';
// eslint-disable-next-line no-useless-return import createDefaultClient from '~/lib/graphql';
return; import PipelineGraphWrapper from './components/graph/graph_component_wrapper.vue';
Vue.use(VueApollo);
const apolloProvider = new VueApollo({
defaultClient: createDefaultClient(),
});
const createPipelinesDetailApp = (selector, pipelineProjectPath, pipelineIid) => {
// eslint-disable-next-line no-new
new Vue({
el: selector,
components: {
PipelineGraphWrapper,
},
apolloProvider,
provide: {
pipelineProjectPath,
pipelineIid,
},
render(createElement) {
return createElement(PipelineGraphWrapper);
},
});
}; };
export { createPipelinesDetailApp }; export { createPipelinesDetailApp };
...@@ -23,4 +23,4 @@ ...@@ -23,4 +23,4 @@
= render "projects/pipelines/with_tabs", pipeline: @pipeline, pipeline_has_errors: pipeline_has_errors = render "projects/pipelines/with_tabs", pipeline: @pipeline, pipeline_has_errors: pipeline_has_errors
.js-pipeline-details-vue{ data: { endpoint: project_pipeline_path(@project, @pipeline, format: :json) } } .js-pipeline-details-vue{ data: { endpoint: project_pipeline_path(@project, @pipeline, format: :json), pipeline_project_path: @project.full_path, pipeline_iid: @pipeline.iid } }
...@@ -30346,6 +30346,9 @@ msgstr "" ...@@ -30346,6 +30346,9 @@ msgstr ""
msgid "We are currently unable to fetch data for this graph." msgid "We are currently unable to fetch data for this graph."
msgstr "" msgstr ""
msgid "We are currently unable to fetch data for this pipeline."
msgstr ""
msgid "We could not determine the path to remove the epic" msgid "We could not determine the path to remove the epic"
msgstr "" msgstr ""
......
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import { shallowMount } from '@vue/test-utils';
import { GlAlert, GlLoadingIcon } from '@gitlab/ui';
import createMockApollo from 'jest/helpers/mock_apollo_helper';
import PipelineGraphWrapper from '~/pipelines/components/graph/graph_component_wrapper.vue';
import PipelineGraph from '~/pipelines/components/graph/graph_component.vue';
import getPipelineDetails from '~/pipelines/graphql/queries/get_pipeline_details.query.graphql';
import { mockPipelineResponse } from './mock_data';
const defaultProvide = {
pipelineProjectPath: 'frog/amphibirama',
pipelineIid: '22',
};
describe('Pipeline graph wrapper', () => {
Vue.use(VueApollo);
let wrapper;
const getAlert = () => wrapper.find(GlAlert);
const getLoadingIcon = () => wrapper.find(GlLoadingIcon);
const getGraph = () => wrapper.find(PipelineGraph);
const createComponent = ({
apolloProvider,
data = {},
provide = defaultProvide,
mountFn = shallowMount,
} = {}) => {
wrapper = mountFn(PipelineGraphWrapper, {
provide,
apolloProvider,
data() {
return {
...data,
};
},
});
};
const createComponentWithApollo = (
getPipelineDetailsHandler = jest.fn().mockResolvedValue(mockPipelineResponse),
) => {
const requestHandlers = [[getPipelineDetails, getPipelineDetailsHandler]];
const apolloProvider = createMockApollo(requestHandlers);
createComponent({ apolloProvider });
};
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
describe('when data is loading', () => {
it('displays the loading icon', () => {
createComponentWithApollo();
expect(getLoadingIcon().exists()).toBe(true);
});
it('does not display the alert', () => {
createComponentWithApollo();
expect(getAlert().exists()).toBe(false);
});
it('does not display the graph', () => {
createComponentWithApollo();
expect(getGraph().exists()).toBe(false);
});
});
describe('when data has loaded', () => {
beforeEach(async () => {
createComponentWithApollo();
jest.runOnlyPendingTimers();
await wrapper.vm.$nextTick();
});
it('does not display the loading icon', () => {
expect(getLoadingIcon().exists()).toBe(false);
});
it('does not display the alert', () => {
expect(getAlert().exists()).toBe(false);
});
it('displays the graph', () => {
expect(getGraph().exists()).toBe(true);
});
});
describe('when there is an error', () => {
beforeEach(async () => {
createComponentWithApollo(jest.fn().mockRejectedValue(new Error('GraphQL error')));
jest.runOnlyPendingTimers();
await wrapper.vm.$nextTick();
});
it('does not display the loading icon', () => {
expect(getLoadingIcon().exists()).toBe(false);
});
it('displays the alert', () => {
expect(getAlert().exists()).toBe(true);
});
it('does not display the graph', () => {
expect(getGraph().exists()).toBe(false);
});
});
});
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