Commit 3270e140 authored by Phil Hughes's avatar Phil Hughes

changed mutation to return new array

this makes the component completly unaware of the store, instead it emits
events to the parent which knows about the store
parent c9d676c1
<script> <script>
import { mapActions } from 'vuex';
import LoadingIcon from '../../../vue_shared/components/loading_icon.vue'; import LoadingIcon from '../../../vue_shared/components/loading_icon.vue';
import Stage from './stage.vue'; import Stage from './stage.vue';
...@@ -17,6 +18,9 @@ export default { ...@@ -17,6 +18,9 @@ export default {
required: true, required: true,
}, },
}, },
methods: {
...mapActions('pipelines', ['fetchJobs', 'toggleStageCollapsed']),
},
}; };
</script> </script>
...@@ -32,6 +36,8 @@ export default { ...@@ -32,6 +36,8 @@ export default {
v-for="stage in stages" v-for="stage in stages"
:key="stage.id" :key="stage.id"
:stage="stage" :stage="stage"
@fetch="fetchJobs"
@toggleCollapsed="toggleStageCollapsed"
/> />
</template> </template>
</div> </div>
......
<script> <script>
import { mapActions } from 'vuex';
import tooltip from '../../../vue_shared/directives/tooltip'; import tooltip from '../../../vue_shared/directives/tooltip';
import Icon from '../../../vue_shared/components/icon.vue'; import Icon from '../../../vue_shared/components/icon.vue';
import CiIcon from '../../../vue_shared/components/ci_icon.vue'; import CiIcon from '../../../vue_shared/components/ci_icon.vue';
...@@ -38,16 +37,17 @@ export default { ...@@ -38,16 +37,17 @@ export default {
return this.stage.jobs.length; return this.stage.jobs.length;
}, },
}, },
created() {
this.fetchJobs(this.stage);
},
mounted() { mounted() {
const { stageTitle } = this.$refs; const { stageTitle } = this.$refs;
this.showTooltip = stageTitle.scrollWidth > stageTitle.offsetWidth; this.showTooltip = stageTitle.scrollWidth > stageTitle.offsetWidth;
this.$emit('fetch', this.stage);
}, },
methods: { methods: {
...mapActions('pipelines', ['fetchJobs', 'toggleStageCollapsed']), toggleCollapsed() {
this.$emit('toggleCollapsed', this.stage.id);
},
}, },
}; };
</script> </script>
...@@ -61,7 +61,7 @@ export default { ...@@ -61,7 +61,7 @@ export default {
:class="{ :class="{
'border-bottom-0': stage.isCollapsed 'border-bottom-0': stage.isCollapsed
}" }"
@click="toggleStageCollapsed(stage.id)" @click="toggleCollapsed"
> >
<ci-icon <ci-icon
:status="stage.status" :status="stage.status"
......
...@@ -39,20 +39,28 @@ export default { ...@@ -39,20 +39,28 @@ export default {
} }
}, },
[types.REQUEST_JOBS](state, id) { [types.REQUEST_JOBS](state, id) {
const stage = state.stages.find(s => s.id === id); state.stages = state.stages.map(stage => ({
stage.isLoading = true; ...stage,
isLoading: stage.id === id ? true : stage.isLoading,
}));
}, },
[types.RECEIVE_JOBS_ERROR](state, id) { [types.RECEIVE_JOBS_ERROR](state, id) {
const stage = state.stages.find(s => s.id === id); state.stages = state.stages.map(stage => ({
stage.isLoading = false; ...stage,
isLoading: stage.id === id ? false : stage.isLoading,
}));
}, },
[types.RECEIVE_JOBS_SUCCESS](state, { id, data }) { [types.RECEIVE_JOBS_SUCCESS](state, { id, data }) {
const stage = state.stages.find(s => s.id === id); state.stages = state.stages.map(stage => ({
stage.isLoading = false; ...stage,
stage.jobs = data.latest_statuses.map(normalizeJob); isLoading: stage.id === id ? false : stage.isLoading,
jobs: data.latest_statuses.map(normalizeJob),
}));
}, },
[types.TOGGLE_STAGE_COLLAPSE](state, id) { [types.TOGGLE_STAGE_COLLAPSE](state, id) {
const stage = state.stages.find(s => s.id === id); state.stages = state.stages.map(stage => ({
stage.isCollapsed = !stage.isCollapsed; ...stage,
isCollapsed: stage.id === id ? !stage.isCollapsed : stage.isCollapsed,
}));
}, },
}; };
...@@ -21,7 +21,12 @@ describe('IDE stages list', () => { ...@@ -21,7 +21,12 @@ describe('IDE stages list', () => {
isCollapsed: false, isCollapsed: false,
})), })),
loading: false, loading: false,
}).$mount(); });
spyOn(vm, 'fetchJobs');
spyOn(vm, 'toggleStageCollapsed');
vm.$mount();
}); });
afterEach(() => { afterEach(() => {
...@@ -42,4 +47,21 @@ describe('IDE stages list', () => { ...@@ -42,4 +47,21 @@ describe('IDE stages list', () => {
done(); done();
}); });
}); });
it('calls toggleStageCollapsed when clicking stage header', done => {
vm.$el.querySelector('.card-header').click();
vm.$nextTick(() => {
expect(vm.toggleStageCollapsed).toHaveBeenCalledWith(0);
done();
});
});
it('calls fetchJobs when stage is mounted', () => {
expect(vm.fetchJobs.calls.count()).toBe(stages.length);
expect(vm.fetchJobs.calls.argsFor(0)).toEqual([vm.stages[0]]);
expect(vm.fetchJobs.calls.argsFor(1)).toEqual([vm.stages[1]]);
});
}); });
import Vue from 'vue'; import Vue from 'vue';
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import { createStore } from '~/ide/stores';
import Stage from '~/ide/components/jobs/stage.vue'; import Stage from '~/ide/components/jobs/stage.vue';
import { createComponentWithStore } from '../../../helpers/vue_mount_component_helper';
import { stages, jobs } from '../../mock_data'; import { stages, jobs } from '../../mock_data';
describe('IDE pipeline stage', () => { describe('IDE pipeline stage', () => {
const Component = Vue.extend(Stage); const Component = Vue.extend(Stage);
let vm; let vm;
let mock;
let stage; let stage;
beforeEach(done => { beforeEach(() => {
const store = createStore(); stage = {
mock = new MockAdapter(axios); ...stages[0],
id: 0,
Vue.set( dropdownPath: stages[0].dropdown_path,
store.state.pipelines, jobs: [...jobs],
'stages', isLoading: false,
stages.map((mappedState, i) => ({ isCollapsed: false,
...mappedState, };
id: i,
dropdownPath: mappedState.dropdown_path, vm = new Component({
jobs: [], propsData: { stage },
isLoading: false,
isCollapsed: false,
})),
);
stage = store.state.pipelines.stages[0];
mock.onGet(stage.dropdownPath).reply(200, {
latest_statuses: jobs,
}); });
vm = createComponentWithStore(Component, store, { spyOn(vm, '$emit');
stage,
}).$mount();
setTimeout(done, 500); vm.$mount();
}); });
afterEach(() => { afterEach(() => {
vm.$destroy(); vm.$destroy();
});
mock.restore(); it('emits fetch event when mounted', () => {
expect(vm.$emit).toHaveBeenCalledWith('fetch', vm.stage);
}); });
it('renders stages details', () => { it('renders stages details', () => {
...@@ -57,9 +43,19 @@ describe('IDE pipeline stage', () => { ...@@ -57,9 +43,19 @@ describe('IDE pipeline stage', () => {
}); });
describe('collapsed', () => { describe('collapsed', () => {
it('toggles collapse status when clicking header', done => { it('emits event when clicking header', done => {
vm.$el.querySelector('.card-header').click(); vm.$el.querySelector('.card-header').click();
vm.$nextTick(() => {
expect(vm.$emit).toHaveBeenCalledWith('toggleCollapsed', vm.stage.id);
done();
});
});
it('toggles collapse status when collapsed', done => {
vm.stage.isCollapsed = true;
vm.$nextTick(() => { vm.$nextTick(() => {
expect(vm.$el.querySelector('.card-body').style.display).toBe('none'); expect(vm.$el.querySelector('.card-body').style.display).toBe('none');
...@@ -68,7 +64,7 @@ describe('IDE pipeline stage', () => { ...@@ -68,7 +64,7 @@ describe('IDE pipeline stage', () => {
}); });
it('sets border bottom class when collapsed', done => { it('sets border bottom class when collapsed', done => {
vm.$el.querySelector('.card-header').click(); vm.stage.isCollapsed = true;
vm.$nextTick(() => { vm.$nextTick(() => {
expect(vm.$el.querySelector('.card-header').classList).toContain('border-bottom-0'); expect(vm.$el.querySelector('.card-header').classList).toContain('border-bottom-0');
......
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