Commit cf093daa authored by Scott Hampton's avatar Scott Hampton Committed by Jose Ivan Vargas

Show multiple builds for coverage

The code coverage number comes from
multiple builds, so we need to clarify to
the user where the number comes from.
parent e25d35f7
<script>
/* eslint-disable vue/require-default-prop, vue/no-v-html */
import { GlIcon, GlLink, GlLoadingIcon, GlSprintf, GlTooltipDirective } from '@gitlab/ui';
import {
GlIcon,
GlLink,
GlLoadingIcon,
GlSprintf,
GlTooltip,
GlTooltipDirective,
} from '@gitlab/ui';
import mrWidgetPipelineMixin from 'ee_else_ce/vue_merge_request_widget/mixins/mr_widget_pipeline';
import { s__ } from '~/locale';
import { s__, n__ } from '~/locale';
import PipelineStage from '~/pipelines/components/pipelines_list/stage.vue';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
......@@ -15,6 +22,7 @@ export default {
GlLoadingIcon,
GlIcon,
GlSprintf,
GlTooltip,
PipelineStage,
TooltipOnTruncate,
LinkedPipelinesMiniList: () =>
......@@ -33,6 +41,11 @@ export default {
type: String,
required: false,
},
buildsWithCoverage: {
type: Array,
required: false,
default: () => [],
},
// This prop needs to be camelCase, html attributes are case insensive
// https://vuejs.org/v2/guide/components.html#camelCase-vs-kebab-case
hasCi: {
......@@ -100,6 +113,16 @@ export default {
}
return '';
},
pipelineCoverageJobNumberText() {
return n__('from %d job', 'from %d jobs', this.buildsWithCoverage.length);
},
pipelineCoverageTooltipDescription() {
return n__(
'Coverage value for this pipeline was calculated by the coverage value of %d job.',
'Coverage value for this pipeline was calculated by averaging the resulting coverage values of %d jobs.',
this.buildsWithCoverage.length,
);
},
},
errorText: s__(
'Pipeline|Could not retrieve the pipeline status. For troubleshooting steps, read the %{linkStart}documentation%{linkEnd}.',
......@@ -139,7 +162,7 @@ export default {
>
<gl-icon
name="question"
:small="12"
:size="12"
tabindex="0"
role="text"
:aria-label="__('Link to go to GitLab pipeline documentation')"
......@@ -189,14 +212,30 @@ export default {
</div>
<div v-if="pipeline.coverage" class="coverage" data-testid="pipeline-coverage">
{{ s__('Pipeline|Coverage') }} {{ pipeline.coverage }}%
<span
v-if="pipelineCoverageDelta"
:class="coverageDeltaClass"
data-testid="pipeline-coverage-delta"
>({{ pipelineCoverageDelta }}%)</span
>
({{ pipelineCoverageDelta }}%)
{{ pipelineCoverageJobNumberText }}
<span ref="pipelineCoverageQuestion">
<gl-icon name="question" :size="12" />
</span>
<gl-tooltip
:target="() => $refs.pipelineCoverageQuestion"
data-testid="pipeline-coverage-tooltip"
>
{{ pipelineCoverageTooltipDescription }}
<div
v-for="(build, index) in buildsWithCoverage"
:key="`${build.name}-${index}`"
class="gl-mt-3 gl-text-left gl-px-4"
>
{{ build.name }} ({{ build.coverage }}%)
</div>
</gl-tooltip>
</div>
</div>
</div>
......
......@@ -77,6 +77,7 @@ export default {
<mr-widget-pipeline
:pipeline="pipeline"
:pipeline-coverage-delta="mr.pipelineCoverageDelta"
:builds-with-coverage="mr.buildsWithCoverage"
:ci-status="mr.ciStatus"
:has-ci="mr.hasCI"
:pipeline-must-succeed="mr.onlyAllowMergeIfPipelineSucceeds"
......
......@@ -52,6 +52,7 @@ export default class MergeRequestStore {
this.divergedCommitsCount = data.diverged_commits_count;
this.pipeline = data.pipeline || {};
this.pipelineCoverageDelta = data.pipeline_coverage_delta;
this.buildsWithCoverage = data.builds_with_coverage;
this.mergePipeline = data.merge_pipeline || {};
this.deployments = this.deployments || data.deployments || [];
this.postMergeDeployments = this.postMergeDeployments || [];
......
---
title: Show multiple jobs contributing to code coverage
merge_request: 41217
author:
type: added
......@@ -7102,6 +7102,11 @@ msgstr ""
msgid "Coverage Fuzzing"
msgstr ""
msgid "Coverage value for this pipeline was calculated by the coverage value of %d job."
msgid_plural "Coverage value for this pipeline was calculated by averaging the resulting coverage values of %d jobs."
msgstr[0] ""
msgstr[1] ""
msgid "Create"
msgstr ""
......@@ -29512,6 +29517,11 @@ msgstr ""
msgid "from"
msgstr ""
msgid "from %d job"
msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
msgid "group"
msgstr ""
......
......@@ -29,6 +29,8 @@ describe('MRWidgetPipeline', () => {
const findAllPipelineStages = () => wrapper.findAll(PipelineStage);
const findPipelineCoverage = () => wrapper.find('[data-testid="pipeline-coverage"]');
const findPipelineCoverageDelta = () => wrapper.find('[data-testid="pipeline-coverage-delta"]');
const findPipelineCoverageTooltipText = () =>
wrapper.find('[data-testid="pipeline-coverage-tooltip"]').text();
const findMonitoringPipelineMessage = () =>
wrapper.find('[data-testid="monitoring-pipeline-message"]');
const findLoadingIcon = () => wrapper.find(GlLoadingIcon);
......@@ -140,6 +142,7 @@ describe('MRWidgetPipeline', () => {
createWrapper(
{
pipelineCoverageDelta: mockData.pipelineCoverageDelta,
buildsWithCoverage: mockData.buildsWithCoverage,
},
mount,
);
......@@ -178,6 +181,22 @@ describe('MRWidgetPipeline', () => {
expect(findPipelineCoverageDelta().exists()).toBe(true);
expect(findPipelineCoverageDelta().text()).toBe(`(${mockData.pipelineCoverageDelta}%)`);
});
it('should render tooltip for jobs contributing to code coverage', () => {
const tooltipText = findPipelineCoverageTooltipText();
const expectedDescription = `Coverage value for this pipeline was calculated by averaging the resulting coverage values of ${mockData.buildsWithCoverage.length} jobs.`;
expect(tooltipText).toContain(expectedDescription);
});
it.each(mockData.buildsWithCoverage)(
'should have name and coverage for build %s listed in tooltip',
build => {
const tooltipText = findPipelineCoverageTooltipText();
expect(tooltipText).toContain(`${build.name} (${build.coverage}%)`);
},
);
});
describe('without commit path', () => {
......
......@@ -193,6 +193,7 @@ export default {
updated_at: '2017-04-07T15:28:44.800Z',
},
pipelineCoverageDelta: '15.25',
buildsWithCoverage: [{ name: 'karma', coverage: '40.2' }, { name: 'rspec', coverage: '80.4' }],
work_in_progress: false,
source_branch_exists: false,
mergeable_discussions_state: 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