Commit 04c2c5a6 authored by PaytonBurdette's avatar PaytonBurdette

Add polling to commit box graph

Add graphql polling to the mini
pipeline graph in the commit box.
This fixes the two graphs being out
of sync.

Changelog: fixed
parent cacf9078
...@@ -3,11 +3,20 @@ import { GlLoadingIcon } from '@gitlab/ui'; ...@@ -3,11 +3,20 @@ import { GlLoadingIcon } from '@gitlab/ui';
import createFlash from '~/flash'; import createFlash from '~/flash';
import { __ } from '~/locale'; import { __ } from '~/locale';
import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_mini_graph.vue'; import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_mini_graph.vue';
import {
getQueryHeaders,
toggleQueryPollingByVisibility,
} from '~/pipelines/components/graph/utils';
import { formatStages } from '../utils';
import getLinkedPipelinesQuery from '../graphql/queries/get_linked_pipelines.query.graphql'; import getLinkedPipelinesQuery from '../graphql/queries/get_linked_pipelines.query.graphql';
import getPipelineStagesQuery from '../graphql/queries/get_pipeline_stages.query.graphql';
import { PIPELINE_STAGES_POLL_INTERVAL } from '../constants';
export default { export default {
i18n: { i18n: {
linkedPipelinesFetchError: __('There was a problem fetching linked pipelines.'), linkedPipelinesFetchError: __('There was a problem fetching linked pipelines.'),
stageConversionError: __('There was a problem handling the pipeline data.'),
stagesFetchError: __('There was a problem fetching the pipeline stages.'),
}, },
components: { components: {
GlLoadingIcon, GlLoadingIcon,
...@@ -22,6 +31,9 @@ export default { ...@@ -22,6 +31,9 @@ export default {
iid: { iid: {
default: '', default: '',
}, },
graphqlResourceEtag: {
default: '',
},
}, },
props: { props: {
stages: { stages: {
...@@ -48,10 +60,31 @@ export default { ...@@ -48,10 +60,31 @@ export default {
createFlash({ message: this.$options.i18n.linkedPipelinesFetchError }); createFlash({ message: this.$options.i18n.linkedPipelinesFetchError });
}, },
}, },
pipelineStages: {
context() {
return getQueryHeaders(this.graphqlResourceEtag);
},
query: getPipelineStagesQuery,
pollInterval: PIPELINE_STAGES_POLL_INTERVAL,
variables() {
return {
fullPath: this.fullPath,
iid: this.iid,
};
},
update({ project }) {
return project?.pipeline?.stages?.nodes || [];
},
error() {
createFlash({ message: this.$options.i18n.stagesFetchError });
},
},
}, },
data() { data() {
return { return {
formattedStages: [],
pipeline: null, pipeline: null,
pipelineStages: [],
}; };
}, },
computed: { computed: {
...@@ -65,6 +98,25 @@ export default { ...@@ -65,6 +98,25 @@ export default {
return this.pipeline?.upstream; return this.pipeline?.upstream;
}, },
}, },
watch: {
pipelineStages() {
// pipelineStages are from GraphQL
// stages are from REST
// we do this to use dropdown_path for fetching jobs on stage click
try {
this.formattedStages = formatStages(this.pipelineStages, this.stages);
} catch (error) {
createFlash({
message: this.$options.i18n.stageConversionError,
captureError: true,
error,
});
}
},
},
mounted() {
toggleQueryPollingByVisibility(this.$apollo.queries.pipelineStages);
},
}; };
</script> </script>
...@@ -79,7 +131,7 @@ export default { ...@@ -79,7 +131,7 @@ export default {
/> />
<pipeline-mini-graph <pipeline-mini-graph
:stages="stages" :stages="formattedStages"
class="gl-display-inline" class="gl-display-inline"
data-testid="commit-box-mini-graph" data-testid="commit-box-mini-graph"
/> />
......
export const PIPELINE_STAGES_POLL_INTERVAL = 10000;
query getPipelineStages($fullPath: ID!, $iid: ID!) {
project(fullPath: $fullPath) {
id
pipeline(iid: $iid) {
id
stages {
nodes {
id
name
detailedStatus {
id
icon
group
}
}
}
}
}
}
...@@ -5,7 +5,7 @@ import createDefaultClient from '~/lib/graphql'; ...@@ -5,7 +5,7 @@ import createDefaultClient from '~/lib/graphql';
Vue.use(VueApollo); Vue.use(VueApollo);
const apolloProvider = new VueApollo({ const apolloProvider = new VueApollo({
defaultClient: createDefaultClient(), defaultClient: createDefaultClient({}, { useGet: true }),
}); });
export const initCommitPipelineMiniGraph = async (selector = '.js-commit-pipeline-mini-graph') => { export const initCommitPipelineMiniGraph = async (selector = '.js-commit-pipeline-mini-graph') => {
...@@ -15,7 +15,7 @@ export const initCommitPipelineMiniGraph = async (selector = '.js-commit-pipelin ...@@ -15,7 +15,7 @@ export const initCommitPipelineMiniGraph = async (selector = '.js-commit-pipelin
return; return;
} }
const { stages, fullPath, iid } = el.dataset; const { stages, fullPath, iid, graphqlResourceEtag } = el.dataset;
// Some commits have no pipeline, code splitting to load the pipeline optionally // Some commits have no pipeline, code splitting to load the pipeline optionally
const { default: CommitBoxPipelineMiniGraph } = await import( const { default: CommitBoxPipelineMiniGraph } = await import(
...@@ -30,6 +30,7 @@ export const initCommitPipelineMiniGraph = async (selector = '.js-commit-pipelin ...@@ -30,6 +30,7 @@ export const initCommitPipelineMiniGraph = async (selector = '.js-commit-pipelin
fullPath, fullPath,
iid, iid,
dataMethod: 'graphql', dataMethod: 'graphql',
graphqlResourceEtag,
}, },
render(createElement) { render(createElement) {
return createElement(CommitBoxPipelineMiniGraph, { return createElement(CommitBoxPipelineMiniGraph, {
......
export const formatStages = (graphQLStages = [], restStages = []) => {
if (graphQLStages.length !== restStages.length) {
throw new Error('Rest stages and graphQl stages must be the same length');
}
return graphQLStages.map((stage, index) => {
return {
name: stage.name,
status: stage.detailedStatus,
dropdown_path: restStages[index]?.dropdown_path || '',
title: restStages[index].title || '',
};
});
};
...@@ -57,7 +57,7 @@ ...@@ -57,7 +57,7 @@
#{ n_(s_('Pipeline|with stage'), s_('Pipeline|with stages'), @last_pipeline.stages_count) } #{ n_(s_('Pipeline|with stage'), s_('Pipeline|with stages'), @last_pipeline.stages_count) }
.mr-widget-pipeline-graph .mr-widget-pipeline-graph
.stage-cell .stage-cell
.js-commit-pipeline-mini-graph{ data: { stages: @last_pipeline_stages.to_json.html_safe, full_path: @project.full_path, iid: @last_pipeline.iid } } .js-commit-pipeline-mini-graph{ data: { stages: @last_pipeline_stages.to_json.html_safe, full_path: @project.full_path, iid: @last_pipeline.iid, graphql_resource_etag: graphql_etag_pipeline_path(@last_pipeline) } }
- if @last_pipeline.duration - if @last_pipeline.duration
in in
= time_interval_in_words @last_pipeline.duration = time_interval_in_words @last_pipeline.duration
......
...@@ -7,12 +7,16 @@ import { extendedWrapper } from 'helpers/vue_test_utils_helper'; ...@@ -7,12 +7,16 @@ import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises'; import waitForPromises from 'helpers/wait_for_promises';
import createFlash from '~/flash'; import createFlash from '~/flash';
import CommitBoxPipelineMiniGraph from '~/projects/commit_box/info/components/commit_box_pipeline_mini_graph.vue'; import CommitBoxPipelineMiniGraph from '~/projects/commit_box/info/components/commit_box_pipeline_mini_graph.vue';
import { PIPELINE_STAGES_POLL_INTERVAL } from '~/projects/commit_box/info/constants';
import getLinkedPipelinesQuery from '~/projects/commit_box/info/graphql/queries/get_linked_pipelines.query.graphql'; import getLinkedPipelinesQuery from '~/projects/commit_box/info/graphql/queries/get_linked_pipelines.query.graphql';
import getPipelineStagesQuery from '~/projects/commit_box/info/graphql/queries/get_pipeline_stages.query.graphql';
import * as graphQlUtils from '~/pipelines/components/graph/utils';
import { import {
mockDownstreamQueryResponse, mockDownstreamQueryResponse,
mockUpstreamQueryResponse, mockUpstreamQueryResponse,
mockUpstreamDownstreamQueryResponse, mockUpstreamDownstreamQueryResponse,
mockStages, mockStages,
mockPipelineStagesQueryResponse,
} from '../mock_data'; } from '../mock_data';
const fullPath = 'gitlab-org/gitlab'; const fullPath = 'gitlab-org/gitlab';
...@@ -30,14 +34,22 @@ describe('Commit box pipeline mini graph', () => { ...@@ -30,14 +34,22 @@ describe('Commit box pipeline mini graph', () => {
.fn() .fn()
.mockResolvedValue(mockUpstreamDownstreamQueryResponse); .mockResolvedValue(mockUpstreamDownstreamQueryResponse);
const failedHandler = jest.fn().mockRejectedValue(new Error('GraphQL error')); const failedHandler = jest.fn().mockRejectedValue(new Error('GraphQL error'));
const stagesHandler = jest.fn().mockResolvedValue(mockPipelineStagesQueryResponse);
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const findMiniGraph = () => wrapper.findByTestId('commit-box-mini-graph'); const findMiniGraph = () => wrapper.findByTestId('commit-box-mini-graph');
const findUpstream = () => wrapper.findByTestId('commit-box-mini-graph-upstream'); const findUpstream = () => wrapper.findByTestId('commit-box-mini-graph-upstream');
const findDownstream = () => wrapper.findByTestId('commit-box-mini-graph-downstream'); const findDownstream = () => wrapper.findByTestId('commit-box-mini-graph-downstream');
const createMockApolloProvider = (handler) => { const advanceToNextFetch = () => {
const requestHandlers = [[getLinkedPipelinesQuery, handler]]; jest.advanceTimersByTime(PIPELINE_STAGES_POLL_INTERVAL);
};
const createMockApolloProvider = (handler = downstreamHandler) => {
const requestHandlers = [
[getLinkedPipelinesQuery, handler],
[getPipelineStagesQuery, stagesHandler],
];
return createMockApollo(requestHandlers); return createMockApollo(requestHandlers);
}; };
...@@ -52,6 +64,7 @@ describe('Commit box pipeline mini graph', () => { ...@@ -52,6 +64,7 @@ describe('Commit box pipeline mini graph', () => {
fullPath, fullPath,
iid, iid,
dataMethod: 'graphql', dataMethod: 'graphql',
graphqlResourceEtag: '/api/graphql:pipelines/id/320',
}, },
apolloProvider: createMockApolloProvider(handler), apolloProvider: createMockApolloProvider(handler),
}), }),
...@@ -64,15 +77,16 @@ describe('Commit box pipeline mini graph', () => { ...@@ -64,15 +77,16 @@ describe('Commit box pipeline mini graph', () => {
describe('loading state', () => { describe('loading state', () => {
it('should display loading state when loading', () => { it('should display loading state when loading', () => {
createComponent(downstreamHandler); createComponent();
expect(findLoadingIcon().exists()).toBe(true); expect(findLoadingIcon().exists()).toBe(true);
expect(findMiniGraph().exists()).toBe(false);
}); });
}); });
describe('loaded state', () => { describe('loaded state', () => {
it('should not display loading state after the query is resolved', async () => { it('should not display loading state after the query is resolved', async () => {
createComponent(downstreamHandler); createComponent();
await waitForPromises(); await waitForPromises();
...@@ -81,7 +95,7 @@ describe('Commit box pipeline mini graph', () => { ...@@ -81,7 +95,7 @@ describe('Commit box pipeline mini graph', () => {
}); });
it('should pass the pipeline path prop for the counter badge', async () => { it('should pass the pipeline path prop for the counter badge', async () => {
createComponent(downstreamHandler); createComponent();
await waitForPromises(); await waitForPromises();
...@@ -105,6 +119,28 @@ describe('Commit box pipeline mini graph', () => { ...@@ -105,6 +119,28 @@ describe('Commit box pipeline mini graph', () => {
expect(findUpstream().exists()).toBe(upstreamRenders); expect(findUpstream().exists()).toBe(upstreamRenders);
}); });
}); });
it('formatted stages should be passed to the pipeline mini graph', async () => {
const stage = mockStages[0];
const expectedStages = [
{
name: stage.name,
status: {
id: stage.status.id,
icon: stage.status.icon,
group: stage.status.group,
},
dropdown_path: stage.dropdown_path,
title: stage.title,
},
];
createComponent();
await waitForPromises();
expect(findMiniGraph().props('stages')).toEqual(expectedStages);
});
}); });
describe('error state', () => { describe('error state', () => {
...@@ -118,4 +154,44 @@ describe('Commit box pipeline mini graph', () => { ...@@ -118,4 +154,44 @@ describe('Commit box pipeline mini graph', () => {
}); });
}); });
}); });
describe('polling', () => {
it('polling interval is set for pipeline stages', () => {
createComponent();
const expectedInterval = wrapper.vm.$apollo.queries.pipelineStages.options.pollInterval;
expect(expectedInterval).toBe(PIPELINE_STAGES_POLL_INTERVAL);
});
it('polls for stages', async () => {
createComponent();
await waitForPromises();
expect(stagesHandler).toHaveBeenCalledTimes(1);
advanceToNextFetch();
await waitForPromises();
expect(stagesHandler).toHaveBeenCalledTimes(2);
advanceToNextFetch();
await waitForPromises();
expect(stagesHandler).toHaveBeenCalledTimes(3);
});
it('toggles pipelineStages polling with visibility check', async () => {
jest.spyOn(graphQlUtils, 'toggleQueryPollingByVisibility');
createComponent();
await waitForPromises();
expect(graphQlUtils.toggleQueryPollingByVisibility).toHaveBeenCalledWith(
wrapper.vm.$apollo.queries.pipelineStages,
);
});
});
}); });
...@@ -104,133 +104,50 @@ export const mockUpstreamDownstreamQueryResponse = { ...@@ -104,133 +104,50 @@ export const mockUpstreamDownstreamQueryResponse = {
}, },
}; };
export const mockStages = [ export const mockPipelineStagesQueryResponse = {
{ data: {
id: 'stage-1', project: {
name: 'build', id: 'gid://gitlab/Project/20',
title: 'build: passed', pipeline: {
status: { id: 'gid://gitlab/Ci::Pipeline/320',
id: 'status-1', stages: {
icon: 'status_success', nodes: [
text: 'passed', {
label: 'passed', __typename: 'CiStage',
group: 'success', id: 'gid://gitlab/Ci::Stage/409',
tooltip: 'passed', name: 'build',
has_details: true, detailedStatus: {
details_path: '/root/ci-project/-/pipelines/611#build', id: 'success-409-409',
illustration: null, group: 'success',
favicon: icon: 'status_success',
'/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png', __typename: 'DetailedStatus',
}, },
path: '/root/ci-project/-/pipelines/611#build', },
dropdown_path: '/root/ci-project/-/pipelines/611/stage.json?stage=build', ],
}, },
{
id: 'stage-2',
name: 'test',
title: 'test: passed',
status: {
id: 'status-2',
icon: 'status_success',
text: 'passed',
label: 'passed',
group: 'success',
tooltip: 'passed',
has_details: true,
details_path: '/root/ci-project/-/pipelines/611#test',
illustration: null,
favicon:
'/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
},
path: '/root/ci-project/-/pipelines/611#test',
dropdown_path: '/root/ci-project/-/pipelines/611/stage.json?stage=test',
},
{
id: 'stage-3',
name: 'test_two',
title: 'test_two: passed',
status: {
id: 'status-3',
icon: 'status_success',
text: 'passed',
label: 'passed',
group: 'success',
tooltip: 'passed',
has_details: true,
details_path: '/root/ci-project/-/pipelines/611#test_two',
illustration: null,
favicon:
'/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
},
path: '/root/ci-project/-/pipelines/611#test_two',
dropdown_path: '/root/ci-project/-/pipelines/611/stage.json?stage=test_two',
},
{
id: 'stage-4',
name: 'manual',
title: 'manual: skipped',
status: {
id: 'status-4',
icon: 'status_skipped',
text: 'skipped',
label: 'skipped',
group: 'skipped',
tooltip: 'skipped',
has_details: true,
details_path: '/root/ci-project/-/pipelines/611#manual',
illustration: null,
favicon:
'/assets/ci_favicons/favicon_status_skipped-0b9c5e543588945e8c4ca57786bbf2d0c56631959c9f853300392d0315be829b.png',
action: {
id: 'action-4',
icon: 'play',
title: 'Play all manual',
path: '/root/ci-project/-/pipelines/611/stages/manual/play_manual',
method: 'post',
button_title: 'Play all manual',
}, },
}, },
path: '/root/ci-project/-/pipelines/611#manual',
dropdown_path: '/root/ci-project/-/pipelines/611/stage.json?stage=manual',
},
{
id: 'stage-5',
name: 'deploy',
title: 'deploy: passed',
status: {
id: 'status-5',
icon: 'status_success',
text: 'passed',
label: 'passed',
group: 'success',
tooltip: 'passed',
has_details: true,
details_path: '/root/ci-project/-/pipelines/611#deploy',
illustration: null,
favicon:
'/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
},
path: '/root/ci-project/-/pipelines/611#deploy',
dropdown_path: '/root/ci-project/-/pipelines/611/stage.json?stage=deploy',
}, },
};
export const mockStages = [
{ {
id: 'stage-6', name: 'build',
name: 'qa', title: 'build: passed',
title: 'qa: passed',
status: { status: {
id: 'status-6', id: 'success-409-409',
icon: 'status_success', icon: 'status_success',
text: 'passed', text: 'passed',
label: 'passed', label: 'passed',
group: 'success', group: 'success',
tooltip: 'passed', tooltip: 'passed',
has_details: true, has_details: true,
details_path: '/root/ci-project/-/pipelines/611#qa', details_path: '/root/ci-project/-/pipelines/318#build',
illustration: null, illustration: null,
favicon: favicon:
'/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png', '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
}, },
path: '/root/ci-project/-/pipelines/611#qa', path: '/root/ci-project/-/pipelines/318#build',
dropdown_path: '/root/ci-project/-/pipelines/611/stage.json?stage=qa', dropdown_path: '/root/ci-project/-/pipelines/318/stage.json?stage=build',
}, },
]; ];
...@@ -37999,12 +37999,18 @@ msgstr "" ...@@ -37999,12 +37999,18 @@ msgstr ""
msgid "There was a problem fetching the keep latest artifacts setting." msgid "There was a problem fetching the keep latest artifacts setting."
msgstr "" msgstr ""
msgid "There was a problem fetching the pipeline stages."
msgstr ""
msgid "There was a problem fetching the projects" msgid "There was a problem fetching the projects"
msgstr "" msgstr ""
msgid "There was a problem fetching users." msgid "There was a problem fetching users."
msgstr "" msgstr ""
msgid "There was a problem handling the pipeline data."
msgstr ""
msgid "There was a problem sending the confirmation email" msgid "There was a problem sending the confirmation email"
msgstr "" msgstr ""
......
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import createMockApollo from 'helpers/mock_apollo_helper';
import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import createFlash from '~/flash';
import CommitBoxPipelineMiniGraph from '~/projects/commit_box/info/components/commit_box_pipeline_mini_graph.vue'; import CommitBoxPipelineMiniGraph from '~/projects/commit_box/info/components/commit_box_pipeline_mini_graph.vue';
import { mockStages } from './mock_data'; import getLinkedPipelinesQuery from '~/projects/commit_box/info/graphql/queries/get_linked_pipelines.query.graphql';
import getPipelineStagesQuery from '~/projects/commit_box/info/graphql/queries/get_pipeline_stages.query.graphql';
import { mockPipelineStagesQueryResponse, mockStages } from './mock_data';
jest.mock('~/flash');
Vue.use(VueApollo);
describe('Commit box pipeline mini graph', () => { describe('Commit box pipeline mini graph', () => {
let wrapper; let wrapper;
...@@ -10,34 +21,36 @@ describe('Commit box pipeline mini graph', () => { ...@@ -10,34 +21,36 @@ describe('Commit box pipeline mini graph', () => {
const findUpstream = () => wrapper.findByTestId('commit-box-mini-graph-upstream'); const findUpstream = () => wrapper.findByTestId('commit-box-mini-graph-upstream');
const findDownstream = () => wrapper.findByTestId('commit-box-mini-graph-downstream'); const findDownstream = () => wrapper.findByTestId('commit-box-mini-graph-downstream');
const createComponent = () => { const stagesHandler = jest.fn().mockResolvedValue(mockPipelineStagesQueryResponse);
const createComponent = ({ props = {} } = {}) => {
const handlers = [
[getLinkedPipelinesQuery, {}],
[getPipelineStagesQuery, stagesHandler],
];
wrapper = extendedWrapper( wrapper = extendedWrapper(
shallowMount(CommitBoxPipelineMiniGraph, { shallowMount(CommitBoxPipelineMiniGraph, {
propsData: { propsData: {
stages: mockStages, stages: mockStages,
...props,
}, },
mocks: { apolloProvider: createMockApollo(handlers),
$apollo: {
queries: {
pipeline: {
loading: false,
},
},
},
},
}), }),
); );
};
beforeEach(() => { return waitForPromises();
createComponent(); };
});
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
}); });
describe('linked pipelines', () => { describe('linked pipelines', () => {
beforeEach(async () => {
await createComponent();
});
it('should display the mini pipeine graph', () => { it('should display the mini pipeine graph', () => {
expect(findMiniGraph().exists()).toBe(true); expect(findMiniGraph().exists()).toBe(true);
}); });
...@@ -47,4 +60,18 @@ describe('Commit box pipeline mini graph', () => { ...@@ -47,4 +60,18 @@ describe('Commit box pipeline mini graph', () => {
expect(findDownstream().exists()).toBe(false); expect(findDownstream().exists()).toBe(false);
}); });
}); });
describe('when data is mismatched', () => {
beforeEach(async () => {
await createComponent({ props: { stages: [] } });
});
it('calls create flash with expected arguments', () => {
expect(createFlash).toHaveBeenCalledWith({
message: 'There was a problem handling the pipeline data.',
captureError: true,
error: new Error('Rest stages and graphQl stages must be the same length'),
});
});
});
}); });
...@@ -115,3 +115,29 @@ export const mockStages = [ ...@@ -115,3 +115,29 @@ export const mockStages = [
dropdown_path: '/root/ci-project/-/pipelines/611/stage.json?stage=qa', dropdown_path: '/root/ci-project/-/pipelines/611/stage.json?stage=qa',
}, },
]; ];
export const mockPipelineStagesQueryResponse = {
data: {
project: {
id: 'gid://gitlab/Project/20',
pipeline: {
id: 'gid://gitlab/Ci::Pipeline/320',
stages: {
nodes: [
{
__typename: 'CiStage',
id: 'gid://gitlab/Ci::Stage/409',
name: 'build',
detailedStatus: {
id: 'success-409-409',
group: 'success',
icon: 'status_success',
__typename: 'DetailedStatus',
},
},
],
},
},
},
},
};
import { formatStages } from '~/projects/commit_box/info/utils';
const graphqlStage = [
{
__typename: 'CiStage',
name: 'deploy',
detailedStatus: {
__typename: 'DetailedStatus',
icon: 'status_success',
group: 'success',
id: 'success-409-409',
},
},
];
const restStage = [
{
name: 'deploy',
title: 'deploy: passed',
status: {
icon: 'status_success',
text: 'passed',
label: 'passed',
group: 'success',
tooltip: 'passed',
has_details: true,
details_path: '/root/ci-project/-/pipelines/318#deploy',
illustration: null,
favicon:
'/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
},
path: '/root/ci-project/-/pipelines/318#deploy',
dropdown_path: '/root/ci-project/-/pipelines/318/stage.json?stage=deploy',
},
];
describe('Utils', () => {
it('combines REST and GraphQL stages correctly for component', () => {
expect(formatStages(graphqlStage, restStage)).toEqual([
{
dropdown_path: '/root/ci-project/-/pipelines/318/stage.json?stage=deploy',
name: 'deploy',
status: {
__typename: 'DetailedStatus',
group: 'success',
icon: 'status_success',
id: 'success-409-409',
},
title: 'deploy: passed',
},
]);
});
it('throws an error if arrays are not the same length', () => {
expect(() => {
formatStages(graphqlStage, []);
}).toThrow('Rest stages and graphQl stages must be the same length');
});
});
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