Commit e378fd28 authored by Winnie Hellmann's avatar Winnie Hellmann Committed by Mike Greiling

Fix transient failure of group_member_contributions/components/app_spec.js

parent 033f523c
<script> <script>
import { __ } from '~/locale'; import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
import Flash from '~/flash';
import COLUMNS from '../constants'; import COLUMNS from '../constants';
import TableHeader from './table_header.vue'; import TableHeader from './table_header.vue';
import TableBody from './table_body.vue'; import TableBody from './table_body.vue';
import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
export default { export default {
columns: COLUMNS, columns: COLUMNS,
...@@ -20,17 +17,11 @@ export default { ...@@ -20,17 +17,11 @@ export default {
type: Object, type: Object,
required: true, required: true,
}, },
service: {
type: Object,
required: true,
},
},
data() {
return {
isLoading: true,
};
}, },
computed: { computed: {
isLoading() {
return this.store.isLoading;
},
members() { members() {
return this.store.members; return this.store.members;
}, },
...@@ -38,24 +29,7 @@ export default { ...@@ -38,24 +29,7 @@ export default {
return this.store.sortOrders; return this.store.sortOrders;
}, },
}, },
mounted() {
this.fetchContributedMembers();
},
methods: { methods: {
fetchContributedMembers() {
this.service
.getContributedMembers()
.then(res => res.data)
.then(members => {
this.store.setColumns(this.$options.columns);
this.store.setMembers(members);
this.isLoading = false;
})
.catch(() => {
this.isLoading = false;
Flash(__('Something went wrong while fetching group member contributions'));
});
},
handleColumnClick(columnName) { handleColumnClick(columnName) {
this.store.sortMembers(columnName); this.store.sortMembers(columnName);
}, },
......
...@@ -3,7 +3,6 @@ import Vue from 'vue'; ...@@ -3,7 +3,6 @@ import Vue from 'vue';
import Translate from '~/vue_shared/translate'; import Translate from '~/vue_shared/translate';
import GroupMemberStore from './store/group_member_store'; import GroupMemberStore from './store/group_member_store';
import GroupMemberService from './service/group_member_service';
import GroupMemberContributionsApp from './components/app.vue'; import GroupMemberContributionsApp from './components/app.vue';
...@@ -16,19 +15,19 @@ export default () => { ...@@ -16,19 +15,19 @@ export default () => {
return false; return false;
} }
const { memberContributionsPath } = el.dataset;
const store = new GroupMemberStore(memberContributionsPath);
store.fetchContributedMembers();
return new Vue({ return new Vue({
el, el,
components: { components: {
GroupMemberContributionsApp, GroupMemberContributionsApp,
}, },
data() { data() {
const { memberContributionsPath } = el.dataset;
const store = new GroupMemberStore();
const service = new GroupMemberService(memberContributionsPath);
return { return {
store, store,
service,
}; };
}, },
render(createElement) { render(createElement) {
......
import axios from '~/lib/utils/axios_utils';
export default class GroupMemberService {
constructor(memberContributionsPath) {
this.memberContributionsPath = memberContributionsPath;
}
getContributedMembers() {
return axios.get(this.memberContributionsPath);
}
}
import axios from '~/lib/utils/axios_utils';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { __ } from '~/locale';
import Flash from '~/flash';
import COLUMNS from '../constants';
export default class GroupMemberStore { export default class GroupMemberStore {
constructor() { constructor(memberContributionsPath) {
this.memberContributionsPath = memberContributionsPath;
this.state = {}; this.state = {};
this.state.isLoading = true;
this.state.members = []; this.state.members = [];
this.state.columns = []; this.state.columns = [];
this.state.sortOrders = {}; this.state.sortOrders = {};
this.state.currentSortedColumn = ''; this.state.currentSortedColumn = '';
} }
get isLoading() {
return this.state.isLoading;
}
get members() { get members() {
return this.state.members; return this.state.members;
} }
...@@ -53,6 +64,22 @@ export default class GroupMemberStore { ...@@ -53,6 +64,22 @@ export default class GroupMemberStore {
} }
} }
fetchContributedMembers() {
return axios
.get(this.memberContributionsPath)
.then(res => res.data)
.then(members => {
this.setColumns(COLUMNS);
this.setMembers(members);
this.state.isLoading = false;
})
.catch(e => {
this.state.isLoading = false;
Flash(__('Something went wrong while fetching group member contributions'));
throw e;
});
}
static formatMember(rawMember) { static formatMember(rawMember) {
return convertObjectPropsToCamelCase(rawMember); return convertObjectPropsToCamelCase(rawMember);
} }
......
import Vue from 'vue'; import Vue from 'vue';
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import mountComponent from 'spec/helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
import AppComponent from 'ee/group_member_contributions/components/app.vue'; import AppComponent from 'ee/group_member_contributions/components/app.vue';
import GroupMemberStore from 'ee/group_member_contributions/store/group_member_store'; import GroupMemberStore from 'ee/group_member_contributions/store/group_member_store';
import GroupMemberService from 'ee/group_member_contributions/service/group_member_service'; import { contributionsPath } from '../mock_data';
import { contributionsPath, rawMembers } from '../mock_data';
const createComponent = () => { const createComponent = () => {
const Component = Vue.extend(AppComponent); const Component = Vue.extend(AppComponent);
const store = new GroupMemberStore(); const store = new GroupMemberStore(contributionsPath);
const service = new GroupMemberService(contributionsPath);
return mountComponent(Component, { return mountComponent(Component, {
store, store,
service,
}); });
}; };
...@@ -34,51 +28,6 @@ describe('AppComponent', () => { ...@@ -34,51 +28,6 @@ describe('AppComponent', () => {
}); });
describe('methods', () => { describe('methods', () => {
describe('fetchContributedMembers', () => {
let mock;
beforeEach(() => {
mock = new MockAdapter(axios);
document.body.innerHTML += '<div class="flash-container"></div>';
});
afterEach(() => {
mock.restore();
document.querySelector('.flash-container').remove();
});
it('calls service.getContributedMembers and sets response to the store on success', done => {
mock.onGet(vm.service.memberContributionsPath).reply(200, rawMembers);
spyOn(vm.store, 'setColumns');
spyOn(vm.store, 'setMembers');
vm.fetchContributedMembers();
expect(vm.isLoading).toBe(true);
setTimeout(() => {
expect(vm.isLoading).toBe(false);
expect(vm.store.setColumns).toHaveBeenCalledWith(jasmine.any(Object));
expect(vm.store.setMembers).toHaveBeenCalledWith(rawMembers);
done();
}, 0);
});
it('calls service.getContributedMembers and sets `isLoading` to false and shows flash message if request failed', done => {
mock.onGet(vm.service.memberContributionsPath).reply(500, {});
vm.fetchContributedMembers();
expect(vm.isLoading).toBe(true);
setTimeout(() => {
expect(vm.isLoading).toBe(false);
expect(document.querySelector('.flash-text').innerText.trim()).toBe(
'Something went wrong while fetching group member contributions',
);
done();
}, 0);
});
});
describe('handleColumnClick', () => { describe('handleColumnClick', () => {
it('calls store.sortMembers with columnName param', () => { it('calls store.sortMembers with columnName param', () => {
spyOn(vm.store, 'sortMembers'); spyOn(vm.store, 'sortMembers');
...@@ -101,7 +50,7 @@ describe('AppComponent', () => { ...@@ -101,7 +50,7 @@ describe('AppComponent', () => {
}); });
it('shows loading icon when isLoading prop is true', done => { it('shows loading icon when isLoading prop is true', done => {
vm.isLoading = true; vm.store.state.isLoading = true;
vm.$nextTick() vm.$nextTick()
.then(() => { .then(() => {
const loadingEl = vm.$el.querySelector('.loading-animation'); const loadingEl = vm.$el.querySelector('.loading-animation');
...@@ -116,7 +65,7 @@ describe('AppComponent', () => { ...@@ -116,7 +65,7 @@ describe('AppComponent', () => {
}); });
it('renders table container element', done => { it('renders table container element', done => {
vm.isLoading = false; vm.store.state.isLoading = false;
vm.$nextTick() vm.$nextTick()
.then(() => { .then(() => {
expect(vm.$el.querySelector('table.table.gl-sortable')).not.toBeNull(); expect(vm.$el.querySelector('table.table.gl-sortable')).not.toBeNull();
......
import axios from '~/lib/utils/axios_utils';
import GroupMemberService from 'ee/group_member_contributions/service/group_member_service';
import { contributionsPath } from '../mock_data';
describe('GroupMemberService', () => {
let service;
beforeEach(() => {
service = new GroupMemberService(contributionsPath);
});
describe('constructor', () => {
it('initializes default properties', () => {
expect(service.memberContributionsPath).toBe(contributionsPath);
});
});
describe('getContributedMembers', () => {
it('returns axios instance for memberContributionsPath', () => {
spyOn(axios, 'get').and.stub();
service.getContributedMembers();
expect(axios.get).toHaveBeenCalledWith(service.memberContributionsPath);
});
});
});
import axios from '~/lib/utils/axios_utils';
import MockAdapter from 'axios-mock-adapter';
import GroupMemberStore from 'ee/group_member_contributions/store/group_member_store'; import GroupMemberStore from 'ee/group_member_contributions/store/group_member_store';
import defaultColumns from 'ee/group_member_contributions/constants'; import defaultColumns from 'ee/group_member_contributions/constants';
import { rawMembers } from '../mock_data'; import { rawMembers, contributionsPath } from '../mock_data';
describe('GroupMemberStore', () => { describe('GroupMemberStore', () => {
let store; let store;
beforeEach(() => { beforeEach(() => {
store = new GroupMemberStore(); store = new GroupMemberStore(contributionsPath);
}); });
describe('setColumns', () => { describe('setColumns', () => {
...@@ -49,4 +52,54 @@ describe('GroupMemberStore', () => { ...@@ -49,4 +52,54 @@ describe('GroupMemberStore', () => {
expect(firstMember.fullname).toBe('Terrell Graham'); expect(firstMember.fullname).toBe('Terrell Graham');
}); });
}); });
describe('fetchContributedMembers', () => {
let mock;
beforeEach(() => {
mock = new MockAdapter(axios);
setFixtures('<div class="flash-container"></div>');
});
afterEach(() => {
mock.restore();
});
it('calls service.getContributedMembers and sets response to the store on success', done => {
mock.onGet(contributionsPath).reply(200, rawMembers);
spyOn(store, 'setColumns');
spyOn(store, 'setMembers');
store
.fetchContributedMembers()
.then(() => {
expect(store.isLoading).toBe(false);
expect(store.setColumns).toHaveBeenCalledWith(jasmine.any(Object));
expect(store.setMembers).toHaveBeenCalledWith(rawMembers);
done();
})
.catch(done.fail);
expect(store.isLoading).toBe(true);
});
it('calls service.getContributedMembers and sets `isLoading` to false and shows flash message if request failed', done => {
mock.onGet(contributionsPath).reply(500, {});
store
.fetchContributedMembers()
.then(() => done.fail('Expected error to be thrown!'))
.catch(e => {
expect(e.message).toBe('Request failed with status code 500');
expect(store.isLoading).toBe(false);
expect(document.querySelector('.flash-text').innerText.trim()).toBe(
'Something went wrong while fetching group member contributions',
);
})
.then(done)
.catch(done.fail);
expect(store.isLoading).toBe(true);
});
});
}); });
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