Update vue-resource
This commit is contained in:
parent
fd692d1066
commit
aaa78199c2
28 changed files with 328 additions and 171 deletions
|
@ -51,8 +51,9 @@ export default () => {
|
|||
methods: {
|
||||
loadFile() {
|
||||
this.$http.get(el.dataset.endpoint)
|
||||
.then(response => response.json())
|
||||
.then((res) => {
|
||||
this.json = res.json();
|
||||
this.json = res;
|
||||
this.loading = false;
|
||||
})
|
||||
.catch((e) => {
|
||||
|
|
|
@ -81,8 +81,9 @@ $(() => {
|
|||
mounted () {
|
||||
Store.disabled = this.disabled;
|
||||
gl.boardService.all()
|
||||
.then(response => response.json())
|
||||
.then((resp) => {
|
||||
resp.json().forEach((board) => {
|
||||
resp.forEach((board) => {
|
||||
const list = Store.addList(board, this.defaultAvatar);
|
||||
|
||||
if (list.type === 'closed') {
|
||||
|
@ -97,7 +98,8 @@ $(() => {
|
|||
|
||||
Store.addBlankState();
|
||||
this.loading = false;
|
||||
}).catch(() => new Flash('An error occurred. Please try again.'));
|
||||
})
|
||||
.catch(() => new Flash('An error occurred. Please try again.'));
|
||||
},
|
||||
methods: {
|
||||
updateTokens() {
|
||||
|
|
|
@ -64,8 +64,9 @@ export default {
|
|||
|
||||
// Save the labels
|
||||
gl.boardService.generateDefaultLists()
|
||||
.then((resp) => {
|
||||
resp.json().forEach((listObj) => {
|
||||
.then(resp => resp.json())
|
||||
.then((data) => {
|
||||
data.forEach((listObj) => {
|
||||
const list = Store.findList('title', listObj.title);
|
||||
|
||||
list.id = listObj.id;
|
||||
|
|
|
@ -88,9 +88,9 @@ gl.issueBoards.IssuesModal = Vue.extend({
|
|||
return gl.boardService.getBacklog(queryData(this.filter.path, {
|
||||
page: this.page,
|
||||
per: this.perPage,
|
||||
})).then((res) => {
|
||||
const data = res.json();
|
||||
|
||||
}))
|
||||
.then(resp => resp.json())
|
||||
.then((data) => {
|
||||
if (clearIssues) {
|
||||
this.issues = [];
|
||||
}
|
||||
|
|
|
@ -40,9 +40,8 @@ class List {
|
|||
|
||||
save () {
|
||||
return gl.boardService.createList(this.label.id)
|
||||
.then((resp) => {
|
||||
const data = resp.json();
|
||||
|
||||
.then(resp => resp.json())
|
||||
.then((data) => {
|
||||
this.id = data.id;
|
||||
this.type = data.list_type;
|
||||
this.position = data.position;
|
||||
|
@ -91,8 +90,8 @@ class List {
|
|||
}
|
||||
|
||||
return gl.boardService.getIssuesForList(this.id, data)
|
||||
.then((resp) => {
|
||||
const data = resp.json();
|
||||
.then(resp => resp.json())
|
||||
.then((data) => {
|
||||
this.loading = false;
|
||||
this.issuesSize = data.size;
|
||||
|
||||
|
@ -109,8 +108,8 @@ class List {
|
|||
this.issuesSize += 1;
|
||||
|
||||
return gl.boardService.newIssue(this.id, issue)
|
||||
.then((resp) => {
|
||||
const data = resp.json();
|
||||
.then(resp => resp.json())
|
||||
.then((data) => {
|
||||
issue.id = data.iid;
|
||||
|
||||
if (this.issuesSize > 1) {
|
||||
|
|
|
@ -23,11 +23,6 @@ class BoardService {
|
|||
url: bulkUpdatePath,
|
||||
},
|
||||
});
|
||||
|
||||
Vue.http.interceptors.push((request, next) => {
|
||||
request.headers['X-CSRF-Token'] = $.rails.csrfToken();
|
||||
next();
|
||||
});
|
||||
}
|
||||
|
||||
all () {
|
||||
|
|
|
@ -51,11 +51,11 @@
|
|||
},
|
||||
methods: {
|
||||
successCallback(resp) {
|
||||
const response = resp.json();
|
||||
|
||||
// depending of the endpoint the response can either bring a `pipelines` key or not.
|
||||
const pipelines = response.pipelines || response;
|
||||
this.setCommonData(pipelines);
|
||||
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);
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* eslint-disable comma-dangle, object-shorthand, func-names, quote-props, no-else-return, camelcase, no-new, max-len */
|
||||
/* eslint-disable comma-dangle, object-shorthand, func-names, quote-props, no-else-return, camelcase, max-len */
|
||||
/* global CommentsStore */
|
||||
/* global ResolveService */
|
||||
/* global Flash */
|
||||
|
@ -64,8 +64,6 @@ const ResolveBtn = Vue.extend({
|
|||
});
|
||||
},
|
||||
resolve: function () {
|
||||
const errorFlashMsg = 'An error occurred when trying to resolve a comment. Please try again.';
|
||||
|
||||
if (!this.canResolve) return;
|
||||
|
||||
let promise;
|
||||
|
@ -79,24 +77,20 @@ const ResolveBtn = Vue.extend({
|
|||
.resolve(this.noteId);
|
||||
}
|
||||
|
||||
promise.then((response) => {
|
||||
this.loading = false;
|
||||
promise
|
||||
.then(resp => resp.json())
|
||||
.then((data) => {
|
||||
this.loading = false;
|
||||
|
||||
if (response.status === 200) {
|
||||
const data = response.json();
|
||||
const resolved_by = data ? data.resolved_by : null;
|
||||
|
||||
CommentsStore.update(this.discussionId, this.noteId, !this.isResolved, resolved_by);
|
||||
this.discussion.updateHeadline(data);
|
||||
gl.mrWidget.checkStatus();
|
||||
} else {
|
||||
new Flash(errorFlashMsg);
|
||||
}
|
||||
|
||||
this.updateTooltip();
|
||||
}).catch(() => {
|
||||
new Flash(errorFlashMsg);
|
||||
});
|
||||
this.updateTooltip();
|
||||
})
|
||||
.catch(() => new Flash('An error occurred when trying to resolve a comment. Please try again.'));
|
||||
}
|
||||
},
|
||||
mounted: function () {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable class-methods-use-this, one-var, camelcase, no-new, comma-dangle, no-param-reassign, max-len */
|
||||
/* global Flash */
|
||||
/* global CommentsStore */
|
||||
|
||||
|
@ -32,27 +31,22 @@ class ResolveServiceClass {
|
|||
promise = this.resolveAll(mergeRequestId, discussionId);
|
||||
}
|
||||
|
||||
promise.then((response) => {
|
||||
discussion.loading = false;
|
||||
|
||||
if (response.status === 200) {
|
||||
const data = response.json();
|
||||
const resolved_by = data ? data.resolved_by : null;
|
||||
promise
|
||||
.then(resp => resp.json())
|
||||
.then((data) => {
|
||||
discussion.loading = false;
|
||||
const resolvedBy = data ? data.resolved_by : null;
|
||||
|
||||
if (isResolved) {
|
||||
discussion.unResolveAllNotes();
|
||||
} else {
|
||||
discussion.resolveAllNotes(resolved_by);
|
||||
discussion.resolveAllNotes(resolvedBy);
|
||||
}
|
||||
|
||||
gl.mrWidget.checkStatus();
|
||||
discussion.updateHeadline(data);
|
||||
} else {
|
||||
throw new Error('An error occurred when trying to resolve discussion.');
|
||||
}
|
||||
}).catch(() => {
|
||||
new Flash('An error occurred when trying to resolve a discussion. Please try again.');
|
||||
});
|
||||
})
|
||||
.catch(() => new Flash('An error occurred when trying to resolve a discussion. Please try again.'));
|
||||
}
|
||||
|
||||
resolveAll(mergeRequestId, discussionId) {
|
||||
|
@ -62,7 +56,7 @@ class ResolveServiceClass {
|
|||
|
||||
return this.discussionResource.save({
|
||||
mergeRequestId,
|
||||
discussionId
|
||||
discussionId,
|
||||
}, {});
|
||||
}
|
||||
|
||||
|
@ -73,7 +67,7 @@ class ResolveServiceClass {
|
|||
|
||||
return this.discussionResource.delete({
|
||||
mergeRequestId,
|
||||
discussionId
|
||||
discussionId,
|
||||
}, {});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
export default {
|
||||
methods: {
|
||||
saveData(resp) {
|
||||
const response = {
|
||||
headers: resp.headers,
|
||||
body: resp.json(),
|
||||
};
|
||||
const headers = resp.headers;
|
||||
return resp.json().then((response) => {
|
||||
this.isLoading = false;
|
||||
|
||||
this.isLoading = false;
|
||||
|
||||
this.store.storeAvailableCount(response.body.available_count);
|
||||
this.store.storeStoppedCount(response.body.stopped_count);
|
||||
this.store.storeEnvironments(response.body.environments);
|
||||
this.store.setPagination(response.headers);
|
||||
this.store.storeAvailableCount(response.available_count);
|
||||
this.store.storeStoppedCount(response.stopped_count);
|
||||
this.store.storeEnvironments(response.environments);
|
||||
this.store.setPagination(headers);
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -99,8 +99,10 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
page: currentPath,
|
||||
}, document.title, currentPath);
|
||||
|
||||
this.updateGroups(response.json());
|
||||
this.updatePagination(response.headers);
|
||||
return response.json().then((data) => {
|
||||
this.updateGroups(data);
|
||||
this.updatePagination(response.headers);
|
||||
});
|
||||
})
|
||||
.catch(this.handleErrorResponse);
|
||||
},
|
||||
|
@ -114,18 +116,19 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
},
|
||||
leaveGroup(group, collection) {
|
||||
this.service.leaveGroup(group.leavePath)
|
||||
.then(resp => resp.json())
|
||||
.then((response) => {
|
||||
$.scrollTo(0);
|
||||
|
||||
this.store.removeGroup(group, collection);
|
||||
|
||||
// eslint-disable-next-line no-new
|
||||
new Flash(response.json().notice, 'notice');
|
||||
new Flash(response.notice, 'notice');
|
||||
})
|
||||
.catch((response) => {
|
||||
.catch((error) => {
|
||||
let message = 'An error occurred. Please try again.';
|
||||
|
||||
if (response.status === 403) {
|
||||
if (error.status === 403) {
|
||||
message = 'Failed to leave the group. Please make sure you are not the only owner';
|
||||
}
|
||||
|
||||
|
|
|
@ -202,10 +202,7 @@ export default {
|
|||
this.poll = new Poll({
|
||||
resource: this.service,
|
||||
method: 'getData',
|
||||
successCallback: (res) => {
|
||||
const data = res.json();
|
||||
this.store.updateState(data);
|
||||
},
|
||||
successCallback: res => res.json().then(data => this.store.updateState(data)),
|
||||
errorCallback(err) {
|
||||
throw new Error(err);
|
||||
},
|
||||
|
|
|
@ -54,9 +54,8 @@ export default class JobMediator {
|
|||
}
|
||||
|
||||
successCallback(response) {
|
||||
const data = response.json();
|
||||
this.state.isLoading = false;
|
||||
this.store.storeJob(data);
|
||||
return response.json().then(data => this.store.storeJob(data));
|
||||
}
|
||||
|
||||
errorCallback() {
|
||||
|
|
|
@ -1270,7 +1270,7 @@ export default class Notes {
|
|||
<div class="timeline-entry-inner">
|
||||
<div class="timeline-icon">
|
||||
<a href="/${currentUsername}">
|
||||
<img class="avatar s40" src="${currentUserAvatar}">
|
||||
<img class="avatar s40" src="${currentUserAvatar}" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="timeline-content ${discussionClass}">
|
||||
|
|
|
@ -129,14 +129,11 @@
|
|||
},
|
||||
|
||||
successCallback(resp) {
|
||||
const response = {
|
||||
headers: resp.headers,
|
||||
body: resp.json(),
|
||||
};
|
||||
|
||||
this.store.storeCount(response.body.count);
|
||||
this.store.storePagination(response.headers);
|
||||
this.setCommonData(response.body.pipelines);
|
||||
return resp.json().then((response) => {
|
||||
this.store.storeCount(response.count);
|
||||
this.store.storePagination(resp.headers);
|
||||
this.setCommonData(response.pipelines);
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -73,8 +73,9 @@ export default {
|
|||
|
||||
fetchJobs() {
|
||||
this.$http.get(this.stage.dropdown_path)
|
||||
.then((response) => {
|
||||
this.dropdownContent = response.json().html;
|
||||
.then(response => response.json())
|
||||
.then((data) => {
|
||||
this.dropdownContent = data.html;
|
||||
this.isLoading = false;
|
||||
})
|
||||
.catch(() => {
|
||||
|
|
|
@ -40,10 +40,10 @@ export default class pipelinesMediator {
|
|||
}
|
||||
|
||||
successCallback(response) {
|
||||
const data = response.json();
|
||||
|
||||
this.state.isLoading = false;
|
||||
this.store.storePipeline(data);
|
||||
return response.json().then((data) => {
|
||||
this.state.isLoading = false;
|
||||
this.store.storePipeline(data);
|
||||
});
|
||||
}
|
||||
|
||||
errorCallback() {
|
||||
|
|
|
@ -28,8 +28,8 @@ export default class SidebarMediator {
|
|||
|
||||
fetch() {
|
||||
this.service.get()
|
||||
.then((response) => {
|
||||
const data = response.json();
|
||||
.then(response => response.json())
|
||||
.then((data) => {
|
||||
this.store.setAssigneeData(data);
|
||||
this.store.setTimeTrackingData(data);
|
||||
})
|
||||
|
|
|
@ -44,9 +44,8 @@
|
|||
text: this.$slots.textarea[0].elm.value,
|
||||
},
|
||||
)
|
||||
.then((res) => {
|
||||
const data = res.json();
|
||||
|
||||
.then(resp => resp.json())
|
||||
.then((data) => {
|
||||
this.markdownPreviewLoading = false;
|
||||
this.markdownPreview = data.body;
|
||||
|
||||
|
|
|
@ -14,11 +14,22 @@ Vue.http.interceptors.push((request, next) => {
|
|||
});
|
||||
});
|
||||
|
||||
// Inject CSRF token so we don't break any tests.
|
||||
// Inject CSRF token and parse headers.
|
||||
// New Vue Resource version uses Headers, we are expecting a plain object to render pagination
|
||||
// and polling.
|
||||
Vue.http.interceptors.push((request, next) => {
|
||||
if ($.rails) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
request.headers['X-CSRF-Token'] = $.rails.csrfToken();
|
||||
request.headers.set('X-CSRF-Token', $.rails.csrfToken());
|
||||
}
|
||||
next();
|
||||
|
||||
next((response) => {
|
||||
// Headers object has a `forEach` property that iterates through all values.
|
||||
const headers = {};
|
||||
|
||||
response.headers.forEach((value, key) => {
|
||||
headers[key] = value;
|
||||
});
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
response.headers = headers;
|
||||
});
|
||||
});
|
||||
|
|
4
changelogs/unreleased/34534-update-vue-resource.yml
Normal file
4
changelogs/unreleased/34534-update-vue-resource.yml
Normal file
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
title: Updates vue resource and code according to breaking changes
|
||||
merge_request:
|
||||
author:
|
|
@ -112,7 +112,50 @@ Vue Resource should only be imported in the service file.
|
|||
Vue.use(VueResource);
|
||||
```
|
||||
|
||||
### CSRF token
|
||||
#### Vue-resource gotchas
|
||||
#### Headers
|
||||
Headers are being parsed into a plain object in an interceptor.
|
||||
In Vue-resource 1.x `headers` object was changed into an `Headers` object. In order to not change all old code, an interceptor was added.
|
||||
|
||||
If you need to write a unit test that takes the headers in consideration, you need to include an interceptor to parse the headers after your test interceptor.
|
||||
You can see an example in `spec/javascripts/environments/environment_spec.js`:
|
||||
```javascript
|
||||
import { headersInterceptor } from './helpers/vue_resource_helper';
|
||||
|
||||
beforeEach(() => {
|
||||
Vue.http.interceptors.push(myInterceptor);
|
||||
Vue.http.interceptors.push(headersInterceptor);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
Vue.http.interceptors = _.without(Vue.http.interceptors, myInterceptor);
|
||||
Vue.http.interceptors = _.without(Vue.http.interceptors, headersInterceptor);
|
||||
});
|
||||
```
|
||||
|
||||
#### `.json()`
|
||||
When making a request to the server, you will most likely need to access the body of the response.
|
||||
Use `.json()` to convert. Because `.json()` returns a Promise the follwoing structure should be used:
|
||||
|
||||
```javascript
|
||||
service.get('url')
|
||||
.then(resp => resp.json())
|
||||
.then((data) => {
|
||||
this.store.storeData(data);
|
||||
})
|
||||
.catch(() => new Flash('Something went wrong'));
|
||||
```
|
||||
|
||||
When using `Poll` (`app/assets/javascripts/lib/utils/poll.js`), the `successCallback` needs to handle `.json()` as a Promise:
|
||||
```javascript
|
||||
successCallback: (response) => {
|
||||
return response.json().then((data) => {
|
||||
// handle the response
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
#### CSRF token
|
||||
We use a Vue Resource interceptor to manage the CSRF token.
|
||||
`app/assets/javascripts/vue_shared/vue_resource_interceptor.js` holds all our common interceptors.
|
||||
Note: You don't need to load `app/assets/javascripts/vue_shared/vue_resource_interceptor.js`
|
||||
|
@ -126,13 +169,13 @@ The following example shows an application:
|
|||
// store.js
|
||||
export default class Store {
|
||||
|
||||
/**
|
||||
/**
|
||||
* This is where we will iniatialize the state of our data.
|
||||
* Usually in a small SPA you don't need any options when starting the store. In the case you do
|
||||
* need guarantee it's an Object and it's documented.
|
||||
*
|
||||
* @param {Object} options
|
||||
*/
|
||||
*
|
||||
* @param {Object} options
|
||||
*/
|
||||
constructor(options) {
|
||||
this.options = options;
|
||||
|
||||
|
@ -205,14 +248,14 @@ import Store from 'store';
|
|||
import Service from 'service';
|
||||
import TodoComponent from 'todoComponent';
|
||||
export default {
|
||||
/**
|
||||
/**
|
||||
* Although most data belongs in the store, each component it's own state.
|
||||
* We want to show a loading spinner while we are fetching the todos, this state belong
|
||||
* in the component.
|
||||
*
|
||||
* We need to access the store methods through all methods of our component.
|
||||
* We need to access the state of our store.
|
||||
*/
|
||||
*/
|
||||
data() {
|
||||
const store = new Store();
|
||||
|
||||
|
@ -396,42 +439,46 @@ need to test the rendered output. [Vue][vue-test] guide's to unit test show us e
|
|||
[Vue Resource Interceptors][vue-resource-interceptor] allow us to add a interceptor with
|
||||
the response we need:
|
||||
|
||||
```javascript
|
||||
// Mock the service to return data
|
||||
const interceptor = (request, next) => {
|
||||
next(request.respondWith(JSON.stringify([{
|
||||
title: 'This is a todo',
|
||||
body: 'This is the text'
|
||||
}]), {
|
||||
status: 200,
|
||||
}));
|
||||
};
|
||||
```javascript
|
||||
// Mock the service to return data
|
||||
const interceptor = (request, next) => {
|
||||
next(request.respondWith(JSON.stringify([{
|
||||
title: 'This is a todo',
|
||||
body: 'This is the text'
|
||||
}]), {
|
||||
status: 200,
|
||||
}));
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
Vue.http.interceptors.push(interceptor);
|
||||
});
|
||||
beforeEach(() => {
|
||||
Vue.http.interceptors.push(interceptor);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
Vue.http.interceptors = _.without(Vue.http.interceptors, interceptor);
|
||||
});
|
||||
afterEach(() => {
|
||||
Vue.http.interceptors = _.without(Vue.http.interceptors, interceptor);
|
||||
});
|
||||
|
||||
it('should do something', (done) => {
|
||||
setTimeout(() => {
|
||||
// Test received data
|
||||
done();
|
||||
}, 0);
|
||||
});
|
||||
```
|
||||
it('should do something', (done) => {
|
||||
setTimeout(() => {
|
||||
// Test received data
|
||||
done();
|
||||
}, 0);
|
||||
});
|
||||
```
|
||||
|
||||
1. Headers interceptor
|
||||
Refer to [this section](vue.md#headers)
|
||||
|
||||
1. Use `$.mount()` to mount the component
|
||||
```javascript
|
||||
// bad
|
||||
new Component({
|
||||
el: document.createElement('div')
|
||||
});
|
||||
|
||||
// good
|
||||
new Component().$mount();
|
||||
```javascript
|
||||
// bad
|
||||
new Component({
|
||||
el: document.createElement('div')
|
||||
});
|
||||
|
||||
// good
|
||||
new Component().$mount();
|
||||
```
|
||||
|
||||
[vue-docs]: http://vuejs.org/guide/index.html
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
"visibilityjs": "^1.2.4",
|
||||
"vue": "^2.2.6",
|
||||
"vue-loader": "^11.3.4",
|
||||
"vue-resource": "^0.9.3",
|
||||
"vue-resource": "^1.3.4",
|
||||
"vue-template-compiler": "^2.2.6",
|
||||
"webpack": "^2.6.1",
|
||||
"webpack-bundle-analyzer": "^2.8.2"
|
||||
|
|
|
@ -2,6 +2,7 @@ import Vue from 'vue';
|
|||
import '~/flash';
|
||||
import environmentsComponent from '~/environments/components/environment.vue';
|
||||
import { environment, folder } from './mock_data';
|
||||
import { headersInterceptor } from '../helpers/vue_resource_helper';
|
||||
|
||||
describe('Environment', () => {
|
||||
preloadFixtures('static/environments/environments.html.raw');
|
||||
|
@ -25,12 +26,14 @@ describe('Environment', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
Vue.http.interceptors.push(environmentsEmptyResponseInterceptor);
|
||||
Vue.http.interceptors.push(headersInterceptor);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
Vue.http.interceptors = _.without(
|
||||
Vue.http.interceptors, environmentsEmptyResponseInterceptor,
|
||||
);
|
||||
Vue.http.interceptors = _.without(Vue.http.interceptors, headersInterceptor);
|
||||
});
|
||||
|
||||
it('should render the empty state', (done) => {
|
||||
|
@ -54,6 +57,10 @@ describe('Environment', () => {
|
|||
|
||||
describe('with paginated environments', () => {
|
||||
const environmentsResponseInterceptor = (request, next) => {
|
||||
next((response) => {
|
||||
response.headers.set('X-nExt-pAge', '2');
|
||||
});
|
||||
|
||||
next(request.respondWith(JSON.stringify({
|
||||
environments: [environment],
|
||||
stopped_count: 1,
|
||||
|
@ -73,6 +80,7 @@ describe('Environment', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
Vue.http.interceptors.push(environmentsResponseInterceptor);
|
||||
Vue.http.interceptors.push(headersInterceptor);
|
||||
component = new EnvironmentsComponent({
|
||||
el: document.querySelector('#environments-list-view'),
|
||||
});
|
||||
|
@ -82,6 +90,7 @@ describe('Environment', () => {
|
|||
Vue.http.interceptors = _.without(
|
||||
Vue.http.interceptors, environmentsResponseInterceptor,
|
||||
);
|
||||
Vue.http.interceptors = _.without(Vue.http.interceptors, headersInterceptor);
|
||||
});
|
||||
|
||||
it('should render a table with environments', (done) => {
|
||||
|
|
|
@ -2,6 +2,7 @@ import Vue from 'vue';
|
|||
import '~/flash';
|
||||
import environmentsFolderViewComponent from '~/environments/folder/environments_folder_view.vue';
|
||||
import { environmentsList } from '../mock_data';
|
||||
import { headersInterceptor } from '../../helpers/vue_resource_helper';
|
||||
|
||||
describe('Environments Folder View', () => {
|
||||
preloadFixtures('static/environments/environments_folder_view.html.raw');
|
||||
|
@ -36,6 +37,8 @@ describe('Environments Folder View', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
Vue.http.interceptors.push(environmentsResponseInterceptor);
|
||||
Vue.http.interceptors.push(headersInterceptor);
|
||||
|
||||
component = new EnvironmentsFolderViewComponent({
|
||||
el: document.querySelector('#environments-folder-list-view'),
|
||||
});
|
||||
|
@ -45,6 +48,7 @@ describe('Environments Folder View', () => {
|
|||
Vue.http.interceptors = _.without(
|
||||
Vue.http.interceptors, environmentsResponseInterceptor,
|
||||
);
|
||||
Vue.http.interceptors = _.without(Vue.http.interceptors, headersInterceptor);
|
||||
});
|
||||
|
||||
it('should render a table with environments', (done) => {
|
||||
|
|
11
spec/javascripts/helpers/vue_resource_helper.js
Normal file
11
spec/javascripts/helpers/vue_resource_helper.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
// eslint-disable-next-line import/prefer-default-export
|
||||
export const headersInterceptor = (request, next) => {
|
||||
next((response) => {
|
||||
const headers = {};
|
||||
response.headers.forEach((value, key) => {
|
||||
headers[key] = value;
|
||||
});
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
response.headers = headers;
|
||||
});
|
||||
};
|
|
@ -3,7 +3,6 @@ import '~/render_math';
|
|||
import '~/render_gfm';
|
||||
import issuableApp from '~/issue_show/components/app.vue';
|
||||
import eventHub from '~/issue_show/event_hub';
|
||||
import Poll from '~/lib/utils/poll';
|
||||
import issueShowData from '../mock_data';
|
||||
|
||||
function formatText(text) {
|
||||
|
@ -11,16 +10,26 @@ function formatText(text) {
|
|||
}
|
||||
|
||||
describe('Issuable output', () => {
|
||||
let requestData = issueShowData.initialRequest;
|
||||
|
||||
document.body.innerHTML = '<span id="task_status"></span>';
|
||||
|
||||
const interceptor = (request, next) => {
|
||||
next(request.respondWith(JSON.stringify(requestData), {
|
||||
status: 200,
|
||||
}));
|
||||
};
|
||||
|
||||
let vm;
|
||||
|
||||
beforeEach(() => {
|
||||
beforeEach((done) => {
|
||||
spyOn(eventHub, '$emit');
|
||||
spyOn(Poll.prototype, 'makeRequest');
|
||||
|
||||
const IssuableDescriptionComponent = Vue.extend(issuableApp);
|
||||
|
||||
requestData = issueShowData.initialRequest;
|
||||
Vue.http.interceptors.push(interceptor);
|
||||
|
||||
vm = new IssuableDescriptionComponent({
|
||||
propsData: {
|
||||
canUpdate: true,
|
||||
|
@ -40,15 +49,17 @@ describe('Issuable output', () => {
|
|||
projectPath: '/',
|
||||
},
|
||||
}).$mount();
|
||||
|
||||
setTimeout(done);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
Vue.http.interceptors = _.without(Vue.http.interceptors, interceptor);
|
||||
|
||||
vm.poll.stop();
|
||||
});
|
||||
|
||||
it('should render a title/description/edited and update title/description/edited on update', (done) => {
|
||||
vm.poll.options.successCallback({
|
||||
json() {
|
||||
return issueShowData.initialRequest;
|
||||
},
|
||||
});
|
||||
|
||||
let editedText;
|
||||
Vue.nextTick()
|
||||
.then(() => {
|
||||
|
@ -64,13 +75,10 @@ describe('Issuable output', () => {
|
|||
expect(editedText.querySelector('time')).toBeTruthy();
|
||||
})
|
||||
.then(() => {
|
||||
vm.poll.options.successCallback({
|
||||
json() {
|
||||
return issueShowData.secondRequest;
|
||||
},
|
||||
});
|
||||
requestData = issueShowData.secondRequest;
|
||||
vm.poll.makeRequest();
|
||||
})
|
||||
.then(Vue.nextTick)
|
||||
.then(() => new Promise(resolve => setTimeout(resolve)))
|
||||
.then(() => {
|
||||
expect(document.querySelector('title').innerText).toContain('2 (#1)');
|
||||
expect(vm.$el.querySelector('.title').innerHTML).toContain('<p>2</p>');
|
||||
|
@ -304,7 +312,7 @@ describe('Issuable output', () => {
|
|||
|
||||
it('stops polling when deleting', (done) => {
|
||||
spyOn(gl.utils, 'visitUrl');
|
||||
spyOn(vm.poll, 'stop');
|
||||
spyOn(vm.poll, 'stop').and.callThrough();
|
||||
spyOn(vm.service, 'deleteIssuable').and.callFake(() => new Promise((resolve) => {
|
||||
resolve({
|
||||
json() {
|
||||
|
@ -347,23 +355,14 @@ describe('Issuable output', () => {
|
|||
|
||||
describe('open form', () => {
|
||||
it('shows locked warning if form is open & data is different', (done) => {
|
||||
vm.poll.options.successCallback({
|
||||
json() {
|
||||
return issueShowData.initialRequest;
|
||||
},
|
||||
});
|
||||
|
||||
Vue.nextTick()
|
||||
.then(() => {
|
||||
vm.openForm();
|
||||
|
||||
vm.poll.options.successCallback({
|
||||
json() {
|
||||
return issueShowData.secondRequest;
|
||||
},
|
||||
});
|
||||
requestData = issueShowData.secondRequest;
|
||||
vm.poll.makeRequest();
|
||||
})
|
||||
.then(Vue.nextTick)
|
||||
.then(() => new Promise(resolve => setTimeout(resolve)))
|
||||
.then(() => {
|
||||
expect(
|
||||
vm.formState.lockedWarningVisible,
|
||||
|
|
102
yarn.lock
102
yarn.lock
|
@ -1575,6 +1575,12 @@ deckar01-task_list@^2.0.0:
|
|||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/deckar01-task_list/-/deckar01-task_list-2.0.0.tgz#7f7a595430d21b3036ed5dfbf97d6b65de18e2c9"
|
||||
|
||||
decompress-response@^3.2.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3"
|
||||
dependencies:
|
||||
mimic-response "^1.0.0"
|
||||
|
||||
deep-extend@~0.4.0:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.1.tgz#efe4113d08085f4e6f9687759810f807469e2253"
|
||||
|
@ -1712,6 +1718,10 @@ dropzone@^4.2.0:
|
|||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/dropzone/-/dropzone-4.2.0.tgz#fbe7acbb9918e0706489072ef663effeef8a79f3"
|
||||
|
||||
duplexer3@^0.1.4:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
|
||||
|
||||
duplexer@^0.1.1, duplexer@~0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1"
|
||||
|
@ -2445,6 +2455,10 @@ get-caller-file@^1.0.1:
|
|||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5"
|
||||
|
||||
get-stream@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
|
||||
|
||||
getpass@^0.1.1:
|
||||
version "0.1.6"
|
||||
resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6"
|
||||
|
@ -2521,6 +2535,25 @@ got@^3.2.0:
|
|||
read-all-stream "^3.0.0"
|
||||
timed-out "^2.0.0"
|
||||
|
||||
got@^7.0.0:
|
||||
version "7.1.0"
|
||||
resolved "https://registry.yarnpkg.com/got/-/got-7.1.0.tgz#05450fd84094e6bbea56f451a43a9c289166385a"
|
||||
dependencies:
|
||||
decompress-response "^3.2.0"
|
||||
duplexer3 "^0.1.4"
|
||||
get-stream "^3.0.0"
|
||||
is-plain-obj "^1.1.0"
|
||||
is-retry-allowed "^1.0.0"
|
||||
is-stream "^1.0.0"
|
||||
isurl "^1.0.0-alpha5"
|
||||
lowercase-keys "^1.0.0"
|
||||
p-cancelable "^0.3.0"
|
||||
p-timeout "^1.1.1"
|
||||
safe-buffer "^5.0.1"
|
||||
timed-out "^4.0.0"
|
||||
url-parse-lax "^1.0.0"
|
||||
url-to-options "^1.0.1"
|
||||
|
||||
graceful-fs@^4.1.11, graceful-fs@^4.1.2:
|
||||
version "4.1.11"
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
|
||||
|
@ -2578,6 +2611,16 @@ has-flag@^1.0.0:
|
|||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
|
||||
|
||||
has-symbol-support-x@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.3.0.tgz#588bd6927eaa0e296afae24160659167fc2be4f8"
|
||||
|
||||
has-to-string-tag-x@^1.2.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.3.0.tgz#78e3d98c3c0ec9413e970eb8d766249a1e13058f"
|
||||
dependencies:
|
||||
has-symbol-support-x "^1.3.0"
|
||||
|
||||
has-unicode@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
|
||||
|
@ -2902,6 +2945,10 @@ is-number@^2.0.2, is-number@^2.1.0:
|
|||
dependencies:
|
||||
kind-of "^3.0.2"
|
||||
|
||||
is-object@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470"
|
||||
|
||||
is-path-cwd@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d"
|
||||
|
@ -2918,7 +2965,7 @@ is-path-inside@^1.0.0:
|
|||
dependencies:
|
||||
path-is-inside "^1.0.1"
|
||||
|
||||
is-plain-obj@^1.0.0:
|
||||
is-plain-obj@^1.0.0, is-plain-obj@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
|
||||
|
||||
|
@ -2950,6 +2997,10 @@ is-resolvable@^1.0.0:
|
|||
dependencies:
|
||||
tryit "^1.0.1"
|
||||
|
||||
is-retry-allowed@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34"
|
||||
|
||||
is-stream@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
|
||||
|
@ -3087,6 +3138,13 @@ istanbul@^0.4.5:
|
|||
which "^1.1.1"
|
||||
wordwrap "^1.0.0"
|
||||
|
||||
isurl@^1.0.0-alpha5:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67"
|
||||
dependencies:
|
||||
has-to-string-tag-x "^1.2.0"
|
||||
is-object "^1.0.1"
|
||||
|
||||
jasmine-core@^2.6.3:
|
||||
version "2.6.3"
|
||||
resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.6.3.tgz#45072950e4a42b1e322fe55c001100a465d77815"
|
||||
|
@ -3633,6 +3691,10 @@ mime@1.3.4, mime@1.3.x, mime@^1.3.4:
|
|||
version "1.3.4"
|
||||
resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53"
|
||||
|
||||
mimic-response@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.0.tgz#df3d3652a73fded6b9b0b24146e6fd052353458e"
|
||||
|
||||
minimalistic-assert@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3"
|
||||
|
@ -3981,6 +4043,14 @@ osenv@^0.1.0:
|
|||
os-homedir "^1.0.0"
|
||||
os-tmpdir "^1.0.0"
|
||||
|
||||
p-cancelable@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa"
|
||||
|
||||
p-finally@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
|
||||
|
||||
p-limit@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.1.0.tgz#b07ff2d9a5d88bec806035895a2bab66a27988bc"
|
||||
|
@ -3991,6 +4061,12 @@ p-locate@^2.0.0:
|
|||
dependencies:
|
||||
p-limit "^1.1.0"
|
||||
|
||||
p-timeout@^1.1.1:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-1.2.0.tgz#9820f99434c5817868b4f34809ee5291660d5b6c"
|
||||
dependencies:
|
||||
p-finally "^1.0.0"
|
||||
|
||||
package-json@^1.0.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/package-json/-/package-json-1.2.0.tgz#c8ecac094227cdf76a316874ed05e27cc939a0e0"
|
||||
|
@ -4419,7 +4495,7 @@ prelude-ls@~1.1.2:
|
|||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
|
||||
|
||||
prepend-http@^1.0.0:
|
||||
prepend-http@^1.0.0, prepend-http@^1.0.1:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
|
||||
|
||||
|
@ -5384,6 +5460,10 @@ timed-out@^2.0.0:
|
|||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-2.0.0.tgz#f38b0ae81d3747d628001f41dafc652ace671c0a"
|
||||
|
||||
timed-out@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f"
|
||||
|
||||
timers-browserify@^1.4.2:
|
||||
version "1.4.2"
|
||||
resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-1.4.2.tgz#c9c58b575be8407375cb5e2462dacee74359f41d"
|
||||
|
@ -5545,6 +5625,12 @@ url-loader@^0.5.8:
|
|||
loader-utils "^1.0.2"
|
||||
mime "1.3.x"
|
||||
|
||||
url-parse-lax@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73"
|
||||
dependencies:
|
||||
prepend-http "^1.0.1"
|
||||
|
||||
url-parse@1.0.x:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.0.5.tgz#0854860422afdcfefeb6c965c662d4800169927b"
|
||||
|
@ -5559,6 +5645,10 @@ url-parse@^1.0.1, url-parse@^1.1.1:
|
|||
querystringify "0.0.x"
|
||||
requires-port "1.0.x"
|
||||
|
||||
url-to-options@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9"
|
||||
|
||||
url@^0.11.0:
|
||||
version "0.11.0"
|
||||
resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
|
||||
|
@ -5657,9 +5747,11 @@ vue-loader@^11.3.4:
|
|||
vue-style-loader "^2.0.0"
|
||||
vue-template-es2015-compiler "^1.2.2"
|
||||
|
||||
vue-resource@^0.9.3:
|
||||
version "0.9.3"
|
||||
resolved "https://registry.yarnpkg.com/vue-resource/-/vue-resource-0.9.3.tgz#ab46e1c44ea219142dcc28ae4043b3b04c80959d"
|
||||
vue-resource@^1.3.4:
|
||||
version "1.3.4"
|
||||
resolved "https://registry.yarnpkg.com/vue-resource/-/vue-resource-1.3.4.tgz#9fc0bdf6a2f5cab430129fc99d347b3deae7b099"
|
||||
dependencies:
|
||||
got "^7.0.0"
|
||||
|
||||
vue-style-loader@^2.0.0:
|
||||
version "2.0.5"
|
||||
|
|
Loading…
Reference in a new issue