Commit 8fa2932d authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch 'ph-axios-2' into 'master'

More conversions to axios

See merge request gitlab-org/gitlab-ce!16800
parents f88fbd2d 965ff965
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, one-var, no-underscore-dangle, one-var-declaration-per-line, object-shorthand, no-unused-vars, no-new, comma-dangle, consistent-return, quotes, dot-notation, quote-props, prefer-arrow-callback, max-len */ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, one-var, no-underscore-dangle, one-var-declaration-per-line, object-shorthand, no-unused-vars, no-new, comma-dangle, consistent-return, quotes, dot-notation, quote-props, prefer-arrow-callback, max-len */
import 'vendor/jquery.waitforimages'; import 'vendor/jquery.waitforimages';
import axios from './lib/utils/axios_utils';
import { addDelimiter } from './lib/utils/text_utility'; import { addDelimiter } from './lib/utils/text_utility';
import Flash from './flash'; import flash from './flash';
import TaskList from './task_list'; import TaskList from './task_list';
import CreateMergeRequestDropdown from './create_merge_request_dropdown'; import CreateMergeRequestDropdown from './create_merge_request_dropdown';
import IssuablesHelper from './helpers/issuables_helper'; import IssuablesHelper from './helpers/issuables_helper';
...@@ -42,12 +43,8 @@ export default class Issue { ...@@ -42,12 +43,8 @@ export default class Issue {
this.disableCloseReopenButton($button); this.disableCloseReopenButton($button);
url = $button.attr('href'); url = $button.attr('href');
return $.ajax({ return axios.put(url)
type: 'PUT', .then(({ data }) => {
url: url
})
.fail(() => new Flash(issueFailMessage))
.done((data) => {
const isClosedBadge = $('div.status-box-issue-closed'); const isClosedBadge = $('div.status-box-issue-closed');
const isOpenBadge = $('div.status-box-open'); const isOpenBadge = $('div.status-box-open');
const projectIssuesCounter = $('.issue_counter'); const projectIssuesCounter = $('.issue_counter');
...@@ -74,9 +71,10 @@ export default class Issue { ...@@ -74,9 +71,10 @@ export default class Issue {
} }
} }
} else { } else {
new Flash(issueFailMessage); flash(issueFailMessage);
} }
}) })
.catch(() => flash(issueFailMessage))
.then(() => { .then(() => {
this.disableCloseReopenButton($button, false); this.disableCloseReopenButton($button, false);
}); });
...@@ -115,24 +113,22 @@ export default class Issue { ...@@ -115,24 +113,22 @@ export default class Issue {
static initMergeRequests() { static initMergeRequests() {
var $container; var $container;
$container = $('#merge-requests'); $container = $('#merge-requests');
return $.getJSON($container.data('url')).fail(function() { return axios.get($container.data('url'))
return new Flash('Failed to load referenced merge requests'); .then(({ data }) => {
}).done(function(data) { if ('html' in data) {
if ('html' in data) { $container.html(data.html);
return $container.html(data.html); }
} }).catch(() => flash('Failed to load referenced merge requests'));
});
} }
static initRelatedBranches() { static initRelatedBranches() {
var $container; var $container;
$container = $('#related-branches'); $container = $('#related-branches');
return $.getJSON($container.data('url')).fail(function() { return axios.get($container.data('url'))
return new Flash('Failed to load related branches'); .then(({ data }) => {
}).done(function(data) { if ('html' in data) {
if ('html' in data) { $container.html(data.html);
return $container.html(data.html); }
} }).catch(() => flash('Failed to load related branches'));
});
} }
} }
import _ from 'underscore'; import _ from 'underscore';
import axios from './lib/utils/axios_utils';
import { visitUrl } from './lib/utils/url_utility'; import { visitUrl } from './lib/utils/url_utility';
import bp from './breakpoints'; import bp from './breakpoints';
import { numberToHumanSize } from './lib/utils/number_utils'; import { numberToHumanSize } from './lib/utils/number_utils';
...@@ -8,6 +9,7 @@ export default class Job { ...@@ -8,6 +9,7 @@ export default class Job {
constructor(options) { constructor(options) {
this.timeout = null; this.timeout = null;
this.state = null; this.state = null;
this.fetchingStatusFavicon = false;
this.options = options || $('.js-build-options').data(); this.options = options || $('.js-build-options').data();
this.pagePath = this.options.pagePath; this.pagePath = this.options.pagePath;
...@@ -171,12 +173,23 @@ export default class Job { ...@@ -171,12 +173,23 @@ export default class Job {
} }
getBuildTrace() { getBuildTrace() {
return $.ajax({ return axios.get(`${this.pagePath}/trace.json`, {
url: `${this.pagePath}/trace.json`, params: { state: this.state },
data: { state: this.state },
}) })
.done((log) => { .then((res) => {
setCiStatusFavicon(`${this.pagePath}/status.json`); const log = res.data;
if (!this.fetchingStatusFavicon) {
this.fetchingStatusFavicon = true;
setCiStatusFavicon(`${this.pagePath}/status.json`)
.then(() => {
this.fetchingStatusFavicon = false;
})
.catch(() => {
this.fetchingStatusFavicon = false;
});
}
if (log.state) { if (log.state) {
this.state = log.state; this.state = log.state;
...@@ -217,7 +230,7 @@ export default class Job { ...@@ -217,7 +230,7 @@ export default class Job {
visitUrl(this.pagePath); visitUrl(this.pagePath);
} }
}) })
.fail(() => { .catch(() => {
this.$buildRefreshAnimation.remove(); this.$buildRefreshAnimation.remove();
}) })
.then(() => { .then(() => {
......
...@@ -2,9 +2,12 @@ ...@@ -2,9 +2,12 @@
/* global Issuable */ /* global Issuable */
/* global ListLabel */ /* global ListLabel */
import _ from 'underscore'; import _ from 'underscore';
import { __ } from './locale';
import axios from './lib/utils/axios_utils';
import IssuableBulkUpdateActions from './issuable_bulk_update_actions'; import IssuableBulkUpdateActions from './issuable_bulk_update_actions';
import DropdownUtils from './filtered_search/dropdown_utils'; import DropdownUtils from './filtered_search/dropdown_utils';
import CreateLabelDropdown from './create_label'; import CreateLabelDropdown from './create_label';
import flash from './flash';
export default class LabelsSelect { export default class LabelsSelect {
constructor(els, options = {}) { constructor(els, options = {}) {
...@@ -82,99 +85,96 @@ export default class LabelsSelect { ...@@ -82,99 +85,96 @@ export default class LabelsSelect {
} }
$loading.removeClass('hidden').fadeIn(); $loading.removeClass('hidden').fadeIn();
$dropdown.trigger('loading.gl.dropdown'); $dropdown.trigger('loading.gl.dropdown');
return $.ajax({ axios.put(issueUpdateURL, data)
type: 'PUT', .then(({ data }) => {
url: issueUpdateURL, var labelCount, template, labelTooltipTitle, labelTitles;
dataType: 'JSON', $loading.fadeOut();
data: data $dropdown.trigger('loaded.gl.dropdown');
}).done(function(data) { $selectbox.hide();
var labelCount, template, labelTooltipTitle, labelTitles; data.issueURLSplit = issueURLSplit;
$loading.fadeOut(); labelCount = 0;
$dropdown.trigger('loaded.gl.dropdown'); if (data.labels.length) {
$selectbox.hide(); template = labelHTMLTemplate(data);
data.issueURLSplit = issueURLSplit; labelCount = data.labels.length;
labelCount = 0; }
if (data.labels.length) { else {
template = labelHTMLTemplate(data); template = labelNoneHTMLTemplate;
labelCount = data.labels.length; }
} $value.removeAttr('style').html(template);
else { $sidebarCollapsedValue.text(labelCount);
template = labelNoneHTMLTemplate;
}
$value.removeAttr('style').html(template);
$sidebarCollapsedValue.text(labelCount);
if (data.labels.length) { if (data.labels.length) {
labelTitles = data.labels.map(function(label) { labelTitles = data.labels.map(function(label) {
return label.title; return label.title;
}); });
if (labelTitles.length > 5) { if (labelTitles.length > 5) {
labelTitles = labelTitles.slice(0, 5); labelTitles = labelTitles.slice(0, 5);
labelTitles.push('and ' + (data.labels.length - 5) + ' more'); labelTitles.push('and ' + (data.labels.length - 5) + ' more');
} }
labelTooltipTitle = labelTitles.join(', '); labelTooltipTitle = labelTitles.join(', ');
} }
else { else {
labelTooltipTitle = ''; labelTooltipTitle = '';
$sidebarLabelTooltip.tooltip('destroy'); $sidebarLabelTooltip.tooltip('destroy');
} }
$sidebarLabelTooltip $sidebarLabelTooltip
.attr('title', labelTooltipTitle) .attr('title', labelTooltipTitle)
.tooltip('fixTitle'); .tooltip('fixTitle');
$('.has-tooltip', $value).tooltip({ $('.has-tooltip', $value).tooltip({
container: 'body' container: 'body'
}); });
}); })
.catch(() => flash(__('Error saving label update.')));
}; };
$dropdown.glDropdown({ $dropdown.glDropdown({
showMenuAbove: showMenuAbove, showMenuAbove: showMenuAbove,
data: function(term, callback) { data: function(term, callback) {
return $.ajax({ axios.get(labelUrl)
url: labelUrl .then((res) => {
}).done(function(data) { let data = _.chain(res.data).groupBy(function(label) {
data = _.chain(data).groupBy(function(label) { return label.title;
return label.title; }).map(function(label) {
}).map(function(label) { var color;
var color; color = _.map(label, function(dup) {
color = _.map(label, function(dup) { return dup.color;
return dup.color;
});
return {
id: label[0].id,
title: label[0].title,
color: color,
duplicate: color.length > 1
};
}).value();
if ($dropdown.hasClass('js-extra-options')) {
var extraData = [];
if (showNo) {
extraData.unshift({
id: 0,
title: 'No Label'
}); });
return {
id: label[0].id,
title: label[0].title,
color: color,
duplicate: color.length > 1
};
}).value();
if ($dropdown.hasClass('js-extra-options')) {
var extraData = [];
if (showNo) {
extraData.unshift({
id: 0,
title: 'No Label'
});
}
if (showAny) {
extraData.unshift({
isAny: true,
title: 'Any Label'
});
}
if (extraData.length) {
extraData.push('divider');
data = extraData.concat(data);
}
} }
if (showAny) {
extraData.unshift({
isAny: true,
title: 'Any Label'
});
}
if (extraData.length) {
extraData.push('divider');
data = extraData.concat(data);
}
}
callback(data); callback(data);
if (showMenuAbove) { if (showMenuAbove) {
$dropdown.data('glDropdown').positionMenuAbove(); $dropdown.data('glDropdown').positionMenuAbove();
} }
}); })
.catch(() => flash(__('Error fetching labels.')));
}, },
renderRow: function(label, instance) { renderRow: function(label, instance) {
var $a, $li, color, colorEl, indeterminate, removesAll, selectedClass, spacing, i, marked, dropdownName, dropdownValue; var $a, $li, color, colorEl, indeterminate, removesAll, selectedClass, spacing, i, marked, dropdownName, dropdownValue;
......
import axios from './axios_utils';
import Cache from './cache'; import Cache from './cache';
class AjaxCache extends Cache { class AjaxCache extends Cache {
...@@ -18,25 +19,18 @@ class AjaxCache extends Cache { ...@@ -18,25 +19,18 @@ class AjaxCache extends Cache {
let pendingRequest = this.pendingRequests[endpoint]; let pendingRequest = this.pendingRequests[endpoint];
if (!pendingRequest) { if (!pendingRequest) {
pendingRequest = new Promise((resolve, reject) => { pendingRequest = axios.get(endpoint)
// jQuery 2 is not Promises/A+ compatible (missing catch) .then(({ data }) => {
$.ajax(endpoint) // eslint-disable-line promise/catch-or-return this.internalStorage[endpoint] = data;
.then(data => resolve(data), delete this.pendingRequests[endpoint];
(jqXHR, textStatus, errorThrown) => { })
const error = new Error(`${endpoint}: ${errorThrown}`); .catch((e) => {
error.textStatus = textStatus; const error = new Error(`${endpoint}: ${e.message}`);
reject(error); error.textStatus = e.message;
},
); delete this.pendingRequests[endpoint];
}) throw error;
.then((data) => { });
this.internalStorage[endpoint] = data;
delete this.pendingRequests[endpoint];
})
.catch((error) => {
delete this.pendingRequests[endpoint];
throw error;
});
this.pendingRequests[endpoint] = pendingRequest; this.pendingRequests[endpoint] = pendingRequest;
} }
......
...@@ -19,6 +19,10 @@ axios.interceptors.response.use((config) => { ...@@ -19,6 +19,10 @@ axios.interceptors.response.use((config) => {
window.activeVueResources -= 1; window.activeVueResources -= 1;
return config; return config;
}, (e) => {
window.activeVueResources -= 1;
return Promise.reject(e);
}); });
export default axios; export default axios;
......
import { getLocationHash } from './url_utility';
import axios from './axios_utils'; import axios from './axios_utils';
import { getLocationHash } from './url_utility';
export const getPagePath = (index = 0) => $('body').attr('data-page').split(':')[index]; export const getPagePath = (index = 0) => $('body').attr('data-page').split(':')[index];
...@@ -28,16 +28,11 @@ export const isInIssuePage = () => { ...@@ -28,16 +28,11 @@ export const isInIssuePage = () => {
return page === 'issues' && action === 'show'; return page === 'issues' && action === 'show';
}; };
export const ajaxGet = url => $.ajax({ export const ajaxGet = url => axios.get(url, {
type: 'GET', params: { format: 'js' },
url, responseType: 'text',
dataType: 'script', }).then(({ data }) => {
}); $.globalEval(data);
export const ajaxPost = (url, data) => $.ajax({
type: 'POST',
url,
data,
}); });
export const rstrip = (val) => { export const rstrip = (val) => {
...@@ -412,7 +407,6 @@ window.gl.utils = { ...@@ -412,7 +407,6 @@ window.gl.utils = {
getGroupSlug, getGroupSlug,
isInIssuePage, isInIssuePage,
ajaxGet, ajaxGet,
ajaxPost,
rstrip, rstrip,
updateTooltipTitle, updateTooltipTitle,
disableButtonIfEmptyField, disableButtonIfEmptyField,
......
/* eslint-disable no-param-reassign, comma-dangle */ /* eslint-disable no-param-reassign, comma-dangle */
import axios from '../lib/utils/axios_utils';
((global) => { ((global) => {
global.mergeConflicts = global.mergeConflicts || {}; global.mergeConflicts = global.mergeConflicts || {};
...@@ -10,20 +11,11 @@ ...@@ -10,20 +11,11 @@
} }
fetchConflictsData() { fetchConflictsData() {
return $.ajax({ return axios.get(this.conflictsPath);
dataType: 'json',
url: this.conflictsPath
});
} }
submitResolveConflicts(data) { submitResolveConflicts(data) {
return $.ajax({ return axios.post(this.resolveConflictsPath, data);
url: this.resolveConflictsPath,
data: JSON.stringify(data),
contentType: 'application/json',
dataType: 'json',
method: 'POST'
});
} }
} }
......
...@@ -38,24 +38,23 @@ $(() => { ...@@ -38,24 +38,23 @@ $(() => {
showDiffViewTypeSwitcher() { return mergeConflictsStore.fileTextTypePresent(); } showDiffViewTypeSwitcher() { return mergeConflictsStore.fileTextTypePresent(); }
}, },
created() { created() {
mergeConflictsService mergeConflictsService.fetchConflictsData()
.fetchConflictsData() .then(({ data }) => {
.done((data) => {
if (data.type === 'error') { if (data.type === 'error') {
mergeConflictsStore.setFailedRequest(data.message); mergeConflictsStore.setFailedRequest(data.message);
} else { } else {
mergeConflictsStore.setConflictsData(data); mergeConflictsStore.setConflictsData(data);
} }
})
.error(() => {
mergeConflictsStore.setFailedRequest();
})
.always(() => {
mergeConflictsStore.setLoadingState(false); mergeConflictsStore.setLoadingState(false);
this.$nextTick(() => { this.$nextTick(() => {
syntaxHighlight($('.js-syntax-highlight')); syntaxHighlight($('.js-syntax-highlight'));
}); });
})
.catch(() => {
mergeConflictsStore.setLoadingState(false);
mergeConflictsStore.setFailedRequest();
}); });
}, },
methods: { methods: {
...@@ -82,10 +81,10 @@ $(() => { ...@@ -82,10 +81,10 @@ $(() => {
mergeConflictsService mergeConflictsService
.submitResolveConflicts(mergeConflictsStore.getCommitData()) .submitResolveConflicts(mergeConflictsStore.getCommitData())
.done((data) => { .then(({ data }) => {
window.location.href = data.redirect_to; window.location.href = data.redirect_to;
}) })
.error(() => { .catch(() => {
mergeConflictsStore.setSubmitState(false); mergeConflictsStore.setSubmitState(false);
new Flash('Failed to save merge conflicts resolutions. Please try again!'); new Flash('Failed to save merge conflicts resolutions. Please try again!');
}); });
......
/* eslint-disable no-new, class-methods-use-this */ /* eslint-disable no-new, class-methods-use-this */
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import Flash from './flash'; import axios from './lib/utils/axios_utils';
import flash from './flash';
import BlobForkSuggestion from './blob/blob_fork_suggestion'; import BlobForkSuggestion from './blob/blob_fork_suggestion';
import initChangesDropdown from './init_changes_dropdown'; import initChangesDropdown from './init_changes_dropdown';
import bp from './breakpoints'; import bp from './breakpoints';
...@@ -244,15 +245,22 @@ export default class MergeRequestTabs { ...@@ -244,15 +245,22 @@ export default class MergeRequestTabs {
if (this.commitsLoaded) { if (this.commitsLoaded) {
return; return;
} }
this.ajaxGet({
url: `${source}.json`, this.toggleLoading(true);
success: (data) => {
axios.get(`${source}.json`)
.then(({ data }) => {
document.querySelector('div#commits').innerHTML = data.html; document.querySelector('div#commits').innerHTML = data.html;
localTimeAgo($('.js-timeago', 'div#commits')); localTimeAgo($('.js-timeago', 'div#commits'));
this.commitsLoaded = true; this.commitsLoaded = true;
this.scrollToElement('#commits'); this.scrollToElement('#commits');
},
}); this.toggleLoading(false);
})
.catch(() => {
this.toggleLoading(false);
flash('An error occurred while fetching this tab.');
});
} }
mountPipelinesView() { mountPipelinesView() {
...@@ -283,9 +291,10 @@ export default class MergeRequestTabs { ...@@ -283,9 +291,10 @@ export default class MergeRequestTabs {
// some pages like MergeRequestsController#new has query parameters on that anchor // some pages like MergeRequestsController#new has query parameters on that anchor
const urlPathname = parseUrlPathname(source); const urlPathname = parseUrlPathname(source);
this.ajaxGet({ this.toggleLoading(true);
url: `${urlPathname}.json${location.search}`,
success: (data) => { axios.get(`${urlPathname}.json${location.search}`)
.then(({ data }) => {
const $container = $('#diffs'); const $container = $('#diffs');
$container.html(data.html); $container.html(data.html);
...@@ -335,8 +344,13 @@ export default class MergeRequestTabs { ...@@ -335,8 +344,13 @@ export default class MergeRequestTabs {
// (discussion and diff tabs) and `:target` only applies to the first // (discussion and diff tabs) and `:target` only applies to the first
anchor.addClass('target'); anchor.addClass('target');
} }
},
}); this.toggleLoading(false);
})
.catch(() => {
this.toggleLoading(false);
flash('An error occurred while fetching this tab.');
});
} }
// Show or hide the loading spinner // Show or hide the loading spinner
...@@ -346,17 +360,6 @@ export default class MergeRequestTabs { ...@@ -346,17 +360,6 @@ export default class MergeRequestTabs {
$('.mr-loading-status .loading').toggle(status); $('.mr-loading-status .loading').toggle(status);
} }
ajaxGet(options) {
const defaults = {
beforeSend: () => this.toggleLoading(true),
error: () => new Flash('An error occurred while fetching this tab.', 'alert'),
complete: () => this.toggleLoading(false),
dataType: 'json',
type: 'GET',
};
$.ajax($.extend({}, defaults, options));
}
diffViewType() { diffViewType() {
return $('.inline-parallel-buttons a.active').data('view-type'); return $('.inline-parallel-buttons a.active').data('view-type');
} }
......
import Flash from './flash'; import axios from './lib/utils/axios_utils';
import flash from './flash';
export default class Milestone { export default class Milestone {
constructor() { constructor() {
...@@ -33,15 +34,12 @@ export default class Milestone { ...@@ -33,15 +34,12 @@ export default class Milestone {
const tabElId = $target.attr('href'); const tabElId = $target.attr('href');
if (endpoint && !$target.hasClass('is-loaded')) { if (endpoint && !$target.hasClass('is-loaded')) {
$.ajax({ axios.get(endpoint)
url: endpoint, .then(({ data }) => {
dataType: 'JSON', $(tabElId).html(data.html);
}) $target.addClass('is-loaded');
.fail(() => new Flash('Error loading milestone tab')) })
.done((data) => { .catch(() => flash('Error loading milestone tab'));
$(tabElId).html(data.html);
$target.addClass('is-loaded');
});
} }
} }
} }
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
/* global Issuable */ /* global Issuable */
/* global ListMilestone */ /* global ListMilestone */
import _ from 'underscore'; import _ from 'underscore';
import axios from './lib/utils/axios_utils';
import { timeFor } from './lib/utils/datetime_utility'; import { timeFor } from './lib/utils/datetime_utility';
export default class MilestoneSelect { export default class MilestoneSelect {
...@@ -52,48 +53,47 @@ export default class MilestoneSelect { ...@@ -52,48 +53,47 @@ export default class MilestoneSelect {
} }
return $dropdown.glDropdown({ return $dropdown.glDropdown({
showMenuAbove: showMenuAbove, showMenuAbove: showMenuAbove,
data: (term, callback) => $.ajax({ data: (term, callback) => axios.get(milestonesUrl)
url: milestonesUrl .then(({ data }) => {
}).done((data) => { const extraOptions = [];
const extraOptions = []; if (showAny) {
if (showAny) { extraOptions.push({
extraOptions.push({ id: 0,
id: 0, name: '',
name: '', title: 'Any Milestone'
title: 'Any Milestone' });
}); }
} if (showNo) {
if (showNo) { extraOptions.push({
extraOptions.push({ id: -1,
id: -1, name: 'No Milestone',
name: 'No Milestone', title: 'No Milestone'
title: 'No Milestone' });
}); }
} if (showUpcoming) {
if (showUpcoming) { extraOptions.push({
extraOptions.push({ id: -2,
id: -2, name: '#upcoming',
name: '#upcoming', title: 'Upcoming'
title: 'Upcoming' });
}); }
} if (showStarted) {
if (showStarted) { extraOptions.push({
extraOptions.push({ id: -3,
id: -3, name: '#started',
name: '#started', title: 'Started'
title: 'Started' });
}); }
} if (extraOptions.length) {
if (extraOptions.length) { extraOptions.push('divider');
extraOptions.push('divider'); }
}
callback(extraOptions.concat(data)); callback(extraOptions.concat(data));
if (showMenuAbove) { if (showMenuAbove) {
$dropdown.data('glDropdown').positionMenuAbove(); $dropdown.data('glDropdown').positionMenuAbove();
} }
$(`[data-milestone-id="${selectedMilestone}"] > a`).addClass('is-active'); $(`[data-milestone-id="${selectedMilestone}"] > a`).addClass('is-active');
}), }),
renderRow: milestone => ` renderRow: milestone => `
<li data-milestone-id="${milestone.name}"> <li data-milestone-id="${milestone.name}">
<a href='#' class='dropdown-menu-milestone-link'> <a href='#' class='dropdown-menu-milestone-link'>
...@@ -200,26 +200,23 @@ export default class MilestoneSelect { ...@@ -200,26 +200,23 @@ export default class MilestoneSelect {
data[abilityName].milestone_id = selected != null ? selected : null; data[abilityName].milestone_id = selected != null ? selected : null;
$loading.removeClass('hidden').fadeIn(); $loading.removeClass('hidden').fadeIn();
$dropdown.trigger('loading.gl.dropdown'); $dropdown.trigger('loading.gl.dropdown');
return $.ajax({ return axios.put(issueUpdateURL, data)
type: 'PUT', .then(({ data }) => {
url: issueUpdateURL, $dropdown.trigger('loaded.gl.dropdown');
data: data $loading.fadeOut();
}).done((data) => { $selectBox.hide();
$dropdown.trigger('loaded.gl.dropdown'); $value.css('display', '');
$loading.fadeOut(); if (data.milestone != null) {
$selectBox.hide(); data.milestone.full_path = this.currentProject.full_path;
$value.css('display', ''); data.milestone.remaining = timeFor(data.milestone.due_date);
if (data.milestone != null) { data.milestone.name = data.milestone.title;
data.milestone.full_path = this.currentProject.full_path; $value.html(milestoneLinkTemplate(data.milestone));
data.milestone.remaining = timeFor(data.milestone.due_date); return $sidebarCollapsedValue.find('span').html(collapsedSidebarLabelTemplate(data.milestone));
data.milestone.name = data.milestone.title; } else {
$value.html(milestoneLinkTemplate(data.milestone)); $value.html(milestoneLinkNoneTemplate);
return $sidebarCollapsedValue.find('span').html(collapsedSidebarLabelTemplate(data.milestone)); return $sidebarCollapsedValue.find('span').text('No');
} else { }
$value.html(milestoneLinkNoneTemplate); });
return $sidebarCollapsedValue.find('span').text('No');
}
});
} }
} }
}); });
......
...@@ -18,13 +18,14 @@ import 'vendor/jquery.atwho'; ...@@ -18,13 +18,14 @@ import 'vendor/jquery.atwho';
import AjaxCache from '~/lib/utils/ajax_cache'; import AjaxCache from '~/lib/utils/ajax_cache';
import axios from './lib/utils/axios_utils'; import axios from './lib/utils/axios_utils';
import { getLocationHash } from './lib/utils/url_utility'; import { getLocationHash } from './lib/utils/url_utility';
import axios from './lib/utils/axios_utils';
import Flash from './flash'; import Flash from './flash';
import CommentTypeToggle from './comment_type_toggle'; import CommentTypeToggle from './comment_type_toggle';
import GLForm from './gl_form'; import GLForm from './gl_form';
import loadAwardsHandler from './awards_handler'; import loadAwardsHandler from './awards_handler';
import Autosave from './autosave'; import Autosave from './autosave';
import TaskList from './task_list'; import TaskList from './task_list';
import { ajaxPost, isInViewport, getPagePath, scrollToElement, isMetaKey } from './lib/utils/common_utils'; import { isInViewport, getPagePath, scrollToElement, isMetaKey } from './lib/utils/common_utils';
import imageDiffHelper from './image_diff/helpers/index'; import imageDiffHelper from './image_diff/helpers/index';
import { localTimeAgo } from './lib/utils/datetime_utility'; import { localTimeAgo } from './lib/utils/datetime_utility';
...@@ -1399,7 +1400,7 @@ export default class Notes { ...@@ -1399,7 +1400,7 @@ export default class Notes {
* 2) Identify comment type; a) Main thread b) Discussion thread c) Discussion resolve * 2) Identify comment type; a) Main thread b) Discussion thread c) Discussion resolve
* 3) Build temporary placeholder element (using `createPlaceholderNote`) * 3) Build temporary placeholder element (using `createPlaceholderNote`)
* 4) Show placeholder note on UI * 4) Show placeholder note on UI
* 5) Perform network request to submit the note using `ajaxPost` * 5) Perform network request to submit the note using `axios.post`
* a) If request is successfully completed * a) If request is successfully completed
* 1. Remove placeholder element * 1. Remove placeholder element
* 2. Show submitted Note element * 2. Show submitted Note element
...@@ -1481,8 +1482,10 @@ export default class Notes { ...@@ -1481,8 +1482,10 @@ export default class Notes {
/* eslint-disable promise/catch-or-return */ /* eslint-disable promise/catch-or-return */
// Make request to submit comment on server // Make request to submit comment on server
ajaxPost(formAction, formData) axios.post(formAction, formData)
.then((note) => { .then((res) => {
const note = res.data;
// Submission successful! remove placeholder // Submission successful! remove placeholder
$notesContainer.find(`#${noteUniqueId}`).remove(); $notesContainer.find(`#${noteUniqueId}`).remove();
...@@ -1555,7 +1558,7 @@ export default class Notes { ...@@ -1555,7 +1558,7 @@ export default class Notes {
} }
$form.trigger('ajax:success', [note]); $form.trigger('ajax:success', [note]);
}).fail(() => { }).catch(() => {
// Submission failed, remove placeholder note and show Flash error message // Submission failed, remove placeholder note and show Flash error message
$notesContainer.find(`#${noteUniqueId}`).remove(); $notesContainer.find(`#${noteUniqueId}`).remove();
...@@ -1594,7 +1597,7 @@ export default class Notes { ...@@ -1594,7 +1597,7 @@ export default class Notes {
* *
* 1) Get Form metadata * 1) Get Form metadata
* 2) Update note element with new content * 2) Update note element with new content
* 3) Perform network request to submit the updated note using `ajaxPost` * 3) Perform network request to submit the updated note using `axios.post`
* a) If request is successfully completed * a) If request is successfully completed
* 1. Show submitted Note element * 1. Show submitted Note element
* b) If request failed * b) If request failed
...@@ -1625,12 +1628,12 @@ export default class Notes { ...@@ -1625,12 +1628,12 @@ export default class Notes {
/* eslint-disable promise/catch-or-return */ /* eslint-disable promise/catch-or-return */
// Make request to update comment on server // Make request to update comment on server
ajaxPost(formAction, formData) axios.post(formAction, formData)
.then((note) => { .then(({ data }) => {
// Submission successful! render final note element // Submission successful! render final note element
this.updateNote(note, $editingNote); this.updateNote(data, $editingNote);
}) })
.fail(() => { .catch(() => {
// Submission failed, revert back to original note // Submission failed, revert back to original note
$noteBodyText.html(_.escape(cachedNoteBodyText)); $noteBodyText.html(_.escape(cachedNoteBodyText));
$editingNote.removeClass('being-posted fade-in'); $editingNote.removeClass('being-posted fade-in');
......
/* eslint-disable space-before-function-paren, one-var, one-var-declaration-per-line, no-use-before-define, comma-dangle, max-len */ /* eslint-disable space-before-function-paren, one-var, one-var-declaration-per-line, no-use-before-define, comma-dangle, max-len */
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import Issue from '~/issue'; import Issue from '~/issue';
import '~/lib/utils/text_utility'; import '~/lib/utils/text_utility';
...@@ -88,20 +90,24 @@ describe('Issue', function() { ...@@ -88,20 +90,24 @@ describe('Issue', function() {
[true, false].forEach((isIssueInitiallyOpen) => { [true, false].forEach((isIssueInitiallyOpen) => {
describe(`with ${isIssueInitiallyOpen ? 'open' : 'closed'} issue`, function() { describe(`with ${isIssueInitiallyOpen ? 'open' : 'closed'} issue`, function() {
const action = isIssueInitiallyOpen ? 'close' : 'reopen'; const action = isIssueInitiallyOpen ? 'close' : 'reopen';
let mock;
function ajaxSpy(req) { function mockCloseButtonResponseSuccess(url, response) {
if (req.url === this.$triggeredButton.attr('href')) { mock.onPut(url).reply(() => {
expect(req.type).toBe('PUT');
expectNewBranchButtonState(true, false); expectNewBranchButtonState(true, false);
return this.issueStateDeferred;
} else if (req.url === Issue.createMrDropdownWrap.dataset.canCreatePath) {
expect(req.type).toBe('GET');
expectNewBranchButtonState(true, false);
return this.canCreateBranchDeferred;
}
expect(req.url).toBe('unexpected'); return [200, response];
return null; });
}
function mockCloseButtonResponseError(url) {
mock.onPut(url).networkError();
}
function mockCanCreateBranch(canCreateBranch) {
mock.onGet(/(.*)\/can_create_branch$/).reply(200, {
can_create_branch: canCreateBranch,
});
} }
beforeEach(function() { beforeEach(function() {
...@@ -111,6 +117,11 @@ describe('Issue', function() { ...@@ -111,6 +117,11 @@ describe('Issue', function() {
loadFixtures('issues/closed-issue.html.raw'); loadFixtures('issues/closed-issue.html.raw');
} }
mock = new MockAdapter(axios);
mock.onGet(/(.*)\/related_branches$/).reply(200, {});
mock.onGet(/(.*)\/referenced_merge_requests$/).reply(200, {});
findElements(isIssueInitiallyOpen); findElements(isIssueInitiallyOpen);
this.issue = new Issue(); this.issue = new Issue();
expectIssueState(isIssueInitiallyOpen); expectIssueState(isIssueInitiallyOpen);
...@@ -120,71 +131,89 @@ describe('Issue', function() { ...@@ -120,71 +131,89 @@ describe('Issue', function() {
this.$projectIssuesCounter = $('.issue_counter').first(); this.$projectIssuesCounter = $('.issue_counter').first();
this.$projectIssuesCounter.text('1,001'); this.$projectIssuesCounter.text('1,001');
this.issueStateDeferred = new jQuery.Deferred(); spyOn(axios, 'get').and.callThrough();
this.canCreateBranchDeferred = new jQuery.Deferred(); });
spyOn(jQuery, 'ajax').and.callFake(ajaxSpy.bind(this)); afterEach(() => {
mock.restore();
$('div.flash-alert').remove();
}); });
it(`${action}s the issue`, function() { it(`${action}s the issue`, function(done) {
this.$triggeredButton.trigger('click'); mockCloseButtonResponseSuccess(this.$triggeredButton.attr('href'), {
this.issueStateDeferred.resolve({
id: 34 id: 34
}); });
this.canCreateBranchDeferred.resolve({ mockCanCreateBranch(!isIssueInitiallyOpen);
can_create_branch: !isIssueInitiallyOpen
});
expectIssueState(!isIssueInitiallyOpen); this.$triggeredButton.trigger('click');
expect(this.$triggeredButton.get(0).getAttribute('disabled')).toBeNull();
expect(this.$projectIssuesCounter.text()).toBe(isIssueInitiallyOpen ? '1,000' : '1,002'); setTimeout(() => {
expectNewBranchButtonState(false, !isIssueInitiallyOpen); expectIssueState(!isIssueInitiallyOpen);
expect(this.$triggeredButton.get(0).getAttribute('disabled')).toBeNull();
expect(this.$projectIssuesCounter.text()).toBe(isIssueInitiallyOpen ? '1,000' : '1,002');
expectNewBranchButtonState(false, !isIssueInitiallyOpen);
done();
});
}); });
it(`fails to ${action} the issue if saved:false`, function() { it(`fails to ${action} the issue if saved:false`, function(done) {
this.$triggeredButton.trigger('click'); mockCloseButtonResponseSuccess(this.$triggeredButton.attr('href'), {
this.issueStateDeferred.resolve({
saved: false saved: false
}); });
this.canCreateBranchDeferred.resolve({ mockCanCreateBranch(isIssueInitiallyOpen);
can_create_branch: isIssueInitiallyOpen
});
expectIssueState(isIssueInitiallyOpen); this.$triggeredButton.trigger('click');
expect(this.$triggeredButton.get(0).getAttribute('disabled')).toBeNull();
expectErrorMessage(); setTimeout(() => {
expect(this.$projectIssuesCounter.text()).toBe('1,001'); expectIssueState(isIssueInitiallyOpen);
expectNewBranchButtonState(false, isIssueInitiallyOpen); expect(this.$triggeredButton.get(0).getAttribute('disabled')).toBeNull();
expectErrorMessage();
expect(this.$projectIssuesCounter.text()).toBe('1,001');
expectNewBranchButtonState(false, isIssueInitiallyOpen);
done();
});
}); });
it(`fails to ${action} the issue if HTTP error occurs`, function() { it(`fails to ${action} the issue if HTTP error occurs`, function(done) {
mockCloseButtonResponseError(this.$triggeredButton.attr('href'));
mockCanCreateBranch(isIssueInitiallyOpen);
this.$triggeredButton.trigger('click'); this.$triggeredButton.trigger('click');
this.issueStateDeferred.reject();
this.canCreateBranchDeferred.resolve({
can_create_branch: isIssueInitiallyOpen
});
expectIssueState(isIssueInitiallyOpen); setTimeout(() => {
expect(this.$triggeredButton.get(0).getAttribute('disabled')).toBeNull(); expectIssueState(isIssueInitiallyOpen);
expectErrorMessage(); expect(this.$triggeredButton.get(0).getAttribute('disabled')).toBeNull();
expect(this.$projectIssuesCounter.text()).toBe('1,001'); expectErrorMessage();
expectNewBranchButtonState(false, isIssueInitiallyOpen); expect(this.$projectIssuesCounter.text()).toBe('1,001');
expectNewBranchButtonState(false, isIssueInitiallyOpen);
done();
});
}); });
it('disables the new branch button if Ajax call fails', function() { it('disables the new branch button if Ajax call fails', function() {
mockCloseButtonResponseError(this.$triggeredButton.attr('href'));
mock.onGet(/(.*)\/can_create_branch$/).networkError();
this.$triggeredButton.trigger('click'); this.$triggeredButton.trigger('click');
this.issueStateDeferred.reject();
this.canCreateBranchDeferred.reject();
expectNewBranchButtonState(false, false); expectNewBranchButtonState(false, false);
}); });
it('does not trigger Ajax call if new branch button is missing', function() { it('does not trigger Ajax call if new branch button is missing', function(done) {
mockCloseButtonResponseError(this.$triggeredButton.attr('href'));
Issue.$btnNewBranch = $(); Issue.$btnNewBranch = $();
this.canCreateBranchDeferred = null; this.canCreateBranchDeferred = null;
this.$triggeredButton.trigger('click'); this.$triggeredButton.trigger('click');
this.issueStateDeferred.reject();
setTimeout(() => {
expect(axios.get).not.toHaveBeenCalled();
done();
});
}); });
}); });
}); });
......
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import { numberToHumanSize } from '~/lib/utils/number_utils'; import { numberToHumanSize } from '~/lib/utils/number_utils';
import * as urlUtils from '~/lib/utils/url_utility'; import * as urlUtils from '~/lib/utils/url_utility';
import '~/lib/utils/datetime_utility'; import '~/lib/utils/datetime_utility';
...@@ -6,11 +8,29 @@ import '~/breakpoints'; ...@@ -6,11 +8,29 @@ import '~/breakpoints';
describe('Job', () => { describe('Job', () => {
const JOB_URL = `${gl.TEST_HOST}/frontend-fixtures/builds-project/-/jobs/1`; const JOB_URL = `${gl.TEST_HOST}/frontend-fixtures/builds-project/-/jobs/1`;
let mock;
let response;
function waitForPromise() {
return new Promise(resolve => requestAnimationFrame(resolve));
}
preloadFixtures('builds/build-with-artifacts.html.raw'); preloadFixtures('builds/build-with-artifacts.html.raw');
beforeEach(() => { beforeEach(() => {
loadFixtures('builds/build-with-artifacts.html.raw'); loadFixtures('builds/build-with-artifacts.html.raw');
spyOn(urlUtils, 'visitUrl');
mock = new MockAdapter(axios);
mock.onGet(new RegExp(`${JOB_URL}/trace.json?(.*)`)).reply(() => [200, response]);
});
afterEach(() => {
mock.restore();
response = {};
}); });
describe('class constructor', () => { describe('class constructor', () => {
...@@ -55,161 +75,159 @@ describe('Job', () => { ...@@ -55,161 +75,159 @@ describe('Job', () => {
}); });
describe('running build', () => { describe('running build', () => {
it('updates the build trace on an interval', function () { it('updates the build trace on an interval', function (done) {
const deferred1 = $.Deferred(); response = {
const deferred2 = $.Deferred();
spyOn($, 'ajax').and.returnValues(deferred1.promise(), deferred2.promise());
spyOn(urlUtils, 'visitUrl');
deferred1.resolve({
html: '<span>Update<span>', html: '<span>Update<span>',
status: 'running', status: 'running',
state: 'newstate', state: 'newstate',
append: true, append: true,
complete: false, complete: false,
}); };
deferred2.resolve({
html: '<span>More</span>',
status: 'running',
state: 'finalstate',
append: true,
complete: true,
});
this.job = new Job(); this.job = new Job();
expect($('#build-trace .js-build-output').text()).toMatch(/Update/); waitForPromise()
expect(this.job.state).toBe('newstate'); .then(() => {
expect($('#build-trace .js-build-output').text()).toMatch(/Update/);
jasmine.clock().tick(4001); expect(this.job.state).toBe('newstate');
expect($('#build-trace .js-build-output').text()).toMatch(/UpdateMore/); response = {
expect(this.job.state).toBe('finalstate'); html: '<span>More</span>',
status: 'running',
state: 'finalstate',
append: true,
complete: true,
};
})
.then(() => jasmine.clock().tick(4001))
.then(waitForPromise)
.then(() => {
expect($('#build-trace .js-build-output').text()).toMatch(/UpdateMore/);
expect(this.job.state).toBe('finalstate');
})
.then(done)
.catch(done.fail);
}); });
it('replaces the entire build trace', () => { it('replaces the entire build trace', (done) => {
const deferred1 = $.Deferred(); response = {
const deferred2 = $.Deferred();
spyOn($, 'ajax').and.returnValues(deferred1.promise(), deferred2.promise());
spyOn(urlUtils, 'visitUrl');
deferred1.resolve({
html: '<span>Update<span>', html: '<span>Update<span>',
status: 'running', status: 'running',
append: false, append: false,
complete: false, complete: false,
}); };
deferred2.resolve({
html: '<span>Different</span>',
status: 'running',
append: false,
});
this.job = new Job(); this.job = new Job();
expect($('#build-trace .js-build-output').text()).toMatch(/Update/); waitForPromise()
.then(() => {
jasmine.clock().tick(4001); expect($('#build-trace .js-build-output').text()).toMatch(/Update/);
expect($('#build-trace .js-build-output').text()).not.toMatch(/Update/); response = {
expect($('#build-trace .js-build-output').text()).toMatch(/Different/); html: '<span>Different</span>',
status: 'running',
append: false,
};
})
.then(() => jasmine.clock().tick(4001))
.then(waitForPromise)
.then(() => {
expect($('#build-trace .js-build-output').text()).not.toMatch(/Update/);
expect($('#build-trace .js-build-output').text()).toMatch(/Different/);
})
.then(done)
.catch(done.fail);
}); });
}); });
describe('truncated information', () => { describe('truncated information', () => {
describe('when size is less than total', () => { describe('when size is less than total', () => {
it('shows information about truncated log', () => { it('shows information about truncated log', (done) => {
spyOn(urlUtils, 'visitUrl'); response = {
const deferred = $.Deferred();
spyOn($, 'ajax').and.returnValue(deferred.promise());
deferred.resolve({
html: '<span>Update</span>', html: '<span>Update</span>',
status: 'success', status: 'success',
append: false, append: false,
size: 50, size: 50,
total: 100, total: 100,
}); };
this.job = new Job(); this.job = new Job();
expect(document.querySelector('.js-truncated-info').classList).not.toContain('hidden'); waitForPromise()
.then(() => {
expect(document.querySelector('.js-truncated-info').classList).not.toContain('hidden');
})
.then(done)
.catch(done.fail);
}); });
it('shows the size in KiB', () => { it('shows the size in KiB', (done) => {
const size = 50; const size = 50;
spyOn(urlUtils, 'visitUrl');
const deferred = $.Deferred();
spyOn($, 'ajax').and.returnValue(deferred.promise()); response = {
deferred.resolve({
html: '<span>Update</span>', html: '<span>Update</span>',
status: 'success', status: 'success',
append: false, append: false,
size, size,
total: 100, total: 100,
}); };
this.job = new Job(); this.job = new Job();
expect( waitForPromise()
document.querySelector('.js-truncated-info-size').textContent.trim(), .then(() => {
).toEqual(`${numberToHumanSize(size)}`); expect(
document.querySelector('.js-truncated-info-size').textContent.trim(),
).toEqual(`${numberToHumanSize(size)}`);
})
.then(done)
.catch(done.fail);
}); });
it('shows incremented size', () => { it('shows incremented size', (done) => {
const deferred1 = $.Deferred(); response = {
const deferred2 = $.Deferred();
spyOn($, 'ajax').and.returnValues(deferred1.promise(), deferred2.promise());
spyOn(urlUtils, 'visitUrl');
deferred1.resolve({
html: '<span>Update</span>', html: '<span>Update</span>',
status: 'success', status: 'success',
append: false, append: false,
size: 50, size: 50,
total: 100, total: 100,
}); };
this.job = new Job(); this.job = new Job();
expect( waitForPromise()
document.querySelector('.js-truncated-info-size').textContent.trim(), .then(() => {
).toEqual(`${numberToHumanSize(50)}`); expect(
document.querySelector('.js-truncated-info-size').textContent.trim(),
jasmine.clock().tick(4001); ).toEqual(`${numberToHumanSize(50)}`);
deferred2.resolve({ response = {
html: '<span>Update</span>', html: '<span>Update</span>',
status: 'success', status: 'success',
append: true, append: true,
size: 10, size: 10,
total: 100, total: 100,
}); };
})
expect( .then(() => jasmine.clock().tick(4001))
document.querySelector('.js-truncated-info-size').textContent.trim(), .then(waitForPromise)
).toEqual(`${numberToHumanSize(60)}`); .then(() => {
expect(
document.querySelector('.js-truncated-info-size').textContent.trim(),
).toEqual(`${numberToHumanSize(60)}`);
})
.then(done)
.catch(done.fail);
}); });
it('renders the raw link', () => { it('renders the raw link', () => {
const deferred = $.Deferred(); response = {
spyOn(urlUtils, 'visitUrl');
spyOn($, 'ajax').and.returnValue(deferred.promise());
deferred.resolve({
html: '<span>Update</span>', html: '<span>Update</span>',
status: 'success', status: 'success',
append: false, append: false,
size: 50, size: 50,
total: 100, total: 100,
}); };
this.job = new Job(); this.job = new Job();
...@@ -220,50 +238,50 @@ describe('Job', () => { ...@@ -220,50 +238,50 @@ describe('Job', () => {
}); });
describe('when size is equal than total', () => { describe('when size is equal than total', () => {
it('does not show the trunctated information', () => { it('does not show the trunctated information', (done) => {
const deferred = $.Deferred(); response = {
spyOn(urlUtils, 'visitUrl');
spyOn($, 'ajax').and.returnValue(deferred.promise());
deferred.resolve({
html: '<span>Update</span>', html: '<span>Update</span>',
status: 'success', status: 'success',
append: false, append: false,
size: 100, size: 100,
total: 100, total: 100,
}); };
this.job = new Job(); this.job = new Job();
expect(document.querySelector('.js-truncated-info').classList).toContain('hidden'); waitForPromise()
.then(() => {
expect(document.querySelector('.js-truncated-info').classList).toContain('hidden');
})
.then(done)
.catch(done.fail);
}); });
}); });
}); });
describe('output trace', () => { describe('output trace', () => {
beforeEach(() => { beforeEach((done) => {
const deferred = $.Deferred(); response = {
spyOn(urlUtils, 'visitUrl');
spyOn($, 'ajax').and.returnValue(deferred.promise());
deferred.resolve({
html: '<span>Update</span>', html: '<span>Update</span>',
status: 'success', status: 'success',
append: false, append: false,
size: 50, size: 50,
total: 100, total: 100,
}); };
this.job = new Job(); this.job = new Job();
waitForPromise()
.then(done)
.catch(done.fail);
}); });
it('should render trace controls', () => { it('should render trace controls', () => {
const controllers = document.querySelector('.controllers'); const controllers = document.querySelector('.controllers');
expect(controllers.querySelector('.js-raw-link-controller')).toBeDefined(); expect(controllers.querySelector('.js-raw-link-controller')).not.toBeNull();
expect(controllers.querySelector('.js-erase-link')).toBeDefined(); expect(controllers.querySelector('.js-scroll-up')).not.toBeNull();
expect(controllers.querySelector('.js-scroll-up')).toBeDefined(); expect(controllers.querySelector('.js-scroll-down')).not.toBeNull();
expect(controllers.querySelector('.js-scroll-down')).toBeDefined();
}); });
it('should render received output', () => { it('should render received output', () => {
...@@ -276,13 +294,13 @@ describe('Job', () => { ...@@ -276,13 +294,13 @@ describe('Job', () => {
describe('getBuildTrace', () => { describe('getBuildTrace', () => {
it('should request build trace with state parameter', (done) => { it('should request build trace with state parameter', (done) => {
spyOn(jQuery, 'ajax').and.callThrough(); spyOn(axios, 'get').and.callThrough();
// eslint-disable-next-line no-new // eslint-disable-next-line no-new
new Job(); new Job();
setTimeout(() => { setTimeout(() => {
expect(jQuery.ajax).toHaveBeenCalledWith( expect(axios.get).toHaveBeenCalledWith(
{ url: `${JOB_URL}/trace.json`, data: { state: '' } }, `${JOB_URL}/trace.json`, { params: { state: '' } },
); );
done(); done();
}, 0); }, 0);
......
/* eslint-disable no-new */ /* eslint-disable no-new */
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import IssuableContext from '~/issuable_context'; import IssuableContext from '~/issuable_context';
import LabelsSelect from '~/labels_select'; import LabelsSelect from '~/labels_select';
...@@ -10,35 +12,44 @@ import '~/users_select'; ...@@ -10,35 +12,44 @@ import '~/users_select';
(() => { (() => {
let saveLabelCount = 0; let saveLabelCount = 0;
let mock;
describe('Issue dropdown sidebar', () => { describe('Issue dropdown sidebar', () => {
preloadFixtures('static/issue_sidebar_label.html.raw'); preloadFixtures('static/issue_sidebar_label.html.raw');
beforeEach(() => { beforeEach(() => {
loadFixtures('static/issue_sidebar_label.html.raw'); loadFixtures('static/issue_sidebar_label.html.raw');
mock = new MockAdapter(axios);
new IssuableContext('{"id":1,"name":"Administrator","username":"root"}'); new IssuableContext('{"id":1,"name":"Administrator","username":"root"}');
new LabelsSelect(); new LabelsSelect();
spyOn(jQuery, 'ajax').and.callFake((req) => { mock.onGet('/root/test/labels.json').reply(() => {
const d = $.Deferred(); const labels = Array(10).fill().map((_, i) => ({
let LABELS_DATA = []; id: i,
title: `test ${i}`,
color: '#5CB85C',
}));
if (req.url === '/root/test/labels.json') { return [200, labels];
for (let i = 0; i < 10; i += 1) { });
LABELS_DATA.push({ id: i, title: `test ${i}`, color: '#5CB85C' });
} mock.onPut('/root/test/issues/2.json').reply(() => {
} else if (req.url === '/root/test/issues/2.json') { const labels = Array(saveLabelCount).fill().map((_, i) => ({
const tmp = []; id: i,
for (let i = 0; i < saveLabelCount; i += 1) { title: `test ${i}`,
tmp.push({ id: i, title: `test ${i}`, color: '#5CB85C' }); color: '#5CB85C',
} }));
LABELS_DATA = { labels: tmp };
}
d.resolve(LABELS_DATA); return [200, { labels }];
return d.promise();
}); });
}); });
afterEach(() => {
mock.restore();
});
it('changes collapsed tooltip when changing labels when less than 5', (done) => { it('changes collapsed tooltip when changing labels when less than 5', (done) => {
saveLabelCount = 5; saveLabelCount = 5;
$('.edit-link').get(0).click(); $('.edit-link').get(0).click();
......
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import AjaxCache from '~/lib/utils/ajax_cache'; import AjaxCache from '~/lib/utils/ajax_cache';
describe('AjaxCache', () => { describe('AjaxCache', () => {
...@@ -87,66 +89,53 @@ describe('AjaxCache', () => { ...@@ -87,66 +89,53 @@ describe('AjaxCache', () => {
}); });
describe('retrieve', () => { describe('retrieve', () => {
let ajaxSpy; let mock;
beforeEach(() => { beforeEach(() => {
spyOn(jQuery, 'ajax').and.callFake(url => ajaxSpy(url)); mock = new MockAdapter(axios);
spyOn(axios, 'get').and.callThrough();
});
afterEach(() => {
mock.restore();
}); });
it('stores and returns data from Ajax call if cache is empty', (done) => { it('stores and returns data from Ajax call if cache is empty', (done) => {
ajaxSpy = (url) => { mock.onGet(dummyEndpoint).reply(200, dummyResponse);
expect(url).toBe(dummyEndpoint);
const deferred = $.Deferred();
deferred.resolve(dummyResponse);
return deferred.promise();
};
AjaxCache.retrieve(dummyEndpoint) AjaxCache.retrieve(dummyEndpoint)
.then((data) => { .then((data) => {
expect(data).toBe(dummyResponse); expect(data).toEqual(dummyResponse);
expect(AjaxCache.internalStorage[dummyEndpoint]).toBe(dummyResponse); expect(AjaxCache.internalStorage[dummyEndpoint]).toEqual(dummyResponse);
}) })
.then(done) .then(done)
.catch(fail); .catch(fail);
}); });
it('makes no Ajax call if request is pending', () => { it('makes no Ajax call if request is pending', (done) => {
const responseDeferred = $.Deferred(); mock.onGet(dummyEndpoint).reply(200, dummyResponse);
ajaxSpy = (url) => {
expect(url).toBe(dummyEndpoint);
// neither reject nor resolve to keep request pending
return responseDeferred.promise();
};
const unexpectedResponse = data => fail(`Did not expect response: ${data}`);
AjaxCache.retrieve(dummyEndpoint) AjaxCache.retrieve(dummyEndpoint)
.then(unexpectedResponse) .then(done)
.catch(fail); .catch(fail);
AjaxCache.retrieve(dummyEndpoint) AjaxCache.retrieve(dummyEndpoint)
.then(unexpectedResponse) .then(done)
.catch(fail); .catch(fail);
expect($.ajax.calls.count()).toBe(1); expect(axios.get.calls.count()).toBe(1);
}); });
it('returns undefined if Ajax call fails and cache is empty', (done) => { it('returns undefined if Ajax call fails and cache is empty', (done) => {
const dummyStatusText = 'exploded'; const errorMessage = 'Network Error';
const dummyErrorMessage = 'server exploded'; mock.onGet(dummyEndpoint).networkError();
ajaxSpy = (url) => {
expect(url).toBe(dummyEndpoint);
const deferred = $.Deferred();
deferred.reject(null, dummyStatusText, dummyErrorMessage);
return deferred.promise();
};
AjaxCache.retrieve(dummyEndpoint) AjaxCache.retrieve(dummyEndpoint)
.then(data => fail(`Received unexpected data: ${JSON.stringify(data)}`)) .then(data => fail(`Received unexpected data: ${JSON.stringify(data)}`))
.catch((error) => { .catch((error) => {
expect(error.message).toBe(`${dummyEndpoint}: ${dummyErrorMessage}`); expect(error.message).toBe(`${dummyEndpoint}: ${errorMessage}`);
expect(error.textStatus).toBe(dummyStatusText); expect(error.textStatus).toBe(errorMessage);
done(); done();
}) })
.catch(fail); .catch(fail);
...@@ -154,7 +143,9 @@ describe('AjaxCache', () => { ...@@ -154,7 +143,9 @@ describe('AjaxCache', () => {
it('makes no Ajax call if matching data exists', (done) => { it('makes no Ajax call if matching data exists', (done) => {
AjaxCache.internalStorage[dummyEndpoint] = dummyResponse; AjaxCache.internalStorage[dummyEndpoint] = dummyResponse;
ajaxSpy = () => fail(new Error('expected no Ajax call!')); mock.onGet(dummyEndpoint).reply(() => {
fail(new Error('expected no Ajax call!'));
});
AjaxCache.retrieve(dummyEndpoint) AjaxCache.retrieve(dummyEndpoint)
.then((data) => { .then((data) => {
...@@ -171,12 +162,7 @@ describe('AjaxCache', () => { ...@@ -171,12 +162,7 @@ describe('AjaxCache', () => {
AjaxCache.internalStorage[dummyEndpoint] = oldDummyResponse; AjaxCache.internalStorage[dummyEndpoint] = oldDummyResponse;
ajaxSpy = (url) => { mock.onGet(dummyEndpoint).reply(200, dummyResponse);
expect(url).toBe(dummyEndpoint);
const deferred = $.Deferred();
deferred.resolve(dummyResponse);
return deferred.promise();
};
// Call without forceRetrieve param // Call without forceRetrieve param
AjaxCache.retrieve(dummyEndpoint) AjaxCache.retrieve(dummyEndpoint)
...@@ -189,7 +175,7 @@ describe('AjaxCache', () => { ...@@ -189,7 +175,7 @@ describe('AjaxCache', () => {
// Call with forceRetrieve param // Call with forceRetrieve param
AjaxCache.retrieve(dummyEndpoint, true) AjaxCache.retrieve(dummyEndpoint, true)
.then((data) => { .then((data) => {
expect(data).toBe(dummyResponse); expect(data).toEqual(dummyResponse);
}) })
.then(done) .then(done)
.catch(fail); .catch(fail);
......
/* eslint-disable promise/catch-or-return */ /* eslint-disable promise/catch-or-return */
import * as commonUtils from '~/lib/utils/common_utils';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import * as commonUtils from '~/lib/utils/common_utils';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
describe('common_utils', () => { describe('common_utils', () => {
...@@ -460,17 +459,6 @@ describe('common_utils', () => { ...@@ -460,17 +459,6 @@ describe('common_utils', () => {
}); });
}); });
describe('ajaxPost', () => {
it('should perform `$.ajax` call and do `POST` request', () => {
const requestURL = '/some/random/api';
const data = { keyname: 'value' };
const ajaxSpy = spyOn($, 'ajax').and.callFake(() => {});
commonUtils.ajaxPost(requestURL, data);
expect(ajaxSpy.calls.allArgs()[0][0].type).toEqual('POST');
});
});
describe('spriteIcon', () => { describe('spriteIcon', () => {
let beforeGon; let beforeGon;
......
/* eslint-disable no-var, comma-dangle, object-shorthand */ /* eslint-disable no-var, comma-dangle, object-shorthand */
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import * as urlUtils from '~/lib/utils/url_utility'; import * as urlUtils from '~/lib/utils/url_utility';
import MergeRequestTabs from '~/merge_request_tabs'; import MergeRequestTabs from '~/merge_request_tabs';
import '~/commit/pipelines/pipelines_bundle'; import '~/commit/pipelines/pipelines_bundle';
...@@ -46,7 +47,7 @@ import 'vendor/jquery.scrollTo'; ...@@ -46,7 +47,7 @@ import 'vendor/jquery.scrollTo';
describe('activateTab', function () { describe('activateTab', function () {
beforeEach(function () { beforeEach(function () {
spyOn($, 'ajax').and.callFake(function () {}); spyOn(axios, 'get').and.returnValue(Promise.resolve({ data: {} }));
loadFixtures('merge_requests/merge_request_with_task_list.html.raw'); loadFixtures('merge_requests/merge_request_with_task_list.html.raw');
this.subject = this.class.activateTab; this.subject = this.class.activateTab;
}); });
...@@ -148,7 +149,7 @@ import 'vendor/jquery.scrollTo'; ...@@ -148,7 +149,7 @@ import 'vendor/jquery.scrollTo';
describe('setCurrentAction', function () { describe('setCurrentAction', function () {
beforeEach(function () { beforeEach(function () {
spyOn($, 'ajax').and.callFake(function () {}); spyOn(axios, 'get').and.returnValue(Promise.resolve({ data: {} }));
this.subject = this.class.setCurrentAction; this.subject = this.class.setCurrentAction;
}); });
...@@ -214,13 +215,21 @@ import 'vendor/jquery.scrollTo'; ...@@ -214,13 +215,21 @@ import 'vendor/jquery.scrollTo';
}); });
describe('tabShown', () => { describe('tabShown', () => {
let mock;
beforeEach(function () { beforeEach(function () {
spyOn($, 'ajax').and.callFake(function (options) { mock = new MockAdapter(axios);
options.success({ html: '' }); mock.onGet(/(.*)\/diffs\.json/).reply(200, {
data: { html: '' },
}); });
loadFixtures('merge_requests/merge_request_with_task_list.html.raw'); loadFixtures('merge_requests/merge_request_with_task_list.html.raw');
}); });
afterEach(() => {
mock.restore();
});
describe('with "Side-by-side"/parallel diff view', () => { describe('with "Side-by-side"/parallel diff view', () => {
beforeEach(function () { beforeEach(function () {
this.class.diffViewType = () => 'parallel'; this.class.diffViewType = () => 'parallel';
...@@ -292,16 +301,20 @@ import 'vendor/jquery.scrollTo'; ...@@ -292,16 +301,20 @@ import 'vendor/jquery.scrollTo';
it('triggers Ajax request to JSON endpoint', function (done) { it('triggers Ajax request to JSON endpoint', function (done) {
const url = '/foo/bar/merge_requests/1/diffs'; const url = '/foo/bar/merge_requests/1/diffs';
spyOn(this.class, 'ajaxGet').and.callFake((options) => {
expect(options.url).toEqual(`${url}.json`); spyOn(axios, 'get').and.callFake((reqUrl) => {
expect(reqUrl).toBe(`${url}.json`);
done(); done();
return Promise.resolve({ data: {} });
}); });
this.class.loadDiff(url); this.class.loadDiff(url);
}); });
it('triggers scroll event when diff already loaded', function (done) { it('triggers scroll event when diff already loaded', function (done) {
spyOn(this.class, 'ajaxGet').and.callFake(() => done.fail()); spyOn(axios, 'get').and.callFake(done.fail);
spyOn(document, 'dispatchEvent'); spyOn(document, 'dispatchEvent');
this.class.diffsLoaded = true; this.class.diffsLoaded = true;
...@@ -316,6 +329,7 @@ import 'vendor/jquery.scrollTo'; ...@@ -316,6 +329,7 @@ import 'vendor/jquery.scrollTo';
describe('with inline diff', () => { describe('with inline diff', () => {
let noteId; let noteId;
let noteLineNumId; let noteLineNumId;
let mock;
beforeEach(() => { beforeEach(() => {
const diffsResponse = getJSONFixture(inlineChangesTabJsonFixture); const diffsResponse = getJSONFixture(inlineChangesTabJsonFixture);
...@@ -330,29 +344,40 @@ import 'vendor/jquery.scrollTo'; ...@@ -330,29 +344,40 @@ import 'vendor/jquery.scrollTo';
.attr('href') .attr('href')
.replace('#', ''); .replace('#', '');
spyOn($, 'ajax').and.callFake(function (options) { mock = new MockAdapter(axios);
options.success(diffsResponse); mock.onGet(/(.*)\/diffs\.json/).reply(200, diffsResponse);
}); });
afterEach(() => {
mock.restore();
}); });
describe('with note fragment hash', () => { describe('with note fragment hash', () => {
it('should expand and scroll to linked fragment hash #note_xxx', function () { it('should expand and scroll to linked fragment hash #note_xxx', function (done) {
spyOn(urlUtils, 'getLocationHash').and.returnValue(noteId); spyOn(urlUtils, 'getLocationHash').and.returnValue(noteId);
this.class.loadDiff('/foo/bar/merge_requests/1/diffs'); this.class.loadDiff('/foo/bar/merge_requests/1/diffs');
expect(noteId.length).toBeGreaterThan(0); setTimeout(() => {
expect(Notes.instance.toggleDiffNote).toHaveBeenCalledWith({ expect(noteId.length).toBeGreaterThan(0);
target: jasmine.any(Object), expect(Notes.instance.toggleDiffNote).toHaveBeenCalledWith({
lineType: 'old', target: jasmine.any(Object),
forceShow: true, lineType: 'old',
forceShow: true,
});
done();
}); });
}); });
it('should gracefully ignore non-existant fragment hash', function () { it('should gracefully ignore non-existant fragment hash', function (done) {
spyOn(urlUtils, 'getLocationHash').and.returnValue('note_something-that-does-not-exist'); spyOn(urlUtils, 'getLocationHash').and.returnValue('note_something-that-does-not-exist');
this.class.loadDiff('/foo/bar/merge_requests/1/diffs'); this.class.loadDiff('/foo/bar/merge_requests/1/diffs');
expect(Notes.instance.toggleDiffNote).not.toHaveBeenCalled(); setTimeout(() => {
expect(Notes.instance.toggleDiffNote).not.toHaveBeenCalled();
done();
});
}); });
}); });
...@@ -370,6 +395,7 @@ import 'vendor/jquery.scrollTo'; ...@@ -370,6 +395,7 @@ import 'vendor/jquery.scrollTo';
describe('with parallel diff', () => { describe('with parallel diff', () => {
let noteId; let noteId;
let noteLineNumId; let noteLineNumId;
let mock;
beforeEach(() => { beforeEach(() => {
const diffsResponse = getJSONFixture(parallelChangesTabJsonFixture); const diffsResponse = getJSONFixture(parallelChangesTabJsonFixture);
...@@ -384,30 +410,40 @@ import 'vendor/jquery.scrollTo'; ...@@ -384,30 +410,40 @@ import 'vendor/jquery.scrollTo';
.attr('href') .attr('href')
.replace('#', ''); .replace('#', '');
spyOn($, 'ajax').and.callFake(function (options) { mock = new MockAdapter(axios);
options.success(diffsResponse); mock.onGet(/(.*)\/diffs\.json/).reply(200, diffsResponse);
}); });
afterEach(() => {
mock.restore();
}); });
describe('with note fragment hash', () => { describe('with note fragment hash', () => {
it('should expand and scroll to linked fragment hash #note_xxx', function () { it('should expand and scroll to linked fragment hash #note_xxx', function (done) {
spyOn(urlUtils, 'getLocationHash').and.returnValue(noteId); spyOn(urlUtils, 'getLocationHash').and.returnValue(noteId);
this.class.loadDiff('/foo/bar/merge_requests/1/diffs'); this.class.loadDiff('/foo/bar/merge_requests/1/diffs');
expect(noteId.length).toBeGreaterThan(0); setTimeout(() => {
expect(Notes.instance.toggleDiffNote).toHaveBeenCalledWith({ expect(noteId.length).toBeGreaterThan(0);
target: jasmine.any(Object), expect(Notes.instance.toggleDiffNote).toHaveBeenCalledWith({
lineType: 'new', target: jasmine.any(Object),
forceShow: true, lineType: 'new',
forceShow: true,
});
done();
}); });
}); });
it('should gracefully ignore non-existant fragment hash', function () { it('should gracefully ignore non-existant fragment hash', function (done) {
spyOn(urlUtils, 'getLocationHash').and.returnValue('note_something-that-does-not-exist'); spyOn(urlUtils, 'getLocationHash').and.returnValue('note_something-that-does-not-exist');
this.class.loadDiff('/foo/bar/merge_requests/1/diffs'); this.class.loadDiff('/foo/bar/merge_requests/1/diffs');
expect(Notes.instance.toggleDiffNote).not.toHaveBeenCalled(); setTimeout(() => {
expect(Notes.instance.toggleDiffNote).not.toHaveBeenCalled();
done();
});
}); });
}); });
......
/* eslint-disable space-before-function-paren, no-unused-expressions, no-var, object-shorthand, comma-dangle, max-len */ /* eslint-disable space-before-function-paren, no-unused-expressions, no-var, object-shorthand, comma-dangle, max-len */
import _ from 'underscore'; import _ from 'underscore';
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import * as urlUtils from '~/lib/utils/url_utility'; import * as urlUtils from '~/lib/utils/url_utility';
import 'autosize'; import 'autosize';
import '~/gl_form'; import '~/gl_form';
import '~/lib/utils/text_utility'; import '~/lib/utils/text_utility';
import '~/render_gfm'; import '~/render_gfm';
import Notes from '~/notes'; import Notes from '~/notes';
import timeoutPromise from './helpers/set_timeout_promise_helper';
(function() { (function() {
window.gon || (window.gon = {}); window.gon || (window.gon = {});
...@@ -119,6 +122,7 @@ import Notes from '~/notes'; ...@@ -119,6 +122,7 @@ import Notes from '~/notes';
let noteEntity; let noteEntity;
let $form; let $form;
let $notesContainer; let $notesContainer;
let mock;
beforeEach(() => { beforeEach(() => {
this.notes = new Notes('', []); this.notes = new Notes('', []);
...@@ -136,24 +140,32 @@ import Notes from '~/notes'; ...@@ -136,24 +140,32 @@ import Notes from '~/notes';
$form = $('form.js-main-target-form'); $form = $('form.js-main-target-form');
$notesContainer = $('ul.main-notes-list'); $notesContainer = $('ul.main-notes-list');
$form.find('textarea.js-note-text').val(sampleComment); $form.find('textarea.js-note-text').val(sampleComment);
mock = new MockAdapter(axios);
mock.onPost(/(.*)\/notes$/).reply(200, noteEntity);
}); });
it('updates note and resets edit form', () => { afterEach(() => {
const deferred = $.Deferred(); mock.restore();
spyOn($, 'ajax').and.returnValue(deferred.promise()); });
it('updates note and resets edit form', (done) => {
spyOn(this.notes, 'revertNoteEditForm'); spyOn(this.notes, 'revertNoteEditForm');
spyOn(this.notes, 'setupNewNote'); spyOn(this.notes, 'setupNewNote');
$('.js-comment-button').click(); $('.js-comment-button').click();
deferred.resolve(noteEntity);
const $targetNote = $notesContainer.find(`#note_${noteEntity.id}`); setTimeout(() => {
const updatedNote = Object.assign({}, noteEntity); const $targetNote = $notesContainer.find(`#note_${noteEntity.id}`);
updatedNote.note = 'bar'; const updatedNote = Object.assign({}, noteEntity);
this.notes.updateNote(updatedNote, $targetNote); updatedNote.note = 'bar';
this.notes.updateNote(updatedNote, $targetNote);
expect(this.notes.revertNoteEditForm).toHaveBeenCalledWith($targetNote);
expect(this.notes.setupNewNote).toHaveBeenCalled();
expect(this.notes.revertNoteEditForm).toHaveBeenCalledWith($targetNote); done();
expect(this.notes.setupNewNote).toHaveBeenCalled(); });
}); });
}); });
...@@ -479,8 +491,19 @@ import Notes from '~/notes'; ...@@ -479,8 +491,19 @@ import Notes from '~/notes';
}; };
let $form; let $form;
let $notesContainer; let $notesContainer;
let mock;
function mockNotesPost() {
mock.onPost(/(.*)\/notes$/).reply(200, note);
}
function mockNotesPostError() {
mock.onPost(/(.*)\/notes$/).networkError();
}
beforeEach(() => { beforeEach(() => {
mock = new MockAdapter(axios);
this.notes = new Notes('', []); this.notes = new Notes('', []);
window.gon.current_username = 'root'; window.gon.current_username = 'root';
window.gon.current_user_fullname = 'Administrator'; window.gon.current_user_fullname = 'Administrator';
...@@ -489,63 +512,92 @@ import Notes from '~/notes'; ...@@ -489,63 +512,92 @@ import Notes from '~/notes';
$form.find('textarea.js-note-text').val(sampleComment); $form.find('textarea.js-note-text').val(sampleComment);
}); });
afterEach(() => {
mock.restore();
});
it('should show placeholder note while new comment is being posted', () => { it('should show placeholder note while new comment is being posted', () => {
mockNotesPost();
$('.js-comment-button').click(); $('.js-comment-button').click();
expect($notesContainer.find('.note.being-posted').length > 0).toEqual(true); expect($notesContainer.find('.note.being-posted').length > 0).toEqual(true);
}); });
it('should remove placeholder note when new comment is done posting', () => { it('should remove placeholder note when new comment is done posting', (done) => {
const deferred = $.Deferred(); mockNotesPost();
spyOn($, 'ajax').and.returnValue(deferred.promise());
$('.js-comment-button').click(); $('.js-comment-button').click();
deferred.resolve(note); setTimeout(() => {
expect($notesContainer.find('.note.being-posted').length).toEqual(0); expect($notesContainer.find('.note.being-posted').length).toEqual(0);
done();
});
}); });
it('should show actual note element when new comment is done posting', () => { it('should show actual note element when new comment is done posting', (done) => {
const deferred = $.Deferred(); mockNotesPost();
spyOn($, 'ajax').and.returnValue(deferred.promise());
$('.js-comment-button').click(); $('.js-comment-button').click();
deferred.resolve(note); setTimeout(() => {
expect($notesContainer.find(`#note_${note.id}`).length > 0).toEqual(true); expect($notesContainer.find(`#note_${note.id}`).length > 0).toEqual(true);
done();
});
}); });
it('should reset Form when new comment is done posting', () => { it('should reset Form when new comment is done posting', (done) => {
const deferred = $.Deferred(); mockNotesPost();
spyOn($, 'ajax').and.returnValue(deferred.promise());
$('.js-comment-button').click(); $('.js-comment-button').click();
deferred.resolve(note); setTimeout(() => {
expect($form.find('textarea.js-note-text').val()).toEqual(''); expect($form.find('textarea.js-note-text').val()).toEqual('');
done();
});
}); });
it('should show flash error message when new comment failed to be posted', () => { it('should show flash error message when new comment failed to be posted', (done) => {
const deferred = $.Deferred(); mockNotesPostError();
spyOn($, 'ajax').and.returnValue(deferred.promise());
$('.js-comment-button').click(); $('.js-comment-button').click();
deferred.reject(); setTimeout(() => {
expect($notesContainer.parent().find('.flash-container .flash-text').is(':visible')).toEqual(true); expect($notesContainer.parent().find('.flash-container .flash-text').is(':visible')).toEqual(true);
done();
});
}); });
it('should show flash error message when comment failed to be updated', () => { it('should show flash error message when comment failed to be updated', (done) => {
const deferred = $.Deferred(); mockNotesPost();
spyOn($, 'ajax').and.returnValue(deferred.promise());
$('.js-comment-button').click(); $('.js-comment-button').click();
deferred.resolve(note); timeoutPromise()
const $noteEl = $notesContainer.find(`#note_${note.id}`); .then(() => {
$noteEl.find('.js-note-edit').click(); const $noteEl = $notesContainer.find(`#note_${note.id}`);
$noteEl.find('textarea.js-note-text').val(updatedComment); $noteEl.find('.js-note-edit').click();
$noteEl.find('.js-comment-save-button').click(); $noteEl.find('textarea.js-note-text').val(updatedComment);
deferred.reject(); mock.restore();
const $updatedNoteEl = $notesContainer.find(`#note_${note.id}`);
expect($updatedNoteEl.hasClass('.being-posted')).toEqual(false); // Remove being-posted visuals mockNotesPostError();
expect($updatedNoteEl.find('.note-text').text().trim()).toEqual(sampleComment); // See if comment reverted back to original
expect($('.flash-container').is(':visible')).toEqual(true); // Flash error message shown $noteEl.find('.js-comment-save-button').click();
})
.then(timeoutPromise)
.then(() => {
const $updatedNoteEl = $notesContainer.find(`#note_${note.id}`);
expect($updatedNoteEl.hasClass('.being-posted')).toEqual(false); // Remove being-posted visuals
expect($updatedNoteEl.find('.note-text').text().trim()).toEqual(sampleComment); // See if comment reverted back to original
expect($('.flash-container').is(':visible')).toEqual(true); // Flash error message shown
done();
})
.catch(done.fail);
}); });
}); });
...@@ -563,8 +615,12 @@ import Notes from '~/notes'; ...@@ -563,8 +615,12 @@ import Notes from '~/notes';
}; };
let $form; let $form;
let $notesContainer; let $notesContainer;
let mock;
beforeEach(() => { beforeEach(() => {
mock = new MockAdapter(axios);
mock.onPost(/(.*)\/notes$/).reply(200, note);
this.notes = new Notes('', []); this.notes = new Notes('', []);
window.gon.current_username = 'root'; window.gon.current_username = 'root';
window.gon.current_user_fullname = 'Administrator'; window.gon.current_user_fullname = 'Administrator';
...@@ -582,15 +638,20 @@ import Notes from '~/notes'; ...@@ -582,15 +638,20 @@ import Notes from '~/notes';
$form.find('textarea.js-note-text').val(sampleComment); $form.find('textarea.js-note-text').val(sampleComment);
}); });
it('should remove slash command placeholder when comment with slash commands is done posting', () => { afterEach(() => {
const deferred = $.Deferred(); mock.restore();
spyOn($, 'ajax').and.returnValue(deferred.promise()); });
it('should remove slash command placeholder when comment with slash commands is done posting', (done) => {
spyOn(gl.awardsHandler, 'addAwardToEmojiBar').and.callThrough(); spyOn(gl.awardsHandler, 'addAwardToEmojiBar').and.callThrough();
$('.js-comment-button').click(); $('.js-comment-button').click();
expect($notesContainer.find('.system-note.being-posted').length).toEqual(1); // Placeholder shown expect($notesContainer.find('.system-note.being-posted').length).toEqual(1); // Placeholder shown
deferred.resolve(note);
expect($notesContainer.find('.system-note.being-posted').length).toEqual(0); // Placeholder removed setTimeout(() => {
expect($notesContainer.find('.system-note.being-posted').length).toEqual(0); // Placeholder removed
done();
});
}); });
}); });
...@@ -607,8 +668,12 @@ import Notes from '~/notes'; ...@@ -607,8 +668,12 @@ import Notes from '~/notes';
}; };
let $form; let $form;
let $notesContainer; let $notesContainer;
let mock;
beforeEach(() => { beforeEach(() => {
mock = new MockAdapter(axios);
mock.onPost(/(.*)\/notes$/).reply(200, note);
this.notes = new Notes('', []); this.notes = new Notes('', []);
window.gon.current_username = 'root'; window.gon.current_username = 'root';
window.gon.current_user_fullname = 'Administrator'; window.gon.current_user_fullname = 'Administrator';
...@@ -617,19 +682,24 @@ import Notes from '~/notes'; ...@@ -617,19 +682,24 @@ import Notes from '~/notes';
$form.find('textarea.js-note-text').html(sampleComment); $form.find('textarea.js-note-text').html(sampleComment);
}); });
it('should not render a script tag', () => { afterEach(() => {
const deferred = $.Deferred(); mock.restore();
spyOn($, 'ajax').and.returnValue(deferred.promise()); });
it('should not render a script tag', (done) => {
$('.js-comment-button').click(); $('.js-comment-button').click();
deferred.resolve(note); setTimeout(() => {
const $noteEl = $notesContainer.find(`#note_${note.id}`); const $noteEl = $notesContainer.find(`#note_${note.id}`);
$noteEl.find('.js-note-edit').click(); $noteEl.find('.js-note-edit').click();
$noteEl.find('textarea.js-note-text').html(updatedComment); $noteEl.find('textarea.js-note-text').html(updatedComment);
$noteEl.find('.js-comment-save-button').click(); $noteEl.find('.js-comment-save-button').click();
const $updatedNoteEl = $notesContainer.find(`#note_${note.id}`).find('.js-task-list-container');
expect($updatedNoteEl.find('.note-text').text().trim()).toEqual('');
const $updatedNoteEl = $notesContainer.find(`#note_${note.id}`).find('.js-task-list-container'); done();
expect($updatedNoteEl.find('.note-text').text().trim()).toEqual(''); });
}); });
}); });
......
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