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