Commit 20ba7d9c authored by Phil Hughes's avatar Phil Hughes

Merge branch 'ee-30286-ci-badge-component' into 'master'

Port of 30286-ci-badge-component to EE

See merge request !1878
parents efb3f52f 877f3e27
/* global Flash */
import { statusClassToSvgMap } from '../../vue_shared/pipeline_svg_icons';
export default {
props: {
stage: {
type: Object,
required: true,
},
},
data() {
return {
builds: '',
spinner: '<span class="fa fa-spinner fa-spin"></span>',
};
},
updated() {
if (this.builds) {
this.stopDropdownClickPropagation();
}
},
methods: {
fetchBuilds(e) {
const ariaExpanded = e.currentTarget.attributes['aria-expanded'];
if (ariaExpanded && (ariaExpanded.textContent === 'true')) return null;
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;
});
},
/**
* When the user right clicks or cmd/ctrl + click in the job name
* the dropdown should not be closed and the link should open in another tab,
* so we stop propagation of the click event inside the dropdown.
*
* Since this component is rendered multiple times per page we need to guarantee we only
* 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();
});
},
},
computed: {
buildsOrSpinner() {
return this.builds ? this.builds : this.spinner;
},
dropdownClass() {
if (this.builds) return 'js-builds-dropdown-container';
return 'js-builds-dropdown-loading builds-dropdown-loading';
},
buildStatus() {
return `Build: ${this.stage.status.label}`;
},
tooltip() {
return `has-tooltip ci-status-icon ci-status-icon-${this.stage.status.group}`;
},
triggerButtonClass() {
return `mini-pipeline-graph-dropdown-toggle has-tooltip js-builds-dropdown-button ci-status-icon-${this.stage.status.group}`;
},
svgHTML() {
return statusClassToSvgMap[this.stage.status.icon];
},
},
watch: {
'stage.title': function stageTitle() {
$(this.$refs.button).tooltip('destroy').tooltip();
},
},
template: `
<div>
<button
@click="fetchBuilds($event)"
:class="triggerButtonClass"
:title="stage.title"
data-placement="top"
data-toggle="dropdown"
type="button"
: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
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"
v-html="buildsOrSpinner">
</div>
</ul>
</div>
`,
};
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
*/ */
/* global Flash */ /* global Flash */
import { statusClassToSvgMap } from '../../vue_shared/pipeline_svg_icons'; import { borderlessStatusIconEntityMap } from '../../vue_shared/ci_status_icons';
export default { export default {
props: { props: {
...@@ -113,7 +113,7 @@ export default { ...@@ -113,7 +113,7 @@ export default {
}, },
svgIcon() { svgIcon() {
return statusClassToSvgMap[this.stage.status.icon]; return borderlessStatusIconEntityMap[this.stage.status.icon];
}, },
}, },
}; };
......
import canceledSvg from 'icons/_icon_status_canceled.svg';
import createdSvg from 'icons/_icon_status_created.svg';
import failedSvg from 'icons/_icon_status_failed.svg';
import manualSvg from 'icons/_icon_status_manual.svg';
import pendingSvg from 'icons/_icon_status_pending.svg';
import runningSvg from 'icons/_icon_status_running.svg';
import skippedSvg from 'icons/_icon_status_skipped.svg';
import successSvg from 'icons/_icon_status_success.svg';
import warningSvg from 'icons/_icon_status_warning.svg';
export default {
props: {
pipeline: {
type: Object,
required: true,
},
},
data() {
const svgsDictionary = {
icon_status_canceled: canceledSvg,
icon_status_created: createdSvg,
icon_status_failed: failedSvg,
icon_status_manual: manualSvg,
icon_status_pending: pendingSvg,
icon_status_running: runningSvg,
icon_status_skipped: skippedSvg,
icon_status_success: successSvg,
icon_status_warning: warningSvg,
};
return {
svg: svgsDictionary[this.pipeline.details.status.icon],
};
},
computed: {
cssClasses() {
return `ci-status ci-${this.pipeline.details.status.group}`;
},
detailsPath() {
const { status } = this.pipeline.details;
return status.has_details ? status.details_path : false;
},
content() {
return `${this.svg} ${this.pipeline.details.status.text}`;
},
},
template: `
<td class="commit-link">
<a
:class="cssClasses"
:href="detailsPath"
v-html="content">
</a>
</td>
`,
};
/* global Flash */ /* global Flash */
import '~/lib/utils/datetime_utility'; import '~/lib/utils/datetime_utility';
import { statusClassToSvgMap } from '../../vue_shared/pipeline_svg_icons'; import { statusIconEntityMap } from '../../vue_shared/ci_status_icons';
import MemoryUsage from './mr_widget_memory_usage'; import MemoryUsage from './mr_widget_memory_usage';
import MRWidgetService from '../services/mr_widget_service'; import MRWidgetService from '../services/mr_widget_service';
...@@ -16,7 +16,7 @@ export default { ...@@ -16,7 +16,7 @@ export default {
}, },
computed: { computed: {
svg() { svg() {
return statusClassToSvgMap.icon_status_success; return statusIconEntityMap.icon_status_success;
}, },
}, },
methods: { methods: {
......
import PipelineStage from '../../pipelines/components/stage'; import PipelineStage from '../../pipelines/components/stage.vue';
import pipelineStatusIcon from '../../vue_shared/components/pipeline_status_icon'; import ciIcon from '../../vue_shared/components/ci_icon.vue';
import { statusClassToSvgMap } from '../../vue_shared/pipeline_svg_icons'; import { statusIconEntityMap } from '../../vue_shared/ci_status_icons';
export default { export default {
name: 'MRWidgetPipeline', name: 'MRWidgetPipeline',
...@@ -9,7 +9,7 @@ export default { ...@@ -9,7 +9,7 @@ export default {
}, },
components: { components: {
'pipeline-stage': PipelineStage, 'pipeline-stage': PipelineStage,
'pipeline-status-icon': pipelineStatusIcon, ciIcon,
}, },
computed: { computed: {
hasCIError() { hasCIError() {
...@@ -18,11 +18,17 @@ export default { ...@@ -18,11 +18,17 @@ export default {
return hasCI && !ciStatus; return hasCI && !ciStatus;
}, },
svg() { svg() {
return statusClassToSvgMap.icon_status_failed; return statusIconEntityMap.icon_status_failed;
}, },
stageText() { stageText() {
return this.mr.pipeline.details.stages.length > 1 ? 'stages' : 'stage'; return this.mr.pipeline.details.stages.length > 1 ? 'stages' : 'stage';
}, },
status() {
return this.mr.pipeline.details.status || {};
},
statusPath() {
return this.status ? this.status.details_path : '';
},
}, },
template: ` template: `
<div class="mr-widget-heading"> <div class="mr-widget-heading">
...@@ -38,7 +44,13 @@ export default { ...@@ -38,7 +44,13 @@ export default {
<span>Could not connect to the CI server. Please check your settings and try again.</span> <span>Could not connect to the CI server. Please check your settings and try again.</span>
</template> </template>
<template v-else> <template v-else>
<pipeline-status-icon :pipelineStatus="mr.pipelineDetailedStatus" /> <div>
<a
class="icon-link"
:href="statusPath">
<ci-icon :status="status" />
</a>
</div>
<span> <span>
Pipeline Pipeline
<a <a
......
import BORDERLESS_CANCELED_SVG from 'icons/_icon_status_canceled_borderless.svg';
import BORDERLESS_CREATED_SVG from 'icons/_icon_status_created_borderless.svg';
import BORDERLESS_FAILED_SVG from 'icons/_icon_status_failed_borderless.svg';
import BORDERLESS_MANUAL_SVG from 'icons/_icon_status_manual_borderless.svg';
import BORDERLESS_PENDING_SVG from 'icons/_icon_status_pending_borderless.svg';
import BORDERLESS_RUNNING_SVG from 'icons/_icon_status_running_borderless.svg';
import BORDERLESS_SKIPPED_SVG from 'icons/_icon_status_skipped_borderless.svg';
import BORDERLESS_SUCCESS_SVG from 'icons/_icon_status_success_borderless.svg';
import BORDERLESS_WARNING_SVG from 'icons/_icon_status_warning_borderless.svg';
import CANCELED_SVG from 'icons/_icon_status_canceled.svg';
import CREATED_SVG from 'icons/_icon_status_created.svg';
import FAILED_SVG from 'icons/_icon_status_failed.svg';
import MANUAL_SVG from 'icons/_icon_status_manual.svg';
import PENDING_SVG from 'icons/_icon_status_pending.svg';
import RUNNING_SVG from 'icons/_icon_status_running.svg';
import SKIPPED_SVG from 'icons/_icon_status_skipped.svg';
import SUCCESS_SVG from 'icons/_icon_status_success.svg';
import WARNING_SVG from 'icons/_icon_status_warning.svg';
export const borderlessStatusIconEntityMap = {
icon_status_canceled: BORDERLESS_CANCELED_SVG,
icon_status_created: BORDERLESS_CREATED_SVG,
icon_status_failed: BORDERLESS_FAILED_SVG,
icon_status_manual: BORDERLESS_MANUAL_SVG,
icon_status_pending: BORDERLESS_PENDING_SVG,
icon_status_running: BORDERLESS_RUNNING_SVG,
icon_status_skipped: BORDERLESS_SKIPPED_SVG,
icon_status_success: BORDERLESS_SUCCESS_SVG,
icon_status_warning: BORDERLESS_WARNING_SVG,
};
export const statusIconEntityMap = {
icon_status_canceled: CANCELED_SVG,
icon_status_created: CREATED_SVG,
icon_status_failed: FAILED_SVG,
icon_status_manual: MANUAL_SVG,
icon_status_pending: PENDING_SVG,
icon_status_running: RUNNING_SVG,
icon_status_skipped: SKIPPED_SVG,
icon_status_success: SUCCESS_SVG,
icon_status_warning: WARNING_SVG,
};
<script>
import ciIcon from './ci_icon.vue';
/**
* Renders CI Badge link with CI icon and status text based on
* API response shared between all places where it is used.
*
* Receives status object containing:
* status: {
* details_path: "/gitlab-org/gitlab-ce/pipelines/8150156" // url
* group:"running" // used for CSS class
* icon: "icon_status_running" // used to render the icon
* label:"running" // used for potential tooltip
* text:"running" // text rendered
* }
*
* Shared between:
* - Pipelines table - first column
* - Jobs table - first column
* - Pipeline show view - header
* - Job show view - header
* - MR widget
*/
export default {
props: {
status: {
type: Object,
required: true,
},
},
components: {
ciIcon,
},
computed: {
cssClass() {
const className = this.status.group;
return className ? `ci-status ci-${this.status.group}` : 'ci-status';
},
},
};
</script>
<template>
<a
:href="status.details_path"
:class="cssClass">
<ci-icon :status="status" />
{{status.text}}
</a>
</template>
<script>
import { statusIconEntityMap } from '../ci_status_icons';
/**
* Renders CI icon based on API response shared between all places where it is used.
*
* Receives status object containing:
* status: {
* details_path: "/gitlab-org/gitlab-ce/pipelines/8150156" // url
* group:"running" // used for CSS class
* icon: "icon_status_running" // used to render the icon
* label:"running" // used for potential tooltip
* text:"running" // text rendered
* }
*
* Used in:
* - Pipelines table Badge
* - Pipelines table mini graph
* - Pipeline graph
* - Pipeline show view badge
* - Jobs table
* - Jobs show view header
* - Jobs show view sidebar
*/
export default {
props: {
status: {
type: Object,
required: true,
},
},
computed: {
statusIconSvg() {
return statusIconEntityMap[this.status.icon];
},
cssClass() {
const status = this.status.group;
return `ci-status-icon ci-status-icon-${status} js-ci-status-icon-${status}`;
},
},
};
</script>
<template>
<span
:class="cssClass"
v-html="statusIconSvg">
</span>
</template>
import { statusClassToSvgMap } from '../pipeline_svg_icons';
export default {
name: 'PipelineStatusIcon',
props: {
pipelineStatus: { type: Object, required: true, default: () => ({}) },
},
computed: {
svg() {
return statusClassToSvgMap[this.pipelineStatus.icon];
},
statusClass() {
return `ci-status-icon ci-status-icon-${this.pipelineStatus.group}`;
},
},
template: `
<div :class="statusClass">
<a class="icon-link" :href="pipelineStatus.details_path">
<span v-html="svg" aria-hidden="true"></span>
</a>
</div>
`,
};
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
import AsyncButtonComponent from '../../pipelines/components/async_button.vue'; import AsyncButtonComponent from '../../pipelines/components/async_button.vue';
import PipelinesActionsComponent from '../../pipelines/components/pipelines_actions'; import PipelinesActionsComponent from '../../pipelines/components/pipelines_actions';
import PipelinesArtifactsComponent from '../../pipelines/components/pipelines_artifacts'; import PipelinesArtifactsComponent from '../../pipelines/components/pipelines_artifacts';
import PipelinesStatusComponent from '../../pipelines/components/status'; import ciBadge from './ci_badge_link.vue';
import PipelinesStageComponent from '../../pipelines/components/stage.vue'; import PipelinesStageComponent from '../../pipelines/components/stage.vue';
import PipelinesUrlComponent from '../../pipelines/components/pipeline_url'; import PipelinesUrlComponent from '../../pipelines/components/pipeline_url';
import PipelinesTimeagoComponent from '../../pipelines/components/time_ago'; import PipelinesTimeagoComponent from '../../pipelines/components/time_ago';
...@@ -39,7 +39,7 @@ export default { ...@@ -39,7 +39,7 @@ export default {
'commit-component': CommitComponent, 'commit-component': CommitComponent,
'dropdown-stage': PipelinesStageComponent, 'dropdown-stage': PipelinesStageComponent,
'pipeline-url': PipelinesUrlComponent, 'pipeline-url': PipelinesUrlComponent,
'status-scope': PipelinesStatusComponent, ciBadge,
'time-ago': PipelinesTimeagoComponent, 'time-ago': PipelinesTimeagoComponent,
}, },
...@@ -197,11 +197,20 @@ export default { ...@@ -197,11 +197,20 @@ export default {
return ''; return '';
}, },
pipelineStatus() {
if (this.pipeline.details && this.pipeline.details.status) {
return this.pipeline.details.status;
}
return {};
},
}, },
template: ` template: `
<tr class="commit"> <tr class="commit">
<status-scope :pipeline="pipeline"/> <td class="commit-link">
<ci-badge :status="pipelineStatus"/>
</td>
<pipeline-url :pipeline="pipeline"></pipeline-url> <pipeline-url :pipeline="pipeline"></pipeline-url>
......
import canceledSvg from 'icons/_icon_status_canceled.svg';
import createdSvg from 'icons/_icon_status_created.svg';
import failedSvg from 'icons/_icon_status_failed.svg';
import manualSvg from 'icons/_icon_status_manual.svg';
import pendingSvg from 'icons/_icon_status_pending.svg';
import runningSvg from 'icons/_icon_status_running.svg';
import skippedSvg from 'icons/_icon_status_skipped.svg';
import successSvg from 'icons/_icon_status_success.svg';
import warningSvg from 'icons/_icon_status_warning.svg';
import canceledBorderlessSvg from 'icons/_icon_status_canceled_borderless.svg';
import createdBorderlessSvg from 'icons/_icon_status_created_borderless.svg';
import failedBorderlessSvg from 'icons/_icon_status_failed_borderless.svg';
import manualBorderlessSvg from 'icons/_icon_status_manual_borderless.svg';
import pendingBorderlessSvg from 'icons/_icon_status_pending_borderless.svg';
import runningBorderlessSvg from 'icons/_icon_status_running_borderless.svg';
import skippedBorderlessSvg from 'icons/_icon_status_skipped_borderless.svg';
import successBorderlessSvg from 'icons/_icon_status_success_borderless.svg';
import warningBorderlessSvg from 'icons/_icon_status_warning_borderless.svg';
export const statusClassToSvgMap = {
icon_status_canceled: canceledSvg,
icon_status_created: createdSvg,
icon_status_failed: failedSvg,
icon_status_manual: manualSvg,
icon_status_pending: pendingSvg,
icon_status_running: runningSvg,
icon_status_skipped: skippedSvg,
icon_status_success: successSvg,
icon_status_warning: warningSvg,
};
export const statusClassToBorderlessSvgMap = {
icon_status_canceled: canceledBorderlessSvg,
icon_status_created: createdBorderlessSvg,
icon_status_failed: failedBorderlessSvg,
icon_status_manual: manualBorderlessSvg,
icon_status_pending: pendingBorderlessSvg,
icon_status_running: runningBorderlessSvg,
icon_status_skipped: skippedBorderlessSvg,
icon_status_success: successBorderlessSvg,
icon_status_warning: warningBorderlessSvg,
};
...@@ -90,11 +90,6 @@ ...@@ -90,11 +90,6 @@
align-items: center; align-items: center;
padding: $gl-padding-top $gl-padding 0; padding: $gl-padding-top $gl-padding 0;
i,
svg {
margin-right: 8px;
}
svg { svg {
position: relative; position: relative;
top: 1px; top: 1px;
...@@ -109,9 +104,10 @@ ...@@ -109,9 +104,10 @@
flex-wrap: wrap; flex-wrap: wrap;
} }
.ci-status-icon > .icon-link svg { .icon-link > .ci-status-icon > svg {
width: 22px; width: 22px;
height: 22px; height: 22px;
margin-right: 8px;
} }
} }
......
---
title: Refactor all CI vue badges to use the same vue component
merge_request:
author:
import Vue from 'vue'; import Vue from 'vue';
import deploymentComponent from '~/vue_merge_request_widget/components/mr_widget_deployment'; import deploymentComponent from '~/vue_merge_request_widget/components/mr_widget_deployment';
import MRWidgetService from '~/vue_merge_request_widget/services/mr_widget_service'; import MRWidgetService from '~/vue_merge_request_widget/services/mr_widget_service';
import { statusClassToSvgMap } from '~/vue_shared/pipeline_svg_icons'; import { statusIconEntityMap } from '~/vue_shared/ci_status_icons';
const deploymentMockData = [ const deploymentMockData = [
{ {
...@@ -45,7 +45,7 @@ describe('MRWidgetDeployment', () => { ...@@ -45,7 +45,7 @@ describe('MRWidgetDeployment', () => {
describe('svg', () => { describe('svg', () => {
it('should have the proper SVG icon', () => { it('should have the proper SVG icon', () => {
const vm = createComponent(deploymentMockData); const vm = createComponent(deploymentMockData);
expect(vm.svg).toEqual(statusClassToSvgMap.icon_status_success); expect(vm.svg).toEqual(statusIconEntityMap.icon_status_success);
}); });
}); });
}); });
......
import Vue from 'vue'; import Vue from 'vue';
import { statusClassToSvgMap } from '~/vue_shared/pipeline_svg_icons'; import { statusIconEntityMap } from '~/vue_shared/ci_status_icons';
import pipelineComponent from '~/vue_merge_request_widget/components/mr_widget_pipeline'; import pipelineComponent from '~/vue_merge_request_widget/components/mr_widget_pipeline';
import mockData from '../mock_data'; import mockData from '../mock_data';
...@@ -24,7 +24,7 @@ describe('MRWidgetPipeline', () => { ...@@ -24,7 +24,7 @@ describe('MRWidgetPipeline', () => {
describe('components', () => { describe('components', () => {
it('should have components added', () => { it('should have components added', () => {
expect(pipelineComponent.components['pipeline-stage']).toBeDefined(); expect(pipelineComponent.components['pipeline-stage']).toBeDefined();
expect(pipelineComponent.components['pipeline-status-icon']).toBeDefined(); expect(pipelineComponent.components.ciIcon).toBeDefined();
}); });
}); });
...@@ -33,7 +33,7 @@ describe('MRWidgetPipeline', () => { ...@@ -33,7 +33,7 @@ describe('MRWidgetPipeline', () => {
it('should have the proper SVG icon', () => { it('should have the proper SVG icon', () => {
const vm = createComponent({ pipeline: mockData.pipeline }); const vm = createComponent({ pipeline: mockData.pipeline });
expect(vm.svg).toEqual(statusClassToSvgMap.icon_status_failed); expect(vm.svg).toEqual(statusIconEntityMap.icon_status_failed);
}); });
}); });
......
import Vue from 'vue';
import ciBadge from '~/vue_shared/components/ci_badge_link.vue';
describe('CI Badge Link Component', () => {
let CIBadge;
const statuses = {
canceled: {
text: 'canceled',
label: 'canceled',
group: 'canceled',
icon: 'icon_status_canceled',
details_path: 'status/canceled',
},
created: {
text: 'created',
label: 'created',
group: 'created',
icon: 'icon_status_created',
details_path: 'status/created',
},
failed: {
text: 'failed',
label: 'failed',
group: 'failed',
icon: 'icon_status_failed',
details_path: 'status/failed',
},
manual: {
text: 'manual',
label: 'manual action',
group: 'manual',
icon: 'icon_status_manual',
details_path: 'status/manual',
},
pending: {
text: 'pending',
label: 'pending',
group: 'pending',
icon: 'icon_status_pending',
details_path: 'status/pending',
},
running: {
text: 'running',
label: 'running',
group: 'running',
icon: 'icon_status_running',
details_path: 'status/running',
},
skipped: {
text: 'skipped',
label: 'skipped',
group: 'skipped',
icon: 'icon_status_skipped',
details_path: 'status/skipped',
},
success_warining: {
text: 'passed',
label: 'passed',
group: 'success_with_warnings',
icon: 'icon_status_warning',
details_path: 'status/warning',
},
success: {
text: 'passed',
label: 'passed',
group: 'passed',
icon: 'icon_status_success',
details_path: 'status/passed',
},
};
it('should render each status badge', () => {
CIBadge = Vue.extend(ciBadge);
Object.keys(statuses).map((status) => {
const vm = new CIBadge({
propsData: {
status: statuses[status],
},
}).$mount();
expect(vm.$el.getAttribute('href')).toEqual(statuses[status].details_path);
expect(vm.$el.textContent.trim()).toEqual(statuses[status].text);
expect(vm.$el.getAttribute('class')).toEqual(`ci-status ci-${statuses[status].group}`);
expect(vm.$el.querySelector('svg')).toBeDefined();
return vm;
});
});
});
import Vue from 'vue';
import ciIcon from '~/vue_shared/components/ci_icon.vue';
describe('CI Icon component', () => {
let CiIcon;
beforeEach(() => {
CiIcon = Vue.extend(ciIcon);
});
it('should render a span element with an svg', () => {
const component = new CiIcon({
propsData: {
status: {
icon: 'icon_status_success',
},
},
}).$mount();
expect(component.$el.tagName).toEqual('SPAN');
expect(component.$el.querySelector('span > svg')).toBeDefined();
});
it('should render a success status', () => {
const component = new CiIcon({
propsData: {
status: {
icon: 'icon_status_success',
group: 'success',
},
},
}).$mount();
expect(component.$el.classList.contains('ci-status-icon-success')).toEqual(true);
});
it('should render a failed status', () => {
const component = new CiIcon({
propsData: {
status: {
icon: 'icon_status_failed',
group: 'failed',
},
},
}).$mount();
expect(component.$el.classList.contains('ci-status-icon-failed')).toEqual(true);
});
it('should render success with warnings status', () => {
const component = new CiIcon({
propsData: {
status: {
icon: 'icon_status_warning',
group: 'warning',
},
},
}).$mount();
expect(component.$el.classList.contains('ci-status-icon-warning')).toEqual(true);
});
it('should render pending status', () => {
const component = new CiIcon({
propsData: {
status: {
icon: 'icon_status_pending',
group: 'pending',
},
},
}).$mount();
expect(component.$el.classList.contains('ci-status-icon-pending')).toEqual(true);
});
it('should render running status', () => {
const component = new CiIcon({
propsData: {
status: {
icon: 'icon_status_running',
group: 'running',
},
},
}).$mount();
expect(component.$el.classList.contains('ci-status-icon-running')).toEqual(true);
});
it('should render created status', () => {
const component = new CiIcon({
propsData: {
status: {
icon: 'icon_status_created',
group: 'created',
},
},
}).$mount();
expect(component.$el.classList.contains('ci-status-icon-created')).toEqual(true);
});
it('should render skipped status', () => {
const component = new CiIcon({
propsData: {
status: {
icon: 'icon_status_skipped',
group: 'skipped',
},
},
}).$mount();
expect(component.$el.classList.contains('ci-status-icon-skipped')).toEqual(true);
});
it('should render canceled status', () => {
const component = new CiIcon({
propsData: {
status: {
icon: 'icon_status_canceled',
group: 'canceled',
},
},
}).$mount();
expect(component.$el.classList.contains('ci-status-icon-canceled')).toEqual(true);
});
it('should render status for manual action', () => {
const component = new CiIcon({
propsData: {
status: {
icon: 'icon_status_manual',
group: 'manual',
},
},
}).$mount();
expect(component.$el.classList.contains('ci-status-icon-manual')).toEqual(true);
});
});
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