Commit 1123d9dc authored by Jose Ivan Vargas's avatar Jose Ivan Vargas

Added more tests and corrected typos

parent 449b0eba
...@@ -5,7 +5,6 @@ import TreeView from '~/tree'; ...@@ -5,7 +5,6 @@ import TreeView from '~/tree';
import BlobViewer from '~/blob/viewer/index'; import BlobViewer from '~/blob/viewer/index';
import Activities from '~/activities'; import Activities from '~/activities';
import { ajaxGet } from '~/lib/utils/common_utils'; import { ajaxGet } from '~/lib/utils/common_utils';
import commitPipelineStatus from '~/projects/tree/components/commit_pipeline_status_component.vue';
import Star from '../../../star'; import Star from '../../../star';
import notificationsDropdown from '../../../notifications_dropdown'; import notificationsDropdown from '../../../notifications_dropdown';
......
...@@ -15,24 +15,23 @@ export default () => { ...@@ -15,24 +15,23 @@ export default () => {
ajaxGet(document.querySelector('.js-tree-content').dataset.logsPath)); ajaxGet(document.querySelector('.js-tree-content').dataset.logsPath));
const commitPipelineStatusEl = document.getElementById('commit-pipeline-status'); const commitPipelineStatusEl = document.getElementById('commit-pipeline-status');
const $statusLink = $('.ci-status-link'); const statusLink = document.querySelector('.commit-actions .ci-status-link');
if ($statusLink.length > 0) { if (statusLink != null) {
$statusLink.remove(); 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,
},
});
},
});
}; };
<script> <script>
import Visibility from 'visibilityjs'; import Visibility from 'visibilityjs';
import ciIcon from '~/vue_shared/components/ci_icon.vue'; 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 Poll from '~/lib/utils/poll';
import Flash from '~/flash'; import Flash from '~/flash';
import { s__, sprintf } from '~/locale';
import tooltip from '~/vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
import CommitPipelineService from '../services/commit_pipeline_service'; import CommitPipelineService from '../services/commit_pipeline_service';
...@@ -12,46 +14,54 @@ ...@@ -12,46 +14,54 @@
}, },
components: { components: {
ciIcon, ciIcon,
loadingIcon,
}, },
props: { props: {
endpoint: { endpoint: {
type: String, type: String,
required: true, 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: { realtime: {
type: Boolean, type: Boolean,
required: false, required: false,
default: true, default: true,
}, }, */
}, },
data() { data() {
return { return {
ciStatus: {}, ciStatus: {},
isLoading: true, isLoading: true,
service: {},
stageTitle: '',
}; };
}, },
computed: {
statusTitle() {
return sprintf(s__('Commits|Commit: %{commitText}'), { commitText: this.ciStatus.text });
},
},
mounted() { mounted() {
this.service = new CommitPipelineService(this.endpoint); this.service = new CommitPipelineService(this.endpoint);
if (this.realtime) { this.initPolling();
this.initPolling();
} else {
this.fetchPipelineCommitData();
}
}, },
methods: { methods: {
successCallback(res) { successCallback(res) {
if (res.data.pipelines.length > 0) { const pipelines = res.data.pipelines;
this.ciStatus = res.data.pipelines[0].details.stages[0].status; if (pipelines.length > 0) {
this.stageTitle = res.data.pipelines[0].details.stages[0].title; // The pipeline entity always keeps the latest pipeline info on the `details.status`
this.isLoading = false; this.ciStatus = pipelines[0].details.status;
} else {
this.isLoading = true;
} }
this.isLoading = false;
}, },
errorCallback(err) { errorCallback() {
Flash(err); this.ciStatus = {
text: 'not found',
icon: 'status_notfound',
group: 'notfound',
};
this.isLoading = false;
Flash(s__('Something went wrong on our end'));
}, },
initPolling() { initPolling() {
this.poll = new Poll({ this.poll = new Poll({
...@@ -78,8 +88,8 @@ ...@@ -78,8 +88,8 @@
}, },
fetchPipelineCommitData() { fetchPipelineCommitData() {
this.service.fetchData() this.service.fetchData()
.then(this.successCallback) .then(this.successCallback)
.catch(this.errorCallback); .catch(this.errorCallback);
}, },
}, },
destroy() { destroy() {
...@@ -88,19 +98,23 @@ ...@@ -88,19 +98,23 @@
}; };
</script> </script>
<template> <template>
<div <div>
v-if="isLoading"> <loading-icon
</div> label="Loading pipeline status"
<a size="3"
v-else v-if="isLoading"
:href="ciStatus.details_path"
>
<ci-icon
v-tooltip
:title="stageTitle"
:aria-label="stageTitle"
data-container="body"
:status="ciStatus"
/> />
</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> </template>
...@@ -196,6 +196,14 @@ ...@@ -196,6 +196,14 @@
@media (min-width: $screen-sm-min) { @media (min-width: $screen-sm-min) {
font-size: 0; font-size: 0;
div {
display: inline;
}
.fa-spinner {
font-size: 12px;
}
span { span {
font-size: 6px; font-size: 6px;
} }
...@@ -226,7 +234,7 @@ ...@@ -226,7 +234,7 @@
.ci-status-icon { .ci-status-icon {
position: relative; position: relative;
top: 3px; top: 1px;
} }
} }
......
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
- if commit.status(ref) - if commit.status(ref)
= render_commit_status(commit, ref: 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" = 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")) = clipboard_button(text: commit.id, title: _("Copy commit SHA to clipboard"))
= link_to_browse_code(project, commit) = link_to_browse_code(project, commit)
......
...@@ -23,7 +23,6 @@ Feature: Project ...@@ -23,7 +23,6 @@ Feature: Project
And I visit project "Shop" page And I visit project "Shop" page
Then I should see project "Shop" README Then I should see project "Shop" README
@javascript
Scenario: I should see last commit with CI Scenario: I should see last commit with CI
Given project "Shop" has CI enabled Given project "Shop" has CI enabled
Given project "Shop" has CI build Given project "Shop" has CI build
......
...@@ -218,7 +218,6 @@ module SharedProject ...@@ -218,7 +218,6 @@ module SharedProject
end end
step 'I should see last commit with CI status' do step 'I should see last commit with CI status' do
sleep 2
page.within ".blob-commit-info" do page.within ".blob-commit-info" do
expect(page).to have_content(project.commit.sha[0..6]) expect(page).to have_content(project.commit.sha[0..6])
expect(page).to have_link("Commit: skipped") expect(page).to have_link("Commit: skipped")
......
...@@ -6,7 +6,7 @@ import mountComponent from '../helpers/vue_mount_component_helper'; ...@@ -6,7 +6,7 @@ import mountComponent from '../helpers/vue_mount_component_helper';
describe('Commit pipeline status component', () => { describe('Commit pipeline status component', () => {
let vm; let vm;
let component; let Component;
let mock; let mock;
const mockCiStatus = { const mockCiStatus = {
details_path: '/root/hello-world/pipelines/1', details_path: '/root/hello-world/pipelines/1',
...@@ -19,34 +19,25 @@ describe('Commit pipeline status component', () => { ...@@ -19,34 +19,25 @@ describe('Commit pipeline status component', () => {
}; };
beforeEach(() => { beforeEach(() => {
mock = new MockAdapter(axios); Component = Vue.extend(commitPipelineStatus);
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();
}); });
describe('While polling pipeline data', () => { describe('While polling pipeline data succesfully', () => {
beforeEach(() => { 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', endpoint: '/dummy/endpoint',
}); });
}); });
...@@ -54,18 +45,58 @@ describe('Commit pipeline status component', () => { ...@@ -54,18 +45,58 @@ describe('Commit pipeline status component', () => {
afterEach(() => { afterEach(() => {
vm.poll.stop(); vm.poll.stop();
vm.$destroy(); 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) => { it('contains a ciStatus when the polling is succesful ', (done) => {
setTimeout(() => { setTimeout(() => {
expect(vm.ciStatus).toEqual(mockCiStatus); expect(vm.ciStatus).toEqual(mockCiStatus);
done(); done();
}, 1000); });
}); });
it('contains a ci-status icon when polling is succesful', (done) => { it('contains a ci-status icon when polling is succesful', (done) => {
setTimeout(() => { setTimeout(() => {
expect(vm.$el.querySelector('.ci-status-icon')).not.toBe(null); 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(); done();
}); });
}); });
......
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