Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-10-16 21:09:04 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-10-16 21:09:04 +0300
commitb58ab6c33c0369e402109d5388d4f6f73b7eb2bb (patch)
treeb4f09ac9cf03dd11328050ab1e26df5fad351695 /spec/frontend/analytics
parent3940f59a61a749824aa4425ebdcaed6f3ed601f2 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend/analytics')
-rw-r--r--spec/frontend/analytics/instance_statistics/apollo_mock_data.js30
-rw-r--r--spec/frontend/analytics/instance_statistics/components/__snapshots__/pipelines_chart_spec.js.snap161
-rw-r--r--spec/frontend/analytics/instance_statistics/components/app_spec.js5
-rw-r--r--spec/frontend/analytics/instance_statistics/components/pipelines_chart_spec.js189
-rw-r--r--spec/frontend/analytics/instance_statistics/utils_spec.js45
5 files changed, 429 insertions, 1 deletions
diff --git a/spec/frontend/analytics/instance_statistics/apollo_mock_data.js b/spec/frontend/analytics/instance_statistics/apollo_mock_data.js
new file mode 100644
index 00000000000..2e4eaf3fc96
--- /dev/null
+++ b/spec/frontend/analytics/instance_statistics/apollo_mock_data.js
@@ -0,0 +1,30 @@
+const defaultPageInfo = { hasPreviousPage: false, startCursor: null, endCursor: null };
+
+export function getApolloResponse(options = {}) {
+ const {
+ pipelinesTotal = [],
+ pipelinesSucceeded = [],
+ pipelinesFailed = [],
+ pipelinesCanceled = [],
+ pipelinesSkipped = [],
+ hasNextPage = false,
+ } = options;
+ return {
+ data: {
+ pipelinesTotal: { pageInfo: { ...defaultPageInfo, hasNextPage }, nodes: pipelinesTotal },
+ pipelinesSucceeded: {
+ pageInfo: { ...defaultPageInfo, hasNextPage },
+ nodes: pipelinesSucceeded,
+ },
+ pipelinesFailed: { pageInfo: { ...defaultPageInfo, hasNextPage }, nodes: pipelinesFailed },
+ pipelinesCanceled: {
+ pageInfo: { ...defaultPageInfo, hasNextPage },
+ nodes: pipelinesCanceled,
+ },
+ pipelinesSkipped: {
+ pageInfo: { ...defaultPageInfo, hasNextPage },
+ nodes: pipelinesSkipped,
+ },
+ },
+ };
+}
diff --git a/spec/frontend/analytics/instance_statistics/components/__snapshots__/pipelines_chart_spec.js.snap b/spec/frontend/analytics/instance_statistics/components/__snapshots__/pipelines_chart_spec.js.snap
new file mode 100644
index 00000000000..0b3b685a9f2
--- /dev/null
+++ b/spec/frontend/analytics/instance_statistics/components/__snapshots__/pipelines_chart_spec.js.snap
@@ -0,0 +1,161 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`PipelinesChart when fetching more data when the fetchMore query returns data passes the data to the line chart 1`] = `
+Array [
+ Object {
+ "data": Array [
+ Array [
+ "2020-06-01",
+ 21,
+ ],
+ Array [
+ "2020-07-01",
+ 10,
+ ],
+ Array [
+ "2020-08-01",
+ 5,
+ ],
+ ],
+ "name": "Total",
+ },
+ Object {
+ "data": Array [
+ Array [
+ "2020-06-01",
+ 21,
+ ],
+ Array [
+ "2020-07-01",
+ 10,
+ ],
+ Array [
+ "2020-08-01",
+ 5,
+ ],
+ ],
+ "name": "Succeeded",
+ },
+ Object {
+ "data": Array [
+ Array [
+ "2020-06-01",
+ 22,
+ ],
+ Array [
+ "2020-07-01",
+ 41,
+ ],
+ Array [
+ "2020-08-01",
+ 5,
+ ],
+ ],
+ "name": "Failed",
+ },
+ Object {
+ "data": Array [
+ Array [
+ "2020-06-01",
+ 21,
+ ],
+ Array [
+ "2020-07-01",
+ 10,
+ ],
+ Array [
+ "2020-08-01",
+ 5,
+ ],
+ ],
+ "name": "Canceled",
+ },
+ Object {
+ "data": Array [
+ Array [
+ "2020-06-01",
+ 21,
+ ],
+ Array [
+ "2020-07-01",
+ 10,
+ ],
+ Array [
+ "2020-08-01",
+ 5,
+ ],
+ ],
+ "name": "Skipped",
+ },
+]
+`;
+
+exports[`PipelinesChart with data passes the data to the line chart 1`] = `
+Array [
+ Object {
+ "data": Array [
+ Array [
+ "2020-06-01",
+ 22,
+ ],
+ Array [
+ "2020-07-01",
+ 41,
+ ],
+ ],
+ "name": "Total",
+ },
+ Object {
+ "data": Array [
+ Array [
+ "2020-06-01",
+ 21,
+ ],
+ Array [
+ "2020-07-01",
+ 10,
+ ],
+ ],
+ "name": "Succeeded",
+ },
+ Object {
+ "data": Array [
+ Array [
+ "2020-06-01",
+ 21,
+ ],
+ Array [
+ "2020-07-01",
+ 10,
+ ],
+ ],
+ "name": "Failed",
+ },
+ Object {
+ "data": Array [
+ Array [
+ "2020-06-01",
+ 22,
+ ],
+ Array [
+ "2020-07-01",
+ 41,
+ ],
+ ],
+ "name": "Canceled",
+ },
+ Object {
+ "data": Array [
+ Array [
+ "2020-06-01",
+ 22,
+ ],
+ Array [
+ "2020-07-01",
+ 41,
+ ],
+ ],
+ "name": "Skipped",
+ },
+]
+`;
diff --git a/spec/frontend/analytics/instance_statistics/components/app_spec.js b/spec/frontend/analytics/instance_statistics/components/app_spec.js
index 242621dc40c..39f6d1b450a 100644
--- a/spec/frontend/analytics/instance_statistics/components/app_spec.js
+++ b/spec/frontend/analytics/instance_statistics/components/app_spec.js
@@ -1,6 +1,7 @@
import { shallowMount } from '@vue/test-utils';
import InstanceStatisticsApp from '~/analytics/instance_statistics/components/app.vue';
import InstanceCounts from '~/analytics/instance_statistics/components//instance_counts.vue';
+import PipelinesChart from '~/analytics/instance_statistics/components/pipelines_chart.vue';
describe('InstanceStatisticsApp', () => {
let wrapper;
@@ -21,4 +22,8 @@ describe('InstanceStatisticsApp', () => {
it('displays the instance counts component', () => {
expect(wrapper.find(InstanceCounts).exists()).toBe(true);
});
+
+ it('displays the pipelines chart component', () => {
+ expect(wrapper.find(PipelinesChart).exists()).toBe(true);
+ });
});
diff --git a/spec/frontend/analytics/instance_statistics/components/pipelines_chart_spec.js b/spec/frontend/analytics/instance_statistics/components/pipelines_chart_spec.js
new file mode 100644
index 00000000000..a06d66f783e
--- /dev/null
+++ b/spec/frontend/analytics/instance_statistics/components/pipelines_chart_spec.js
@@ -0,0 +1,189 @@
+import { createLocalVue, shallowMount } from '@vue/test-utils';
+import { GlLineChart } from '@gitlab/ui/dist/charts';
+import { GlAlert } from '@gitlab/ui';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'jest/helpers/mock_apollo_helper';
+import PipelinesChart from '~/analytics/instance_statistics/components/pipelines_chart.vue';
+import pipelinesStatsQuery from '~/analytics/instance_statistics/graphql/queries/pipeline_stats.query.graphql';
+import ChartSkeletonLoader from '~/vue_shared/components/resizable_chart/skeleton_loader.vue';
+import { mockCountsData1, mockCountsData2 } from '../mock_data';
+import { getApolloResponse } from '../apollo_mock_data';
+
+const localVue = createLocalVue();
+localVue.use(VueApollo);
+
+describe('PipelinesChart', () => {
+ let wrapper;
+ let queryHandler;
+
+ const createApolloProvider = pipelineStatsHandler => {
+ return createMockApollo([[pipelinesStatsQuery, pipelineStatsHandler]]);
+ };
+
+ const createComponent = apolloProvider => {
+ return shallowMount(PipelinesChart, {
+ localVue,
+ apolloProvider,
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ const findLoader = () => wrapper.find(ChartSkeletonLoader);
+ const findChart = () => wrapper.find(GlLineChart);
+ const findAlert = () => wrapper.find(GlAlert);
+
+ describe('while loading', () => {
+ beforeEach(() => {
+ queryHandler = jest.fn().mockReturnValue(new Promise(() => {}));
+ const apolloProvider = createApolloProvider(queryHandler);
+ wrapper = createComponent(apolloProvider);
+ });
+
+ it('requests data', () => {
+ expect(queryHandler).toBeCalledTimes(1);
+ });
+
+ it('displays the skeleton loader', () => {
+ expect(findLoader().exists()).toBe(true);
+ });
+
+ it('hides the chart', () => {
+ expect(findChart().exists()).toBe(false);
+ });
+
+ it('does not show an error', () => {
+ expect(findAlert().exists()).toBe(false);
+ });
+ });
+
+ describe('without data', () => {
+ beforeEach(() => {
+ const emptyResponse = getApolloResponse();
+ queryHandler = jest.fn().mockResolvedValue(emptyResponse);
+ const apolloProvider = createApolloProvider(queryHandler);
+ wrapper = createComponent(apolloProvider);
+ });
+
+ it('renders an no data message', () => {
+ expect(findAlert().text()).toBe('There is no data available.');
+ });
+
+ it('hides the skeleton loader', () => {
+ expect(findLoader().exists()).toBe(false);
+ });
+
+ it('renders the chart', () => {
+ expect(findChart().exists()).toBe(false);
+ });
+ });
+
+ describe('with data', () => {
+ beforeEach(() => {
+ const response = getApolloResponse({
+ pipelinesTotal: mockCountsData1,
+ pipelinesSucceeded: mockCountsData2,
+ pipelinesFailed: mockCountsData2,
+ pipelinesCanceled: mockCountsData1,
+ pipelinesSkipped: mockCountsData1,
+ });
+ queryHandler = jest.fn().mockResolvedValue(response);
+ const apolloProvider = createApolloProvider(queryHandler);
+ wrapper = createComponent(apolloProvider);
+ });
+
+ it('requests data', () => {
+ expect(queryHandler).toBeCalledTimes(1);
+ });
+
+ it('hides the skeleton loader', () => {
+ expect(findLoader().exists()).toBe(false);
+ });
+
+ it('renders the chart', () => {
+ expect(findChart().exists()).toBe(true);
+ });
+
+ it('passes the data to the line chart', () => {
+ expect(findChart().props('data')).toMatchSnapshot();
+ });
+
+ it('does not show an error', () => {
+ expect(findAlert().exists()).toBe(false);
+ });
+ });
+
+ describe('when fetching more data', () => {
+ const recordedAt = '2020-08-01';
+ describe('when the fetchMore query returns data', () => {
+ beforeEach(async () => {
+ const newData = { recordedAt, count: 5 };
+ const firstResponse = getApolloResponse({
+ pipelinesTotal: mockCountsData2,
+ pipelinesSucceeded: mockCountsData2,
+ pipelinesFailed: mockCountsData1,
+ pipelinesCanceled: mockCountsData2,
+ pipelinesSkipped: mockCountsData2,
+ hasNextPage: true,
+ });
+ const secondResponse = getApolloResponse({
+ pipelinesTotal: [newData],
+ pipelinesSucceeded: [newData],
+ pipelinesFailed: [newData],
+ pipelinesCanceled: [newData],
+ pipelinesSkipped: [newData],
+ hasNextPage: false,
+ });
+ queryHandler = jest
+ .fn()
+ .mockResolvedValueOnce(firstResponse)
+ .mockResolvedValueOnce(secondResponse);
+ const apolloProvider = createApolloProvider(queryHandler);
+ wrapper = createComponent(apolloProvider);
+
+ await wrapper.vm.$nextTick();
+ });
+
+ it('requests data twice', () => {
+ expect(queryHandler).toBeCalledTimes(2);
+ });
+
+ it('passes the data to the line chart', () => {
+ expect(findChart().props('data')).toMatchSnapshot();
+ });
+ });
+
+ describe('when the fetchMore query throws an error', () => {
+ beforeEach(async () => {
+ const response = getApolloResponse({
+ pipelinesTotal: mockCountsData2,
+ pipelinesSucceeded: mockCountsData2,
+ pipelinesFailed: mockCountsData1,
+ pipelinesCanceled: mockCountsData2,
+ pipelinesSkipped: mockCountsData2,
+ hasNextPage: true,
+ });
+ queryHandler = jest.fn().mockResolvedValue(response);
+ const apolloProvider = createApolloProvider(queryHandler);
+ wrapper = createComponent(apolloProvider);
+ jest
+ .spyOn(wrapper.vm.$apollo.queries.pipelineStats, 'fetchMore')
+ .mockImplementation(jest.fn().mockRejectedValue());
+ await wrapper.vm.$nextTick();
+ });
+
+ it('calls fetchMore', () => {
+ expect(wrapper.vm.$apollo.queries.pipelineStats.fetchMore).toHaveBeenCalledTimes(1);
+ });
+
+ it('show an error message', () => {
+ expect(findAlert().text()).toBe(
+ 'Could not load the pipelines chart. Please refresh the page to try again.',
+ );
+ });
+ });
+ });
+});
diff --git a/spec/frontend/analytics/instance_statistics/utils_spec.js b/spec/frontend/analytics/instance_statistics/utils_spec.js
index f6ea81eb678..d480238419b 100644
--- a/spec/frontend/analytics/instance_statistics/utils_spec.js
+++ b/spec/frontend/analytics/instance_statistics/utils_spec.js
@@ -1,4 +1,8 @@
-import { getAverageByMonth } from '~/analytics/instance_statistics/utils';
+import {
+ getAverageByMonth,
+ extractValues,
+ sortByDate,
+} from '~/analytics/instance_statistics/utils';
import {
mockCountsData1,
mockCountsData2,
@@ -39,3 +43,42 @@ describe('getAverageByMonth', () => {
});
});
});
+
+describe('extractValues', () => {
+ it('extracts only requested values', () => {
+ const data = { fooBar: { baz: 'quis' }, ignored: 'ignored' };
+ expect(extractValues(data, ['fooBar'], 'foo', 'baz')).toEqual({ bazBar: 'quis' });
+ });
+
+ it('is able to extract multiple values', () => {
+ const data = {
+ fooBar: { baz: 'quis' },
+ fooBaz: { baz: 'quis' },
+ fooQuis: { baz: 'quis' },
+ };
+ expect(extractValues(data, ['fooBar', 'fooBaz', 'fooQuis'], 'foo', 'baz')).toEqual({
+ bazBar: 'quis',
+ bazBaz: 'quis',
+ bazQuis: 'quis',
+ });
+ });
+
+ it('returns empty data set when keys are not found', () => {
+ const data = { foo: { baz: 'quis' }, ignored: 'ignored' };
+ expect(extractValues(data, ['fooBar'], 'foo', 'baz')).toEqual({});
+ });
+
+ it('returns empty data when params are missing', () => {
+ expect(extractValues()).toEqual({});
+ });
+});
+
+describe('sortByDate', () => {
+ it('sorts the array by date', () => {
+ expect(sortByDate(mockCountsData1)).toStrictEqual([...mockCountsData1].reverse());
+ });
+
+ it('does not modify the original array', () => {
+ expect(sortByDate(countsMonthlyChartData1)).not.toBe(countsMonthlyChartData1);
+ });
+});