Skip to content
Snippets Groups Projects
Unverified Commit 2a9b1830 authored by Filipa Lacerda's avatar Filipa Lacerda
Browse files

Replace vue resources with axios for pipelines table

parent de36ca81
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -55,22 +55,20 @@
},
methods: {
successCallback(resp) {
return resp.json().then((response) => {
// depending of the endpoint the response can either bring a `pipelines` key or not.
const pipelines = response.pipelines || response;
this.setCommonData(pipelines);
// depending of the endpoint the response can either bring a `pipelines` key or not.
const pipelines = resp.data.pipelines || resp.data;
this.setCommonData(pipelines);
 
const updatePipelinesEvent = new CustomEvent('update-pipelines-count', {
detail: {
pipelines: response,
},
});
// notifiy to update the count in tabs
if (this.$el.parentElement) {
this.$el.parentElement.dispatchEvent(updatePipelinesEvent);
}
const updatePipelinesEvent = new CustomEvent('update-pipelines-count', {
detail: {
pipelines: resp.data,
},
});
// notifiy to update the count in tabs
if (this.$el.parentElement) {
this.$el.parentElement.dispatchEvent(updatePipelinesEvent);
}
},
},
};
Loading
Loading
Loading
Loading
@@ -7,10 +7,7 @@
import TablePagination from '../../vue_shared/components/table_pagination.vue';
import NavigationTabs from '../../vue_shared/components/navigation_tabs.vue';
import NavigationControls from './nav_controls.vue';
import {
getParameterByName,
parseQueryStringIntoObject,
} from '../../lib/utils/common_utils';
import { getParameterByName } from '../../lib/utils/common_utils';
import CIPaginationMixin from '../../vue_shared/mixins/ci_pagination_api_mixin';
 
export default {
Loading
Loading
@@ -19,10 +16,7 @@
NavigationTabs,
NavigationControls,
},
mixins: [
pipelinesMixin,
CIPaginationMixin,
],
mixins: [pipelinesMixin, CIPaginationMixin],
props: {
store: {
type: Object,
Loading
Loading
@@ -147,25 +141,26 @@
*/
shouldRenderTabs() {
const { stateMap } = this.$options;
return this.hasMadeRequest &&
[
stateMap.loading,
stateMap.tableList,
stateMap.error,
stateMap.emptyTab,
].includes(this.stateToRender);
return (
this.hasMadeRequest &&
[stateMap.loading, stateMap.tableList, stateMap.error, stateMap.emptyTab].includes(
this.stateToRender,
)
);
},
 
shouldRenderButtons() {
return (this.newPipelinePath ||
this.resetCachePath ||
this.ciLintPath) && this.shouldRenderTabs;
return (
(this.newPipelinePath || this.resetCachePath || this.ciLintPath) && this.shouldRenderTabs
);
},
 
shouldRenderPagination() {
return !this.isLoading &&
return (
!this.isLoading &&
this.state.pipelines.length &&
this.state.pageInfo.total > this.state.pageInfo.perPage;
this.state.pageInfo.total > this.state.pageInfo.perPage
);
},
 
emptyTabMessage() {
Loading
Loading
@@ -229,15 +224,13 @@
},
methods: {
successCallback(resp) {
return resp.json().then((response) => {
// Because we are polling & the user is interacting verify if the response received
// matches the last request made
if (_.isEqual(parseQueryStringIntoObject(resp.url.split('?')[1]), this.requestData)) {
this.store.storeCount(response.count);
this.store.storePagination(resp.headers);
this.setCommonData(response.pipelines);
}
});
// Because we are polling & the user is interacting verify if the response received
// matches the last request made
if (_.isEqual(resp.config.params, this.requestData)) {
this.store.storeCount(resp.data.count);
this.store.storePagination(resp.headers);
this.setCommonData(resp.data.pipelines);
}
},
/**
* Handles URL and query parameter changes.
Loading
Loading
@@ -251,8 +244,9 @@
this.updateInternalState(parameters);
 
// fetch new data
return this.service.getPipelines(this.requestData)
.then((response) => {
return this.service
.getPipelines(this.requestData)
.then(response => {
this.isLoading = false;
this.successCallback(response);
 
Loading
Loading
@@ -271,13 +265,11 @@
handleResetRunnersCache(endpoint) {
this.isResetCacheButtonLoading = true;
 
this.service.postAction(endpoint)
this.service
.postAction(endpoint)
.then(() => {
this.isResetCacheButtonLoading = false;
createFlash(
s__('Pipelines|Project cache successfully reset.'),
'notice',
);
createFlash(s__('Pipelines|Project cache successfully reset.'), 'notice');
})
.catch(() => {
this.isResetCacheButtonLoading = false;
Loading
Loading
/* eslint-disable class-methods-use-this */
import Vue from 'vue';
import VueResource from 'vue-resource';
import '../../vue_shared/vue_resource_interceptor';
Vue.use(VueResource);
import axios from '../../lib/utils/axios_utils';
 
export default class PipelinesService {
/**
* Commits and merge request endpoints need to be requested with `.json`.
*
* The url provided to request the pipelines in the new merge request
* page already has `.json`.
*
* @param {String} root
*/
* Commits and merge request endpoints need to be requested with `.json`.
*
* The url provided to request the pipelines in the new merge request
* page already has `.json`.
*
* @param {String} root
*/
constructor(root) {
let endpoint;
if (root.indexOf('.json') === -1) {
endpoint = `${root}.json`;
this.endpoint = `${root}.json`;
} else {
endpoint = root;
this.endpoint = root;
}
this.pipelines = Vue.resource(endpoint);
}
 
getPipelines(data = {}) {
const { scope, page } = data;
return this.pipelines.get({ scope, page });
return axios.get(this.endpoint, {
params: { scope, page },
});
}
 
/**
Loading
Loading
@@ -38,7 +30,8 @@ export default class PipelinesService {
* @param {String} endpoint
* @return {Promise}
*/
// eslint-disable-next-line class-methods-use-this
postAction(endpoint) {
return Vue.http.post(`${endpoint}.json`);
return axios.post(`${endpoint}.json`);
}
}
title: Replace vue resource with axios in pipelines table
merge_request:
author:
type: other
\ No newline at end of file
import _ from 'underscore';
import Vue from 'vue';
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import pipelinesTable from '~/commit/pipelines/pipelines_table.vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
 
describe('Pipelines table in Commits and Merge requests', () => {
const jsonFixtureName = 'pipelines/pipelines.json';
let pipeline;
let PipelinesTable;
let mock;
let vm;
 
preloadFixtures(jsonFixtureName);
 
beforeEach(() => {
mock = new MockAdapter(axios);
const pipelines = getJSONFixture(jsonFixtureName).pipelines;
 
PipelinesTable = Vue.extend(pipelinesTable);
pipeline = pipelines.find(p => p.user !== null && p.commit !== null);
});
 
afterEach(() => {
vm.$destroy();
mock.restore();
});
describe('successful request', () => {
describe('without pipelines', () => {
const pipelinesEmptyResponse = (request, next) => {
next(request.respondWith(JSON.stringify([]), {
status: 200,
}));
};
beforeEach(function () {
Vue.http.interceptors.push(pipelinesEmptyResponse);
this.component = new PipelinesTable({
propsData: {
endpoint: 'endpoint',
helpPagePath: 'foo',
emptyStateSvgPath: 'foo',
errorStateSvgPath: 'foo',
autoDevopsHelpPath: 'foo',
},
}).$mount();
});
mock.onGet('endpoint.json').reply(200, []);
 
afterEach(function () {
Vue.http.interceptors = _.without(
Vue.http.interceptors, pipelinesEmptyResponse,
);
this.component.$destroy();
vm = mountComponent(PipelinesTable, {
endpoint: 'endpoint.json',
helpPagePath: 'foo',
emptyStateSvgPath: 'foo',
errorStateSvgPath: 'foo',
autoDevopsHelpPath: 'foo',
});
});
 
it('should render the empty state', function (done) {
setTimeout(() => {
expect(this.component.$el.querySelector('.empty-state')).toBeDefined();
expect(this.component.$el.querySelector('.realtime-loading')).toBe(null);
expect(this.component.$el.querySelector('.js-pipelines-error-state')).toBe(null);
expect(vm.$el.querySelector('.empty-state')).toBeDefined();
expect(vm.$el.querySelector('.realtime-loading')).toBe(null);
expect(vm.$el.querySelector('.js-pipelines-error-state')).toBe(null);
done();
}, 1);
}, 0);
});
});
 
describe('with pipelines', () => {
const pipelinesResponse = (request, next) => {
next(request.respondWith(JSON.stringify([pipeline]), {
status: 200,
}));
};
beforeEach(() => {
Vue.http.interceptors.push(pipelinesResponse);
this.component = new PipelinesTable({
propsData: {
endpoint: 'endpoint',
helpPagePath: 'foo',
emptyStateSvgPath: 'foo',
errorStateSvgPath: 'foo',
autoDevopsHelpPath: 'foo',
},
}).$mount();
});
afterEach(() => {
Vue.http.interceptors = _.without(
Vue.http.interceptors, pipelinesResponse,
);
this.component.$destroy();
mock.onGet('endpoint.json').reply(200, [pipeline]);
vm = mountComponent(PipelinesTable, {
endpoint: 'endpoint.json',
helpPagePath: 'foo',
emptyStateSvgPath: 'foo',
errorStateSvgPath: 'foo',
autoDevopsHelpPath: 'foo',
});
});
 
it('should render a table with the received pipelines', (done) => {
setTimeout(() => {
expect(this.component.$el.querySelectorAll('.ci-table .commit').length).toEqual(1);
expect(this.component.$el.querySelector('.realtime-loading')).toBe(null);
expect(this.component.$el.querySelector('.empty-state')).toBe(null);
expect(this.component.$el.querySelector('.js-pipelines-error-state')).toBe(null);
expect(vm.$el.querySelectorAll('.ci-table .commit').length).toEqual(1);
expect(vm.$el.querySelector('.realtime-loading')).toBe(null);
expect(vm.$el.querySelector('.empty-state')).toBe(null);
expect(vm.$el.querySelector('.js-pipelines-error-state')).toBe(null);
done();
}, 0);
});
});
 
describe('pipeline badge counts', () => {
const pipelinesResponse = (request, next) => {
next(request.respondWith(JSON.stringify([pipeline]), {
status: 200,
}));
};
beforeEach(() => {
Vue.http.interceptors.push(pipelinesResponse);
});
afterEach(() => {
Vue.http.interceptors = _.without(Vue.http.interceptors, pipelinesResponse);
this.component.$destroy();
mock.onGet('endpoint.json').reply(200, [pipeline]);
});
 
it('should receive update-pipelines-count event', (done) => {
Loading
Loading
@@ -119,54 +88,38 @@ describe('Pipelines table in Commits and Merge requests', () => {
done();
});
 
this.component = new PipelinesTable({
propsData: {
endpoint: 'endpoint',
helpPagePath: 'foo',
emptyStateSvgPath: 'foo',
errorStateSvgPath: 'foo',
autoDevopsHelpPath: 'foo',
},
}).$mount();
element.appendChild(this.component.$el);
});
});
});
describe('unsuccessfull request', () => {
const pipelinesErrorResponse = (request, next) => {
next(request.respondWith(JSON.stringify([]), {
status: 500,
}));
};
beforeEach(function () {
Vue.http.interceptors.push(pipelinesErrorResponse);
this.component = new PipelinesTable({
propsData: {
endpoint: 'endpoint',
vm = mountComponent(PipelinesTable, {
endpoint: 'endpoint.json',
helpPagePath: 'foo',
emptyStateSvgPath: 'foo',
errorStateSvgPath: 'foo',
autoDevopsHelpPath: 'foo',
},
}).$mount();
});
element.appendChild(vm.$el);
});
});
});
 
afterEach(function () {
Vue.http.interceptors = _.without(
Vue.http.interceptors, pipelinesErrorResponse,
);
this.component.$destroy();
describe('unsuccessfull request', () => {
beforeEach(() => {
mock.onGet('endpoint.json').reply(500, []);
vm = mountComponent(PipelinesTable, {
endpoint: 'endpoint.json',
helpPagePath: 'foo',
emptyStateSvgPath: 'foo',
errorStateSvgPath: 'foo',
autoDevopsHelpPath: 'foo',
});
});
 
it('should render error state', function (done) {
setTimeout(() => {
expect(this.component.$el.querySelector('.js-pipelines-error-state')).toBeDefined();
expect(this.component.$el.querySelector('.realtime-loading')).toBe(null);
expect(this.component.$el.querySelector('.js-empty-state')).toBe(null);
expect(this.component.$el.querySelector('.ci-table')).toBe(null);
expect(vm.$el.querySelector('.js-pipelines-error-state')).toBeDefined();
expect(vm.$el.querySelector('.realtime-loading')).toBe(null);
expect(vm.$el.querySelector('.js-empty-state')).toBe(null);
expect(vm.$el.querySelector('.ci-table')).toBe(null);
done();
}, 0);
});
Loading
Loading
import _ from 'underscore';
import Vue from 'vue';
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import pipelinesComp from '~/pipelines/components/pipelines.vue';
import Store from '~/pipelines/stores/pipelines_store';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
Loading
Loading
@@ -12,6 +13,8 @@ describe('Pipelines', () => {
let PipelinesComponent;
let pipelines;
let vm;
let mock;
const paths = {
endpoint: 'twitter/flight/pipelines.json',
autoDevopsPath: '/help/topics/autodevops/index.md',
Loading
Loading
@@ -34,6 +37,8 @@ describe('Pipelines', () => {
};
 
beforeEach(() => {
mock = new MockAdapter(axios);
pipelines = getJSONFixture(jsonFixtureName);
 
PipelinesComponent = Vue.extend(pipelinesComp);
Loading
Loading
@@ -41,38 +46,14 @@ describe('Pipelines', () => {
 
afterEach(() => {
vm.$destroy();
mock.restore();
});
 
const pipelinesInterceptor = (request, next) => {
next(request.respondWith(JSON.stringify(pipelines), {
status: 200,
}));
};
const emptyStateInterceptor = (request, next) => {
next(request.respondWith(JSON.stringify({
pipelines: [],
count: {
all: 0,
pending: 0,
running: 0,
finished: 0,
},
}), {
status: 200,
}));
};
const errorInterceptor = (request, next) => {
next(request.respondWith(JSON.stringify({}), {
status: 500,
}));
};
describe('With permission', () => {
describe('With pipelines in main tab', () => {
beforeEach((done) => {
Vue.http.interceptors.push(pipelinesInterceptor);
mock.onGet('twitter/flight/pipelines.json').reply(200, pipelines);
vm = mountComponent(PipelinesComponent, {
store: new Store(),
hasGitlabCi: true,
Loading
Loading
@@ -85,12 +66,6 @@ describe('Pipelines', () => {
});
});
 
afterEach(() => {
Vue.http.interceptors = _.without(
Vue.http.interceptors, pipelinesInterceptor,
);
});
it('renders tabs', () => {
expect(vm.$el.querySelector('.js-pipelines-tab-all').textContent.trim()).toContain('All');
});
Loading
Loading
@@ -116,7 +91,15 @@ describe('Pipelines', () => {
 
describe('Without pipelines on main tab with CI', () => {
beforeEach((done) => {
Vue.http.interceptors.push(emptyStateInterceptor);
mock.onGet('twitter/flight/pipelines.json').reply(200, {
pipelines: [],
count: {
all: 0,
pending: 0,
running: 0,
finished: 0,
},
});
vm = mountComponent(PipelinesComponent, {
store: new Store(),
hasGitlabCi: true,
Loading
Loading
@@ -129,12 +112,6 @@ describe('Pipelines', () => {
});
});
 
afterEach(() => {
Vue.http.interceptors = _.without(
Vue.http.interceptors, emptyStateInterceptor,
);
});
it('renders tabs', () => {
expect(vm.$el.querySelector('.js-pipelines-tab-all').textContent.trim()).toContain('All');
});
Loading
Loading
@@ -158,7 +135,15 @@ describe('Pipelines', () => {
 
describe('Without pipelines nor CI', () => {
beforeEach((done) => {
Vue.http.interceptors.push(emptyStateInterceptor);
mock.onGet('twitter/flight/pipelines.json').reply(200, {
pipelines: [],
count: {
all: 0,
pending: 0,
running: 0,
finished: 0,
},
});
vm = mountComponent(PipelinesComponent, {
store: new Store(),
hasGitlabCi: false,
Loading
Loading
@@ -171,12 +156,6 @@ describe('Pipelines', () => {
});
});
 
afterEach(() => {
Vue.http.interceptors = _.without(
Vue.http.interceptors, emptyStateInterceptor,
);
});
it('renders empty state', () => {
expect(vm.$el.querySelector('.js-empty-state h4').textContent.trim()).toEqual('Build with confidence');
expect(vm.$el.querySelector('.js-get-started-pipelines').getAttribute('href')).toEqual(paths.helpPagePath);
Loading
Loading
@@ -192,7 +171,7 @@ describe('Pipelines', () => {
 
describe('When API returns error', () => {
beforeEach((done) => {
Vue.http.interceptors.push(errorInterceptor);
mock.onGet('twitter/flight/pipelines.json').reply(500, {});
vm = mountComponent(PipelinesComponent, {
store: new Store(),
hasGitlabCi: false,
Loading
Loading
@@ -205,12 +184,6 @@ describe('Pipelines', () => {
});
});
 
afterEach(() => {
Vue.http.interceptors = _.without(
Vue.http.interceptors, errorInterceptor,
);
});
it('renders tabs', () => {
expect(vm.$el.querySelector('.js-pipelines-tab-all').textContent.trim()).toContain('All');
});
Loading
Loading
@@ -230,7 +203,8 @@ describe('Pipelines', () => {
describe('Without permission', () => {
describe('With pipelines in main tab', () => {
beforeEach((done) => {
Vue.http.interceptors.push(pipelinesInterceptor);
mock.onGet('twitter/flight/pipelines.json').reply(200, pipelines);
vm = mountComponent(PipelinesComponent, {
store: new Store(),
hasGitlabCi: false,
Loading
Loading
@@ -243,12 +217,6 @@ describe('Pipelines', () => {
});
});
 
afterEach(() => {
Vue.http.interceptors = _.without(
Vue.http.interceptors, pipelinesInterceptor,
);
});
it('renders tabs', () => {
expect(vm.$el.querySelector('.js-pipelines-tab-all').textContent.trim()).toContain('All');
});
Loading
Loading
@@ -268,7 +236,16 @@ describe('Pipelines', () => {
 
describe('Without pipelines on main tab with CI', () => {
beforeEach((done) => {
Vue.http.interceptors.push(emptyStateInterceptor);
mock.onGet('twitter/flight/pipelines.json').reply(200, {
pipelines: [],
count: {
all: 0,
pending: 0,
running: 0,
finished: 0,
},
});
vm = mountComponent(PipelinesComponent, {
store: new Store(),
hasGitlabCi: true,
Loading
Loading
@@ -281,11 +258,6 @@ describe('Pipelines', () => {
});
});
 
afterEach(() => {
Vue.http.interceptors = _.without(
Vue.http.interceptors, emptyStateInterceptor,
);
});
it('renders tabs', () => {
expect(vm.$el.querySelector('.js-pipelines-tab-all').textContent.trim()).toContain('All');
});
Loading
Loading
@@ -303,7 +275,16 @@ describe('Pipelines', () => {
 
describe('Without pipelines nor CI', () => {
beforeEach((done) => {
Vue.http.interceptors.push(emptyStateInterceptor);
mock.onGet('twitter/flight/pipelines.json').reply(200, {
pipelines: [],
count: {
all: 0,
pending: 0,
running: 0,
finished: 0,
},
});
vm = mountComponent(PipelinesComponent, {
store: new Store(),
hasGitlabCi: false,
Loading
Loading
@@ -316,12 +297,6 @@ describe('Pipelines', () => {
});
});
 
afterEach(() => {
Vue.http.interceptors = _.without(
Vue.http.interceptors, emptyStateInterceptor,
);
});
it('renders empty state without button to set CI', () => {
expect(vm.$el.querySelector('.js-empty-state').textContent.trim()).toEqual('This project is not currently set up to run pipelines.');
expect(vm.$el.querySelector('.js-get-started-pipelines')).toBeNull();
Loading
Loading
@@ -337,7 +312,8 @@ describe('Pipelines', () => {
 
describe('When API returns error', () => {
beforeEach((done) => {
Vue.http.interceptors.push(errorInterceptor);
mock.onGet('twitter/flight/pipelines.json').reply(500, {});
vm = mountComponent(PipelinesComponent, {
store: new Store(),
hasGitlabCi: false,
Loading
Loading
@@ -350,12 +326,6 @@ describe('Pipelines', () => {
});
});
 
afterEach(() => {
Vue.http.interceptors = _.without(
Vue.http.interceptors, errorInterceptor,
);
});
it('renders tabs', () => {
expect(vm.$el.querySelector('.js-pipelines-tab-all').textContent.trim()).toContain('All');
});
Loading
Loading
@@ -375,7 +345,8 @@ describe('Pipelines', () => {
describe('successfull request', () => {
describe('with pipelines', () => {
beforeEach(() => {
Vue.http.interceptors.push(pipelinesInterceptor);
mock.onGet('twitter/flight/pipelines.json').reply(200, pipelines);
vm = mountComponent(PipelinesComponent, {
store: new Store(),
hasGitlabCi: true,
Loading
Loading
@@ -384,12 +355,6 @@ describe('Pipelines', () => {
});
});
 
afterEach(() => {
Vue.http.interceptors = _.without(
Vue.http.interceptors, pipelinesInterceptor,
);
});
it('should render table', (done) => {
setTimeout(() => {
expect(vm.$el.querySelector('.table-holder')).toBeDefined();
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment