Commit 8ca5afdf authored by Filipa Lacerda's avatar Filipa Lacerda Committed by Jacob Schatz

FE: Resolve "Performance issues when processing large build traces with Ansi2html"

parent 9216f59a
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, no-use-before-define, no-param-reassign, quotes, yoda, no-else-return, consistent-return, comma-dangle, object-shorthand, prefer-template, one-var, one-var-declaration-per-line, no-unused-vars, max-len, vars-on-top */ /* eslint-disable func-names, wrap-iife, no-use-before-define,
consistent-return, prefer-rest-params */
/* global Breakpoints */ /* global Breakpoints */
var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; }; const bind = function (fn, me) { return function () { return fn.apply(me, arguments); }; };
var AUTO_SCROLL_OFFSET = 75; const AUTO_SCROLL_OFFSET = 75;
var DOWN_BUILD_TRACE = '#down-build-trace'; const DOWN_BUILD_TRACE = '#down-build-trace';
window.Build = (function() { window.Build = (function () {
Build.timeout = null; Build.timeout = null;
Build.state = null; Build.state = null;
function Build(options) { function Build(options) {
options = options || $('.js-build-options').data(); this.options = options || $('.js-build-options').data();
this.pageUrl = options.pageUrl;
this.buildUrl = options.buildUrl; this.pageUrl = this.options.pageUrl;
this.buildStatus = options.buildStatus; this.buildUrl = this.options.buildUrl;
this.state = options.logState; this.buildStatus = this.options.buildStatus;
this.buildStage = options.buildStage; this.state = this.options.logState;
this.updateDropdown = bind(this.updateDropdown, this); this.buildStage = this.options.buildStage;
this.$document = $(document); this.$document = $(document);
this.updateDropdown = bind(this.updateDropdown, this);
this.$body = $('body'); this.$body = $('body');
this.$buildTrace = $('#build-trace'); this.$buildTrace = $('#build-trace');
this.$autoScrollContainer = $('.autoscroll-container'); this.$autoScrollContainer = $('.autoscroll-container');
...@@ -29,112 +33,110 @@ window.Build = (function() { ...@@ -29,112 +33,110 @@ window.Build = (function() {
this.$scrollTopBtn = $('#scroll-top'); this.$scrollTopBtn = $('#scroll-top');
this.$scrollBottomBtn = $('#scroll-bottom'); this.$scrollBottomBtn = $('#scroll-bottom');
this.$buildRefreshAnimation = $('.js-build-refresh'); this.$buildRefreshAnimation = $('.js-build-refresh');
this.$buildScroll = $('#js-build-scroll');
this.$truncatedInfo = $('.js-truncated-info');
clearTimeout(Build.timeout); clearTimeout(Build.timeout);
// Init breakpoint checker // Init breakpoint checker
this.bp = Breakpoints.get(); this.bp = Breakpoints.get();
this.initSidebar(); this.initSidebar();
this.$buildScroll = $('#js-build-scroll');
this.populateJobs(this.buildStage); this.populateJobs(this.buildStage);
this.updateStageDropdownText(this.buildStage); this.updateStageDropdownText(this.buildStage);
this.sidebarOnResize(); this.sidebarOnResize();
this.$document.off('click', '.js-sidebar-build-toggle').on('click', '.js-sidebar-build-toggle', this.sidebarOnClick.bind(this)); this.$document
this.$document.off('click', '.stage-item').on('click', '.stage-item', this.updateDropdown); .off('click', '.js-sidebar-build-toggle')
.on('click', '.js-sidebar-build-toggle', this.sidebarOnClick.bind(this));
this.$document
.off('click', '.stage-item')
.on('click', '.stage-item', this.updateDropdown);
this.$document.on('scroll', this.initScrollMonitor.bind(this)); this.$document.on('scroll', this.initScrollMonitor.bind(this));
$(window).off('resize.build').on('resize.build', this.sidebarOnResize.bind(this));
$('a', this.$buildScroll).off('click.stepTrace').on('click.stepTrace', this.stepTrace); $(window)
.off('resize.build')
.on('resize.build', this.sidebarOnResize.bind(this));
$('a', this.$buildScroll)
.off('click.stepTrace')
.on('click.stepTrace', this.stepTrace);
this.updateArtifactRemoveDate(); this.updateArtifactRemoveDate();
if ($('#build-trace').length) {
this.getInitialBuildTrace();
this.initScrollButtonAffix(); this.initScrollButtonAffix();
}
this.invokeBuildTrace(); this.invokeBuildTrace();
} }
Build.prototype.initSidebar = function() { Build.prototype.initSidebar = function () {
this.$sidebar = $('.js-build-sidebar'); this.$sidebar = $('.js-build-sidebar');
this.$sidebar.niceScroll(); this.$sidebar.niceScroll();
this.$document.off('click', '.js-sidebar-build-toggle').on('click', '.js-sidebar-build-toggle', this.toggleSidebar); this.$document
}; .off('click', '.js-sidebar-build-toggle')
.on('click', '.js-sidebar-build-toggle', this.toggleSidebar);
Build.prototype.location = function() {
return window.location.href.split("#")[0];
}; };
Build.prototype.invokeBuildTrace = function() { Build.prototype.invokeBuildTrace = function () {
var continueRefreshStatuses = ['running', 'pending']; return this.getBuildTrace();
// Continue to update build trace when build is running or pending
if (continueRefreshStatuses.indexOf(this.buildStatus) !== -1) {
// Check for new build output if user still watching build page
// Only valid for runnig build when output changes during time
Build.timeout = setTimeout((function(_this) {
return function() {
if (_this.location() === _this.pageUrl) {
return _this.getBuildTrace();
}
}; };
})(this), 4000);
}
};
Build.prototype.getInitialBuildTrace = function() {
var removeRefreshStatuses = ['success', 'failed', 'canceled', 'skipped'];
Build.prototype.getBuildTrace = function () {
return $.ajax({ return $.ajax({
url: this.pageUrl + "/trace.json", url: `${this.pageUrl}/trace.json`,
dataType: 'json', dataType: 'json',
success: function(buildData) { data: {
$('.js-build-output').html(buildData.html); state: this.state,
gl.utils.setCiStatusFavicon(`${this.pageUrl}/status.json`); },
if (window.location.hash === DOWN_BUILD_TRACE) { success: ((log) => {
$("html,body").scrollTop(this.$buildTrace.height()); const $buildContainer = $('.js-build-output');
}
if (removeRefreshStatuses.indexOf(buildData.status) !== -1) {
this.$buildRefreshAnimation.remove();
return this.initScrollMonitor();
}
}.bind(this)
});
};
Build.prototype.getBuildTrace = function() {
return $.ajax({
url: this.pageUrl + "/trace.json?state=" + (encodeURIComponent(this.state)),
dataType: "json",
success: (function(_this) {
return function(log) {
var pageUrl;
if (log.state) { if (log.state) {
_this.state = log.state; this.state = log.state;
} }
_this.invokeBuildTrace();
if (log.status === "running") {
if (log.append) { if (log.append) {
$('.js-build-output').append(log.html); $buildContainer.append(log.html);
} else {
$buildContainer.html(log.html);
if (log.truncated) {
$('.js-truncated-info-size').html(` ${log.size} `);
this.$truncatedInfo.removeClass('hidden');
this.initAffixTruncatedInfo();
} else { } else {
$('.js-build-output').html(log.html); this.$truncatedInfo.addClass('hidden');
} }
return _this.checkAutoscroll(); }
} else if (log.status !== _this.buildStatus) {
pageUrl = _this.pageUrl; this.checkAutoscroll();
if (_this.$autoScrollStatus.data('state') === 'enabled') {
if (!log.complete) {
Build.timeout = setTimeout(() => {
this.invokeBuildTrace();
}, 4000);
} else {
this.$buildRefreshAnimation.remove();
}
if (log.status !== this.buildStatus) {
let pageUrl = this.pageUrl;
if (this.$autoScrollStatus.data('state') === 'enabled') {
pageUrl += DOWN_BUILD_TRACE; pageUrl += DOWN_BUILD_TRACE;
} }
return gl.utils.visitUrl(pageUrl); gl.utils.visitUrl(pageUrl);
} }
}; }),
})(this) error: () => {
this.$buildRefreshAnimation.remove();
return this.initScrollMonitor();
},
}); });
}; };
Build.prototype.checkAutoscroll = function() { Build.prototype.checkAutoscroll = function () {
if (this.$autoScrollStatus.data("state") === "enabled") { if (this.$autoScrollStatus.data('state') === 'enabled') {
return $("html,body").scrollTop(this.$buildTrace.height()); return $('html,body').scrollTop(this.$buildTrace.height());
} }
// Handle a situation where user started new build // Handle a situation where user started new build
...@@ -146,7 +148,7 @@ window.Build = (function() { ...@@ -146,7 +148,7 @@ window.Build = (function() {
} }
}; };
Build.prototype.initScrollButtonAffix = function() { Build.prototype.initScrollButtonAffix = function () {
// Hide everything initially // Hide everything initially
this.$scrollTopBtn.hide(); this.$scrollTopBtn.hide();
this.$scrollBottomBtn.hide(); this.$scrollBottomBtn.hide();
...@@ -167,15 +169,17 @@ window.Build = (function() { ...@@ -167,15 +169,17 @@ window.Build = (function() {
// - Show Top Arrow button // - Show Top Arrow button
// - Show Bottom Arrow button // - Show Bottom Arrow button
// - Disable Autoscroll and hide indicator (when build is running) // - Disable Autoscroll and hide indicator (when build is running)
Build.prototype.initScrollMonitor = function() { Build.prototype.initScrollMonitor = function () {
if (!gl.utils.isInViewport(this.$upBuildTrace.get(0)) && !gl.utils.isInViewport(this.$downBuildTrace.get(0))) { if (!gl.utils.isInViewport(this.$upBuildTrace.get(0)) &&
!gl.utils.isInViewport(this.$downBuildTrace.get(0))) {
// User is somewhere in middle of Build Log // User is somewhere in middle of Build Log
this.$scrollTopBtn.show(); this.$scrollTopBtn.show();
if (this.buildStatus === 'success' || this.buildStatus === 'failed') { // Check if Build is completed if (this.buildStatus === 'success' || this.buildStatus === 'failed') { // Check if Build is completed
this.$scrollBottomBtn.show(); this.$scrollBottomBtn.show();
} else if (this.$buildRefreshAnimation.is(':visible') && !gl.utils.isInViewport(this.$buildRefreshAnimation.get(0))) { } else if (this.$buildRefreshAnimation.is(':visible') &&
!gl.utils.isInViewport(this.$buildRefreshAnimation.get(0))) {
this.$scrollBottomBtn.show(); this.$scrollBottomBtn.show();
} else { } else {
this.$scrollBottomBtn.hide(); this.$scrollBottomBtn.hide();
...@@ -186,10 +190,13 @@ window.Build = (function() { ...@@ -186,10 +190,13 @@ window.Build = (function() {
this.$autoScrollContainer.hide(); this.$autoScrollContainer.hide();
this.$autoScrollStatusText.removeClass('animate'); this.$autoScrollStatusText.removeClass('animate');
} else { } else {
this.$autoScrollContainer.css({ top: this.$body.outerHeight() - AUTO_SCROLL_OFFSET }).show(); this.$autoScrollContainer.css({
top: this.$body.outerHeight() - AUTO_SCROLL_OFFSET,
}).show();
this.$autoScrollStatusText.addClass('animate'); this.$autoScrollStatusText.addClass('animate');
} }
} else if (gl.utils.isInViewport(this.$upBuildTrace.get(0)) && !gl.utils.isInViewport(this.$downBuildTrace.get(0))) { } else if (gl.utils.isInViewport(this.$upBuildTrace.get(0)) &&
!gl.utils.isInViewport(this.$downBuildTrace.get(0))) {
// User is at Top of Build Log // User is at Top of Build Log
this.$scrollTopBtn.hide(); this.$scrollTopBtn.hide();
...@@ -197,17 +204,22 @@ window.Build = (function() { ...@@ -197,17 +204,22 @@ window.Build = (function() {
this.$autoScrollContainer.hide(); this.$autoScrollContainer.hide();
this.$autoScrollStatusText.removeClass('animate'); this.$autoScrollStatusText.removeClass('animate');
} else if ((!gl.utils.isInViewport(this.$upBuildTrace.get(0)) && gl.utils.isInViewport(this.$downBuildTrace.get(0))) || } else if ((!gl.utils.isInViewport(this.$upBuildTrace.get(0)) &&
(this.$buildRefreshAnimation.is(':visible') && gl.utils.isInViewport(this.$buildRefreshAnimation.get(0)))) { gl.utils.isInViewport(this.$downBuildTrace.get(0))) ||
(this.$buildRefreshAnimation.is(':visible') &&
gl.utils.isInViewport(this.$buildRefreshAnimation.get(0)))) {
// User is at Bottom of Build Log // User is at Bottom of Build Log
this.$scrollTopBtn.show(); this.$scrollTopBtn.show();
this.$scrollBottomBtn.hide(); this.$scrollBottomBtn.hide();
// Show and Reposition Autoscroll Status Indicator // Show and Reposition Autoscroll Status Indicator
this.$autoScrollContainer.css({ top: this.$body.outerHeight() - AUTO_SCROLL_OFFSET }).show(); this.$autoScrollContainer.css({
top: this.$body.outerHeight() - AUTO_SCROLL_OFFSET,
}).show();
this.$autoScrollStatusText.addClass('animate'); this.$autoScrollStatusText.addClass('animate');
} else if (gl.utils.isInViewport(this.$upBuildTrace.get(0)) && gl.utils.isInViewport(this.$downBuildTrace.get(0))) { } else if (gl.utils.isInViewport(this.$upBuildTrace.get(0)) &&
gl.utils.isInViewport(this.$downBuildTrace.get(0))) {
// Build Log height is small // Build Log height is small
this.$scrollTopBtn.hide(); this.$scrollTopBtn.hide();
...@@ -218,65 +230,81 @@ window.Build = (function() { ...@@ -218,65 +230,81 @@ window.Build = (function() {
this.$autoScrollStatusText.removeClass('animate'); this.$autoScrollStatusText.removeClass('animate');
} }
if (this.buildStatus === "running" || this.buildStatus === "pending") { if (this.buildStatus === 'running' || this.buildStatus === 'pending') {
// Check if Refresh Animation is in Viewport and enable Autoscroll, disable otherwise. // Check if Refresh Animation is in Viewport and enable Autoscroll, disable otherwise.
this.$autoScrollStatus.data("state", gl.utils.isInViewport(this.$buildRefreshAnimation.get(0)) ? 'enabled' : 'disabled'); this.$autoScrollStatus.data(
'state',
gl.utils.isInViewport(this.$buildRefreshAnimation.get(0)) ? 'enabled' : 'disabled',
);
} }
}; };
Build.prototype.shouldHideSidebarForViewport = function() { Build.prototype.shouldHideSidebarForViewport = function () {
var bootstrapBreakpoint; const bootstrapBreakpoint = this.bp.getBreakpointSize();
bootstrapBreakpoint = this.bp.getBreakpointSize();
return bootstrapBreakpoint === 'xs' || bootstrapBreakpoint === 'sm'; return bootstrapBreakpoint === 'xs' || bootstrapBreakpoint === 'sm';
}; };
Build.prototype.toggleSidebar = function(shouldHide) { Build.prototype.toggleSidebar = function (shouldHide) {
var shouldShow = typeof shouldHide === 'boolean' ? !shouldHide : undefined; const shouldShow = typeof shouldHide === 'boolean' ? !shouldHide : undefined;
this.$buildScroll.toggleClass('sidebar-expanded', shouldShow) this.$buildScroll.toggleClass('sidebar-expanded', shouldShow)
.toggleClass('sidebar-collapsed', shouldHide); .toggleClass('sidebar-collapsed', shouldHide);
this.$truncatedInfo.toggleClass('sidebar-expanded', shouldShow)
.toggleClass('sidebar-collapsed', shouldHide);
this.$sidebar.toggleClass('right-sidebar-expanded', shouldShow) this.$sidebar.toggleClass('right-sidebar-expanded', shouldShow)
.toggleClass('right-sidebar-collapsed', shouldHide); .toggleClass('right-sidebar-collapsed', shouldHide);
}; };
Build.prototype.sidebarOnResize = function() { Build.prototype.sidebarOnResize = function () {
this.toggleSidebar(this.shouldHideSidebarForViewport()); this.toggleSidebar(this.shouldHideSidebarForViewport());
}; };
Build.prototype.sidebarOnClick = function() { Build.prototype.sidebarOnClick = function () {
if (this.shouldHideSidebarForViewport()) this.toggleSidebar(); if (this.shouldHideSidebarForViewport()) this.toggleSidebar();
}; };
Build.prototype.updateArtifactRemoveDate = function() { Build.prototype.updateArtifactRemoveDate = function () {
var $date, date; const $date = $('.js-artifacts-remove');
$date = $('.js-artifacts-remove');
if ($date.length) { if ($date.length) {
date = $date.text(); const date = $date.text();
return $date.text(gl.utils.timeFor(new Date(date.replace(/([0-9]+)-([0-9]+)-([0-9]+)/g, '$1/$2/$3')), ' ')); return $date.text(
gl.utils.timeFor(new Date(date.replace(/([0-9]+)-([0-9]+)-([0-9]+)/g, '$1/$2/$3')), ' '),
);
} }
}; };
Build.prototype.populateJobs = function(stage) { Build.prototype.populateJobs = function (stage) {
$('.build-job').hide(); $('.build-job').hide();
$('.build-job[data-stage="' + stage + '"]').show(); $(`.build-job[data-stage="${stage}"]`).show();
}; };
Build.prototype.updateStageDropdownText = function(stage) { Build.prototype.updateStageDropdownText = function (stage) {
$('.stage-selection').text(stage); $('.stage-selection').text(stage);
}; };
Build.prototype.updateDropdown = function(e) { Build.prototype.updateDropdown = function (e) {
e.preventDefault(); e.preventDefault();
var stage = e.currentTarget.text; const stage = e.currentTarget.text;
this.updateStageDropdownText(stage); this.updateStageDropdownText(stage);
this.populateJobs(stage); this.populateJobs(stage);
}; };
Build.prototype.stepTrace = function(e) { Build.prototype.stepTrace = function (e) {
var $currentTarget;
e.preventDefault(); e.preventDefault();
$currentTarget = $(e.currentTarget);
const $currentTarget = $(e.currentTarget);
$.scrollTo($currentTarget.attr('href'), { $.scrollTo($currentTarget.attr('href'), {
offset: 0 offset: 0,
});
};
Build.prototype.initAffixTruncatedInfo = function () {
const offsetTop = this.$buildTrace.offset().top;
this.$truncatedInfo.affix({
offset: {
top: offsetTop,
},
}); });
}; };
......
...@@ -57,6 +57,37 @@ ...@@ -57,6 +57,37 @@
margin-right: 5px; margin-right: 5px;
} }
} }
.truncated-info {
text-align: center;
border-bottom: 1px solid;
background-color: $black-transparent;
height: 45px;
&.affix {
top: 0;
}
// with sidebar
&.affix.sidebar-expanded {
right: 312px;
left: 22px;
}
// without sidebar
&.affix.sidebar-collapsed {
right: 20px;
left: 20px;
}
&.affix-top {
position: absolute;
top: 0;
margin: 0 auto;
right: 5px;
left: 5px;
}
}
} }
.scroll-controls { .scroll-controls {
...@@ -186,6 +217,7 @@ ...@@ -186,6 +217,7 @@
white-space: pre; white-space: pre;
overflow-x: auto; overflow-x: auto;
font-size: 12px; font-size: 12px;
position: relative;
.fa-refresh { .fa-refresh {
font-size: 24px; font-size: 24px;
......
...@@ -71,6 +71,11 @@ ...@@ -71,6 +71,11 @@
= custom_icon('scroll_down_hover_active') = custom_icon('scroll_down_hover_active')
#up-build-trace #up-build-trace
%pre.build-trace#build-trace %pre.build-trace#build-trace
.js-truncated-info.truncated-info.hidden
%span<
Showing last
%span.js-truncated-info-size><
KiB of log
%code.bash.js-build-output %code.bash.js-build-output
.build-loader-animation.js-build-refresh .build-loader-animation.js-build-refresh
......
...@@ -64,58 +64,33 @@ describe('Build', () => { ...@@ -64,58 +64,33 @@ describe('Build', () => {
}); });
}); });
describe('initial build trace', () => {
beforeEach(() => {
new Build();
});
it('displays the initial build trace', () => {
expect($.ajax.calls.count()).toBe(1);
const [{ url, dataType, success, context }] = $.ajax.calls.argsFor(0);
expect(url).toBe(
`${BUILD_URL}/trace.json`,
);
expect(dataType).toBe('json');
expect(success).toEqual(jasmine.any(Function));
spyOn(gl.utils, 'setCiStatusFavicon').and.callFake(() => {});
success.call(context, { html: '<span>Example</span>', status: 'running' });
expect($('#build-trace .js-build-output').text()).toMatch(/Example/);
});
it('removes the spinner', () => {
const [{ success, context }] = $.ajax.calls.argsFor(0);
spyOn(gl.utils, 'setCiStatusFavicon').and.callFake(() => {});
success.call(context, { trace_html: '<span>Example</span>', status: 'success' });
expect($('.js-build-refresh').length).toBe(0);
});
});
describe('running build', () => { describe('running build', () => {
beforeEach(function () { beforeEach(function () {
$('.js-build-options').data('buildStatus', 'running');
this.build = new Build(); this.build = new Build();
spyOn(this.build, 'location').and.returnValue(BUILD_URL);
}); });
it('updates the build trace on an interval', function () { it('updates the build trace on an interval', function () {
spyOn(gl.utils, 'visitUrl');
jasmine.clock().tick(4001); jasmine.clock().tick(4001);
expect($.ajax.calls.count()).toBe(2); expect($.ajax.calls.count()).toBe(1);
let [{ url, dataType, success, context }] = $.ajax.calls.argsFor(1);
expect(url).toBe( // We have to do it this way to prevent Webpack to fail to compile
`${BUILD_URL}/trace.json?state=`, // when destructuring assignments and reusing
); // the same variables names inside the same scope
expect(dataType).toBe('json'); let args = $.ajax.calls.argsFor(0)[0];
expect(success).toEqual(jasmine.any(Function));
expect(args.url).toBe(`${BUILD_URL}/trace.json`);
success.call(context, { expect(args.dataType).toBe('json');
expect(args.success).toEqual(jasmine.any(Function));
args.success.call($, {
html: '<span>Update<span>', html: '<span>Update<span>',
status: 'running', status: 'running',
state: 'newstate', state: 'newstate',
append: true, append: true,
complete: false,
}); });
expect($('#build-trace .js-build-output').text()).toMatch(/Update/); expect($('#build-trace .js-build-output').text()).toMatch(/Update/);
...@@ -123,17 +98,20 @@ describe('Build', () => { ...@@ -123,17 +98,20 @@ describe('Build', () => {
jasmine.clock().tick(4001); jasmine.clock().tick(4001);
expect($.ajax.calls.count()).toBe(3); expect($.ajax.calls.count()).toBe(2);
[{ url, dataType, success, context }] = $.ajax.calls.argsFor(2);
expect(url).toBe(`${BUILD_URL}/trace.json?state=newstate`); args = $.ajax.calls.argsFor(1)[0];
expect(dataType).toBe('json'); expect(args.url).toBe(`${BUILD_URL}/trace.json`);
expect(success).toEqual(jasmine.any(Function)); expect(args.dataType).toBe('json');
expect(args.data.state).toBe('newstate');
expect(args.success).toEqual(jasmine.any(Function));
success.call(context, { args.success.call($, {
html: '<span>More</span>', html: '<span>More</span>',
status: 'running', status: 'running',
state: 'finalstate', state: 'finalstate',
append: true, append: true,
complete: true,
}); });
expect($('#build-trace .js-build-output').text()).toMatch(/UpdateMore/); expect($('#build-trace .js-build-output').text()).toMatch(/UpdateMore/);
...@@ -141,19 +119,22 @@ describe('Build', () => { ...@@ -141,19 +119,22 @@ describe('Build', () => {
}); });
it('replaces the entire build trace', () => { it('replaces the entire build trace', () => {
spyOn(gl.utils, 'visitUrl');
jasmine.clock().tick(4001); jasmine.clock().tick(4001);
let [{ success, context }] = $.ajax.calls.argsFor(1); let args = $.ajax.calls.argsFor(0)[0];
success.call(context, { args.success.call($, {
html: '<span>Update</span>', html: '<span>Update</span>',
status: 'running', status: 'running',
append: true, append: false,
complete: false,
}); });
expect($('#build-trace .js-build-output').text()).toMatch(/Update/); expect($('#build-trace .js-build-output').text()).toMatch(/Update/);
jasmine.clock().tick(4001); jasmine.clock().tick(4001);
[{ success, context }] = $.ajax.calls.argsFor(2); args = $.ajax.calls.argsFor(1)[0];
success.call(context, { args.success.call($, {
html: '<span>Different</span>', html: '<span>Different</span>',
status: 'running', status: 'running',
append: false, append: false,
...@@ -163,15 +144,34 @@ describe('Build', () => { ...@@ -163,15 +144,34 @@ describe('Build', () => {
expect($('#build-trace .js-build-output').text()).toMatch(/Different/); expect($('#build-trace .js-build-output').text()).toMatch(/Different/);
}); });
it('shows information about truncated log', () => {
jasmine.clock().tick(4001);
const [{ success }] = $.ajax.calls.argsFor(0);
success.call($, {
html: '<span>Update</span>',
status: 'success',
append: false,
truncated: true,
size: '50',
});
expect(
$('#build-trace .js-truncated-info').text().trim(),
).toContain('Showing last 50 KiB of log');
expect($('#build-trace .js-truncated-info-size').text()).toMatch('50');
});
it('reloads the page when the build is done', () => { it('reloads the page when the build is done', () => {
spyOn(gl.utils, 'visitUrl'); spyOn(gl.utils, 'visitUrl');
jasmine.clock().tick(4001); jasmine.clock().tick(4001);
const [{ success, context }] = $.ajax.calls.argsFor(1); const [{ success }] = $.ajax.calls.argsFor(0);
success.call(context, { success.call($, {
html: '<span>Final</span>', html: '<span>Final</span>',
status: 'passed', status: 'passed',
append: true, append: true,
complete: true,
}); });
expect(gl.utils.visitUrl).toHaveBeenCalledWith(BUILD_URL); expect(gl.utils.visitUrl).toHaveBeenCalledWith(BUILD_URL);
......
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