summaryrefslogtreecommitdiff
path: root/spec/frontend/monitoring/components
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-03-31 09:08:16 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-03-31 09:08:16 +0000
commit6044caed20964a70c1ac6c5a3365d567ed96dfde (patch)
tree3fe8f14b4acbd542265544843efeb6f59b5d3efe /spec/frontend/monitoring/components
parent92077e0f8d70c70a908395808b16f98ecd3a5fcd (diff)
downloadgitlab-ce-6044caed20964a70c1ac6c5a3365d567ed96dfde.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend/monitoring/components')
-rw-r--r--spec/frontend/monitoring/components/embeds/embed_group_spec.js163
-rw-r--r--spec/frontend/monitoring/components/embeds/metric_embed_spec.js102
-rw-r--r--spec/frontend/monitoring/components/embeds/mock_data.js87
-rw-r--r--spec/frontend/monitoring/components/panel_type_spec.js72
4 files changed, 414 insertions, 10 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/components/embeds/metric_embed_spec.js b/spec/frontend/monitoring/components/embeds/metric_embed_spec.js
new file mode 100644
index 00000000000..d0fe22cefec
--- /dev/null
+++ b/spec/frontend/monitoring/components/embeds/metric_embed_spec.js
@@ -0,0 +1,102 @@
+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 MetricEmbed from '~/monitoring/components/embeds/metric_embed.vue';
+import { groups, initialState, metricsData, metricsWithData } from './mock_data';
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('MetricEmbed', () => {
+ let wrapper;
+ let store;
+ let actions;
+ let metricsWithDataGetter;
+
+ function mountComponent() {
+ wrapper = shallowMount(MetricEmbed, {
+ localVue,
+ store,
+ propsData: {
+ dashboardUrl: TEST_HOST,
+ },
+ });
+ }
+
+ beforeEach(() => {
+ actions = {
+ setFeatureFlags: jest.fn(),
+ setShowErrorBanner: jest.fn(),
+ setEndpoints: jest.fn(),
+ setTimeRange: jest.fn(),
+ fetchDashboard: jest.fn(),
+ };
+
+ metricsWithDataGetter = jest.fn();
+
+ store = new Vuex.Store({
+ modules: {
+ monitoringDashboard: {
+ namespaced: true,
+ actions,
+ getters: {
+ metricsWithData: () => metricsWithDataGetter,
+ },
+ state: initialState,
+ },
+ },
+ });
+ });
+
+ afterEach(() => {
+ metricsWithDataGetter.mockClear();
+ if (wrapper) {
+ wrapper.destroy();
+ }
+ });
+
+ describe('no metrics are available yet', () => {
+ beforeEach(() => {
+ mountComponent();
+ });
+
+ it('shows an empty state when no metrics are present', () => {
+ expect(wrapper.find('.metrics-embed').exists()).toBe(true);
+ expect(wrapper.find(PanelType).exists()).toBe(false);
+ });
+ });
+
+ describe('metrics are available', () => {
+ beforeEach(() => {
+ store.state.monitoringDashboard.dashboard.panelGroups = groups;
+ store.state.monitoringDashboard.dashboard.panelGroups[0].panels = metricsData;
+
+ metricsWithDataGetter.mockReturnValue(metricsWithData);
+
+ mountComponent();
+ });
+
+ it('calls actions to fetch data', () => {
+ const expectedTimeRangePayload = expect.objectContaining({
+ start: expect.any(String),
+ end: expect.any(String),
+ });
+
+ expect(actions.setTimeRange).toHaveBeenCalledTimes(1);
+ expect(actions.setTimeRange.mock.calls[0][1]).toEqual(expectedTimeRangePayload);
+
+ expect(actions.fetchDashboard).toHaveBeenCalled();
+ });
+
+ it('shows a chart when metrics are present', () => {
+ expect(wrapper.find('.metrics-embed').exists()).toBe(true);
+ expect(wrapper.find(PanelType).exists()).toBe(true);
+ expect(wrapper.findAll(PanelType).length).toBe(2);
+ });
+
+ it('includes groupId with dashboardUrl', () => {
+ expect(wrapper.find(PanelType).props('groupId')).toBe(TEST_HOST);
+ });
+ });
+});
diff --git a/spec/frontend/monitoring/components/embeds/mock_data.js b/spec/frontend/monitoring/components/embeds/mock_data.js
new file mode 100644
index 00000000000..9cf66e52d22
--- /dev/null
+++ b/spec/frontend/monitoring/components/embeds/mock_data.js
@@ -0,0 +1,87 @@
+import { TEST_HOST } from 'helpers/test_constants';
+
+export const metricsWithData = ['15_metric_a', '16_metric_b'];
+
+export const groups = [
+ {
+ panels: [
+ {
+ title: 'Memory Usage (Total)',
+ type: 'area-chart',
+ y_label: 'Total Memory Used',
+ metrics: null,
+ },
+ ],
+ },
+];
+
+const result = [
+ {
+ values: [
+ ['Mon', 1220],
+ ['Tue', 932],
+ ['Wed', 901],
+ ['Thu', 934],
+ ['Fri', 1290],
+ ['Sat', 1330],
+ ['Sun', 1320],
+ ],
+ },
+];
+
+export const metricsData = [
+ {
+ metrics: [
+ {
+ metricId: '15_metric_a',
+ result,
+ },
+ ],
+ },
+ {
+ metrics: [
+ {
+ metricId: '16_metric_b',
+ result,
+ },
+ ],
+ },
+];
+
+export const initialState = () => ({
+ dashboard: {
+ panel_groups: [],
+ },
+ 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);
+ });
+ });
});