From 859a6fb938bb9ee2a317c46dfa4fcc1af49608f0 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Thu, 18 Feb 2021 10:34:06 +0000 Subject: Add latest changes from gitlab-org/gitlab@13-9-stable-ee --- .../pipelines/charts/components/app_spec.js | 168 +++++++++++++-------- .../components/ci_cd_analytics_charts_spec.js | 94 ++++++++++++ .../charts/components/pipeline_charts_spec.js | 72 ++++----- .../projects/pipelines/charts/mock_data.js | 10 ++ 4 files changed, 245 insertions(+), 99 deletions(-) create mode 100644 spec/frontend/projects/pipelines/charts/components/ci_cd_analytics_charts_spec.js (limited to 'spec/frontend/projects/pipelines/charts') diff --git a/spec/frontend/projects/pipelines/charts/components/app_spec.js b/spec/frontend/projects/pipelines/charts/components/app_spec.js index 44329944097..e8aace14db4 100644 --- a/spec/frontend/projects/pipelines/charts/components/app_spec.js +++ b/spec/frontend/projects/pipelines/charts/components/app_spec.js @@ -1,32 +1,19 @@ -import { merge } from 'lodash'; -import { createLocalVue, shallowMount } from '@vue/test-utils'; -import VueApollo from 'vue-apollo'; import { GlTabs, GlTab } from '@gitlab/ui'; -import createMockApollo from 'helpers/mock_apollo_helper'; +import { shallowMount } from '@vue/test-utils'; +import { merge } from 'lodash'; +import setWindowLocation from 'helpers/set_window_location_helper'; +import { TEST_HOST } from 'helpers/test_constants'; +import { mergeUrlParams, updateHistory, getParameterValues } from '~/lib/utils/url_utility'; import Component from '~/projects/pipelines/charts/components/app.vue'; import PipelineCharts from '~/projects/pipelines/charts/components/pipeline_charts.vue'; -import getPipelineCountByStatus from '~/projects/pipelines/charts/graphql/queries/get_pipeline_count_by_status.query.graphql'; -import getProjectPipelineStatistics from '~/projects/pipelines/charts/graphql/queries/get_project_pipeline_statistics.query.graphql'; -import { mockPipelineCount, mockPipelineStatistics } from '../mock_data'; -const projectPath = 'gitlab-org/gitlab'; -const localVue = createLocalVue(); -localVue.use(VueApollo); +jest.mock('~/lib/utils/url_utility'); const DeploymentFrequencyChartsStub = { name: 'DeploymentFrequencyCharts', render: () => {} }; describe('ProjectsPipelinesChartsApp', () => { let wrapper; - function createMockApolloProvider() { - const requestHandlers = [ - [getPipelineCountByStatus, jest.fn().mockResolvedValue(mockPipelineCount)], - [getProjectPipelineStatistics, jest.fn().mockResolvedValue(mockPipelineStatistics)], - ]; - - return createMockApollo(requestHandlers); - } - function createComponent(mountOptions = {}) { wrapper = shallowMount( Component, @@ -34,11 +21,8 @@ describe('ProjectsPipelinesChartsApp', () => { {}, { provide: { - projectPath, shouldRenderDeploymentFrequencyCharts: false, }, - localVue, - apolloProvider: createMockApolloProvider(), stubs: { DeploymentFrequencyCharts: DeploymentFrequencyChartsStub, }, @@ -57,52 +41,15 @@ describe('ProjectsPipelinesChartsApp', () => { wrapper = null; }); - describe('pipelines charts', () => { - it('displays the pipeline charts', () => { - const chart = wrapper.find(PipelineCharts); - const analytics = mockPipelineStatistics.data.project.pipelineAnalytics; - - const { - totalPipelines: total, - successfulPipelines: success, - failedPipelines: failed, - } = mockPipelineCount.data.project; - - expect(chart.exists()).toBe(true); - expect(chart.props()).toMatchObject({ - counts: { - failed: failed.count, - success: success.count, - total: total.count, - successRatio: (success.count / (success.count + failed.count)) * 100, - }, - lastWeek: { - labels: analytics.weekPipelinesLabels, - totals: analytics.weekPipelinesTotals, - success: analytics.weekPipelinesSuccessful, - }, - lastMonth: { - labels: analytics.monthPipelinesLabels, - totals: analytics.monthPipelinesTotals, - success: analytics.monthPipelinesSuccessful, - }, - lastYear: { - labels: analytics.yearPipelinesLabels, - totals: analytics.yearPipelinesTotals, - success: analytics.yearPipelinesSuccessful, - }, - timesChart: { - labels: analytics.pipelineTimesLabels, - values: analytics.pipelineTimesValues, - }, - }); - }); - }); - - const findDeploymentFrequencyCharts = () => wrapper.find(DeploymentFrequencyChartsStub); const findGlTabs = () => wrapper.find(GlTabs); const findAllGlTab = () => wrapper.findAll(GlTab); const findGlTabAt = (i) => findAllGlTab().at(i); + const findDeploymentFrequencyCharts = () => wrapper.find(DeploymentFrequencyChartsStub); + const findPipelineCharts = () => wrapper.find(PipelineCharts); + + it('renders the pipeline charts', () => { + expect(findPipelineCharts().exists()).toBe(true); + }); describe('when shouldRenderDeploymentFrequencyCharts is true', () => { beforeEach(() => { @@ -115,6 +62,97 @@ describe('ProjectsPipelinesChartsApp', () => { expect(findGlTabAt(1).attributes('title')).toBe('Deployments'); expect(findDeploymentFrequencyCharts().exists()).toBe(true); }); + + it('sets the tab and url when a tab is clicked', async () => { + let chartsPath; + setWindowLocation(`${TEST_HOST}/gitlab-org/gitlab-test/-/pipelines/charts`); + + mergeUrlParams.mockImplementation(({ chart }, path) => { + expect(chart).toBe('deployments'); + expect(path).toBe(window.location.pathname); + chartsPath = `${path}?chart=${chart}`; + return chartsPath; + }); + + updateHistory.mockImplementation(({ url }) => { + expect(url).toBe(chartsPath); + }); + const tabs = findGlTabs(); + + expect(tabs.attributes('value')).toBe('0'); + + tabs.vm.$emit('input', 1); + + await wrapper.vm.$nextTick(); + + expect(tabs.attributes('value')).toBe('1'); + }); + + it('should not try to push history if the tab does not change', async () => { + setWindowLocation(`${TEST_HOST}/gitlab-org/gitlab-test/-/pipelines/charts`); + + mergeUrlParams.mockImplementation(({ chart }, path) => `${path}?chart=${chart}`); + + const tabs = findGlTabs(); + + expect(tabs.attributes('value')).toBe('0'); + + tabs.vm.$emit('input', 0); + + await wrapper.vm.$nextTick(); + + expect(updateHistory).not.toHaveBeenCalled(); + }); + }); + + describe('when provided with a query param', () => { + it.each` + chart | tab + ${'deployments'} | ${'1'} + ${'pipelines'} | ${'0'} + ${'fake'} | ${'0'} + ${''} | ${'0'} + `('shows the correct tab for URL parameter "$chart"', ({ chart, tab }) => { + setWindowLocation(`${TEST_HOST}/gitlab-org/gitlab-test/-/pipelines/charts?chart=${chart}`); + getParameterValues.mockImplementation((name) => { + expect(name).toBe('chart'); + return chart ? [chart] : []; + }); + createComponent({ provide: { shouldRenderDeploymentFrequencyCharts: true } }); + expect(findGlTabs().attributes('value')).toBe(tab); + }); + + it('should set the tab when the back button is clicked', async () => { + let popstateHandler; + + window.addEventListener = jest.fn(); + + window.addEventListener.mockImplementation((event, handler) => { + if (event === 'popstate') { + popstateHandler = handler; + } + }); + + getParameterValues.mockImplementation((name) => { + expect(name).toBe('chart'); + return []; + }); + + createComponent({ provide: { shouldRenderDeploymentFrequencyCharts: true } }); + + expect(findGlTabs().attributes('value')).toBe('0'); + + getParameterValues.mockImplementationOnce((name) => { + expect(name).toBe('chart'); + return ['deployments']; + }); + + popstateHandler(); + + await wrapper.vm.$nextTick(); + + expect(findGlTabs().attributes('value')).toBe('1'); + }); }); describe('when shouldRenderDeploymentFrequencyCharts is false', () => { diff --git a/spec/frontend/projects/pipelines/charts/components/ci_cd_analytics_charts_spec.js b/spec/frontend/projects/pipelines/charts/components/ci_cd_analytics_charts_spec.js new file mode 100644 index 00000000000..037530ddd48 --- /dev/null +++ b/spec/frontend/projects/pipelines/charts/components/ci_cd_analytics_charts_spec.js @@ -0,0 +1,94 @@ +import { GlSegmentedControl } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; +import { nextTick } from 'vue'; +import CiCdAnalyticsAreaChart from '~/projects/pipelines/charts/components/ci_cd_analytics_area_chart.vue'; +import CiCdAnalyticsCharts from '~/projects/pipelines/charts/components/ci_cd_analytics_charts.vue'; +import { transformedAreaChartData, chartOptions } from '../mock_data'; + +const DEFAULT_PROPS = { + chartOptions, + charts: [ + { + range: 'test range 1', + title: 'title 1', + data: transformedAreaChartData, + }, + { + range: 'test range 2', + title: 'title 2', + data: transformedAreaChartData, + }, + { + range: 'test range 3', + title: 'title 3', + data: transformedAreaChartData, + }, + ], +}; + +describe('~/projects/pipelines/charts/components/ci_cd_analytics_charts.vue', () => { + let wrapper; + + const createWrapper = (props = {}) => + shallowMount(CiCdAnalyticsCharts, { + propsData: { + ...DEFAULT_PROPS, + ...props, + }, + }); + + afterEach(() => { + if (wrapper) { + wrapper.destroy(); + wrapper = null; + } + }); + + describe('segmented control', () => { + let segmentedControl; + + beforeEach(() => { + wrapper = createWrapper(); + segmentedControl = wrapper.find(GlSegmentedControl); + }); + + it('should default to the first chart', () => { + expect(segmentedControl.props('checked')).toBe(0); + }); + + it('should use the title and index as values', () => { + const options = segmentedControl.props('options'); + expect(options).toHaveLength(3); + expect(options).toEqual([ + { + text: 'title 1', + value: 0, + }, + { + text: 'title 2', + value: 1, + }, + { + text: 'title 3', + value: 2, + }, + ]); + }); + + it('should select a different chart on change', async () => { + segmentedControl.vm.$emit('input', 1); + + const chart = wrapper.find(CiCdAnalyticsAreaChart); + + await nextTick(); + + expect(chart.props('chartData')).toEqual(transformedAreaChartData); + expect(chart.text()).toBe('Date range: test range 2'); + }); + }); + + it('should not display charts if there are no charts', () => { + wrapper = createWrapper({ charts: [] }); + expect(wrapper.find(CiCdAnalyticsAreaChart).exists()).toBe(false); + }); +}); diff --git a/spec/frontend/projects/pipelines/charts/components/pipeline_charts_spec.js b/spec/frontend/projects/pipelines/charts/components/pipeline_charts_spec.js index 598055d5828..c5cfe783569 100644 --- a/spec/frontend/projects/pipelines/charts/components/pipeline_charts_spec.js +++ b/spec/frontend/projects/pipelines/charts/components/pipeline_charts_spec.js @@ -1,35 +1,37 @@ -import { shallowMount } from '@vue/test-utils'; import { GlColumnChart } from '@gitlab/ui/dist/charts'; -import StatisticsList from '~/projects/pipelines/charts/components/statistics_list.vue'; -import CiCdAnalyticsAreaChart from '~/projects/pipelines/charts/components/ci_cd_analytics_area_chart.vue'; +import { createLocalVue, shallowMount } from '@vue/test-utils'; +import VueApollo from 'vue-apollo'; +import createMockApollo from 'helpers/mock_apollo_helper'; +import CiCdAnalyticsCharts from '~/projects/pipelines/charts/components/ci_cd_analytics_charts.vue'; import PipelineCharts from '~/projects/pipelines/charts/components/pipeline_charts.vue'; -import { - counts, - timesChartData as timesChart, - areaChartData as lastWeek, - areaChartData as lastMonth, - lastYearChartData as lastYear, -} from '../mock_data'; +import StatisticsList from '~/projects/pipelines/charts/components/statistics_list.vue'; +import getPipelineCountByStatus from '~/projects/pipelines/charts/graphql/queries/get_pipeline_count_by_status.query.graphql'; +import getProjectPipelineStatistics from '~/projects/pipelines/charts/graphql/queries/get_project_pipeline_statistics.query.graphql'; +import { mockPipelineCount, mockPipelineStatistics } from '../mock_data'; + +const projectPath = 'gitlab-org/gitlab'; +const localVue = createLocalVue(); +localVue.use(VueApollo); -describe('ProjectsPipelinesChartsApp', () => { +describe('~/projects/pipelines/charts/components/pipeline_charts.vue', () => { let wrapper; + function createMockApolloProvider() { + const requestHandlers = [ + [getPipelineCountByStatus, jest.fn().mockResolvedValue(mockPipelineCount)], + [getProjectPipelineStatistics, jest.fn().mockResolvedValue(mockPipelineStatistics)], + ]; + + return createMockApollo(requestHandlers); + } + beforeEach(() => { wrapper = shallowMount(PipelineCharts, { - propsData: { - counts, - timesChart, - lastWeek, - lastMonth, - lastYear, - }, provide: { - projectPath: 'test/project', - shouldRenderDeploymentFrequencyCharts: true, - }, - stubs: { - DeploymentFrequencyCharts: true, + projectPath, }, + localVue, + apolloProvider: createMockApolloProvider(), }); }); @@ -43,7 +45,12 @@ describe('ProjectsPipelinesChartsApp', () => { const list = wrapper.find(StatisticsList); expect(list.exists()).toBe(true); - expect(list.props('counts')).toBe(counts); + expect(list.props('counts')).toEqual({ + total: 34, + success: 23, + failed: 1, + successRatio: (23 / (23 + 1)) * 100, + }); }); it('displays the commit duration chart', () => { @@ -58,20 +65,17 @@ describe('ProjectsPipelinesChartsApp', () => { }); describe('pipelines charts', () => { - it('displays 3 area charts', () => { - expect(wrapper.findAll(CiCdAnalyticsAreaChart)).toHaveLength(3); + it('displays the charts components', () => { + expect(wrapper.find(CiCdAnalyticsCharts).exists()).toBe(true); }); describe('displays individual correctly', () => { it('renders with the correct data', () => { - const charts = wrapper.findAll(CiCdAnalyticsAreaChart); - for (let i = 0; i < charts.length; i += 1) { - const chart = charts.at(i); - - expect(chart.exists()).toBeTruthy(); - expect(chart.props('chartData')).toBe(wrapper.vm.areaCharts[i].data); - expect(chart.text()).toBe(wrapper.vm.areaCharts[i].title); - } + const charts = wrapper.find(CiCdAnalyticsCharts); + expect(charts.props()).toEqual({ + charts: wrapper.vm.areaCharts, + chartOptions: wrapper.vm.$options.areaChartOptions, + }); }); }); }); diff --git a/spec/frontend/projects/pipelines/charts/mock_data.js b/spec/frontend/projects/pipelines/charts/mock_data.js index 3bc09f0b0a0..2e2c594102c 100644 --- a/spec/frontend/projects/pipelines/charts/mock_data.js +++ b/spec/frontend/projects/pipelines/charts/mock_data.js @@ -57,6 +57,16 @@ export const mockPipelineCount = { }, }; +export const chartOptions = { + xAxis: { + name: 'X axis title', + type: 'category', + }, + yAxis: { + name: 'Y axis title', + }, +}; + export const mockPipelineStatistics = { data: { project: { -- cgit v1.2.1