diff options
author | Jose Ivan Vargas <jvargas@gitlab.com> | 2018-01-23 12:50:58 -0600 |
---|---|---|
committer | Jose Ivan Vargas <jvargas@gitlab.com> | 2018-02-01 09:41:30 -0600 |
commit | 1123d9dc460353cbc3b46606cc2235f0433f35e1 (patch) | |
tree | 04807a5e04d880b37d7841118a868184c375f65d | |
parent | 449b0ebaf6f3ca65b48f372293117acc9a7e0abc (diff) | |
download | gitlab-ce-1123d9dc460353cbc3b46606cc2235f0433f35e1.tar.gz |
Added more tests and corrected typos35779-realtime-update-of-pipeline-status-in-files-view
8 files changed, 131 insertions, 82 deletions
diff --git a/app/assets/javascripts/pages/projects/show/index.js b/app/assets/javascripts/pages/projects/show/index.js index 4c42fda16d7..55154cdddcb 100644 --- a/app/assets/javascripts/pages/projects/show/index.js +++ b/app/assets/javascripts/pages/projects/show/index.js @@ -5,7 +5,6 @@ import TreeView from '~/tree'; import BlobViewer from '~/blob/viewer/index'; import Activities from '~/activities'; import { ajaxGet } from '~/lib/utils/common_utils'; -import commitPipelineStatus from '~/projects/tree/components/commit_pipeline_status_component.vue'; import Star from '../../../star'; import notificationsDropdown from '../../../notifications_dropdown'; diff --git a/app/assets/javascripts/pages/projects/tree/show/index.js b/app/assets/javascripts/pages/projects/tree/show/index.js index f14c3f86687..c4b3356e478 100644 --- a/app/assets/javascripts/pages/projects/tree/show/index.js +++ b/app/assets/javascripts/pages/projects/tree/show/index.js @@ -15,24 +15,23 @@ export default () => { ajaxGet(document.querySelector('.js-tree-content').dataset.logsPath)); const commitPipelineStatusEl = document.getElementById('commit-pipeline-status'); - const $statusLink = $('.ci-status-link'); - if ($statusLink.length > 0) { - $statusLink.remove(); + const statusLink = document.querySelector('.commit-actions .ci-status-link'); + if (statusLink != null) { + statusLink.remove(); + // eslint-disable-next-line no-new + new Vue({ + el: commitPipelineStatusEl, + components: { + commitPipelineStatus, + }, + render(createElement) { + return createElement('commit-pipeline-status', { + props: { + endpoint: commitPipelineStatusEl.dataset.endpoint, + }, + }); + }, + }); } - commitPipelineStatusEl.classList.remove('hidden'); - // eslint-disable-next-line no-new - new Vue({ - el: '#commit-pipeline-status', - components: { - commitPipelineStatus, - }, - render(createElement) { - return createElement('commit-pipeline-status', { - props: { - endpoint: commitPipelineStatusEl.dataset.endpoint, - }, - }); - }, - }); }; 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 e13acf8555a..63f20a0041d 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,8 +1,10 @@ <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'; @@ -12,46 +14,54 @@ }, components: { ciIcon, + loadingIcon, }, props: { endpoint: { type: String, required: true, }, + /* 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: { type: Boolean, required: false, default: true, - }, + }, */ }, data() { return { ciStatus: {}, isLoading: true, - service: {}, - stageTitle: '', }; }, + computed: { + statusTitle() { + return sprintf(s__('Commits|Commit: %{commitText}'), { commitText: this.ciStatus.text }); + }, + }, mounted() { this.service = new CommitPipelineService(this.endpoint); - if (this.realtime) { - this.initPolling(); - } else { - this.fetchPipelineCommitData(); - } + this.initPolling(); }, methods: { successCallback(res) { - if (res.data.pipelines.length > 0) { - this.ciStatus = res.data.pipelines[0].details.stages[0].status; - this.stageTitle = res.data.pipelines[0].details.stages[0].title; - this.isLoading = false; - } else { - this.isLoading = true; + const pipelines = res.data.pipelines; + 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(err) { - Flash(err); + 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({ @@ -78,8 +88,8 @@ }, fetchPipelineCommitData() { this.service.fetchData() - .then(this.successCallback) - .catch(this.errorCallback); + .then(this.successCallback) + .catch(this.errorCallback); }, }, destroy() { @@ -88,19 +98,23 @@ }; </script> <template> - <div - v-if="isLoading"> - </div> - <a - v-else - :href="ciStatus.details_path" - > - <ci-icon - v-tooltip - :title="stageTitle" - :aria-label="stageTitle" - data-container="body" - :status="ciStatus" + <div> + <loading-icon + label="Loading pipeline status" + size="3" + v-if="isLoading" /> - </a> + <a + v-else + :href="ciStatus.details_path" + > + <ci-icon + v-tooltip + :title="statusTitle" + :aria-label="statusTitle" + data-container="body" + :status="ciStatus" + /> + </a> + </div> </template> diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss index adfd72556b8..17801ed5910 100644 --- a/app/assets/stylesheets/pages/commits.scss +++ b/app/assets/stylesheets/pages/commits.scss @@ -196,6 +196,14 @@ @media (min-width: $screen-sm-min) { font-size: 0; + div { + display: inline; + } + + .fa-spinner { + font-size: 12px; + } + span { font-size: 6px; } @@ -226,7 +234,7 @@ .ci-status-icon { position: relative; - top: 3px; + top: 1px; } } diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml index c94e10947e6..90272ad9554 100644 --- a/app/views/projects/commits/_commit.html.haml +++ b/app/views/projects/commits/_commit.html.haml @@ -51,7 +51,7 @@ - if commit.status(ref) = render_commit_status(commit, ref: ref) - #commit-pipeline-status.hidden{ data: { endpoint: pipelines_project_commit_path(project, commit.id) } } + #commit-pipeline-status{ data: { endpoint: pipelines_project_commit_path(project, commit.id) } } = link_to commit.short_id, link, class: "commit-sha btn btn-transparent btn-link" = clipboard_button(text: commit.id, title: _("Copy commit SHA to clipboard")) = link_to_browse_code(project, commit) diff --git a/features/project/project.feature b/features/project/project.feature index bcd72c5c5a3..23817ef3ac9 100644 --- a/features/project/project.feature +++ b/features/project/project.feature @@ -23,7 +23,6 @@ Feature: Project And I visit project "Shop" page Then I should see project "Shop" README - @javascript Scenario: I should see last commit with CI Given project "Shop" has CI enabled Given project "Shop" has CI build diff --git a/features/steps/shared/project.rb b/features/steps/shared/project.rb index 923d54a6545..affbccccdf9 100644 --- a/features/steps/shared/project.rb +++ b/features/steps/shared/project.rb @@ -218,7 +218,6 @@ module SharedProject end step 'I should see last commit with CI status' do - sleep 2 page.within ".blob-commit-info" do expect(page).to have_content(project.commit.sha[0..6]) expect(page).to have_link("Commit: skipped") diff --git a/spec/javascripts/commit/commit_pipeline_status_component_spec.js b/spec/javascripts/commit/commit_pipeline_status_component_spec.js index 2a52097e0d5..90f290e845e 100644 --- a/spec/javascripts/commit/commit_pipeline_status_component_spec.js +++ b/spec/javascripts/commit/commit_pipeline_status_component_spec.js @@ -6,7 +6,7 @@ import mountComponent from '../helpers/vue_mount_component_helper'; describe('Commit pipeline status component', () => { let vm; - let component; + let Component; let mock; const mockCiStatus = { details_path: '/root/hello-world/pipelines/1', @@ -19,34 +19,25 @@ describe('Commit pipeline status component', () => { }; beforeEach(() => { - mock = new MockAdapter(axios); - mock.onGet('/dummy/endpoint').reply(() => { - const res = Promise.resolve([200, { - pipelines: [ - { - details: { - stages: [ - { - status: mockCiStatus, - title: 'Commit: canceled', - }, - ], - }, - }, - ], - }]); - return res; - }); - component = Vue.extend(commitPipelineStatus); - }); - - afterEach(() => { - mock.reset(); + Component = Vue.extend(commitPipelineStatus); }); - describe('While polling pipeline data', () => { + describe('While polling pipeline data succesfully', () => { beforeEach(() => { - vm = mountComponent(component, { + mock = new MockAdapter(axios); + mock.onGet('/dummy/endpoint').reply(() => { + const res = Promise.resolve([200, { + pipelines: [ + { + details: { + status: mockCiStatus, + }, + }, + ], + }]); + return res; + }); + vm = mountComponent(Component, { endpoint: '/dummy/endpoint', }); }); @@ -54,18 +45,58 @@ describe('Commit pipeline status component', () => { afterEach(() => { vm.poll.stop(); vm.$destroy(); + mock.restore(); + }); + + it('shows the loading icon when polling is starting', (done) => { + expect(vm.$el.querySelector('.loading-container')).not.toBe(null); + setTimeout(() => { + expect(vm.$el.querySelector('.loading-container')).toBe(null); + done(); + }); }); it('contains a ciStatus when the polling is succesful ', (done) => { setTimeout(() => { expect(vm.ciStatus).toEqual(mockCiStatus); done(); - }, 1000); + }); }); it('contains a ci-status icon when polling is succesful', (done) => { setTimeout(() => { expect(vm.$el.querySelector('.ci-status-icon')).not.toBe(null); + expect(vm.$el.querySelector('.ci-status-icon').classList).toContain(`ci-status-icon-${mockCiStatus.group}`); + done(); + }); + }); + }); + + describe('When polling data was not succesful', () => { + beforeEach(() => { + mock = new MockAdapter(axios); + mock.onGet('/dummy/endpoint').reply(() => { + const res = Promise.reject([502, { }]); + return res; + }); + vm = new Component({ + props: { + endpoint: '/dummy/endpoint', + }, + }); + }); + + afterEach(() => { + vm.poll.stop(); + vm.$destroy(); + mock.restore(); + }); + + it('calls an errorCallback', (done) => { + spyOn(vm, 'errorCallback').and.callThrough(); + vm.$mount(); + setTimeout(() => { + expect(vm.errorCallback.calls.count()).toEqual(1); done(); }); }); |