diff options
Diffstat (limited to 'spec/frontend/cycle_analytics')
-rw-r--r-- | spec/frontend/cycle_analytics/metric_popover_spec.js | 102 | ||||
-rw-r--r-- | spec/frontend/cycle_analytics/mock_data.js | 41 | ||||
-rw-r--r-- | spec/frontend/cycle_analytics/store/actions_spec.js | 144 | ||||
-rw-r--r-- | spec/frontend/cycle_analytics/store/mutations_spec.js | 1 | ||||
-rw-r--r-- | spec/frontend/cycle_analytics/utils_spec.js | 96 | ||||
-rw-r--r-- | spec/frontend/cycle_analytics/value_stream_metrics_spec.js | 58 |
6 files changed, 351 insertions, 91 deletions
diff --git a/spec/frontend/cycle_analytics/metric_popover_spec.js b/spec/frontend/cycle_analytics/metric_popover_spec.js new file mode 100644 index 00000000000..5a622fcacd5 --- /dev/null +++ b/spec/frontend/cycle_analytics/metric_popover_spec.js @@ -0,0 +1,102 @@ +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/mock_data.js b/spec/frontend/cycle_analytics/mock_data.js index 1882457960a..c482bd4e910 100644 --- a/spec/frontend/cycle_analytics/mock_data.js +++ b/spec/frontend/cycle_analytics/mock_data.js @@ -1,10 +1,14 @@ -/* eslint-disable import/no-deprecated */ +import valueStreamAnalyticsStages from 'test_fixtures/projects/analytics/value_stream_analytics/stages.json'; +import issueStageFixtures from 'test_fixtures/projects/analytics/value_stream_analytics/events/issue.json'; +import planStageFixtures from 'test_fixtures/projects/analytics/value_stream_analytics/events/plan.json'; +import reviewStageFixtures from 'test_fixtures/projects/analytics/value_stream_analytics/events/review.json'; +import codeStageFixtures from 'test_fixtures/projects/analytics/value_stream_analytics/events/code.json'; +import testStageFixtures from 'test_fixtures/projects/analytics/value_stream_analytics/events/test.json'; +import stagingStageFixtures from 'test_fixtures/projects/analytics/value_stream_analytics/events/staging.json'; -import { getJSONFixture } from 'helpers/fixtures'; import { TEST_HOST } from 'helpers/test_constants'; import { DEFAULT_VALUE_STREAM, - DEFAULT_DAYS_IN_PAST, PAGINATION_TYPE, PAGINATION_SORT_DIRECTION_DESC, PAGINATION_SORT_FIELD_END_EVENT, @@ -12,6 +16,7 @@ import { import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import { getDateInPast } from '~/lib/utils/datetime_utility'; +const DEFAULT_DAYS_IN_PAST = 30; export const createdBefore = new Date(2019, 0, 14); export const createdAfter = getDateInPast(createdBefore, DEFAULT_DAYS_IN_PAST); @@ -20,28 +25,16 @@ export const deepCamelCase = (obj) => convertObjectPropsToCamelCase(obj, { deep: export const getStageByTitle = (stages, title) => stages.find((stage) => stage.title && stage.title.toLowerCase().trim() === title) || {}; -const fixtureEndpoints = { - customizableCycleAnalyticsStagesAndEvents: - 'projects/analytics/value_stream_analytics/stages.json', - stageEvents: (stage) => `projects/analytics/value_stream_analytics/events/${stage}.json`, - metricsData: 'projects/analytics/value_stream_analytics/summary.json', -}; - -export const metricsData = getJSONFixture(fixtureEndpoints.metricsData); - -export const customizableStagesAndEvents = getJSONFixture( - fixtureEndpoints.customizableCycleAnalyticsStagesAndEvents, -); - export const defaultStages = ['issue', 'plan', 'review', 'code', 'test', 'staging']; -const stageFixtures = defaultStages.reduce((acc, stage) => { - const events = getJSONFixture(fixtureEndpoints.stageEvents(stage)); - return { - ...acc, - [stage]: events, - }; -}, {}); +const stageFixtures = { + issue: issueStageFixtures, + plan: planStageFixtures, + review: reviewStageFixtures, + code: codeStageFixtures, + test: testStageFixtures, + staging: stagingStageFixtures, +}; export const summary = [ { value: '20', title: 'New Issues' }, @@ -260,7 +253,7 @@ export const selectedProjects = [ }, ]; -export const rawValueStreamStages = customizableStagesAndEvents.stages; +export const rawValueStreamStages = valueStreamAnalyticsStages.stages; export const valueStreamStages = rawValueStreamStages.map((s) => convertObjectPropsToCamelCase(s, { deep: true }), diff --git a/spec/frontend/cycle_analytics/store/actions_spec.js b/spec/frontend/cycle_analytics/store/actions_spec.js index 993e6b6b73a..e775e941b4c 100644 --- a/spec/frontend/cycle_analytics/store/actions_spec.js +++ b/spec/frontend/cycle_analytics/store/actions_spec.js @@ -57,22 +57,12 @@ describe('Project Value Stream Analytics actions', () => { const mutationTypes = (arr) => arr.map(({ type }) => type); - const mockFetchStageDataActions = [ - { type: 'setLoading', payload: true }, - { type: 'fetchCycleAnalyticsData' }, - { type: 'fetchStageData' }, - { type: 'fetchStageMedians' }, - { type: 'fetchStageCountValues' }, - { type: 'setLoading', payload: false }, - ]; - describe.each` - action | payload | expectedActions | expectedMutations - ${'setLoading'} | ${true} | ${[]} | ${[{ type: 'SET_LOADING', payload: true }]} - ${'setDateRange'} | ${{ createdAfter, createdBefore }} | ${mockFetchStageDataActions} | ${[mockSetDateActionCommit]} - ${'setFilters'} | ${[]} | ${mockFetchStageDataActions} | ${[]} - ${'setSelectedStage'} | ${{ selectedStage }} | ${[{ type: 'fetchStageData' }]} | ${[{ type: 'SET_SELECTED_STAGE', payload: { selectedStage } }]} - ${'setSelectedValueStream'} | ${{ selectedValueStream }} | ${[{ type: 'fetchValueStreamStages' }, { type: 'fetchCycleAnalyticsData' }]} | ${[{ type: 'SET_SELECTED_VALUE_STREAM', payload: { selectedValueStream } }]} + action | payload | expectedActions | expectedMutations + ${'setDateRange'} | ${{ createdAfter, createdBefore }} | ${[{ type: 'refetchStageData' }]} | ${[mockSetDateActionCommit]} + ${'setFilters'} | ${[]} | ${[{ type: 'refetchStageData' }]} | ${[]} + ${'setSelectedStage'} | ${{ selectedStage }} | ${[{ type: 'refetchStageData' }]} | ${[{ type: 'SET_SELECTED_STAGE', payload: { selectedStage } }]} + ${'setSelectedValueStream'} | ${{ selectedValueStream }} | ${[{ type: 'fetchValueStreamStages' }]} | ${[{ type: 'SET_SELECTED_VALUE_STREAM', payload: { selectedValueStream } }]} `('$action', ({ action, payload, expectedActions, expectedMutations }) => { const types = mutationTypes(expectedMutations); it(`will dispatch ${expectedActions} and commit ${types}`, () => @@ -86,9 +76,18 @@ describe('Project Value Stream Analytics actions', () => { }); describe('initializeVsa', () => { - let mockDispatch; - let mockCommit; - const payload = { endpoints: mockEndpoints }; + const selectedAuthor = 'Author'; + const selectedMilestone = 'Milestone 1'; + const selectedAssigneeList = ['Assignee 1', 'Assignee 2']; + const selectedLabelList = ['Label 1', 'Label 2']; + const payload = { + endpoints: mockEndpoints, + selectedAuthor, + selectedMilestone, + selectedAssigneeList, + selectedLabelList, + selectedStage, + }; const mockFilterEndpoints = { groupEndpoint: 'foo', labelsEndpoint: mockLabelsPath, @@ -96,27 +95,63 @@ describe('Project Value Stream Analytics actions', () => { projectEndpoint: '/namespace/-/analytics/value_stream_analytics/value_streams', }; + it('will dispatch fetchValueStreams actions and commit SET_LOADING and INITIALIZE_VSA', () => { + return testAction({ + action: actions.initializeVsa, + state: {}, + payload, + expectedMutations: [ + { type: 'INITIALIZE_VSA', payload }, + { type: 'SET_LOADING', payload: true }, + { type: 'SET_LOADING', payload: false }, + ], + expectedActions: [ + { type: 'filters/setEndpoints', payload: mockFilterEndpoints }, + { + type: 'filters/initialize', + payload: { selectedAuthor, selectedMilestone, selectedAssigneeList, selectedLabelList }, + }, + { type: 'fetchValueStreams' }, + { type: 'setInitialStage', payload: selectedStage }, + ], + }); + }); + }); + + describe('setInitialStage', () => { beforeEach(() => { - mockDispatch = jest.fn(() => Promise.resolve()); - mockCommit = jest.fn(); + state = { ...state, stages: allowedStages }; }); - it('will dispatch the setLoading and fetchValueStreams actions and commit INITIALIZE_VSA', async () => { - await actions.initializeVsa( - { - ...state, - dispatch: mockDispatch, - commit: mockCommit, - }, - payload, - ); - expect(mockCommit).toHaveBeenCalledWith('INITIALIZE_VSA', { endpoints: mockEndpoints }); - - expect(mockDispatch).toHaveBeenCalledTimes(4); - expect(mockDispatch).toHaveBeenCalledWith('filters/setEndpoints', mockFilterEndpoints); - expect(mockDispatch).toHaveBeenCalledWith('setLoading', true); - expect(mockDispatch).toHaveBeenCalledWith('fetchValueStreams'); - expect(mockDispatch).toHaveBeenCalledWith('setLoading', false); + describe('with a selected stage', () => { + it('will commit `SET_SELECTED_STAGE` and fetchValueStreamStageData actions', () => { + const fakeStage = { ...selectedStage, id: 'fake', name: 'fake-stae' }; + return testAction({ + action: actions.setInitialStage, + state, + payload: fakeStage, + expectedMutations: [ + { + type: 'SET_SELECTED_STAGE', + payload: fakeStage, + }, + ], + expectedActions: [{ type: 'fetchValueStreamStageData' }], + }); + }); + }); + + describe('without a selected stage', () => { + it('will select the first stage from the value stream', () => { + const [firstStage] = allowedStages; + testAction({ + action: actions.setInitialStage, + state, + payload: null, + expectedMutations: [{ type: 'SET_SELECTED_STAGE', payload: firstStage }], + expectedActions: [{ type: 'fetchValueStreamStageData' }], + }); + }); }); }); @@ -270,12 +305,7 @@ describe('Project Value Stream Analytics actions', () => { state, payload: {}, expectedMutations: [{ type: 'REQUEST_VALUE_STREAMS' }], - expectedActions: [ - { type: 'receiveValueStreamsSuccess' }, - { type: 'setSelectedStage' }, - { type: 'fetchStageMedians' }, - { type: 'fetchStageCountValues' }, - ], + expectedActions: [{ type: 'receiveValueStreamsSuccess' }], })); describe('with a failing request', () => { @@ -483,4 +513,34 @@ describe('Project Value Stream Analytics actions', () => { })); }); }); + + describe('refetchStageData', () => { + it('will commit SET_LOADING and dispatch fetchValueStreamStageData actions', () => + testAction({ + action: actions.refetchStageData, + state, + payload: {}, + expectedMutations: [ + { type: 'SET_LOADING', payload: true }, + { type: 'SET_LOADING', payload: false }, + ], + expectedActions: [{ type: 'fetchValueStreamStageData' }], + })); + }); + + describe('fetchValueStreamStageData', () => { + it('will dispatch the fetchCycleAnalyticsData, fetchStageData, fetchStageMedians and fetchStageCountValues actions', () => + testAction({ + action: actions.fetchValueStreamStageData, + state, + payload: {}, + expectedMutations: [], + expectedActions: [ + { type: 'fetchCycleAnalyticsData' }, + { type: 'fetchStageData' }, + { type: 'fetchStageMedians' }, + { type: 'fetchStageCountValues' }, + ], + })); + }); }); diff --git a/spec/frontend/cycle_analytics/store/mutations_spec.js b/spec/frontend/cycle_analytics/store/mutations_spec.js index 4860225c995..2670a390e9c 100644 --- a/spec/frontend/cycle_analytics/store/mutations_spec.js +++ b/spec/frontend/cycle_analytics/store/mutations_spec.js @@ -101,6 +101,7 @@ describe('Project Value Stream Analytics mutations', () => { ${types.SET_SELECTED_VALUE_STREAM} | ${selectedValueStream} | ${'selectedValueStream'} | ${selectedValueStream} ${types.SET_PAGINATION} | ${pagination} | ${'pagination'} | ${{ ...pagination, sort: PAGINATION_SORT_FIELD_END_EVENT, direction: PAGINATION_SORT_DIRECTION_DESC }} ${types.SET_PAGINATION} | ${{ ...pagination, sort: 'duration', direction: 'asc' }} | ${'pagination'} | ${{ ...pagination, sort: 'duration', direction: 'asc' }} + ${types.SET_SELECTED_STAGE} | ${selectedStage} | ${'selectedStage'} | ${selectedStage} ${types.RECEIVE_VALUE_STREAMS_SUCCESS} | ${[selectedValueStream]} | ${'valueStreams'} | ${[selectedValueStream]} ${types.RECEIVE_VALUE_STREAM_STAGES_SUCCESS} | ${{ stages: rawValueStreamStages }} | ${'stages'} | ${valueStreamStages} ${types.RECEIVE_STAGE_MEDIANS_SUCCESS} | ${rawStageMedians} | ${'medians'} | ${formattedStageMedians} diff --git a/spec/frontend/cycle_analytics/utils_spec.js b/spec/frontend/cycle_analytics/utils_spec.js index 74d64cd8d71..a6d6d022781 100644 --- a/spec/frontend/cycle_analytics/utils_spec.js +++ b/spec/frontend/cycle_analytics/utils_spec.js @@ -1,11 +1,11 @@ -import { useFakeDate } from 'helpers/fake_date'; +import metricsData from 'test_fixtures/projects/analytics/value_stream_analytics/summary.json'; import { transformStagesForPathNavigation, medianTimeToParsedSeconds, formatMedianValues, filterStagesByHiddenStatus, - calculateFormattedDayInPast, prepareTimeMetricsData, + buildCycleAnalyticsInitialData, } from '~/cycle_analytics/utils'; import { slugify } from '~/lib/utils/text_utility'; import { @@ -14,7 +14,6 @@ import { stageMedians, pathNavIssueMetric, rawStageMedians, - metricsData, } from './mock_data'; describe('Value stream analytics utils', () => { @@ -90,14 +89,6 @@ describe('Value stream analytics utils', () => { }); }); - describe('calculateFormattedDayInPast', () => { - useFakeDate(1815, 11, 10); - - it('will return 2 dates, now and past', () => { - expect(calculateFormattedDayInPast(5)).toEqual({ now: '1815-12-10', past: '1815-12-05' }); - }); - }); - describe('prepareTimeMetricsData', () => { let prepared; const [first, second] = metricsData; @@ -125,4 +116,87 @@ describe('Value stream analytics utils', () => { ]); }); }); + + describe('buildCycleAnalyticsInitialData', () => { + let res = null; + const projectId = '5'; + const createdAfter = '2021-09-01'; + const createdBefore = '2021-11-06'; + const groupId = '146'; + const groupPath = 'fake-group'; + const fullPath = 'fake-group/fake-project'; + const labelsPath = '/fake-group/fake-project/-/labels.json'; + const milestonesPath = '/fake-group/fake-project/-/milestones.json'; + const requestPath = '/fake-group/fake-project/-/value_stream_analytics'; + + const rawData = { + projectId, + createdBefore, + createdAfter, + fullPath, + requestPath, + labelsPath, + milestonesPath, + groupId, + groupPath, + }; + + describe('with minimal data', () => { + beforeEach(() => { + res = buildCycleAnalyticsInitialData(rawData); + }); + + it('sets the projectId', () => { + expect(res.projectId).toBe(parseInt(projectId, 10)); + }); + + it('sets the date range', () => { + expect(res.createdBefore).toEqual(new Date(createdBefore)); + expect(res.createdAfter).toEqual(new Date(createdAfter)); + }); + + it('sets the endpoints', () => { + const { endpoints } = res; + expect(endpoints.fullPath).toBe(fullPath); + expect(endpoints.requestPath).toBe(requestPath); + expect(endpoints.labelsPath).toBe(labelsPath); + expect(endpoints.milestonesPath).toBe(milestonesPath); + expect(endpoints.groupId).toBe(parseInt(groupId, 10)); + expect(endpoints.groupPath).toBe(groupPath); + }); + + it('returns null when there is no stage', () => { + expect(res.selectedStage).toBeNull(); + }); + + it('returns false for missing features', () => { + expect(res.features.cycleAnalyticsForGroups).toBe(false); + }); + }); + + describe('with a stage set', () => { + const jsonStage = '{"id":"fakeStage","title":"fakeStage"}'; + + it('parses the selectedStage data', () => { + res = buildCycleAnalyticsInitialData({ ...rawData, stage: jsonStage }); + + const { selectedStage: stage } = res; + + expect(stage.id).toBe('fakeStage'); + expect(stage.title).toBe('fakeStage'); + }); + }); + + describe('with features set', () => { + const fakeFeatures = { cycleAnalyticsForGroups: true }; + + it('sets the feature flags', () => { + res = buildCycleAnalyticsInitialData({ + ...rawData, + gon: { licensed_features: fakeFeatures }, + }); + expect(res.features).toEqual(fakeFeatures); + }); + }); + }); }); diff --git a/spec/frontend/cycle_analytics/value_stream_metrics_spec.js b/spec/frontend/cycle_analytics/value_stream_metrics_spec.js index ffdb49a828c..c97e4845bc2 100644 --- a/spec/frontend/cycle_analytics/value_stream_metrics_spec.js +++ b/spec/frontend/cycle_analytics/value_stream_metrics_spec.js @@ -1,13 +1,16 @@ import { GlDeprecatedSkeletonLoading as GlSkeletonLoading } from '@gitlab/ui'; import { GlSingleStat } from '@gitlab/ui/dist/charts'; import { shallowMount } from '@vue/test-utils'; +import metricsData from 'test_fixtures/projects/analytics/value_stream_analytics/summary.json'; import waitForPromises from 'helpers/wait_for_promises'; import { METRIC_TYPE_SUMMARY } from '~/api/analytics_api'; import ValueStreamMetrics from '~/cycle_analytics/components/value_stream_metrics.vue'; import createFlash from '~/flash'; -import { group, metricsData } from './mock_data'; +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; @@ -43,7 +46,6 @@ describe('ValueStreamMetrics', () => { afterEach(() => { wrapper.destroy(); - wrapper = null; }); describe('with successful requests', () => { @@ -55,7 +57,23 @@ describe('ValueStreamMetrics', () => { it('will display a loader with pending requests', async () => { await wrapper.vm.$nextTick(); - expect(wrapper.find(GlSkeletonLoading).exists()).toBe(true); + expect(wrapper.findComponent(GlSkeletonLoading).exists()).toBe(true); + }); + + it('renders hidden GlSingleStat components for each metric', async () => { + await waitForPromises(); + + wrapper.setData({ isLoading: true }); + + await wrapper.vm.$nextTick(); + + const components = findMetrics(); + + expect(components).toHaveLength(metricsData.length); + + metricsData.forEach((metric, index) => { + expect(components.at(index).isVisible()).toBe(false); + }); }); describe('with data loaded', () => { @@ -67,19 +85,31 @@ describe('ValueStreamMetrics', () => { expectToHaveRequest({ params: {} }); }); - it.each` - index | value | title | unit - ${0} | ${metricsData[0].value} | ${metricsData[0].title} | ${metricsData[0].unit} - ${1} | ${metricsData[1].value} | ${metricsData[1].title} | ${metricsData[1].unit} - ${2} | ${metricsData[2].value} | ${metricsData[2].title} | ${metricsData[2].unit} - ${3} | ${metricsData[3].value} | ${metricsData[3].title} | ${metricsData[3].unit} - `( - 'renders a single stat component for the $title with value and unit', - ({ index, value, title, unit }) => { + 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`, () => { const metric = findMetrics().at(index); expect(metric.props()).toMatchObject({ value, title, unit: unit ?? '' }); - }, - ); + 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); |