diff options
Diffstat (limited to 'spec/frontend/monitoring')
-rw-r--r-- | spec/frontend/monitoring/components/embeds/embed_group_spec.js | 163 | ||||
-rw-r--r-- | spec/frontend/monitoring/components/embeds/metric_embed_spec.js (renamed from spec/frontend/monitoring/embed/embed_spec.js) | 6 | ||||
-rw-r--r-- | spec/frontend/monitoring/components/embeds/mock_data.js (renamed from spec/frontend/monitoring/embed/mock_data.js) | 33 | ||||
-rw-r--r-- | spec/frontend/monitoring/components/panel_type_spec.js | 72 | ||||
-rw-r--r-- | spec/frontend/monitoring/mock_data.js | 17 | ||||
-rw-r--r-- | spec/frontend/monitoring/store/embed_group/actions_spec.js | 16 | ||||
-rw-r--r-- | spec/frontend/monitoring/store/embed_group/getters_spec.js | 19 | ||||
-rw-r--r-- | spec/frontend/monitoring/store/embed_group/mutations_spec.js | 16 |
8 files changed, 329 insertions, 13 deletions
diff --git a/spec/frontend/monitoring/components/embeds/embed_group_spec.js b/spec/frontend/monitoring/components/embeds/embed_group_spec.js new file mode 100644 index 00000000000..54d21def603 --- /dev/null +++ b/spec/frontend/monitoring/components/embeds/embed_group_spec.js @@ -0,0 +1,163 @@ +import { createLocalVue, mount, shallowMount } from '@vue/test-utils'; +import Vuex from 'vuex'; +import { GlButton, GlCard } from '@gitlab/ui'; +import { TEST_HOST } from 'helpers/test_constants'; +import EmbedGroup from '~/monitoring/components/embeds/embed_group.vue'; +import MetricEmbed from '~/monitoring/components/embeds/metric_embed.vue'; +import { + addModuleAction, + initialEmbedGroupState, + singleEmbedProps, + dashboardEmbedProps, + multipleEmbedProps, +} from './mock_data'; + +const localVue = createLocalVue(); +localVue.use(Vuex); + +describe('Embed Group', () => { + let wrapper; + let store; + const metricsWithDataGetter = jest.fn(); + + function mountComponent({ urls = [TEST_HOST], shallow = true, stubs } = {}) { + const mountMethod = shallow ? shallowMount : mount; + wrapper = mountMethod(EmbedGroup, { + localVue, + store, + propsData: { + urls, + }, + stubs, + }); + } + + beforeEach(() => { + store = new Vuex.Store({ + modules: { + embedGroup: { + namespaced: true, + actions: { addModule: jest.fn() }, + getters: { metricsWithData: metricsWithDataGetter }, + state: initialEmbedGroupState, + }, + }, + }); + store.registerModule = jest.fn(); + jest.spyOn(store, 'dispatch'); + }); + + afterEach(() => { + metricsWithDataGetter.mockReset(); + if (wrapper) { + wrapper.destroy(); + } + }); + + describe('interactivity', () => { + it('hides the component when no chart data is loaded', () => { + metricsWithDataGetter.mockReturnValue([]); + mountComponent(); + + expect(wrapper.find(GlCard).isVisible()).toBe(false); + }); + + it('shows the component when chart data is loaded', () => { + metricsWithDataGetter.mockReturnValue([1]); + mountComponent(); + + expect(wrapper.find(GlCard).isVisible()).toBe(true); + }); + + it('is expanded by default', () => { + metricsWithDataGetter.mockReturnValue([1]); + mountComponent({ shallow: false, stubs: { MetricEmbed: '<div />' } }); + + expect(wrapper.find('.card-body').classes()).not.toContain('d-none'); + }); + + it('collapses when clicked', done => { + metricsWithDataGetter.mockReturnValue([1]); + mountComponent({ shallow: false, stubs: { MetricEmbed: '<div />' } }); + + wrapper.find(GlButton).trigger('click'); + + wrapper.vm.$nextTick(() => { + expect(wrapper.find('.card-body').classes()).toContain('d-none'); + done(); + }); + }); + }); + + describe('single metrics', () => { + beforeEach(() => { + metricsWithDataGetter.mockReturnValue([1]); + mountComponent(); + }); + + it('renders an Embed component', () => { + expect(wrapper.find(MetricEmbed).exists()).toBe(true); + }); + + it('passes the correct props to the Embed component', () => { + expect(wrapper.find(MetricEmbed).props()).toEqual(singleEmbedProps()); + }); + + it('adds the monitoring dashboard module', () => { + expect(store.dispatch).toHaveBeenCalledWith(addModuleAction, 'monitoringDashboard/0'); + }); + }); + + describe('dashboard metrics', () => { + beforeEach(() => { + metricsWithDataGetter.mockReturnValue([2]); + mountComponent(); + }); + + it('passes the correct props to the dashboard Embed component', () => { + expect(wrapper.find(MetricEmbed).props()).toEqual(dashboardEmbedProps()); + }); + + it('adds the monitoring dashboard module', () => { + expect(store.dispatch).toHaveBeenCalledWith(addModuleAction, 'monitoringDashboard/0'); + }); + }); + + describe('multiple metrics', () => { + beforeEach(() => { + metricsWithDataGetter.mockReturnValue([1, 1]); + mountComponent({ urls: [TEST_HOST, TEST_HOST] }); + }); + + it('creates Embed components', () => { + expect(wrapper.findAll(MetricEmbed)).toHaveLength(2); + }); + + it('passes the correct props to the Embed components', () => { + expect(wrapper.findAll(MetricEmbed).wrappers.map(item => item.props())).toEqual( + multipleEmbedProps(), + ); + }); + + it('adds multiple monitoring dashboard modules', () => { + expect(store.dispatch).toHaveBeenCalledWith(addModuleAction, 'monitoringDashboard/0'); + expect(store.dispatch).toHaveBeenCalledWith(addModuleAction, 'monitoringDashboard/1'); + }); + }); + + describe('button text', () => { + it('has a singular label when there is one embed', () => { + metricsWithDataGetter.mockReturnValue([1]); + mountComponent({ shallow: false, stubs: { MetricEmbed: '<div />' } }); + + expect(wrapper.find(GlButton).text()).toBe('Hide chart'); + }); + + it('has a plural label when there are multiple embeds', () => { + metricsWithDataGetter.mockReturnValue([2]); + mountComponent({ shallow: false, stubs: { MetricEmbed: '<div />' } }); + + expect(wrapper.find(GlButton).text()).toBe('Hide charts'); + }); + }); +}); diff --git a/spec/frontend/monitoring/embed/embed_spec.js b/spec/frontend/monitoring/components/embeds/metric_embed_spec.js index 850092c4a72..d0fe22cefec 100644 --- a/spec/frontend/monitoring/embed/embed_spec.js +++ b/spec/frontend/monitoring/components/embeds/metric_embed_spec.js @@ -2,20 +2,20 @@ import { createLocalVue, shallowMount } from '@vue/test-utils'; import Vuex from 'vuex'; import PanelType from 'ee_else_ce/monitoring/components/panel_type.vue'; import { TEST_HOST } from 'helpers/test_constants'; -import Embed from '~/monitoring/components/embed.vue'; +import MetricEmbed from '~/monitoring/components/embeds/metric_embed.vue'; import { groups, initialState, metricsData, metricsWithData } from './mock_data'; const localVue = createLocalVue(); localVue.use(Vuex); -describe('Embed', () => { +describe('MetricEmbed', () => { let wrapper; let store; let actions; let metricsWithDataGetter; function mountComponent() { - wrapper = shallowMount(Embed, { + wrapper = shallowMount(MetricEmbed, { localVue, store, propsData: { diff --git a/spec/frontend/monitoring/embed/mock_data.js b/spec/frontend/monitoring/components/embeds/mock_data.js index da8eb8c0fc4..9cf66e52d22 100644 --- a/spec/frontend/monitoring/embed/mock_data.js +++ b/spec/frontend/monitoring/components/embeds/mock_data.js @@ -1,3 +1,5 @@ +import { TEST_HOST } from 'helpers/test_constants'; + export const metricsWithData = ['15_metric_a', '16_metric_b']; export const groups = [ @@ -52,3 +54,34 @@ export const initialState = () => ({ }, useDashboardEndpoint: true, }); + +export const initialEmbedGroupState = () => ({ + modules: [], +}); + +export const singleEmbedProps = () => ({ + dashboardUrl: TEST_HOST, + containerClass: 'col-lg-12', + namespace: 'monitoringDashboard/0', +}); + +export const dashboardEmbedProps = () => ({ + dashboardUrl: TEST_HOST, + containerClass: 'col-lg-6', + namespace: 'monitoringDashboard/0', +}); + +export const multipleEmbedProps = () => [ + { + dashboardUrl: TEST_HOST, + containerClass: 'col-lg-6', + namespace: 'monitoringDashboard/0', + }, + { + dashboardUrl: TEST_HOST, + containerClass: 'col-lg-6', + namespace: 'monitoringDashboard/1', + }, +]; + +export const addModuleAction = 'embedGroup/addModule'; diff --git a/spec/frontend/monitoring/components/panel_type_spec.js b/spec/frontend/monitoring/components/panel_type_spec.js index 927d93ab697..782a276a91b 100644 --- a/spec/frontend/monitoring/components/panel_type_spec.js +++ b/spec/frontend/monitoring/components/panel_type_spec.js @@ -8,8 +8,17 @@ import PanelType from '~/monitoring/components/panel_type.vue'; import EmptyChart from '~/monitoring/components/charts/empty_chart.vue'; import TimeSeriesChart from '~/monitoring/components/charts/time_series.vue'; import AnomalyChart from '~/monitoring/components/charts/anomaly.vue'; -import { anomalyMockGraphData, graphDataPrometheusQueryRange } from 'jest/monitoring/mock_data'; -import { createStore } from '~/monitoring/stores'; +import { + anomalyMockGraphData, + graphDataPrometheusQueryRange, + mockLogsHref, + mockLogsPath, + mockNamespace, + mockNamespacedData, + mockTimeRange, +} from 'jest/monitoring/mock_data'; +import { createStore, monitoringDashboard } from '~/monitoring/stores'; +import { createStore as createEmbedGroupStore } from '~/monitoring/stores/embed_group'; global.IS_EE = true; global.URL.createObjectURL = jest.fn(); @@ -29,6 +38,7 @@ describe('Panel Type component', () => { const exampleText = 'example_text'; const findCopyLink = () => wrapper.find({ ref: 'copyChartLink' }); + const findTimeChart = () => wrapper.find({ ref: 'timeChart' }); const createWrapper = props => { wrapper = shallowMount(PanelType, { @@ -99,8 +109,6 @@ describe('Panel Type component', () => { }); describe('when graph data is available', () => { - const findTimeChart = () => wrapper.find({ ref: 'timeChart' }); - beforeEach(() => { createWrapper({ graphData: graphDataPrometheusQueryRange, @@ -242,10 +250,6 @@ describe('Panel Type component', () => { }); describe('View Logs dropdown item', () => { - const mockLogsPath = '/path/to/logs'; - const mockTimeRange = { duration: { seconds: 120 } }; - - const findTimeChart = () => wrapper.find({ ref: 'timeChart' }); const findViewLogsLink = () => wrapper.find({ ref: 'viewLogsLink' }); beforeEach(() => { @@ -292,8 +296,7 @@ describe('Panel Type component', () => { state.timeRange = mockTimeRange; return wrapper.vm.$nextTick(() => { - const href = `${mockLogsPath}?duration_seconds=${mockTimeRange.duration.seconds}`; - expect(findViewLogsLink().attributes('href')).toMatch(href); + expect(findViewLogsLink().attributes('href')).toMatch(mockLogsHref); }); }); @@ -388,4 +391,53 @@ describe('Panel Type component', () => { }); }); }); + + describe('when using dynamic modules', () => { + const { mockDeploymentData, mockProjectPath } = mockNamespacedData; + + beforeEach(() => { + store = createEmbedGroupStore(); + store.registerModule(mockNamespace, monitoringDashboard); + store.state.embedGroup.modules.push(mockNamespace); + + wrapper = shallowMount(PanelType, { + propsData: { + graphData: graphDataPrometheusQueryRange, + namespace: mockNamespace, + }, + store, + mocks, + }); + }); + + it('handles namespaced time range and logs path state', () => { + store.state[mockNamespace].timeRange = mockTimeRange; + store.state[mockNamespace].logsPath = mockLogsPath; + + return wrapper.vm.$nextTick().then(() => { + expect(wrapper.find({ ref: 'viewLogsLink' }).attributes().href).toBe(mockLogsHref); + }); + }); + + it('handles namespaced deployment data state', () => { + store.state[mockNamespace].deploymentData = mockDeploymentData; + + return wrapper.vm.$nextTick().then(() => { + expect(findTimeChart().props().deploymentData).toEqual(mockDeploymentData); + }); + }); + + it('handles namespaced project path state', () => { + store.state[mockNamespace].projectPath = mockProjectPath; + + return wrapper.vm.$nextTick().then(() => { + expect(findTimeChart().props().projectPath).toBe(mockProjectPath); + }); + }); + + it('it renders a time series chart with no errors', () => { + expect(wrapper.find(TimeSeriesChart).isVueInstance()).toBe(true); + expect(wrapper.find(TimeSeriesChart).exists()).toBe(true); + }); + }); }); diff --git a/spec/frontend/monitoring/mock_data.js b/spec/frontend/monitoring/mock_data.js index 284b7a0997f..58693723624 100644 --- a/spec/frontend/monitoring/mock_data.js +++ b/spec/frontend/monitoring/mock_data.js @@ -750,3 +750,20 @@ export const barMockData = { }, ], }; + +export const baseNamespace = 'monitoringDashboard'; + +export const mockNamespace = `${baseNamespace}/1`; + +export const mockNamespaces = [`${baseNamespace}/1`, `${baseNamespace}/2`]; + +export const mockTimeRange = { duration: { seconds: 120 } }; + +export const mockNamespacedData = { + mockDeploymentData: ['mockDeploymentData'], + mockProjectPath: '/mockProjectPath', +}; + +export const mockLogsPath = '/mockLogsPath'; + +export const mockLogsHref = `${mockLogsPath}?duration_seconds=${mockTimeRange.duration.seconds}`; diff --git a/spec/frontend/monitoring/store/embed_group/actions_spec.js b/spec/frontend/monitoring/store/embed_group/actions_spec.js new file mode 100644 index 00000000000..5bdfc506cff --- /dev/null +++ b/spec/frontend/monitoring/store/embed_group/actions_spec.js @@ -0,0 +1,16 @@ +// import store from '~/monitoring/stores/embed_group'; +import * as actions from '~/monitoring/stores/embed_group/actions'; +import * as types from '~/monitoring/stores/embed_group/mutation_types'; +import { mockNamespace } from '../../mock_data'; + +describe('Embed group actions', () => { + describe('addModule', () => { + it('adds a module to the store', () => { + const commit = jest.fn(); + + actions.addModule({ commit }, mockNamespace); + + expect(commit).toHaveBeenCalledWith(types.ADD_MODULE, mockNamespace); + }); + }); +}); diff --git a/spec/frontend/monitoring/store/embed_group/getters_spec.js b/spec/frontend/monitoring/store/embed_group/getters_spec.js new file mode 100644 index 00000000000..e3241e41f5e --- /dev/null +++ b/spec/frontend/monitoring/store/embed_group/getters_spec.js @@ -0,0 +1,19 @@ +import { metricsWithData } from '~/monitoring/stores/embed_group/getters'; +import { mockNamespaces } from '../../mock_data'; + +describe('Embed group getters', () => { + describe('metricsWithData', () => { + it('correctly sums the number of metrics with data', () => { + const mockMetric = {}; + const state = { + modules: mockNamespaces, + }; + const rootGetters = { + [`${mockNamespaces[0]}/metricsWithData`]: () => [mockMetric], + [`${mockNamespaces[1]}/metricsWithData`]: () => [mockMetric, mockMetric], + }; + + expect(metricsWithData(state, null, null, rootGetters)).toEqual([1, 2]); + }); + }); +}); diff --git a/spec/frontend/monitoring/store/embed_group/mutations_spec.js b/spec/frontend/monitoring/store/embed_group/mutations_spec.js new file mode 100644 index 00000000000..a1d04e23e41 --- /dev/null +++ b/spec/frontend/monitoring/store/embed_group/mutations_spec.js @@ -0,0 +1,16 @@ +import state from '~/monitoring/stores/embed_group/state'; +import mutations from '~/monitoring/stores/embed_group/mutations'; +import * as types from '~/monitoring/stores/embed_group/mutation_types'; +import { mockNamespace } from '../../mock_data'; + +describe('Embed group mutations', () => { + describe('ADD_MODULE', () => { + it('should add a module', () => { + const stateCopy = state(); + + mutations[types.ADD_MODULE](stateCopy, mockNamespace); + + expect(stateCopy.modules).toEqual([mockNamespace]); + }); + }); +}); |