summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWinnie Hellmann <winnie@gitlab.com>2018-07-23 14:58:21 +0000
committerPhil Hughes <me@iamphill.com>2018-07-23 14:58:21 +0000
commit91bbdc907d72fa5bd6d30ded825c2b90dd59d28e (patch)
tree46ca1c8c4919b3ff3b8241c57bb301952a888267
parent1a959e1bf4269b3c74cb317d18bcc624436aabc5 (diff)
downloadgitlab-ce-91bbdc907d72fa5bd6d30ded825c2b90dd59d28e.tar.gz
Display GPG status on repository and blob pages
-rw-r--r--app/assets/javascripts/gpg_badges.js31
-rw-r--r--app/assets/javascripts/pages/projects/blob/show/index.js3
-rw-r--r--app/assets/javascripts/pages/projects/show/index.js3
-rw-r--r--app/assets/javascripts/pages/projects/tree/show/index.js6
-rw-r--r--app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue162
-rw-r--r--app/assets/javascripts/vue_shared/components/clipboard_button.vue13
-rw-r--r--app/assets/stylesheets/framework/buttons.scss4
-rw-r--r--app/assets/stylesheets/pages/commits.scss6
-rw-r--r--app/helpers/button_helper.rb2
-rw-r--r--app/helpers/ci_status_helper.rb13
-rw-r--r--app/views/projects/blob/show.html.haml2
-rw-r--r--app/views/projects/show.html.haml4
-rw-r--r--app/views/projects/tree/show.html.haml3
-rw-r--r--app/views/sherlock/queries/_general.html.haml4
-rw-r--r--changelogs/unreleased/winh-tree-view-gpg.yml5
-rw-r--r--locale/gitlab.pot2
-rw-r--r--spec/helpers/button_helper_spec.rb6
-rw-r--r--spec/javascripts/gpg_badges_spec.js76
-rw-r--r--spec/javascripts/vue_shared/components/clipboard_button_spec.js2
19 files changed, 213 insertions, 134 deletions
diff --git a/app/assets/javascripts/gpg_badges.js b/app/assets/javascripts/gpg_badges.js
index 029fd6a67d4..efba6fc1aff 100644
--- a/app/assets/javascripts/gpg_badges.js
+++ b/app/assets/javascripts/gpg_badges.js
@@ -1,23 +1,36 @@
import $ from 'jquery';
import { parseQueryStringIntoObject } from '~/lib/utils/common_utils';
import axios from '~/lib/utils/axios_utils';
-import flash from '~/flash';
+import createFlash from '~/flash';
import { __ } from '~/locale';
export default class GpgBadges {
static fetch() {
- const badges = $('.js-loading-gpg-badge');
const tag = $('.js-signature-container');
+ if (tag.length === 0) {
+ return Promise.resolve();
+ }
+
+ const badges = $('.js-loading-gpg-badge');
badges.html('<i class="fa fa-spinner fa-spin"></i>');
+ const displayError = () => createFlash(__('An error occurred while loading commit signatures'));
+
+ const endpoint = tag.data('signaturesPath');
+ if (!endpoint) {
+ displayError();
+ return Promise.reject(new Error('Missing commit signatures endpoint!'));
+ }
+
const params = parseQueryStringIntoObject(tag.serialize());
- return axios.get(tag.data('signaturesPath'), { params })
- .then(({ data }) => {
- data.signatures.forEach((signature) => {
- badges.filter(`[data-commit-sha="${signature.commit_sha}"]`).replaceWith(signature.html);
- });
- })
- .catch(() => flash(__('An error occurred while loading commits')));
+ return axios
+ .get(endpoint, { params })
+ .then(({ data }) => {
+ data.signatures.forEach(signature => {
+ badges.filter(`[data-commit-sha="${signature.commit_sha}"]`).replaceWith(signature.html);
+ });
+ })
+ .catch(displayError);
}
}
diff --git a/app/assets/javascripts/pages/projects/blob/show/index.js b/app/assets/javascripts/pages/projects/blob/show/index.js
index 85c6862d629..84e5bb3c46e 100644
--- a/app/assets/javascripts/pages/projects/blob/show/index.js
+++ b/app/assets/javascripts/pages/projects/blob/show/index.js
@@ -2,6 +2,7 @@ import Vue from 'vue';
import commitPipelineStatus from '~/projects/tree/components/commit_pipeline_status_component.vue';
import BlobViewer from '~/blob/viewer/index';
import initBlob from '~/pages/projects/init_blob';
+import GpgBadges from '~/gpg_badges';
document.addEventListener('DOMContentLoaded', () => {
new BlobViewer(); // eslint-disable-line no-new
@@ -26,4 +27,6 @@ document.addEventListener('DOMContentLoaded', () => {
},
});
}
+
+ GpgBadges.fetch();
});
diff --git a/app/assets/javascripts/pages/projects/show/index.js b/app/assets/javascripts/pages/projects/show/index.js
index 3b0f0f960b8..d2dc0c4570e 100644
--- a/app/assets/javascripts/pages/projects/show/index.js
+++ b/app/assets/javascripts/pages/projects/show/index.js
@@ -7,6 +7,7 @@ import TreeView from '~/tree';
import BlobViewer from '~/blob/viewer/index';
import Activities from '~/activities';
import { ajaxGet } from '~/lib/utils/common_utils';
+import GpgBadges from '~/gpg_badges';
import Star from '../../../star';
import notificationsDropdown from '../../../notifications_dropdown';
@@ -38,4 +39,6 @@ document.addEventListener('DOMContentLoaded', () => {
$(treeSlider).waitForImages(() => {
ajaxGet(document.querySelector('.js-tree-content').dataset.logsPath);
});
+
+ GpgBadges.fetch();
});
diff --git a/app/assets/javascripts/pages/projects/tree/show/index.js b/app/assets/javascripts/pages/projects/tree/show/index.js
index 7ad082a5e61..33d69d891d8 100644
--- a/app/assets/javascripts/pages/projects/tree/show/index.js
+++ b/app/assets/javascripts/pages/projects/tree/show/index.js
@@ -2,6 +2,7 @@ import $ from 'jquery';
import Vue from 'vue';
import initBlob from '~/blob_edit/blob_bundle';
import commitPipelineStatus from '~/projects/tree/components/commit_pipeline_status_component.vue';
+import GpgBadges from '~/gpg_badges';
import TreeView from '../../../../tree';
import ShortcutsNavigation from '../../../../shortcuts_navigation';
import BlobViewer from '../../../../blob/viewer';
@@ -14,7 +15,8 @@ document.addEventListener('DOMContentLoaded', () => {
new BlobViewer(); // eslint-disable-line no-new
new NewCommitForm($('.js-create-dir-form')); // eslint-disable-line no-new
$('#tree-slider').waitForImages(() =>
- ajaxGet(document.querySelector('.js-tree-content').dataset.logsPath));
+ ajaxGet(document.querySelector('.js-tree-content').dataset.logsPath),
+ );
initBlob();
const commitPipelineStatusEl = document.querySelector('.js-commit-pipeline-status');
@@ -36,4 +38,6 @@ document.addEventListener('DOMContentLoaded', () => {
},
});
}
+
+ GpgBadges.fetch();
});
diff --git a/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue b/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue
index a4c7c143e56..1c1e17563a1 100644
--- a/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue
+++ b/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue
@@ -1,27 +1,27 @@
<script>
- import Visibility from 'visibilityjs';
- import ciIcon from '~/vue_shared/components/ci_icon.vue';
- import loadingIcon from '~/vue_shared/components/loading_icon.vue';
- import Poll from '~/lib/utils/poll';
- import Flash from '~/flash';
- import { s__, sprintf } from '~/locale';
- import tooltip from '~/vue_shared/directives/tooltip';
- import CommitPipelineService from '../services/commit_pipeline_service';
+import Visibility from 'visibilityjs';
+import ciIcon from '~/vue_shared/components/ci_icon.vue';
+import loadingIcon from '~/vue_shared/components/loading_icon.vue';
+import Poll from '~/lib/utils/poll';
+import Flash from '~/flash';
+import { s__, sprintf } from '~/locale';
+import tooltip from '~/vue_shared/directives/tooltip';
+import CommitPipelineService from '../services/commit_pipeline_service';
- export default {
- directives: {
- tooltip,
+export default {
+ directives: {
+ tooltip,
+ },
+ components: {
+ ciIcon,
+ loadingIcon,
+ },
+ props: {
+ endpoint: {
+ type: String,
+ required: true,
},
- components: {
- ciIcon,
- loadingIcon,
- },
- props: {
- endpoint: {
- type: String,
- required: true,
- },
- /* This prop can be used to replace some of the `render_commit_status`
+ /* This prop can be used to replace some of the `render_commit_status`
used across GitLab, this way we could use this vue component and add a
realtime status where it makes sense
realtime: {
@@ -29,76 +29,77 @@
required: false,
default: true,
}, */
+ },
+ data() {
+ return {
+ ciStatus: {},
+ isLoading: true,
+ };
+ },
+ computed: {
+ statusTitle() {
+ return sprintf(s__('Commits|Commit: %{commitText}'), { commitText: this.ciStatus.text });
},
- data() {
- return {
- ciStatus: {},
- isLoading: true,
- };
- },
- computed: {
- statusTitle() {
- return sprintf(s__('Commits|Commit: %{commitText}'), { commitText: this.ciStatus.text });
- },
+ },
+ mounted() {
+ this.service = new CommitPipelineService(this.endpoint);
+ this.initPolling();
+ },
+ methods: {
+ successCallback(res) {
+ const { pipelines } = res.data;
+ if (pipelines.length > 0) {
+ // The pipeline entity always keeps the latest pipeline info on the `details.status`
+ this.ciStatus = pipelines[0].details.status;
+ }
+ this.isLoading = false;
},
- mounted() {
- this.service = new CommitPipelineService(this.endpoint);
- this.initPolling();
+ errorCallback() {
+ this.ciStatus = {
+ text: 'not found',
+ icon: 'status_notfound',
+ group: 'notfound',
+ };
+ this.isLoading = false;
+ Flash(s__('Something went wrong on our end'));
},
- methods: {
- successCallback(res) {
- const { pipelines } = res.data;
- if (pipelines.length > 0) {
- // The pipeline entity always keeps the latest pipeline info on the `details.status`
- this.ciStatus = pipelines[0].details.status;
- }
- this.isLoading = false;
- },
- errorCallback() {
- this.ciStatus = {
- text: 'not found',
- icon: 'status_notfound',
- group: 'notfound',
- };
- this.isLoading = false;
- Flash(s__('Something went wrong on our end'));
- },
- initPolling() {
- this.poll = new Poll({
- resource: this.service,
- method: 'fetchData',
- successCallback: response => this.successCallback(response),
- errorCallback: this.errorCallback,
- });
+ initPolling() {
+ this.poll = new Poll({
+ resource: this.service,
+ method: 'fetchData',
+ successCallback: response => this.successCallback(response),
+ errorCallback: this.errorCallback,
+ });
+
+ if (!Visibility.hidden()) {
+ this.isLoading = true;
+ this.poll.makeRequest();
+ } else {
+ this.fetchPipelineCommitData();
+ }
+ Visibility.change(() => {
if (!Visibility.hidden()) {
- this.isLoading = true;
- this.poll.makeRequest();
+ this.poll.restart();
} else {
- this.fetchPipelineCommitData();
+ this.poll.stop();
}
-
- Visibility.change(() => {
- if (!Visibility.hidden()) {
- this.poll.restart();
- } else {
- this.poll.stop();
- }
- });
- },
- fetchPipelineCommitData() {
- this.service.fetchData()
- .then(this.successCallback)
- .catch(this.errorCallback);
- },
+ });
},
- destroy() {
- this.poll.stop();
+ fetchPipelineCommitData() {
+ this.service
+ .fetchData()
+ .then(this.successCallback)
+ .catch(this.errorCallback);
},
- };
+ },
+ destroy() {
+ this.poll.stop();
+ },
+};
</script>
<template>
- <div>
+ <div class="ci-status-link">
<loading-icon
v-if="isLoading"
label="Loading pipeline status"
@@ -113,6 +114,7 @@
:title="statusTitle"
:aria-label="statusTitle"
:status="ciStatus"
+ :size="24"
data-container="body"
/>
</a>
diff --git a/app/assets/javascripts/vue_shared/components/clipboard_button.vue b/app/assets/javascripts/vue_shared/components/clipboard_button.vue
index dc5760bce28..d272bf3f55f 100644
--- a/app/assets/javascripts/vue_shared/components/clipboard_button.vue
+++ b/app/assets/javascripts/vue_shared/components/clipboard_button.vue
@@ -13,12 +13,19 @@
* />
*/
import tooltip from '../directives/tooltip';
+import Icon from '../components/icon.vue';
export default {
name: 'ClipboardButton',
+
directives: {
tooltip,
},
+
+ components: {
+ Icon,
+ },
+
props: {
text: {
type: String,
@@ -58,10 +65,6 @@ export default {
type="button"
class="btn"
>
- <i
- aria-hidden="true"
- class="fa fa-clipboard"
- >
- </i>
+ <icon name="duplicate" />
</button>
</template>
diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss
index 523fcb05a87..646cedd79ed 100644
--- a/app/assets/stylesheets/framework/buttons.scss
+++ b/app/assets/stylesheets/framework/buttons.scss
@@ -294,6 +294,10 @@
.btn-clipboard {
border: 0;
padding: 0 5px;
+
+ svg {
+ top: auto;
+ }
}
.input-group-prepend,
diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss
index f75be4e01cd..63585e26022 100644
--- a/app/assets/stylesheets/pages/commits.scss
+++ b/app/assets/stylesheets/pages/commits.scss
@@ -205,7 +205,7 @@
> .ci-status-link,
> .btn,
> .commit-sha-group {
- margin-left: $gl-padding-8;
+ margin-left: $gl-padding;
}
}
@@ -235,10 +235,6 @@
fill: $gl-text-color-secondary;
}
- .fa-clipboard {
- color: $gl-text-color-secondary;
- }
-
:first-child {
border-bottom-left-radius: $border-radius-default;
border-top-left-radius: $border-radius-default;
diff --git a/app/helpers/button_helper.rb b/app/helpers/button_helper.rb
index 3605d6a3c95..0171a880164 100644
--- a/app/helpers/button_helper.rb
+++ b/app/helpers/button_helper.rb
@@ -51,7 +51,7 @@ module ButtonHelper
}
content_tag :button, button_attributes do
- concat(icon('clipboard', 'aria-hidden': 'true')) unless hide_button_icon
+ concat(sprite_icon('duplicate')) unless hide_button_icon
concat(button_text)
end
end
diff --git a/app/helpers/ci_status_helper.rb b/app/helpers/ci_status_helper.rb
index f49b5c7b51a..330959e536d 100644
--- a/app/helpers/ci_status_helper.rb
+++ b/app/helpers/ci_status_helper.rb
@@ -56,7 +56,7 @@ module CiStatusHelper
status.humanize
end
- def ci_icon_for_status(status)
+ def ci_icon_for_status(status, size: 16)
if detailed_status?(status)
return sprite_icon(status.icon)
end
@@ -85,7 +85,7 @@ module CiStatusHelper
'status_canceled'
end
- sprite_icon(icon_name, size: 16)
+ sprite_icon(icon_name, size: size)
end
def pipeline_status_cache_key(pipeline_status)
@@ -111,7 +111,8 @@ module CiStatusHelper
'commit',
commit.status(ref),
path,
- tooltip_placement: tooltip_placement)
+ tooltip_placement: tooltip_placement,
+ icon_size: 24)
end
def render_pipeline_status(pipeline, tooltip_placement: 'left')
@@ -125,16 +126,16 @@ module CiStatusHelper
Ci::Runner.instance_type.blank?
end
- def render_status_with_link(type, status, path = nil, tooltip_placement: 'left', cssclass: '', container: 'body')
+ def render_status_with_link(type, status, path = nil, tooltip_placement: 'left', cssclass: '', container: 'body', icon_size: 16)
klass = "ci-status-link ci-status-icon-#{status.dasherize} #{cssclass}"
title = "#{type.titleize}: #{ci_label_for_status(status)}"
data = { toggle: 'tooltip', placement: tooltip_placement, container: container }
if path
- link_to ci_icon_for_status(status), path,
+ link_to ci_icon_for_status(status, size: icon_size), path,
class: klass, title: title, data: data
else
- content_tag :span, ci_icon_for_status(status),
+ content_tag :span, ci_icon_for_status(status, size: icon_size),
class: klass, title: title, data: data
end
end
diff --git a/app/views/projects/blob/show.html.haml b/app/views/projects/blob/show.html.haml
index efb8175398b..5edab38bd64 100644
--- a/app/views/projects/blob/show.html.haml
+++ b/app/views/projects/blob/show.html.haml
@@ -3,6 +3,8 @@
- page_title @blob.path, @ref
+.js-signature-container{ data: { 'signatures-path': namespace_project_signatures_path } }
+
%div{ class: container_class }
= render 'projects/last_push'
diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml
index e28accd5b43..803ecca48f7 100644
--- a/app/views/projects/show.html.haml
+++ b/app/views/projects/show.html.haml
@@ -8,6 +8,10 @@
= render partial: 'flash_messages', locals: { project: @project }
+- if @project.repository_exists? && !@project.empty_repo?
+ - signatures_path = namespace_project_signatures_path(project_id: @project.path, id: @project.default_branch)
+ .js-signature-container{ data: { 'signatures-path': signatures_path } }
+
%div{ class: [container_class, ("limit-container-width" unless fluid_layout)] }
= render "projects/last_push"
diff --git a/app/views/projects/tree/show.html.haml b/app/views/projects/tree/show.html.haml
index 3b4057e56d0..ace8120eeff 100644
--- a/app/views/projects/tree/show.html.haml
+++ b/app/views/projects/tree/show.html.haml
@@ -1,11 +1,14 @@
- @no_container = true
- breadcrumb_title _("Repository")
- @content_class = "limit-container-width" unless fluid_layout
+- signatures_path = namespace_project_signatures_path(namespace_id: @project.namespace.path, project_id: @project.path, id: @ref)
- page_title @path.presence || _("Files"), @ref
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, project_commits_url(@project, @ref, rss_url_options), title: "#{@project.name}:#{@ref} commits")
+.js-signature-container{ data: { 'signatures-path': signatures_path } }
+
%div{ class: [(container_class), ("limit-container-width" unless fluid_layout)] }
= render 'projects/last_push'
= render 'projects/files', commit: @last_commit, project: @project, ref: @ref, content_url: project_tree_path(@project, @id)
diff --git a/app/views/sherlock/queries/_general.html.haml b/app/views/sherlock/queries/_general.html.haml
index 37747faed62..ddc089b0bd7 100644
--- a/app/views/sherlock/queries/_general.html.haml
+++ b/app/views/sherlock/queries/_general.html.haml
@@ -27,7 +27,7 @@
.card-header
.float-right
%button.js-clipboard-trigger.btn.btn-sm{ title: t('sherlock.copy_to_clipboard'), type: :button }
- %i.fa.fa-clipboard
+ = sprite_icon('duplicate')
%pre.hidden
= @query.formatted_query
%strong
@@ -42,7 +42,7 @@
.card-header
.float-right
%button.js-clipboard-trigger.btn.btn-sm{ title: t('sherlock.copy_to_clipboard'), type: :button }
- %i.fa.fa-clipboard
+ = sprite_icon('duplicate')
%pre.hidden
= @query.explain
%strong
diff --git a/changelogs/unreleased/winh-tree-view-gpg.yml b/changelogs/unreleased/winh-tree-view-gpg.yml
new file mode 100644
index 00000000000..84d63814a47
--- /dev/null
+++ b/changelogs/unreleased/winh-tree-view-gpg.yml
@@ -0,0 +1,5 @@
+---
+title: Display GPG status on repository and blob pages
+merge_request: 20524
+author:
+type: changed
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 75b88a2cb2f..09a35b5da07 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -465,7 +465,7 @@ msgstr ""
msgid "An error occurred while importing project: ${details}"
msgstr ""
-msgid "An error occurred while loading commits"
+msgid "An error occurred while loading commit signatures"
msgstr ""
msgid "An error occurred while loading diff"
diff --git a/spec/helpers/button_helper_spec.rb b/spec/helpers/button_helper_spec.rb
index fee8df10129..630f3eff258 100644
--- a/spec/helpers/button_helper_spec.rb
+++ b/spec/helpers/button_helper_spec.rb
@@ -121,6 +121,8 @@ describe ButtonHelper do
end
describe 'clipboard_button' do
+ include IconsHelper
+
let(:user) { create(:user) }
let(:project) { build_stubbed(:project) }
@@ -145,7 +147,7 @@ describe ButtonHelper do
expect(element.attr('data-clipboard-text')).to eq(nil)
expect(element.inner_text).to eq("")
- expect(element).to have_selector('.fa.fa-clipboard')
+ expect(element.to_html).to include sprite_icon('duplicate')
end
end
@@ -178,7 +180,7 @@ describe ButtonHelper do
context 'with `hide_button_icon` attribute provided' do
it 'shows copy to clipboard button without tooltip support' do
- expect(element(hide_button_icon: true)).not_to have_selector('.fa.fa-clipboard')
+ expect(element(hide_button_icon: true).to_html).not_to include sprite_icon('duplicate')
end
end
end
diff --git a/spec/javascripts/gpg_badges_spec.js b/spec/javascripts/gpg_badges_spec.js
index 97c771dcfd3..78330dd9633 100644
--- a/spec/javascripts/gpg_badges_spec.js
+++ b/spec/javascripts/gpg_badges_spec.js
@@ -1,23 +1,27 @@
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import GpgBadges from '~/gpg_badges';
+import { TEST_HOST } from 'spec/test_constants';
describe('GpgBadges', () => {
let mock;
const dummyCommitSha = 'n0m0rec0ffee';
const dummyBadgeHtml = 'dummy html';
const dummyResponse = {
- signatures: [{
- commit_sha: dummyCommitSha,
- html: dummyBadgeHtml,
- }],
+ signatures: [
+ {
+ commit_sha: dummyCommitSha,
+ html: dummyBadgeHtml,
+ },
+ ],
};
+ const dummyUrl = `${TEST_HOST}/dummy/signatures`;
beforeEach(() => {
mock = new MockAdapter(axios);
setFixtures(`
<form
- class="commits-search-form js-signature-container" data-signatures-path="/hello" action="/hello"
+ class="commits-search-form js-signature-container" data-signatures-path="${dummyUrl}" action="${dummyUrl}"
method="get">
<input name="utf8" type="hidden" value="✓">
<input type="search" name="search" id="commits-search"class="form-control search-text-input input-short">
@@ -32,25 +36,55 @@ describe('GpgBadges', () => {
mock.restore();
});
- it('displays a loading spinner', (done) => {
- mock.onGet('/hello').reply(200);
+ it('does not make a request if there is no container element', done => {
+ setFixtures('');
+ spyOn(axios, 'get');
- GpgBadges.fetch().then(() => {
- expect(document.querySelector('.js-loading-gpg-badge:empty')).toBe(null);
- const spinners = document.querySelectorAll('.js-loading-gpg-badge i.fa.fa-spinner.fa-spin');
- expect(spinners.length).toBe(1);
- done();
- }).catch(done.fail);
+ GpgBadges.fetch()
+ .then(() => {
+ expect(axios.get).not.toHaveBeenCalled();
+ })
+ .then(done)
+ .catch(done.fail);
});
- it('replaces the loading spinner', (done) => {
- mock.onGet('/hello').reply(200, dummyResponse);
+ it('throws an error if the endpoint is missing', done => {
+ setFixtures('<div class="js-signature-container"></div>');
+ spyOn(axios, 'get');
- GpgBadges.fetch().then(() => {
- expect(document.querySelector('.js-loading-gpg-badge')).toBe(null);
- const parentContainer = document.querySelector('.parent-container');
- expect(parentContainer.innerHTML.trim()).toEqual(dummyBadgeHtml);
- done();
- }).catch(done.fail);
+ GpgBadges.fetch()
+ .then(() => done.fail('Expected error to be thrown'))
+ .catch(error => {
+ expect(error.message).toBe('Missing commit signatures endpoint!');
+ expect(axios.get).not.toHaveBeenCalled();
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('displays a loading spinner', done => {
+ mock.onGet(dummyUrl).replyOnce(200);
+
+ GpgBadges.fetch()
+ .then(() => {
+ expect(document.querySelector('.js-loading-gpg-badge:empty')).toBe(null);
+ const spinners = document.querySelectorAll('.js-loading-gpg-badge i.fa.fa-spinner.fa-spin');
+ expect(spinners.length).toBe(1);
+ done();
+ })
+ .catch(done.fail);
+ });
+
+ it('replaces the loading spinner', done => {
+ mock.onGet(dummyUrl).replyOnce(200, dummyResponse);
+
+ GpgBadges.fetch()
+ .then(() => {
+ expect(document.querySelector('.js-loading-gpg-badge')).toBe(null);
+ const parentContainer = document.querySelector('.parent-container');
+ expect(parentContainer.innerHTML.trim()).toEqual(dummyBadgeHtml);
+ done();
+ })
+ .catch(done.fail);
});
});
diff --git a/spec/javascripts/vue_shared/components/clipboard_button_spec.js b/spec/javascripts/vue_shared/components/clipboard_button_spec.js
index 97f0fbb04db..e135690349e 100644
--- a/spec/javascripts/vue_shared/components/clipboard_button_spec.js
+++ b/spec/javascripts/vue_shared/components/clipboard_button_spec.js
@@ -21,7 +21,7 @@ describe('clipboard button', () => {
it('renders a button for clipboard', () => {
expect(vm.$el.tagName).toEqual('BUTTON');
expect(vm.$el.getAttribute('data-clipboard-text')).toEqual('copy me');
- expect(vm.$el.querySelector('i').className).toEqual('fa fa-clipboard');
+ expect(vm.$el).toHaveSpriteIcon('duplicate');
});
it('should have a tooltip with default values', () => {