Commit 51edb567 authored by mfluharty's avatar mfluharty

Change store creation to reduce complexity

Based on review feedback,
Move store creation into vue component initialization
Dispatch the fetchReport action right after store creation
Move dataset variables from props to initialState
Eliminate actions/mutations that set dataset variables (and their specs)
In spec, mock the store instead of mocking the axios requests
parent f7dfe54e
...@@ -1091,7 +1091,7 @@ button.mini-pipeline-graph-dropdown-toggle { ...@@ -1091,7 +1091,7 @@ button.mini-pipeline-graph-dropdown-toggle {
} }
.codequality-report { .codequality-report {
> .media { .media {
padding: $gl-padding; padding: $gl-padding;
} }
......
...@@ -6,28 +6,15 @@ import ReportSection from '~/reports/components/report_section.vue'; ...@@ -6,28 +6,15 @@ import ReportSection from '~/reports/components/report_section.vue';
import PaginationLinks from '~/vue_shared/components/pagination_links.vue'; import PaginationLinks from '~/vue_shared/components/pagination_links.vue';
import { n__, s__, sprintf } from '~/locale'; import { n__, s__, sprintf } from '~/locale';
import createStore from './store';
export default { export default {
store: createStore(),
components: { components: {
ReportSection, ReportSection,
PaginationLinks, PaginationLinks,
}, },
mixins: [reportsMixin], mixins: [reportsMixin],
componentNames, componentNames,
props: {
codequalityReportDownloadPath: {
type: String,
required: true,
},
blobPath: {
type: String,
required: true,
},
},
computed: { computed: {
...mapState(['isLoadingCodequality', 'loadingCodequalityFailed', 'endpoint', 'pageInfo']), ...mapState(['isLoadingCodequality', 'loadingCodequalityFailed', 'pageInfo']),
...mapGetters(['codequalityIssues', 'codequalityIssueTotal']), ...mapGetters(['codequalityIssues', 'codequalityIssueTotal']),
hasCodequalityIssues() { hasCodequalityIssues() {
return this.codequalityIssueTotal > 0; return this.codequalityIssueTotal > 0;
...@@ -54,13 +41,8 @@ export default { ...@@ -54,13 +41,8 @@ export default {
return this.checkReportStatus(this.isLoadingCodequality, this.loadingCodequalityFailed); return this.checkReportStatus(this.isLoadingCodequality, this.loadingCodequalityFailed);
}, },
}, },
created() {
this.setEndpoint(this.codequalityReportDownloadPath);
this.setBlobPath(this.blobPath);
this.fetchReport();
},
methods: { methods: {
...mapActions(['setEndpoint', 'setBlobPath', 'setPage', 'fetchReport']), ...mapActions(['setPage']),
translateText(type) { translateText(type) {
return { return {
error: sprintf(s__('ciReport|Failed to load %{reportName} report'), { error: sprintf(s__('ciReport|Failed to load %{reportName} report'), {
......
...@@ -5,9 +5,6 @@ import { s__ } from '~/locale'; ...@@ -5,9 +5,6 @@ import { s__ } from '~/locale';
import MergeRequestStore from 'ee/vue_merge_request_widget/stores/mr_widget_store'; import MergeRequestStore from 'ee/vue_merge_request_widget/stores/mr_widget_store';
export const setEndpoint = ({ commit }, data) => commit(types.SET_ENDPOINT, data);
export const setBlobPath = ({ commit }, data) => commit(types.SET_BLOB_PATH, data);
export const setPage = ({ commit }, page) => commit(types.SET_PAGE, page); export const setPage = ({ commit }, page) => commit(types.SET_PAGE, page);
export const requestReport = ({ commit }) => commit(types.REQUEST_REPORT); export const requestReport = ({ commit }) => commit(types.REQUEST_REPORT);
......
...@@ -7,10 +7,13 @@ import mutations from './mutations'; ...@@ -7,10 +7,13 @@ import mutations from './mutations';
Vue.use(Vuex); Vue.use(Vuex);
export default () => export default (initialState = {}) =>
new Vuex.Store({ new Vuex.Store({
actions, actions,
getters, getters,
mutations, mutations,
state, state: {
...state(),
...initialState,
},
}); });
export const SET_ENDPOINT = 'SET_ENDPOINT';
export const SET_BLOB_PATH = 'SET_BLOB_PATH';
export const SET_PAGE = 'SET_PAGE'; export const SET_PAGE = 'SET_PAGE';
export const REQUEST_REPORT = 'REQUEST_REPORT'; export const REQUEST_REPORT = 'REQUEST_REPORT';
export const RECEIVE_REPORT_SUCCESS = 'RECEIVE_REPORT_SUCCESS'; export const RECEIVE_REPORT_SUCCESS = 'RECEIVE_REPORT_SUCCESS';
......
import * as types from './mutation_types'; import * as types from './mutation_types';
export default { export default {
[types.SET_ENDPOINT](state, endpoint) {
Object.assign(state, { endpoint });
},
[types.SET_BLOB_PATH](state, blobPath) {
Object.assign(state, { blobPath });
},
[types.SET_PAGE](state, page) { [types.SET_PAGE](state, page) {
Object.assign(state, { Object.assign(state, {
pageInfo: Object.assign(state.pageInfo, { pageInfo: Object.assign(state.pageInfo, {
......
import Vue from 'vue'; import Vue from 'vue';
import CodequalityReportApp from 'ee/codequality_report/codequality_report.vue'; import CodequalityReportApp from 'ee/codequality_report/codequality_report.vue';
import Translate from '~/vue_shared/translate'; import Translate from '~/vue_shared/translate';
import createStore from 'ee/codequality_report/store';
Vue.use(Translate); Vue.use(Translate);
...@@ -10,20 +11,17 @@ export default () => { ...@@ -10,20 +11,17 @@ export default () => {
if (codequalityTab) { if (codequalityTab) {
const { codequalityReportDownloadPath, blobPath } = codequalityTab.dataset; const { codequalityReportDownloadPath, blobPath } = codequalityTab.dataset;
const store = createStore({ endpoint: codequalityReportDownloadPath, blobPath });
store.dispatch('fetchReport');
// eslint-disable-next-line no-new // eslint-disable-next-line no-new
new Vue({ new Vue({
el: codequalityTab, el: codequalityTab,
components: { components: {
CodequalityReportApp, CodequalityReportApp,
}, },
render(createElement) { store,
return createElement('codequality-report-app', { render: createElement => createElement('codequality-report-app'),
props: {
codequalityReportDownloadPath,
blobPath,
},
});
},
}); });
} }
}; };
import MockAdapter from 'axios-mock-adapter'; import Vuex from 'vuex';
import axios from '~/lib/utils/axios_utils';
import { TEST_HOST } from 'helpers/test_constants';
import CodequalityReportApp from 'ee/codequality_report/codequality_report.vue'; import CodequalityReportApp from 'ee/codequality_report/codequality_report.vue';
import store from 'ee/codequality_report/store'; import { parsedIssues } from './mock_data';
import { parsedIssues, unparsedIssues } from './mock_data'; import { mount, createLocalVue } from '@vue/test-utils';
import { mount } from '@vue/test-utils';
import waitForPromises from 'helpers/wait_for_promises';
import createFlash from '~/flash';
jest.mock('~/flash', () => jest.fn()); jest.mock('~/flash');
const localVue = createLocalVue();
localVue.use(Vuex);
describe('Codequality report app', () => { describe('Codequality report app', () => {
let wrapper; let wrapper;
let mock; let store;
const codequalityReportDownloadPath = `${TEST_HOST}/codequality_report`; const createComponent = (state = {}, issues = []) => {
store = new Vuex.Store({
state: {
pageInfo: {},
...state,
},
getters: {
codequalityIssues: () => issues,
codequalityIssueTotal: () => issues.length,
},
});
const createComponent = (props = {}) => {
wrapper = mount(CodequalityReportApp, { wrapper = mount(CodequalityReportApp, {
localVue,
store, store,
propsData: {
codequalityReportDownloadPath,
blobPath: '/root/test-codequality/blob/feature-branch',
...props,
},
}); });
}; };
...@@ -31,18 +34,13 @@ describe('Codequality report app', () => { ...@@ -31,18 +34,13 @@ describe('Codequality report app', () => {
const findSuccessIcon = () => wrapper.find('.js-ci-status-icon-success'); const findSuccessIcon = () => wrapper.find('.js-ci-status-icon-success');
const findWarningIcon = () => wrapper.find('.js-ci-status-icon-warning'); const findWarningIcon = () => wrapper.find('.js-ci-status-icon-warning');
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
mock.restore();
}); });
describe('when loading', () => { describe('when loading', () => {
beforeEach(() => { beforeEach(() => {
createComponent(); createComponent({ isLoadingCodequality: true });
}); });
it('shows a loading state', () => { it('shows a loading state', () => {
...@@ -52,34 +50,24 @@ describe('Codequality report app', () => { ...@@ -52,34 +50,24 @@ describe('Codequality report app', () => {
describe('on error', () => { describe('on error', () => {
beforeEach(() => { beforeEach(() => {
mock.onGet(codequalityReportDownloadPath).reply(500); createComponent({ loadingCodequalityFailed: true });
createComponent();
return waitForPromises();
}); });
it('shows a warning icon and error message', () => { it('shows a warning icon and error message', () => {
expect(findWarningIcon().exists()).toBe(true); expect(findWarningIcon().exists()).toBe(true);
expect(findStatus().text()).toBe('Failed to load codeclimate report'); expect(findStatus().text()).toBe('Failed to load codeclimate report');
}); });
it('shows a flash message', () => {
expect(createFlash).toHaveBeenCalled();
});
}); });
describe('when there are codequality issues', () => { describe('when there are codequality issues', () => {
beforeEach(() => { beforeEach(() => {
mock.onGet(codequalityReportDownloadPath).reply(200, unparsedIssues); createComponent({}, parsedIssues);
createComponent();
return waitForPromises();
}); });
it('renders the codequality issues', () => { it('renders the codequality issues', () => {
const expectedIssueTotal = parsedIssues.length; const expectedIssueTotal = parsedIssues.length;
expect(wrapper.vm.$store.state.allCodequalityIssues).toEqual(parsedIssues); expect(findWarningIcon().exists()).toBe(true);
expect(findStatus().text()).toBe(`Found ${expectedIssueTotal} code quality issues`); expect(findStatus().text()).toBe(`Found ${expectedIssueTotal} code quality issues`);
expect(wrapper.findAll('.report-block-list-issue').length).toBe(expectedIssueTotal); expect(wrapper.findAll('.report-block-list-issue').length).toBe(expectedIssueTotal);
}); });
...@@ -87,14 +75,10 @@ describe('Codequality report app', () => { ...@@ -87,14 +75,10 @@ describe('Codequality report app', () => {
describe('when there are no codequality issues', () => { describe('when there are no codequality issues', () => {
beforeEach(() => { beforeEach(() => {
mock.onGet(codequalityReportDownloadPath).reply(200, []); createComponent({}, []);
createComponent();
return waitForPromises();
}); });
it('shows a message that no codequality issues were found', () => { it('shows a message that no codequality issues were found', () => {
expect(wrapper.vm.$store.state.allCodequalityIssues).toEqual([]);
expect(findSuccessIcon().exists()).toBe(true); expect(findSuccessIcon().exists()).toBe(true);
expect(findStatus().text()).toBe('No code quality issues found'); expect(findStatus().text()).toBe('No code quality issues found');
expect(wrapper.findAll('.report-block-list-issue').length).toBe(0); expect(wrapper.findAll('.report-block-list-issue').length).toBe(0);
......
...@@ -27,32 +27,6 @@ describe('Codequality report actions', () => { ...@@ -27,32 +27,6 @@ describe('Codequality report actions', () => {
mock.restore(); mock.restore();
}); });
describe('setEndpoint', () => {
it('sets the endpoint', done => {
testAction(
actions.setEndpoint,
'endpoint',
state,
[{ type: types.SET_ENDPOINT, payload: 'endpoint' }],
[],
done,
);
});
});
describe('setBlobPath', () => {
it('sets the blob path', done => {
testAction(
actions.setBlobPath,
'blobPath',
state,
[{ type: types.SET_BLOB_PATH, payload: 'blobPath' }],
[],
done,
);
});
});
describe('setPage', () => { describe('setPage', () => {
it('sets the page number', done => { it('sets the page number', done => {
testAction(actions.setPage, 12, state, [{ type: types.SET_PAGE, payload: 12 }], [], done); testAction(actions.setPage, 12, state, [{ type: types.SET_PAGE, payload: 12 }], [], done);
......
...@@ -13,20 +13,6 @@ describe('Codequality report mutations', () => { ...@@ -13,20 +13,6 @@ describe('Codequality report mutations', () => {
state = defaultState; state = defaultState;
}); });
describe('set endpoint', () => {
it('should set endpoint', () => {
mutations[types.SET_ENDPOINT](state, 'endpoint');
expect(state.endpoint).toBe('endpoint');
});
});
describe('set blob path', () => {
it('should set blob path', () => {
mutations[types.SET_BLOB_PATH](state, 'blobPath');
expect(state.blobPath).toBe('blobPath');
});
});
describe('set page', () => { describe('set page', () => {
it('should set page', () => { it('should set page', () => {
mutations[types.SET_PAGE](state, 4); mutations[types.SET_PAGE](state, 4);
......
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