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:
Diffstat (limited to 'spec/frontend/cycle_analytics')
-rw-r--r--spec/frontend/cycle_analytics/base_spec.js2
-rw-r--r--spec/frontend/cycle_analytics/filter_bar_spec.js9
-rw-r--r--spec/frontend/cycle_analytics/metric_popover_spec.js102
-rw-r--r--spec/frontend/cycle_analytics/stage_table_spec.js3
-rw-r--r--spec/frontend/cycle_analytics/utils_spec.js31
-rw-r--r--spec/frontend/cycle_analytics/value_stream_metrics_spec.js80
6 files changed, 57 insertions, 170 deletions
diff --git a/spec/frontend/cycle_analytics/base_spec.js b/spec/frontend/cycle_analytics/base_spec.js
index 9a9415cc12a..7b1ef71da63 100644
--- a/spec/frontend/cycle_analytics/base_spec.js
+++ b/spec/frontend/cycle_analytics/base_spec.js
@@ -3,11 +3,11 @@ import { shallowMount } from '@vue/test-utils';
import Vue from 'vue';
import Vuex from 'vuex';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import ValueStreamMetrics from '~/analytics/shared/components/value_stream_metrics.vue';
import BaseComponent from '~/cycle_analytics/components/base.vue';
import PathNavigation from '~/cycle_analytics/components/path_navigation.vue';
import StageTable from '~/cycle_analytics/components/stage_table.vue';
import ValueStreamFilters from '~/cycle_analytics/components/value_stream_filters.vue';
-import ValueStreamMetrics from '~/cycle_analytics/components/value_stream_metrics.vue';
import { NOT_ENOUGH_DATA_ERROR } from '~/cycle_analytics/constants';
import initState from '~/cycle_analytics/store/state';
import {
diff --git a/spec/frontend/cycle_analytics/filter_bar_spec.js b/spec/frontend/cycle_analytics/filter_bar_spec.js
index 407f21bd956..36933790cf7 100644
--- a/spec/frontend/cycle_analytics/filter_bar_spec.js
+++ b/spec/frontend/cycle_analytics/filter_bar_spec.js
@@ -1,4 +1,5 @@
-import { createLocalVue, shallowMount } from '@vue/test-utils';
+import { shallowMount } from '@vue/test-utils';
+import Vue, { nextTick } from 'vue';
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import Vuex from 'vuex';
@@ -15,8 +16,7 @@ import * as utils from '~/vue_shared/components/filtered_search_bar/filtered_sea
import initialFiltersState from '~/vue_shared/components/filtered_search_bar/store/modules/filters/state';
import UrlSync from '~/vue_shared/components/url_sync.vue';
-const localVue = createLocalVue();
-localVue.use(Vuex);
+Vue.use(Vuex);
const milestoneTokenType = 'milestone';
const labelsTokenType = 'labels';
@@ -42,7 +42,7 @@ const defaultParams = {
};
async function shouldMergeUrlParams(wrapper, result) {
- await wrapper.vm.$nextTick();
+ await nextTick();
expect(urlUtils.mergeUrlParams).toHaveBeenCalledWith(result, window.location.href, {
spreadArrays: true,
});
@@ -77,7 +77,6 @@ describe('Filter bar', () => {
const createComponent = (initialStore) => {
return shallowMount(FilterBar, {
- localVue,
store: initialStore,
propsData: {
groupPath: 'foo',
diff --git a/spec/frontend/cycle_analytics/metric_popover_spec.js b/spec/frontend/cycle_analytics/metric_popover_spec.js
deleted file mode 100644
index 5a622fcacd5..00000000000
--- a/spec/frontend/cycle_analytics/metric_popover_spec.js
+++ /dev/null
@@ -1,102 +0,0 @@
-import { GlLink, GlIcon } from '@gitlab/ui';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import MetricPopover from '~/cycle_analytics/components/metric_popover.vue';
-
-const MOCK_METRIC = {
- key: 'deployment-frequency',
- label: 'Deployment Frequency',
- value: '10.0',
- unit: 'per day',
- description: 'Average number of deployments to production per day.',
- links: [],
-};
-
-describe('MetricPopover', () => {
- let wrapper;
-
- const createComponent = (props = {}) => {
- return shallowMountExtended(MetricPopover, {
- propsData: {
- target: 'deployment-frequency',
- ...props,
- },
- stubs: {
- 'gl-popover': { template: '<div><slot name="title"></slot><slot></slot></div>' },
- },
- });
- };
-
- const findMetricLabel = () => wrapper.findByTestId('metric-label');
- const findAllMetricLinks = () => wrapper.findAll('[data-testid="metric-link"]');
- const findMetricDescription = () => wrapper.findByTestId('metric-description');
- const findMetricDocsLink = () => wrapper.findByTestId('metric-docs-link');
- const findMetricDocsLinkIcon = () => findMetricDocsLink().find(GlIcon);
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('renders the metric label', () => {
- wrapper = createComponent({ metric: MOCK_METRIC });
- expect(findMetricLabel().text()).toBe(MOCK_METRIC.label);
- });
-
- it('renders the metric description', () => {
- wrapper = createComponent({ metric: MOCK_METRIC });
- expect(findMetricDescription().text()).toBe(MOCK_METRIC.description);
- });
-
- describe('with links', () => {
- const links = [
- {
- name: 'Deployment frequency',
- url: '/groups/gitlab-org/-/analytics/ci_cd?tab=deployment-frequency',
- label: 'Dashboard',
- },
- {
- name: 'Another link',
- url: '/groups/gitlab-org/-/analytics/another-link',
- label: 'Another link',
- },
- ];
- const docsLink = {
- name: 'Deployment frequency',
- url: '/help/user/analytics/index#definitions',
- label: 'Go to docs',
- docs_link: true,
- };
- const linksWithDocs = [...links, docsLink];
-
- describe.each`
- hasDocsLink | allLinks | displayedMetricLinks
- ${true} | ${linksWithDocs} | ${links}
- ${false} | ${links} | ${links}
- `(
- 'when one link has docs_link=$hasDocsLink',
- ({ hasDocsLink, allLinks, displayedMetricLinks }) => {
- beforeEach(() => {
- wrapper = createComponent({ metric: { ...MOCK_METRIC, links: allLinks } });
- });
-
- displayedMetricLinks.forEach((link, idx) => {
- it(`renders a link for "${link.name}"`, () => {
- const allLinkContainers = findAllMetricLinks();
-
- expect(allLinkContainers.at(idx).text()).toContain(link.name);
- expect(allLinkContainers.at(idx).find(GlLink).attributes('href')).toBe(link.url);
- });
- });
-
- it(`${hasDocsLink ? 'renders' : "doesn't render"} a docs link`, () => {
- expect(findMetricDocsLink().exists()).toBe(hasDocsLink);
-
- if (hasDocsLink) {
- expect(findMetricDocsLink().attributes('href')).toBe(docsLink.url);
- expect(findMetricDocsLink().text()).toBe(docsLink.label);
- expect(findMetricDocsLinkIcon().attributes('name')).toBe('external-link');
- }
- });
- },
- );
- });
-});
diff --git a/spec/frontend/cycle_analytics/stage_table_spec.js b/spec/frontend/cycle_analytics/stage_table_spec.js
index 9605dce2668..107fe5fc865 100644
--- a/spec/frontend/cycle_analytics/stage_table_spec.js
+++ b/spec/frontend/cycle_analytics/stage_table_spec.js
@@ -1,5 +1,6 @@
import { GlEmptyState, GlLoadingIcon, GlTable } from '@gitlab/ui';
import { shallowMount, mount } from '@vue/test-utils';
+import { nextTick } from 'vue';
import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import StageTable from '~/cycle_analytics/components/stage_table.vue';
@@ -263,7 +264,7 @@ describe('StageTable', () => {
expect(wrapper.emitted('handleUpdatePagination')).toBeUndefined();
findPagination().vm.$emit('input', 2);
- await wrapper.vm.$nextTick();
+ await nextTick();
expect(wrapper.emitted('handleUpdatePagination')[0]).toEqual([{ page: 2 }]);
});
diff --git a/spec/frontend/cycle_analytics/utils_spec.js b/spec/frontend/cycle_analytics/utils_spec.js
index a6d6d022781..51405a1ba4d 100644
--- a/spec/frontend/cycle_analytics/utils_spec.js
+++ b/spec/frontend/cycle_analytics/utils_spec.js
@@ -1,13 +1,10 @@
-import metricsData from 'test_fixtures/projects/analytics/value_stream_analytics/summary.json';
import {
transformStagesForPathNavigation,
medianTimeToParsedSeconds,
formatMedianValues,
filterStagesByHiddenStatus,
- prepareTimeMetricsData,
buildCycleAnalyticsInitialData,
} from '~/cycle_analytics/utils';
-import { slugify } from '~/lib/utils/text_utility';
import {
selectedStage,
allowedStages,
@@ -89,34 +86,6 @@ describe('Value stream analytics utils', () => {
});
});
- describe('prepareTimeMetricsData', () => {
- let prepared;
- const [first, second] = metricsData;
- const firstKey = slugify(first.title);
- const secondKey = slugify(second.title);
-
- beforeEach(() => {
- prepared = prepareTimeMetricsData([first, second], {
- [firstKey]: { description: 'Is a value that is good' },
- });
- });
-
- it('will add a `key` based on the title', () => {
- expect(prepared).toMatchObject([{ key: firstKey }, { key: secondKey }]);
- });
-
- it('will add a `label` key', () => {
- expect(prepared).toMatchObject([{ label: 'New Issues' }, { label: 'Commits' }]);
- });
-
- it('will add a popover description using the key if it is provided', () => {
- expect(prepared).toMatchObject([
- { description: 'Is a value that is good' },
- { description: '' },
- ]);
- });
- });
-
describe('buildCycleAnalyticsInitialData', () => {
let res = null;
const projectId = '5';
diff --git a/spec/frontend/cycle_analytics/value_stream_metrics_spec.js b/spec/frontend/cycle_analytics/value_stream_metrics_spec.js
index 082db2cc312..7a539b262fc 100644
--- a/spec/frontend/cycle_analytics/value_stream_metrics_spec.js
+++ b/spec/frontend/cycle_analytics/value_stream_metrics_spec.js
@@ -1,20 +1,22 @@
import { GlDeprecatedSkeletonLoading as GlSkeletonLoading } from '@gitlab/ui';
-import { GlSingleStat } from '@gitlab/ui/dist/charts';
import { shallowMount } from '@vue/test-utils';
+import { nextTick } from 'vue';
import metricsData from 'test_fixtures/projects/analytics/value_stream_analytics/summary.json';
import waitForPromises from 'helpers/wait_for_promises';
+import ValueStreamMetrics from '~/analytics/shared/components/value_stream_metrics.vue';
import { METRIC_TYPE_SUMMARY } from '~/api/analytics_api';
-import ValueStreamMetrics from '~/cycle_analytics/components/value_stream_metrics.vue';
+import { METRICS_POPOVER_CONTENT } from '~/analytics/shared/constants';
+import { prepareTimeMetricsData } from '~/analytics/shared/utils';
+import MetricTile from '~/analytics/shared/components/metric_tile.vue';
import createFlash from '~/flash';
-import { redirectTo } from '~/lib/utils/url_utility';
import { group } from './mock_data';
jest.mock('~/flash');
-jest.mock('~/lib/utils/url_utility');
describe('ValueStreamMetrics', () => {
let wrapper;
let mockGetValueStreamSummaryMetrics;
+ let mockFilterFn;
const { full_path: requestPath } = group;
const fakeReqName = 'Mock metrics';
@@ -24,17 +26,18 @@ describe('ValueStreamMetrics', () => {
name: fakeReqName,
});
- const createComponent = ({ requestParams = {} } = {}) => {
+ const createComponent = (props = {}) => {
return shallowMount(ValueStreamMetrics, {
propsData: {
requestPath,
- requestParams,
+ requestParams: {},
requests: [metricsRequestFactory()],
+ ...props,
},
});
};
- const findMetrics = () => wrapper.findAllComponents(GlSingleStat);
+ const findMetrics = () => wrapper.findAllComponents(MetricTile);
const expectToHaveRequest = (fields) => {
expect(mockGetValueStreamSummaryMetrics).toHaveBeenCalledWith({
@@ -55,19 +58,19 @@ describe('ValueStreamMetrics', () => {
});
it('will display a loader with pending requests', async () => {
- await wrapper.vm.$nextTick();
+ await nextTick();
expect(wrapper.findComponent(GlSkeletonLoading).exists()).toBe(true);
});
- it('renders hidden GlSingleStat components for each metric', async () => {
+ it('renders hidden MetricTile components for each metric', async () => {
await waitForPromises();
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
// eslint-disable-next-line no-restricted-syntax
wrapper.setData({ isLoading: true });
- await wrapper.vm.$nextTick();
+ await nextTick();
const components = findMetrics();
@@ -88,35 +91,52 @@ describe('ValueStreamMetrics', () => {
});
describe.each`
- index | value | title | unit | clickable
- ${0} | ${metricsData[0].value} | ${metricsData[0].title} | ${metricsData[0].unit} | ${false}
- ${1} | ${metricsData[1].value} | ${metricsData[1].title} | ${metricsData[1].unit} | ${false}
- ${2} | ${metricsData[2].value} | ${metricsData[2].title} | ${metricsData[2].unit} | ${false}
- ${3} | ${metricsData[3].value} | ${metricsData[3].title} | ${metricsData[3].unit} | ${true}
- `('metric tiles', ({ index, value, title, unit, clickable }) => {
- it(`renders a single stat component for "${title}" with value and unit`, () => {
+ index | identifier | value | label
+ ${0} | ${metricsData[0].identifier} | ${metricsData[0].value} | ${metricsData[0].title}
+ ${1} | ${metricsData[1].identifier} | ${metricsData[1].value} | ${metricsData[1].title}
+ ${2} | ${metricsData[2].identifier} | ${metricsData[2].value} | ${metricsData[2].title}
+ ${3} | ${metricsData[3].identifier} | ${metricsData[3].value} | ${metricsData[3].title}
+ `('metric tiles', ({ identifier, index, value, label }) => {
+ it(`renders a metric tile component for "${label}"`, () => {
const metric = findMetrics().at(index);
- expect(metric.props()).toMatchObject({ value, title, unit: unit ?? '' });
+ expect(metric.props('metric')).toMatchObject({ identifier, value, label });
expect(metric.isVisible()).toBe(true);
});
-
- it(`${
- clickable ? 'redirects' : "doesn't redirect"
- } when the user clicks the "${title}" metric`, () => {
- const metric = findMetrics().at(index);
- metric.vm.$emit('click');
- if (clickable) {
- expect(redirectTo).toHaveBeenCalledWith(metricsData[index].links[0].url);
- } else {
- expect(redirectTo).not.toHaveBeenCalled();
- }
- });
});
it('will not display a loading icon', () => {
expect(wrapper.find(GlSkeletonLoading).exists()).toBe(false);
});
+ describe('filterFn', () => {
+ const transferedMetricsData = prepareTimeMetricsData(metricsData, METRICS_POPOVER_CONTENT);
+
+ it('with a filter function, will call the function with the metrics data', async () => {
+ const filteredData = [
+ { identifier: 'issues', value: '3', title: 'New Issues', description: 'foo' },
+ ];
+ mockFilterFn = jest.fn(() => filteredData);
+
+ wrapper = createComponent({
+ filterFn: mockFilterFn,
+ });
+
+ await waitForPromises();
+
+ expect(mockFilterFn).toHaveBeenCalledWith(transferedMetricsData);
+ expect(wrapper.vm.metrics).toEqual(filteredData);
+ });
+
+ it('without a filter function, it will only update the metrics', async () => {
+ wrapper = createComponent();
+
+ await waitForPromises();
+
+ expect(mockFilterFn).not.toHaveBeenCalled();
+ expect(wrapper.vm.metrics).toEqual(transferedMetricsData);
+ });
+ });
+
describe('with additional params', () => {
beforeEach(async () => {
wrapper = createComponent({