summaryrefslogtreecommitdiff
path: root/spec/frontend/analytics
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/analytics')
-rw-r--r--spec/frontend/analytics/instance_statistics/components/app_spec.js5
-rw-r--r--spec/frontend/analytics/instance_statistics/components/users_chart_spec.js200
-rw-r--r--spec/frontend/analytics/instance_statistics/mock_data.js12
3 files changed, 217 insertions, 0 deletions
diff --git a/spec/frontend/analytics/instance_statistics/components/app_spec.js b/spec/frontend/analytics/instance_statistics/components/app_spec.js
index 39f6d1b450a..df13c9f82a9 100644
--- a/spec/frontend/analytics/instance_statistics/components/app_spec.js
+++ b/spec/frontend/analytics/instance_statistics/components/app_spec.js
@@ -2,6 +2,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';
+import UsersChart from '~/analytics/instance_statistics/components/users_chart.vue';
describe('InstanceStatisticsApp', () => {
let wrapper;
@@ -26,4 +27,8 @@ describe('InstanceStatisticsApp', () => {
it('displays the pipelines chart component', () => {
expect(wrapper.find(PipelinesChart).exists()).toBe(true);
});
+
+ it('displays the users chart component', () => {
+ expect(wrapper.find(UsersChart).exists()).toBe(true);
+ });
});
diff --git a/spec/frontend/analytics/instance_statistics/components/users_chart_spec.js b/spec/frontend/analytics/instance_statistics/components/users_chart_spec.js
new file mode 100644
index 00000000000..7509c1e6626
--- /dev/null
+++ b/spec/frontend/analytics/instance_statistics/components/users_chart_spec.js
@@ -0,0 +1,200 @@
+import { createLocalVue, shallowMount } from '@vue/test-utils';
+import { GlAreaChart } from '@gitlab/ui/dist/charts';
+import { GlAlert } from '@gitlab/ui';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'jest/helpers/mock_apollo_helper';
+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, mockPageInfo } from '../mock_data';
+
+const localVue = createLocalVue();
+localVue.use(VueApollo);
+
+describe('UsersChart', () => {
+ let wrapper;
+ let queryHandler;
+
+ const mockApolloResponse = ({ loading = false, hasNextPage = false, users }) => ({
+ data: {
+ users: {
+ pageInfo: { ...mockPageInfo, hasNextPage },
+ nodes: users,
+ loading,
+ },
+ },
+ });
+
+ const mockQueryResponse = ({ users, loading = false, hasNextPage = false }) => {
+ const apolloQueryResponse = mockApolloResponse({ loading, hasNextPage, users });
+ if (loading) {
+ return jest.fn().mockReturnValue(new Promise(() => {}));
+ }
+ if (hasNextPage) {
+ return jest
+ .fn()
+ .mockResolvedValueOnce(apolloQueryResponse)
+ .mockResolvedValueOnce(
+ mockApolloResponse({
+ loading,
+ hasNextPage: false,
+ users: [{ recordedAt: '2020-07-21', count: 5 }],
+ }),
+ );
+ }
+ return jest.fn().mockResolvedValue(apolloQueryResponse);
+ };
+
+ const createComponent = ({
+ loadingError = false,
+ loading = false,
+ users = [],
+ hasNextPage = false,
+ } = {}) => {
+ queryHandler = mockQueryResponse({ users, loading, hasNextPage });
+
+ return shallowMount(UsersChart, {
+ props: {
+ startDate: useFakeDate(2020, 9, 26),
+ endDate: useFakeDate(2020, 10, 1),
+ totalDataPoints: mockCountsData2.length,
+ },
+ localVue,
+ apolloProvider: createMockApollo([[usersQuery, queryHandler]]),
+ data() {
+ return { loadingError };
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ const findLoader = () => wrapper.find(ChartSkeletonLoader);
+ const findAlert = () => wrapper.find(GlAlert);
+ const findChart = () => wrapper.find(GlAreaChart);
+
+ describe('while loading', () => {
+ beforeEach(() => {
+ wrapper = createComponent({ loading: true });
+ });
+
+ it('displays the skeleton loader', () => {
+ expect(findLoader().exists()).toBe(true);
+ });
+
+ it('hides the chart', () => {
+ expect(findChart().exists()).toBe(false);
+ });
+ });
+
+ describe('without data', () => {
+ beforeEach(async () => {
+ wrapper = createComponent({ users: [] });
+ await wrapper.vm.$nextTick();
+ });
+
+ 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(async () => {
+ wrapper = createComponent({ users: mockCountsData2 });
+ await wrapper.vm.$nextTick();
+ });
+
+ 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')).toEqual([
+ { data: roundedSortedCountsMonthlyChartData2, name: 'Total users' },
+ ]);
+ });
+ });
+
+ describe('with errors', () => {
+ beforeEach(async () => {
+ wrapper = createComponent({ loadingError: true });
+ await wrapper.vm.$nextTick();
+ });
+
+ it('renders an error message', () => {
+ expect(findAlert().text()).toBe(
+ 'Could not load the user chart. Please refresh the page to try again.',
+ );
+ });
+
+ it('hides the skeleton loader', () => {
+ expect(findLoader().exists()).toBe(false);
+ });
+
+ it('renders the chart', () => {
+ expect(findChart().exists()).toBe(false);
+ });
+ });
+
+ describe('when fetching more data', () => {
+ describe('when the fetchMore query returns data', () => {
+ beforeEach(async () => {
+ wrapper = createComponent({
+ users: mockCountsData2,
+ hasNextPage: true,
+ });
+
+ jest.spyOn(wrapper.vm.$apollo.queries.users, 'fetchMore');
+ await wrapper.vm.$nextTick();
+ });
+
+ it('requests data twice', () => {
+ expect(queryHandler).toBeCalledTimes(2);
+ });
+
+ it('calls fetchMore', () => {
+ expect(wrapper.vm.$apollo.queries.users.fetchMore).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe('when the fetchMore query throws an error', () => {
+ beforeEach(() => {
+ wrapper = createComponent({
+ users: mockCountsData2,
+ hasNextPage: true,
+ });
+
+ jest
+ .spyOn(wrapper.vm.$apollo.queries.users, 'fetchMore')
+ .mockImplementation(jest.fn().mockRejectedValue());
+ return wrapper.vm.$nextTick();
+ });
+
+ it('calls fetchMore', () => {
+ expect(wrapper.vm.$apollo.queries.users.fetchMore).toHaveBeenCalledTimes(1);
+ });
+
+ it('renders an error message', () => {
+ expect(findAlert().text()).toBe(
+ 'Could not load the user chart. Please refresh the page to try again.',
+ );
+ });
+ });
+ });
+});
diff --git a/spec/frontend/analytics/instance_statistics/mock_data.js b/spec/frontend/analytics/instance_statistics/mock_data.js
index c3f5069da28..b737db4c55f 100644
--- a/spec/frontend/analytics/instance_statistics/mock_data.js
+++ b/spec/frontend/analytics/instance_statistics/mock_data.js
@@ -28,3 +28,15 @@ export const countsMonthlyChartData2 = [
['2020-07-01', 9.5], // average of 2020-07-x items
['2020-06-01', 20.666666666666668], // average of 2020-06-x items
];
+
+export const roundedSortedCountsMonthlyChartData2 = [
+ ['2020-06-01', 21], // average of 2020-06-x items
+ ['2020-07-01', 10], // average of 2020-07-x items
+];
+
+export const mockPageInfo = {
+ hasNextPage: false,
+ hasPreviousPage: false,
+ startCursor: null,
+ endCursor: null,
+};