diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-11-06 18:09:14 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-11-06 18:09:14 +0300 |
commit | a268b09416c8dc3da3af38933028fa26375b88e0 (patch) | |
tree | 8f10484408a40e386b79f8bb3c2f4095dded85f7 /spec/frontend/analytics | |
parent | 4ff56b118438f4fa6191b691fd968c75d8e94d5a (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend/analytics')
7 files changed, 103 insertions, 299 deletions
diff --git a/spec/frontend/analytics/instance_statistics/apollo_mock_data.js b/spec/frontend/analytics/instance_statistics/apollo_mock_data.js index 8697830672e..98eabd577ee 100644 --- a/spec/frontend/analytics/instance_statistics/apollo_mock_data.js +++ b/spec/frontend/analytics/instance_statistics/apollo_mock_data.js @@ -5,36 +5,7 @@ const defaultPageInfo = { 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, - }, - }, - }; -} - -const mockApolloResponse = ({ hasNextPage = false, key, data }) => ({ +export const mockApolloResponse = ({ hasNextPage = false, key, data }) => ({ data: { [key]: { pageInfo: { ...defaultPageInfo, hasNextPage }, @@ -43,13 +14,8 @@ const mockApolloResponse = ({ hasNextPage = false, key, data }) => ({ }, }); -export const mockQueryResponse = ({ - key, - data = [], - loading = false, - hasNextPage = false, - additionalData = [], -}) => { +export const mockQueryResponse = ({ key, data = [], loading = false, additionalData = [] }) => { + const hasNextPage = Boolean(additionalData.length); const response = mockApolloResponse({ hasNextPage, key, data }); if (loading) { return jest.fn().mockReturnValue(new Promise(() => {})); diff --git a/spec/frontend/analytics/instance_statistics/components/__snapshots__/instance_statistics_count_chart_spec.js.snap b/spec/frontend/analytics/instance_statistics/components/__snapshots__/instance_statistics_count_chart_spec.js.snap index 2e76db65a0a..29bcd5f223b 100644 --- a/spec/frontend/analytics/instance_statistics/components/__snapshots__/instance_statistics_count_chart_spec.js.snap +++ b/spec/frontend/analytics/instance_statistics/components/__snapshots__/instance_statistics_count_chart_spec.js.snap @@ -5,87 +5,19 @@ 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, + 22, ], Array [ "2020-08-01", 5, ], ], - "name": "Skipped", + "name": "Mock Query", }, ] `; @@ -95,67 +27,15 @@ 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", + "name": "Mock Query", }, ] `; diff --git a/spec/frontend/analytics/instance_statistics/components/app_spec.js b/spec/frontend/analytics/instance_statistics/components/app_spec.js index 159a7763d11..8ac663b3046 100644 --- a/spec/frontend/analytics/instance_statistics/components/app_spec.js +++ b/spec/frontend/analytics/instance_statistics/components/app_spec.js @@ -25,11 +25,14 @@ describe('InstanceStatisticsApp', () => { expect(wrapper.find(InstanceCounts).exists()).toBe(true); }); - it('displays the instance statistics count chart component', () => { - const allCharts = wrapper.findAll(InstanceStatisticsCountChart); - expect(allCharts).toHaveLength(2); - expect(allCharts.at(0).exists()).toBe(true); - expect(allCharts.at(1).exists()).toBe(true); + ['Pipelines', 'Issues & Merge Requests'].forEach(instance => { + it(`displays the ${instance} chart`, () => { + const chartTitles = wrapper + .findAll(InstanceStatisticsCountChart) + .wrappers.map(chartComponent => chartComponent.props('chartTitle')); + + expect(chartTitles).toContain(instance); + }); }); it('displays the users chart component', () => { diff --git a/spec/frontend/analytics/instance_statistics/components/instance_statistics_count_chart_spec.js b/spec/frontend/analytics/instance_statistics/components/instance_statistics_count_chart_spec.js index 6efca20b67a..275a84988f8 100644 --- a/spec/frontend/analytics/instance_statistics/components/instance_statistics_count_chart_spec.js +++ b/spec/frontend/analytics/instance_statistics/components/instance_statistics_count_chart_spec.js @@ -4,46 +4,44 @@ import { GlAlert } from '@gitlab/ui'; import VueApollo from 'vue-apollo'; import createMockApollo from 'jest/helpers/mock_apollo_helper'; import InstanceStatisticsCountChart from '~/analytics/instance_statistics/components/instance_statistics_count_chart.vue'; -import pipelinesStatsQuery from '~/analytics/instance_statistics/graphql/queries/pipeline_stats.query.graphql'; +import statsQuery from '~/analytics/instance_statistics/graphql/queries/instance_count.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'; +import { mockCountsData1 } from '../mock_data'; +import { mockQueryResponse, mockApolloResponse } from '../apollo_mock_data'; const localVue = createLocalVue(); localVue.use(VueApollo); -const PIPELINES_KEY_TO_NAME_MAP = { - total: 'Total', - succeeded: 'Succeeded', - failed: 'Failed', - canceled: 'Canceled', - skipped: 'Skipped', -}; const loadChartErrorMessage = 'My load error message'; const noDataMessage = 'My no data message'; +const queryResponseDataKey = 'instanceStatisticsMeasurements'; +const identifier = 'MOCK_QUERY'; +const mockQueryConfig = { + identifier, + title: 'Mock Query', + query: statsQuery, + loadError: 'Failed to load mock query data', +}; + +const mockChartConfig = { + loadChartErrorMessage, + noDataMessage, + chartTitle: 'Foo', + yAxisTitle: 'Bar', + xAxisTitle: 'Baz', + queries: [mockQueryConfig], +}; + describe('InstanceStatisticsCountChart', () => { let wrapper; let queryHandler; - const createApolloProvider = pipelineStatsHandler => { - return createMockApollo([[pipelinesStatsQuery, pipelineStatsHandler]]); - }; - - const createComponent = apolloProvider => { + const createComponent = ({ responseHandler }) => { return shallowMount(InstanceStatisticsCountChart, { localVue, - apolloProvider, - propsData: { - keyToNameMap: PIPELINES_KEY_TO_NAME_MAP, - prefix: 'pipelines', - loadChartErrorMessage, - noDataMessage, - chartTitle: 'Foo', - yAxisTitle: 'Bar', - xAxisTitle: 'Baz', - query: pipelinesStatsQuery, - }, + apolloProvider: createMockApollo([[statsQuery, responseHandler]]), + propsData: { ...mockChartConfig }, }); }; @@ -58,9 +56,8 @@ describe('InstanceStatisticsCountChart', () => { describe('while loading', () => { beforeEach(() => { - queryHandler = jest.fn().mockReturnValue(new Promise(() => {})); - const apolloProvider = createApolloProvider(queryHandler); - wrapper = createComponent(apolloProvider); + queryHandler = mockQueryResponse({ key: queryResponseDataKey, loading: true }); + wrapper = createComponent({ responseHandler: queryHandler }); }); it('requests data', () => { @@ -82,10 +79,8 @@ describe('InstanceStatisticsCountChart', () => { describe('without data', () => { beforeEach(() => { - const emptyResponse = getApolloResponse(); - queryHandler = jest.fn().mockResolvedValue(emptyResponse); - const apolloProvider = createApolloProvider(queryHandler); - wrapper = createComponent(apolloProvider); + queryHandler = mockQueryResponse({ key: queryResponseDataKey, data: [] }); + wrapper = createComponent({ responseHandler: queryHandler }); }); it('renders an no data message', () => { @@ -103,16 +98,8 @@ describe('InstanceStatisticsCountChart', () => { 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); + queryHandler = mockQueryResponse({ key: queryResponseDataKey, data: mockCountsData1 }); + wrapper = createComponent({ responseHandler: queryHandler }); }); it('requests data', () => { @@ -140,30 +127,14 @@ describe('InstanceStatisticsCountChart', () => { 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, + const newData = [{ recordedAt, count: 5 }]; + queryHandler = mockQueryResponse({ + key: queryResponseDataKey, + data: mockCountsData1, + additionalData: newData, }); - queryHandler = jest - .fn() - .mockResolvedValueOnce(firstResponse) - .mockResolvedValueOnce(secondResponse); - const apolloProvider = createApolloProvider(queryHandler); - wrapper = createComponent(apolloProvider); + wrapper = createComponent({ responseHandler: queryHandler }); await wrapper.vm.$nextTick(); }); @@ -178,25 +149,24 @@ describe('InstanceStatisticsCountChart', () => { 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); + queryHandler = jest.fn().mockResolvedValueOnce( + mockApolloResponse({ + key: queryResponseDataKey, + data: mockCountsData1, + hasNextPage: true, + }), + ); + + wrapper = createComponent({ responseHandler: queryHandler }); jest - .spyOn(wrapper.vm.$apollo.queries.pipelineStats, 'fetchMore') + .spyOn(wrapper.vm.$apollo.queries[identifier], 'fetchMore') .mockImplementation(jest.fn().mockRejectedValue()); + await wrapper.vm.$nextTick(); }); it('calls fetchMore', () => { - expect(wrapper.vm.$apollo.queries.pipelineStats.fetchMore).toHaveBeenCalledTimes(1); + expect(wrapper.vm.$apollo.queries[identifier].fetchMore).toHaveBeenCalledTimes(1); }); it('show an error message', () => { diff --git a/spec/frontend/analytics/instance_statistics/components/projects_and_groups_chart_spec.js b/spec/frontend/analytics/instance_statistics/components/projects_and_groups_chart_spec.js index 265c867719b..d9f42430aa8 100644 --- a/spec/frontend/analytics/instance_statistics/components/projects_and_groups_chart_spec.js +++ b/spec/frontend/analytics/instance_statistics/components/projects_and_groups_chart_spec.js @@ -25,23 +25,21 @@ describe('ProjectsAndGroupChart', () => { groups = [], projectsLoading = false, groupsLoading = false, - projectsHasNextPage = false, - groupsHasNextPage = false, + projectsAdditionalData = [], + groupsAdditionalData = [], } = {}) => { queryResponses = { projects: mockQueryResponse({ key: 'projects', data: projects, loading: projectsLoading, - hasNextPage: projectsHasNextPage, - additionalData: mockAdditionalData, + additionalData: projectsAdditionalData, }), groups: mockQueryResponse({ key: 'groups', data: groups, loading: groupsLoading, - hasNextPage: groupsHasNextPage, - additionalData: mockAdditionalData, + additionalData: groupsAdditionalData, }), }; @@ -169,9 +167,9 @@ describe('ProjectsAndGroupChart', () => { }); describe.each` - metric | loadingState | newData - ${'projects'} | ${{ projectsHasNextPage: true }} | ${{ projects: mockCountsData2 }} - ${'groups'} | ${{ groupsHasNextPage: true }} | ${{ groups: mockCountsData2 }} + metric | loadingState | newData + ${'projects'} | ${{ projectsAdditionalData: mockAdditionalData }} | ${{ projects: mockCountsData2 }} + ${'groups'} | ${{ groupsAdditionalData: mockAdditionalData }} | ${{ groups: mockCountsData2 }} `('$metric - fetchMore', ({ metric, loadingState, newData }) => { describe('when the fetchMore query returns data', () => { beforeEach(async () => { diff --git a/spec/frontend/analytics/instance_statistics/components/users_chart_spec.js b/spec/frontend/analytics/instance_statistics/components/users_chart_spec.js index 2942df95fdf..6ed9d203f3d 100644 --- a/spec/frontend/analytics/instance_statistics/components/users_chart_spec.js +++ b/spec/frontend/analytics/instance_statistics/components/users_chart_spec.js @@ -7,7 +7,11 @@ import { useFakeDate } from 'helpers/fake_date'; import UsersChart from '~/analytics/instance_statistics/components/users_chart.vue'; import ChartSkeletonLoader from '~/vue_shared/components/resizable_chart/skeleton_loader.vue'; import usersQuery from '~/analytics/instance_statistics/graphql/queries/users.query.graphql'; -import { mockCountsData2, roundedSortedCountsMonthlyChartData2 } from '../mock_data'; +import { + mockCountsData1, + mockCountsData2, + roundedSortedCountsMonthlyChartData2, +} from '../mock_data'; import { mockQueryResponse } from '../apollo_mock_data'; const localVue = createLocalVue(); @@ -21,9 +25,9 @@ describe('UsersChart', () => { loadingError = false, loading = false, users = [], - hasNextPage = false, + additionalData = [], } = {}) => { - queryHandler = mockQueryResponse({ key: 'users', data: users, loading, hasNextPage }); + queryHandler = mockQueryResponse({ key: 'users', data: users, loading, additionalData }); return shallowMount(UsersChart, { props: { @@ -128,7 +132,7 @@ describe('UsersChart', () => { beforeEach(async () => { wrapper = createComponent({ users: mockCountsData2, - hasNextPage: true, + additionalData: mockCountsData1, }); jest.spyOn(wrapper.vm.$apollo.queries.users, 'fetchMore'); @@ -148,7 +152,7 @@ describe('UsersChart', () => { beforeEach(() => { wrapper = createComponent({ users: mockCountsData2, - hasNextPage: true, + additionalData: mockCountsData1, }); jest diff --git a/spec/frontend/analytics/instance_statistics/utils_spec.js b/spec/frontend/analytics/instance_statistics/utils_spec.js index 1a0cf35ead1..3fd89c7f740 100644 --- a/spec/frontend/analytics/instance_statistics/utils_spec.js +++ b/spec/frontend/analytics/instance_statistics/utils_spec.js @@ -1,7 +1,7 @@ import { getAverageByMonth, - extractValues, - sortByDate, + getEarliestDate, + generateDataKeys, } from '~/analytics/instance_statistics/utils'; import { mockCountsData1, @@ -44,55 +44,38 @@ describe('getAverageByMonth', () => { }); }); -describe('extractValues', () => { - it('extracts only requested values', () => { - const data = { fooBar: { baz: 'quis' }, ignored: 'ignored' }; - expect(extractValues(data, ['bar'], 'foo', 'baz')).toEqual({ bazBar: 'quis' }); +describe('getEarliestDate', () => { + it('returns the date of the final item in the array', () => { + expect(getEarliestDate(mockCountsData1)).toBe('2020-06-12'); }); - it('it renames with the `renameKey` if provided', () => { - const data = { fooBar: { baz: 'quis' }, ignored: 'ignored' }; - expect(extractValues(data, ['bar'], 'foo', 'baz', { renameKey: 'renamed' })).toEqual({ - renamedBar: 'quis', - }); + it('returns null for an empty array', () => { + expect(getEarliestDate([])).toBeNull(); }); - it('is able to get nested data', () => { - const data = { fooBar: { even: [{ further: 'nested' }] }, ignored: 'ignored' }; - expect(extractValues(data, ['bar'], 'foo', 'even[0].further')).toEqual({ - 'even[0].furtherBar': 'nested', - }); - }); - - it('is able to extract multiple values', () => { - const data = { - fooBar: { baz: 'quis' }, - fooBaz: { baz: 'quis' }, - fooQuis: { baz: 'quis' }, - }; - expect(extractValues(data, ['bar', 'baz', 'quis'], 'foo', 'baz')).toEqual({ - bazBar: 'quis', - bazBaz: 'quis', - bazQuis: 'quis', - }); + it("returns null if the array has data but `recordedAt` isn't defined", () => { + expect( + getEarliestDate(mockCountsData1.map(({ recordedAt: date, ...rest }) => ({ date, ...rest }))), + ).toBeNull(); }); +}); - it('returns empty data set when keys are not found', () => { - const data = { foo: { baz: 'quis' }, ignored: 'ignored' }; - expect(extractValues(data, ['bar'], 'foo', 'baz')).toEqual({}); - }); +describe('generateDataKeys', () => { + const fakeQueries = [ + { identifier: 'from' }, + { identifier: 'first' }, + { identifier: 'to' }, + { identifier: 'last' }, + ]; - it('returns empty data when params are missing', () => { - expect(extractValues()).toEqual({}); - }); -}); + const defaultValue = 'default value'; + const res = generateDataKeys(fakeQueries, defaultValue); -describe('sortByDate', () => { - it('sorts the array by date', () => { - expect(sortByDate(mockCountsData1)).toStrictEqual([...mockCountsData1].reverse()); + it('extracts each query identifier and sets them as object keys', () => { + expect(Object.keys(res)).toEqual(['from', 'first', 'to', 'last']); }); - it('does not modify the original array', () => { - expect(sortByDate(countsMonthlyChartData1)).not.toBe(countsMonthlyChartData1); + it('sets every value to the `defaultValue` provided', () => { + expect(Object.values(res)).toEqual(Array(fakeQueries.length).fill(defaultValue)); }); }); |