diff options
Diffstat (limited to 'spec/frontend/vue_merge_request_widget/components/mr_widget_pipeline_spec.js')
-rw-r--r-- | spec/frontend/vue_merge_request_widget/components/mr_widget_pipeline_spec.js | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/spec/frontend/vue_merge_request_widget/components/mr_widget_pipeline_spec.js b/spec/frontend/vue_merge_request_widget/components/mr_widget_pipeline_spec.js new file mode 100644 index 00000000000..6347e3c3be3 --- /dev/null +++ b/spec/frontend/vue_merge_request_widget/components/mr_widget_pipeline_spec.js @@ -0,0 +1,282 @@ +import { GlLoadingIcon } from '@gitlab/ui'; +import { shallowMount, mount } from '@vue/test-utils'; +import axios from 'axios'; +import MockAdapter from 'axios-mock-adapter'; +import { trimText } from 'helpers/text_helper'; +import { extendedWrapper } from 'helpers/vue_test_utils_helper'; +import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_mini_graph.vue'; +import PipelineStage from '~/pipelines/components/pipelines_list/pipeline_stage.vue'; +import PipelineComponent from '~/vue_merge_request_widget/components/mr_widget_pipeline.vue'; +import { SUCCESS } from '~/vue_merge_request_widget/constants'; +import mockData from '../mock_data'; + +describe('MRWidgetPipeline', () => { + let wrapper; + + const defaultProps = { + pipeline: mockData.pipeline, + ciStatus: SUCCESS, + hasCi: true, + mrTroubleshootingDocsPath: 'help', + ciTroubleshootingDocsPath: 'ci-help', + }; + + const ciErrorMessage = + 'Could not retrieve the pipeline status. For troubleshooting steps, read the documentation.'; + const monitoringMessage = 'Checking pipeline status.'; + + const findCIErrorMessage = () => wrapper.findByTestId('ci-error-message'); + const findPipelineID = () => wrapper.findByTestId('pipeline-id'); + const findPipelineInfoContainer = () => wrapper.findByTestId('pipeline-info-container'); + const findCommitLink = () => wrapper.findByTestId('commit-link'); + const findPipelineFinishedAt = () => wrapper.findByTestId('finished-at'); + const findPipelineMiniGraph = () => wrapper.findComponent(PipelineMiniGraph); + const findAllPipelineStages = () => wrapper.findAllComponents(PipelineStage); + const findPipelineCoverage = () => wrapper.findByTestId('pipeline-coverage'); + const findPipelineCoverageDelta = () => wrapper.findByTestId('pipeline-coverage-delta'); + const findPipelineCoverageTooltipText = () => + wrapper.findByTestId('pipeline-coverage-tooltip').text(); + const findPipelineCoverageDeltaTooltipText = () => + wrapper.findByTestId('pipeline-coverage-delta-tooltip').text(); + const findMonitoringPipelineMessage = () => wrapper.findByTestId('monitoring-pipeline-message'); + const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); + + const mockArtifactsRequest = () => new MockAdapter(axios).onGet().reply(200, []); + + const createWrapper = (props = {}, mountFn = shallowMount) => { + wrapper = extendedWrapper( + mountFn(PipelineComponent, { + propsData: { + ...defaultProps, + ...props, + }, + }), + ); + }; + + afterEach(() => { + if (wrapper?.destroy) { + wrapper.destroy(); + wrapper = null; + } + }); + + it('should render CI error if there is a pipeline, but no status', () => { + createWrapper({ ciStatus: null }, mount); + expect(findCIErrorMessage().text()).toBe(ciErrorMessage); + }); + + it('should render a loading state when no pipeline is found', () => { + createWrapper({ pipeline: {} }, mount); + + expect(findMonitoringPipelineMessage().text()).toBe(monitoringMessage); + expect(findLoadingIcon().exists()).toBe(true); + }); + + describe('with a pipeline', () => { + beforeEach(() => { + mockArtifactsRequest(); + + createWrapper( + { + pipelineCoverageDelta: mockData.pipelineCoverageDelta, + buildsWithCoverage: mockData.buildsWithCoverage, + }, + mount, + ); + }); + + it('should render pipeline ID', () => { + expect(findPipelineID().text().trim()).toBe(`#${mockData.pipeline.id}`); + }); + + it('should render pipeline status and commit id', () => { + expect(findPipelineInfoContainer().text()).toMatch(mockData.pipeline.details.status.label); + + expect(findCommitLink().text().trim()).toBe(mockData.pipeline.commit.short_id); + + expect(findCommitLink().attributes('href')).toBe(mockData.pipeline.commit.commit_path); + }); + + it('should render pipeline finished timestamp', () => { + expect(findPipelineFinishedAt().attributes()).toMatchObject({ + title: 'Apr 7, 2017 2:00pm UTC', + datetime: mockData.pipeline.details.finished_at, + }); + }); + + it('should render pipeline graph', () => { + expect(findPipelineMiniGraph().exists()).toBe(true); + expect(findAllPipelineStages()).toHaveLength(mockData.pipeline.details.stages.length); + }); + + describe('should render pipeline coverage information', () => { + it('should render coverage percentage', () => { + expect(findPipelineCoverage().text()).toMatch( + `Test coverage ${mockData.pipeline.coverage}%`, + ); + }); + + it('should render coverage delta', () => { + 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 = `Test 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.each` + style | coverageState | coverageChangeText | styleClass | pipelineCoverageDelta + ${'no special'} | ${'the same'} | ${'not change'} | ${''} | ${'0'} + ${'success'} | ${'increased'} | ${'increase'} | ${'text-success'} | ${'10'} + ${'danger'} | ${'decreased'} | ${'decrease'} | ${'text-danger'} | ${'-10'} + `( + 'if test coverage is $coverageState', + ({ style, styleClass, coverageChangeText, pipelineCoverageDelta }) => { + it(`coverage delta should have ${style}`, () => { + createWrapper({ pipelineCoverageDelta }); + expect(findPipelineCoverageDelta().classes()).toEqual(styleClass ? [styleClass] : []); + }); + + it(`coverage delta tooltip should say that the coverage will ${coverageChangeText}`, () => { + createWrapper({ pipelineCoverageDelta }); + expect(findPipelineCoverageDeltaTooltipText()).toContain(coverageChangeText); + }); + }, + ); + }); + }); + + describe('without commit path', () => { + beforeEach(() => { + const mockCopy = JSON.parse(JSON.stringify(mockData)); + delete mockCopy.pipeline.commit; + + createWrapper({}, mount); + }); + + it('should render pipeline ID', () => { + expect(findPipelineID().text().trim()).toBe(`#${mockData.pipeline.id}`); + }); + + it('should render pipeline status', () => { + expect(findPipelineInfoContainer().text()).toMatch(mockData.pipeline.details.status.label); + }); + + it('should render pipeline graph with correct styles', () => { + const stagesCount = mockData.pipeline.details.stages.length; + + expect(findPipelineMiniGraph().exists()).toBe(true); + expect(findPipelineMiniGraph().findAll('.mr-widget-pipeline-stages')).toHaveLength( + stagesCount, + ); + + expect(findAllPipelineStages()).toHaveLength(stagesCount); + }); + + it('should render coverage information', () => { + expect(findPipelineCoverage().text()).toMatch(`Test coverage ${mockData.pipeline.coverage}%`); + }); + }); + + describe('without coverage', () => { + beforeEach(() => { + const mockCopy = JSON.parse(JSON.stringify(mockData)); + delete mockCopy.pipeline.coverage; + + createWrapper({ pipeline: mockCopy.pipeline }); + }); + + it('should not render a coverage component', () => { + expect(findPipelineCoverage().exists()).toBe(false); + }); + }); + + describe('without a pipeline graph', () => { + beforeEach(() => { + const mockCopy = JSON.parse(JSON.stringify(mockData)); + delete mockCopy.pipeline.details.stages; + + createWrapper({ + pipeline: mockCopy.pipeline, + }); + }); + + it('should not render a pipeline graph', () => { + expect(findPipelineMiniGraph().exists()).toBe(false); + }); + }); + + describe('for each type of pipeline', () => { + let pipeline; + + beforeEach(() => { + ({ pipeline } = JSON.parse(JSON.stringify(mockData))); + + pipeline.details.name = 'Pipeline'; + pipeline.merge_request_event_type = undefined; + pipeline.ref.tag = false; + pipeline.ref.branch = false; + }); + + const factory = () => { + createWrapper({ + pipeline, + sourceBranchLink: mockData.source_branch_link, + }); + }; + + describe('for a branch pipeline', () => { + it('renders a pipeline widget that reads "Pipeline <ID> <status> for <SHA> on <branch>"', () => { + pipeline.ref.branch = true; + + factory(); + + const expected = `Pipeline #${pipeline.id} ${pipeline.details.status.label} for ${pipeline.commit.short_id} on ${mockData.source_branch_link}`; + const actual = trimText(findPipelineInfoContainer().text()); + + expect(actual).toBe(expected); + }); + }); + + describe('for a tag pipeline', () => { + it('renders a pipeline widget that reads "Pipeline <ID> <status> for <SHA> on <branch>"', () => { + pipeline.ref.tag = true; + + factory(); + + const expected = `Pipeline #${pipeline.id} ${pipeline.details.status.label} for ${pipeline.commit.short_id}`; + const actual = trimText(findPipelineInfoContainer().text()); + + expect(actual).toBe(expected); + }); + }); + + describe('for a detached merge request pipeline', () => { + it('renders a pipeline widget that reads "Detached merge request pipeline <ID> <status> for <SHA>"', () => { + pipeline.details.name = 'Detached merge request pipeline'; + pipeline.merge_request_event_type = 'detached'; + + factory(); + + const expected = `Detached merge request pipeline #${pipeline.id} ${pipeline.details.status.label} for ${pipeline.commit.short_id}`; + const actual = trimText(findPipelineInfoContainer().text()); + + expect(actual).toBe(expected); + }); + }); + }); +}); |