Skip to content
Snippets Groups Projects
Commit 7f40d220 authored by Filipa Lacerda's avatar Filipa Lacerda Committed by Phil Hughes
Browse files

Resolve "Jobs dropdown in mini graph should close when we receive an error"

Former-commit-id: 1ac15de9
parent a212d5ee
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -28,7 +28,9 @@ export default class MiniPipelineGraph {
* All dropdown events are fired at the .dropdown-menu's parent element.
*/
bindEvents() {
$(document).off('shown.bs.dropdown', this.container).on('shown.bs.dropdown', this.container, this.getBuildsList);
$(document)
.off('shown.bs.dropdown', this.container)
.on('shown.bs.dropdown', this.container, this.getBuildsList);
}
 
/**
Loading
Loading
@@ -91,6 +93,9 @@ export default class MiniPipelineGraph {
},
error: () => {
this.toggleLoading(button);
if ($(button).parent().hasClass('open')) {
$(button).dropdown('toggle');
}
new Flash('An error occurred while fetching the builds.', 'alert');
},
});
Loading
Loading
Loading
Loading
@@ -2,13 +2,6 @@
import StatusIconEntityMap from '../../ci_status_icons';
 
export default {
data() {
return {
builds: '',
spinner: '<span class="fa fa-spinner fa-spin"></span>',
};
},
props: {
stage: {
type: Object,
Loading
Loading
@@ -16,6 +9,13 @@ export default {
},
},
 
data() {
return {
builds: '',
spinner: '<span class="fa fa-spinner fa-spin"></span>',
};
},
updated() {
if (this.builds) {
this.stopDropdownClickPropagation();
Loading
Loading
@@ -31,7 +31,13 @@ export default {
return this.$http.get(this.stage.dropdown_path)
.then((response) => {
this.builds = JSON.parse(response.body).html;
}, () => {
})
.catch(() => {
// If dropdown is opened we'll close it.
if (this.$el.classList.contains('open')) {
$(this.$refs.dropdown).dropdown('toggle');
}
const flash = new Flash('Something went wrong on our end.');
return flash;
});
Loading
Loading
@@ -46,9 +52,10 @@ export default {
* target the click event of this component.
*/
stopDropdownClickPropagation() {
$(this.$el.querySelectorAll('.js-builds-dropdown-list a.mini-pipeline-graph-dropdown-item')).on('click', (e) => {
e.stopPropagation();
});
$(this.$el.querySelectorAll('.js-builds-dropdown-list a.mini-pipeline-graph-dropdown-item'))
.on('click', (e) => {
e.stopPropagation();
});
},
},
computed: {
Loading
Loading
@@ -81,12 +88,22 @@ export default {
data-placement="top"
data-toggle="dropdown"
type="button"
:aria-label="stage.title">
<span v-html="svgHTML" aria-hidden="true"></span>
<i class="fa fa-caret-down" aria-hidden="true"></i>
:aria-label="stage.title"
ref="dropdown">
<span
v-html="svgHTML"
aria-hidden="true">
</span>
<i
class="fa fa-caret-down"
aria-hidden="true" />
</button>
<ul class="dropdown-menu mini-pipeline-graph-dropdown-menu js-builds-dropdown-container">
<div class="arrow-up" aria-hidden="true"></div>
<ul
ref="dropdown-content"
class="dropdown-menu mini-pipeline-graph-dropdown-menu js-builds-dropdown-container">
<div
class="arrow-up"
aria-hidden="true"></div>
<div
:class="dropdownClass"
class="js-builds-dropdown-list scrollable-menu"
Loading
Loading
Loading
Loading
@@ -195,7 +195,6 @@
border: 1px solid $dropdown-border-color;
border-radius: $border-radius-base;
box-shadow: 0 2px 4px $dropdown-shadow-color;
overflow: hidden;
@include set-invisible;
 
@media (max-width: $screen-sm-min) {
Loading
Loading
Loading
Loading
@@ -3,70 +3,84 @@
import MiniPipelineGraph from '~/mini_pipeline_graph_dropdown';
import '~/flash';
 
(() => {
describe('Mini Pipeline Graph Dropdown', () => {
preloadFixtures('static/mini_dropdown_graph.html.raw');
describe('Mini Pipeline Graph Dropdown', () => {
preloadFixtures('static/mini_dropdown_graph.html.raw');
 
beforeEach(() => {
loadFixtures('static/mini_dropdown_graph.html.raw');
});
beforeEach(() => {
loadFixtures('static/mini_dropdown_graph.html.raw');
});
 
describe('When is initialized', () => {
it('should initialize without errors when no options are given', () => {
const miniPipelineGraph = new MiniPipelineGraph();
describe('When is initialized', () => {
it('should initialize without errors when no options are given', () => {
const miniPipelineGraph = new MiniPipelineGraph();
 
expect(miniPipelineGraph.dropdownListSelector).toEqual('.js-builds-dropdown-container');
});
expect(miniPipelineGraph.dropdownListSelector).toEqual('.js-builds-dropdown-container');
});
 
it('should set the container as the given prop', () => {
const container = '.foo';
it('should set the container as the given prop', () => {
const container = '.foo';
 
const miniPipelineGraph = new MiniPipelineGraph({ container });
const miniPipelineGraph = new MiniPipelineGraph({ container });
 
expect(miniPipelineGraph.container).toEqual(container);
});
expect(miniPipelineGraph.container).toEqual(container);
});
});
 
describe('When dropdown is clicked', () => {
it('should call getBuildsList', () => {
const getBuildsListSpy = spyOn(MiniPipelineGraph.prototype, 'getBuildsList').and.callFake(function () {});
describe('When dropdown is clicked', () => {
it('should call getBuildsList', () => {
const getBuildsListSpy = spyOn(
MiniPipelineGraph.prototype,
'getBuildsList',
).and.callFake(function () {});
 
new MiniPipelineGraph({ container: '.js-builds-dropdown-tests' }).bindEvents();
new MiniPipelineGraph({ container: '.js-builds-dropdown-tests' }).bindEvents();
 
document.querySelector('.js-builds-dropdown-button').click();
document.querySelector('.js-builds-dropdown-button').click();
 
expect(getBuildsListSpy).toHaveBeenCalled();
});
expect(getBuildsListSpy).toHaveBeenCalled();
});
 
it('should make a request to the endpoint provided in the html', () => {
const ajaxSpy = spyOn($, 'ajax').and.callFake(function () {});
it('should make a request to the endpoint provided in the html', () => {
const ajaxSpy = spyOn($, 'ajax').and.callFake(function () {});
 
new MiniPipelineGraph({ container: '.js-builds-dropdown-tests' }).bindEvents();
new MiniPipelineGraph({ container: '.js-builds-dropdown-tests' }).bindEvents();
 
document.querySelector('.js-builds-dropdown-button').click();
expect(ajaxSpy.calls.allArgs()[0][0].url).toEqual('foobar');
});
document.querySelector('.js-builds-dropdown-button').click();
expect(ajaxSpy.calls.allArgs()[0][0].url).toEqual('foobar');
});
 
it('should not close when user uses cmd/ctrl + click', () => {
spyOn($, 'ajax').and.callFake(function (params) {
params.success({
html: `<li>
<a class="mini-pipeline-graph-dropdown-item" href="#">
<span class="ci-status-icon ci-status-icon-failed"></span>
<span class="ci-build-text">build</span>
</a>
<a class="ci-action-icon-wrapper js-ci-action-icon" href="#"></a>
</li>`,
});
it('should not close when user uses cmd/ctrl + click', () => {
spyOn($, 'ajax').and.callFake(function (params) {
params.success({
html: `<li>
<a class="mini-pipeline-graph-dropdown-item" href="#">
<span class="ci-status-icon ci-status-icon-failed"></span>
<span class="ci-build-text">build</span>
</a>
<a class="ci-action-icon-wrapper js-ci-action-icon" href="#"></a>
</li>`,
});
new MiniPipelineGraph({ container: '.js-builds-dropdown-tests' }).bindEvents();
});
new MiniPipelineGraph({ container: '.js-builds-dropdown-tests' }).bindEvents();
 
document.querySelector('.js-builds-dropdown-button').click();
document.querySelector('.js-builds-dropdown-button').click();
 
document.querySelector('a.mini-pipeline-graph-dropdown-item').click();
document.querySelector('a.mini-pipeline-graph-dropdown-item').click();
 
expect($('.js-builds-dropdown-list').is(':visible')).toEqual(true);
});
expect($('.js-builds-dropdown-list').is(':visible')).toEqual(true);
});
});
})();
it('should close the dropdown when request returns an error', (done) => {
spyOn($, 'ajax').and.callFake(options => options.error());
new MiniPipelineGraph({ container: '.js-builds-dropdown-tests' }).bindEvents();
document.querySelector('.js-builds-dropdown-button').click();
setTimeout(() => {
expect($('.js-builds-dropdown-tests .dropdown').hasClass('open')).toEqual(false);
done();
}, 0);
});
});
Loading
Loading
@@ -63,4 +63,19 @@ describe('Pipelines Stage', () => {
expect(minifiedComponent).toContain(expectedSVG);
});
});
describe('when request fails', () => {
it('closes dropdown', () => {
spyOn($, 'ajax').and.callFake(options => options.error());
const StageComponent = Vue.extend(Stage);
const component = new StageComponent({
propsData: { stage: { status: { icon: 'foo' } } },
}).$mount();
expect(
component.$el.classList.contains('open'),
).toEqual(false);
});
});
});
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment