Commit bd1122ee authored by Paul Slaughter's avatar Paul Slaughter

Fix vue render error for IDE status bar

**What?**

A Vue warning that `ide_status_bar` sent a `Boolean` to a `String`
property (`img-src).

**What was the fix?**

Previously, `latestPipeline` could be one of the following values:

|          |        |
|----------|--------|
| `null`   | The pipeline hasn't loaded yet |
| `false`  | The pipeline has loaded, but nothing was returned. |
| `Object` | The piepline has loaded. |

Giving a semantic meaning to different falsey values hurts
maintainability. This commit fixes the above problem by removing the
`false` value and introducing a `hasLoadedPipeline` state property.
parent 7926384f
...@@ -24,7 +24,13 @@ export default { ...@@ -24,7 +24,13 @@ export default {
...mapState(['pipelinesEmptyStateSvgPath', 'links']), ...mapState(['pipelinesEmptyStateSvgPath', 'links']),
...mapGetters(['currentProject']), ...mapGetters(['currentProject']),
...mapGetters('pipelines', ['jobsCount', 'failedJobsCount', 'failedStages', 'pipelineFailed']), ...mapGetters('pipelines', ['jobsCount', 'failedJobsCount', 'failedStages', 'pipelineFailed']),
...mapState('pipelines', ['isLoadingPipeline', 'latestPipeline', 'stages', 'isLoadingJobs']), ...mapState('pipelines', [
'isLoadingPipeline',
'hasLoadedPipeline',
'latestPipeline',
'stages',
'isLoadingJobs',
]),
ciLintText() { ciLintText() {
return sprintf( return sprintf(
__('You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}.'), __('You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}.'),
...@@ -36,7 +42,7 @@ export default { ...@@ -36,7 +42,7 @@ export default {
); );
}, },
showLoadingIcon() { showLoadingIcon() {
return this.isLoadingPipeline && this.latestPipeline === null; return this.isLoadingPipeline && !this.hasLoadedPipeline;
}, },
}, },
created() { created() {
...@@ -51,7 +57,7 @@ export default { ...@@ -51,7 +57,7 @@ export default {
<template> <template>
<div class="ide-pipeline"> <div class="ide-pipeline">
<gl-loading-icon v-if="showLoadingIcon" :size="2" class="prepend-top-default" /> <gl-loading-icon v-if="showLoadingIcon" :size="2" class="prepend-top-default" />
<template v-else-if="latestPipeline !== null"> <template v-else-if="hasLoadedPipeline">
<header v-if="latestPipeline" class="ide-tree-header ide-pipeline-header"> <header v-if="latestPipeline" class="ide-tree-header ide-pipeline-header">
<ci-icon :status="latestPipeline.details.status" :size="24" /> <ci-icon :status="latestPipeline.details.status" :size="24" />
<span class="prepend-left-8"> <span class="prepend-left-8">
...@@ -62,7 +68,7 @@ export default { ...@@ -62,7 +68,7 @@ export default {
</span> </span>
</header> </header>
<empty-state <empty-state
v-if="latestPipeline === false" v-if="!latestPipeline"
:help-page-path="links.ciHelpPagePath" :help-page-path="links.ciHelpPagePath"
:empty-state-svg-path="pipelinesEmptyStateSvgPath" :empty-state-svg-path="pipelinesEmptyStateSvgPath"
:can-set-ci="true" :can-set-ci="true"
......
...@@ -10,6 +10,7 @@ export default { ...@@ -10,6 +10,7 @@ export default {
}, },
[types.RECEIVE_LASTEST_PIPELINE_SUCCESS](state, pipeline) { [types.RECEIVE_LASTEST_PIPELINE_SUCCESS](state, pipeline) {
state.isLoadingPipeline = false; state.isLoadingPipeline = false;
state.hasLoadedPipeline = true;
if (pipeline) { if (pipeline) {
state.latestPipeline = { state.latestPipeline = {
...@@ -34,7 +35,7 @@ export default { ...@@ -34,7 +35,7 @@ export default {
}; };
}); });
} else { } else {
state.latestPipeline = false; state.latestPipeline = null;
} }
}, },
[types.REQUEST_JOBS](state, id) { [types.REQUEST_JOBS](state, id) {
......
export default () => ({ export default () => ({
isLoadingPipeline: true, isLoadingPipeline: true,
hasLoadedPipeline: false,
isLoadingJobs: false, isLoadingJobs: false,
latestPipeline: null, latestPipeline: null,
stages: [], stages: [],
......
...@@ -11,6 +11,8 @@ describe('IDE pipelines list', () => { ...@@ -11,6 +11,8 @@ describe('IDE pipelines list', () => {
let vm; let vm;
let mock; let mock;
const findLoadingState = () => vm.$el.querySelector('.loading-container');
beforeEach(done => { beforeEach(done => {
const store = createStore(); const store = createStore();
...@@ -95,7 +97,7 @@ describe('IDE pipelines list', () => { ...@@ -95,7 +97,7 @@ describe('IDE pipelines list', () => {
describe('empty state', () => { describe('empty state', () => {
it('renders pipelines empty state', done => { it('renders pipelines empty state', done => {
vm.$store.state.pipelines.latestPipeline = false; vm.$store.state.pipelines.latestPipeline = null;
vm.$nextTick(() => { vm.$nextTick(() => {
expect(vm.$el.querySelector('.empty-state')).not.toBe(null); expect(vm.$el.querySelector('.empty-state')).not.toBe(null);
...@@ -106,15 +108,30 @@ describe('IDE pipelines list', () => { ...@@ -106,15 +108,30 @@ describe('IDE pipelines list', () => {
}); });
describe('loading state', () => { describe('loading state', () => {
it('renders loading state when there is no latest pipeline', done => { beforeEach(() => {
vm.$store.state.pipelines.latestPipeline = null;
vm.$store.state.pipelines.isLoadingPipeline = true; vm.$store.state.pipelines.isLoadingPipeline = true;
});
vm.$nextTick(() => { it('does not render when pipeline has loaded before', done => {
expect(vm.$el.querySelector('.loading-container')).not.toBe(null); vm.$store.state.pipelines.hasLoadedPipeline = true;
done(); vm.$nextTick()
}); .then(() => {
expect(findLoadingState()).toBe(null);
})
.then(done)
.catch(done.fail);
});
it('renders loading state when there is no latest pipeline', done => {
vm.$store.state.pipelines.hasLoadedPipeline = false;
vm.$nextTick()
.then(() => {
expect(findLoadingState()).not.toBe(null);
})
.then(done)
.catch(done.fail);
}); });
}); });
}); });
...@@ -27,63 +27,71 @@ describe('IDE pipelines mutations', () => { ...@@ -27,63 +27,71 @@ describe('IDE pipelines mutations', () => {
}); });
describe(types.RECEIVE_LASTEST_PIPELINE_SUCCESS, () => { describe(types.RECEIVE_LASTEST_PIPELINE_SUCCESS, () => {
it('sets loading to false on success', () => { const itSetsPipelineLoadingStates = () => {
mutations[types.RECEIVE_LASTEST_PIPELINE_SUCCESS]( it('sets has loaded to true', () => {
mockedState, expect(mockedState.hasLoadedPipeline).toBe(true);
fullPipelinesResponse.data.pipelines[0], });
);
expect(mockedState.isLoadingPipeline).toBe(false); it('sets loading to false on success', () => {
}); expect(mockedState.isLoadingPipeline).toBe(false);
});
};
describe('with pipeline', () => {
beforeEach(() => {
mutations[types.RECEIVE_LASTEST_PIPELINE_SUCCESS](
mockedState,
fullPipelinesResponse.data.pipelines[0],
);
});
it('sets latestPipeline', () => { itSetsPipelineLoadingStates();
mutations[types.RECEIVE_LASTEST_PIPELINE_SUCCESS](
mockedState,
fullPipelinesResponse.data.pipelines[0],
);
expect(mockedState.latestPipeline).toEqual({ it('sets latestPipeline', () => {
id: '51', expect(mockedState.latestPipeline).toEqual({
path: 'test', id: '51',
commit: { id: '123' }, path: 'test',
details: { status: jasmine.any(Object) }, commit: { id: '123' },
yamlError: undefined, details: { status: jasmine.any(Object) },
yamlError: undefined,
});
}); });
});
it('does not set latest pipeline if pipeline is null', () => { it('sets stages', () => {
mutations[types.RECEIVE_LASTEST_PIPELINE_SUCCESS](mockedState, null); expect(mockedState.stages.length).toBe(2);
expect(mockedState.stages).toEqual([
expect(mockedState.latestPipeline).toEqual(false); {
id: 0,
dropdownPath: stages[0].dropdown_path,
name: stages[0].name,
status: stages[0].status,
isCollapsed: false,
isLoading: false,
jobs: [],
},
{
id: 1,
dropdownPath: stages[1].dropdown_path,
name: stages[1].name,
status: stages[1].status,
isCollapsed: false,
isLoading: false,
jobs: [],
},
]);
});
}); });
it('sets stages', () => { describe('with null', () => {
mutations[types.RECEIVE_LASTEST_PIPELINE_SUCCESS]( beforeEach(() => {
mockedState, mutations[types.RECEIVE_LASTEST_PIPELINE_SUCCESS](mockedState, null);
fullPipelinesResponse.data.pipelines[0], });
);
expect(mockedState.stages.length).toBe(2); itSetsPipelineLoadingStates();
expect(mockedState.stages).toEqual([
{ it('does not set latest pipeline if pipeline is null', () => {
id: 0, expect(mockedState.latestPipeline).toEqual(null);
dropdownPath: stages[0].dropdown_path, });
name: stages[0].name,
status: stages[0].status,
isCollapsed: false,
isLoading: false,
jobs: [],
},
{
id: 1,
dropdownPath: stages[1].dropdown_path,
name: stages[1].name,
status: stages[1].status,
isCollapsed: false,
isLoading: false,
jobs: [],
},
]);
}); });
}); });
......
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