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/monitoring/components/dashboard_header_spec.js')
-rw-r--r--spec/frontend/monitoring/components/dashboard_header_spec.js372
1 files changed, 282 insertions, 90 deletions
diff --git a/spec/frontend/monitoring/components/dashboard_header_spec.js b/spec/frontend/monitoring/components/dashboard_header_spec.js
index 5a1a615c703..5cf24706ebd 100644
--- a/spec/frontend/monitoring/components/dashboard_header_spec.js
+++ b/spec/frontend/monitoring/components/dashboard_header_spec.js
@@ -1,16 +1,23 @@
import { shallowMount } from '@vue/test-utils';
+import { GlNewDropdownItem, GlSearchBoxByType, GlLoadingIcon, GlButton } from '@gitlab/ui';
import { createStore } from '~/monitoring/stores';
+import * as types from '~/monitoring/stores/mutation_types';
+import DateTimePicker from '~/vue_shared/components/date_time_picker/date_time_picker.vue';
+import RefreshButton from '~/monitoring/components/refresh_button.vue';
import DashboardHeader from '~/monitoring/components/dashboard_header.vue';
-import DuplicateDashboardModal from '~/monitoring/components/duplicate_dashboard_modal.vue';
-import CreateDashboardModal from '~/monitoring/components/create_dashboard_modal.vue';
-import { setupAllDashboards } from '../store_utils';
+import DashboardsDropdown from '~/monitoring/components/dashboards_dropdown.vue';
+import ActionsMenu from '~/monitoring/components/dashboard_actions_menu.vue';
+import { setupAllDashboards, setupStoreWithDashboard, setupStoreWithData } from '../store_utils';
import {
+ environmentData,
dashboardGitResponse,
selfMonitoringDashboardGitResponse,
dashboardHeaderProps,
} from '../mock_data';
import { redirectTo } from '~/lib/utils/url_utility';
+const mockProjectPath = 'https://path/to/project';
+
jest.mock('~/lib/utils/url_utility', () => ({
redirectTo: jest.fn(),
queryToObject: jest.fn(),
@@ -21,13 +28,22 @@ describe('Dashboard header', () => {
let store;
let wrapper;
- const findActionsMenu = () => wrapper.find('[data-testid="actions-menu"]');
- const findCreateDashboardMenuItem = () =>
- findActionsMenu().find('[data-testid="action-create-dashboard"]');
- const findCreateDashboardDuplicateItem = () =>
- findActionsMenu().find('[data-testid="action-duplicate-dashboard"]');
- const findDuplicateDashboardModal = () => wrapper.find(DuplicateDashboardModal);
- const findCreateDashboardModal = () => wrapper.find('[data-testid="create-dashboard-modal"]');
+ const findDashboardDropdown = () => wrapper.find(DashboardsDropdown);
+
+ const findEnvsDropdown = () => wrapper.find({ ref: 'monitorEnvironmentsDropdown' });
+ const findEnvsDropdownItems = () => findEnvsDropdown().findAll(GlNewDropdownItem);
+ const findEnvsDropdownSearch = () => findEnvsDropdown().find(GlSearchBoxByType);
+ const findEnvsDropdownSearchMsg = () => wrapper.find({ ref: 'monitorEnvironmentsDropdownMsg' });
+ const findEnvsDropdownLoadingIcon = () => findEnvsDropdown().find(GlLoadingIcon);
+
+ const findDateTimePicker = () => wrapper.find(DateTimePicker);
+ const findRefreshButton = () => wrapper.find(RefreshButton);
+
+ const findActionsMenu = () => wrapper.find(ActionsMenu);
+
+ const setSearchTerm = searchTerm => {
+ store.commit(`monitoringDashboard/${types.SET_ENVIRONMENTS_FILTER}`, searchTerm);
+ };
const createShallowWrapper = (props = {}, options = {}) => {
wrapper = shallowMount(DashboardHeader, {
@@ -45,139 +61,315 @@ describe('Dashboard header', () => {
wrapper.destroy();
});
- describe('when a dashboard has been duplicated in the duplicate dashboard modal', () => {
+ describe('dashboards dropdown', () => {
beforeEach(() => {
- store.state.monitoringDashboard.projectPath = 'root/sandbox';
+ store.commit(`monitoringDashboard/${types.SET_INITIAL_STATE}`, {
+ projectPath: mockProjectPath,
+ });
+
+ createShallowWrapper();
});
- /**
- * The duplicate dashboard modal gets called both by a menu item from the
- * dashboards dropdown and by an item from the actions menu.
- *
- * This spec is context agnostic, so it addresses all cases where the
- * duplicate dashboard modal gets called.
- */
- it('redirects to the newly created dashboard', () => {
- delete window.location;
- window.location = new URL('https://localhost');
- const newDashboard = dashboardGitResponse[1];
+ it('shows the dashboard dropdown', () => {
+ expect(findDashboardDropdown().exists()).toBe(true);
+ });
- createShallowWrapper();
+ it('when an out of the box dashboard is selected, encodes dashboard path', () => {
+ findDashboardDropdown().vm.$emit('selectDashboard', {
+ path: '.gitlab/dashboards/dashboard&copy.yml',
+ out_of_the_box_dashboard: true,
+ display_name: 'A display name',
+ });
- const newDashboardUrl = 'root/sandbox/-/metrics/dashboard.yml';
- findDuplicateDashboardModal().vm.$emit('dashboardDuplicated', newDashboard);
+ expect(redirectTo).toHaveBeenCalledWith(
+ `${mockProjectPath}/-/metrics/.gitlab%2Fdashboards%2Fdashboard%26copy.yml`,
+ );
+ });
- return wrapper.vm.$nextTick().then(() => {
- expect(redirectTo).toHaveBeenCalled();
- expect(redirectTo).toHaveBeenCalledWith(newDashboardUrl);
+ it('when a custom dashboard is selected, encodes dashboard display name', () => {
+ findDashboardDropdown().vm.$emit('selectDashboard', {
+ path: '.gitlab/dashboards/file&path.yml',
+ display_name: 'dashboard&copy.yml',
});
+
+ expect(redirectTo).toHaveBeenCalledWith(`${mockProjectPath}/-/metrics/dashboard%26copy.yml`);
});
});
- describe('actions menu', () => {
+ describe('environments dropdown', () => {
beforeEach(() => {
- store.state.monitoringDashboard.projectPath = '';
createShallowWrapper();
});
- it('is rendered if projectPath is set in store', () => {
- store.state.monitoringDashboard.projectPath = 'https://path/to/project';
+ it('shows the environments dropdown', () => {
+ expect(findEnvsDropdown().exists()).toBe(true);
+ });
- return wrapper.vm.$nextTick().then(() => {
- expect(findActionsMenu().exists()).toBe(true);
+ it('renders a search input', () => {
+ expect(findEnvsDropdownSearch().exists()).toBe(true);
+ });
+
+ describe('when environments data is not loaded', () => {
+ beforeEach(() => {
+ setupStoreWithDashboard(store);
+ return wrapper.vm.$nextTick();
+ });
+
+ it('there are no environments listed', () => {
+ expect(findEnvsDropdownItems()).toHaveLength(0);
+ });
+ });
+
+ describe('when environments data is loaded', () => {
+ const currentDashboard = dashboardGitResponse[0].path;
+ const currentEnvironmentName = environmentData[0].name;
+
+ beforeEach(() => {
+ setupStoreWithData(store);
+ store.state.monitoringDashboard.projectPath = mockProjectPath;
+ store.state.monitoringDashboard.currentDashboard = currentDashboard;
+ store.state.monitoringDashboard.currentEnvironmentName = currentEnvironmentName;
+
+ return wrapper.vm.$nextTick();
+ });
+
+ it('renders dropdown items with the environment name', () => {
+ const path = `${mockProjectPath}/-/metrics/${encodeURIComponent(currentDashboard)}`;
+
+ findEnvsDropdownItems().wrappers.forEach((itemWrapper, index) => {
+ const { name, id } = environmentData[index];
+ const idParam = encodeURIComponent(id);
+
+ expect(itemWrapper.text()).toBe(name);
+ expect(itemWrapper.attributes('href')).toBe(`${path}?environment=${idParam}`);
+ });
+ });
+
+ it('environments dropdown items can be checked', () => {
+ const items = findEnvsDropdownItems();
+ const checkItems = findEnvsDropdownItems().filter(item => item.props('isCheckItem'));
+
+ expect(items).toHaveLength(checkItems.length);
+ });
+
+ it('checks the currently selected environment', () => {
+ const selectedItems = findEnvsDropdownItems().filter(item => item.props('isChecked'));
+
+ expect(selectedItems).toHaveLength(1);
+ expect(selectedItems.at(0).text()).toBe(currentEnvironmentName);
+ });
+
+ it('filters rendered dropdown items', () => {
+ const searchTerm = 'production';
+ const resultEnvs = environmentData.filter(({ name }) => name.indexOf(searchTerm) !== -1);
+ setSearchTerm(searchTerm);
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findEnvsDropdownItems()).toHaveLength(resultEnvs.length);
+ });
+ });
+
+ it('does not filter dropdown items if search term is empty string', () => {
+ const searchTerm = '';
+ setSearchTerm(searchTerm);
+
+ return wrapper.vm.$nextTick(() => {
+ expect(findEnvsDropdownItems()).toHaveLength(environmentData.length);
+ });
+ });
+
+ it("shows error message if search term doesn't match", () => {
+ const searchTerm = 'does-not-exist';
+ setSearchTerm(searchTerm);
+
+ return wrapper.vm.$nextTick(() => {
+ expect(findEnvsDropdownSearchMsg().isVisible()).toBe(true);
+ });
+ });
+
+ it('shows loading element when environments fetch is still loading', () => {
+ store.commit(`monitoringDashboard/${types.REQUEST_ENVIRONMENTS_DATA}`);
+
+ return wrapper.vm
+ .$nextTick()
+ .then(() => {
+ expect(findEnvsDropdownLoadingIcon().exists()).toBe(true);
+ })
+ .then(() => {
+ store.commit(
+ `monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`,
+ environmentData,
+ );
+ })
+ .then(() => {
+ expect(findEnvsDropdownLoadingIcon().exists()).toBe(false);
+ });
});
});
+ });
- it('is not rendered if projectPath is not set in store', () => {
- expect(findActionsMenu().exists()).toBe(false);
+ describe('date time picker', () => {
+ beforeEach(() => {
+ createShallowWrapper();
});
- it('contains a modal', () => {
- store.state.monitoringDashboard.projectPath = 'https://path/to/project';
+ it('is rendered', () => {
+ expect(findDateTimePicker().exists()).toBe(true);
+ });
- return wrapper.vm.$nextTick().then(() => {
- expect(findActionsMenu().contains(CreateDashboardModal)).toBe(true);
+ describe('timezone setting', () => {
+ const setupWithTimezone = value => {
+ store = createStore({ dashboardTimezone: value });
+ createShallowWrapper();
+ };
+
+ describe('local timezone is enabled by default', () => {
+ it('shows the data time picker in local timezone', () => {
+ expect(findDateTimePicker().props('utc')).toBe(false);
+ });
+ });
+
+ describe('when LOCAL timezone is enabled', () => {
+ beforeEach(() => {
+ setupWithTimezone('LOCAL');
+ });
+
+ it('shows the data time picker in local timezone', () => {
+ expect(findDateTimePicker().props('utc')).toBe(false);
+ });
+ });
+
+ describe('when UTC timezone is enabled', () => {
+ beforeEach(() => {
+ setupWithTimezone('UTC');
+ });
+
+ it('shows the data time picker in UTC format', () => {
+ expect(findDateTimePicker().props('utc')).toBe(true);
+ });
});
});
+ });
+
+ describe('refresh button', () => {
+ beforeEach(() => {
+ createShallowWrapper();
+ });
+
+ it('is rendered', () => {
+ expect(findRefreshButton().exists()).toBe(true);
+ });
+ });
+
+ describe('external dashboard link', () => {
+ beforeEach(() => {
+ store.state.monitoringDashboard.externalDashboardUrl = '/mockUrl';
+ createShallowWrapper();
+
+ return wrapper.vm.$nextTick();
+ });
+
+ it('shows the link', () => {
+ const externalDashboardButton = wrapper.find('.js-external-dashboard-link');
+
+ expect(externalDashboardButton.exists()).toBe(true);
+ expect(externalDashboardButton.is(GlButton)).toBe(true);
+ expect(externalDashboardButton.text()).toContain('View full dashboard');
+ });
+ });
- const duplicableCases = [
- null, // When no path is specified, it uses the default dashboard path.
+ describe('actions menu', () => {
+ const ootbDashboards = [
dashboardGitResponse[0].path,
- dashboardGitResponse[2].path,
selfMonitoringDashboardGitResponse[0].path,
];
+ const customDashboards = [
+ dashboardGitResponse[1].path,
+ selfMonitoringDashboardGitResponse[1].path,
+ ];
- describe.each(duplicableCases)(
- 'when the selected dashboard can be duplicated',
- dashboardPath => {
- it('contains a "Create New" menu item and a "Duplicate Dashboard" menu item', () => {
- store.state.monitoringDashboard.projectPath = 'https://path/to/project';
- setupAllDashboards(store, dashboardPath);
+ it('is rendered', () => {
+ createShallowWrapper();
- return wrapper.vm.$nextTick().then(() => {
- expect(findCreateDashboardMenuItem().exists()).toBe(true);
- expect(findCreateDashboardDuplicateItem().exists()).toBe(true);
- });
+ expect(findActionsMenu().exists()).toBe(true);
+ });
+
+ describe('adding metrics prop', () => {
+ it.each(ootbDashboards)('gets passed true if current dashboard is OOTB', dashboardPath => {
+ createShallowWrapper({ customMetricsAvailable: true });
+
+ store.state.monitoringDashboard.emptyState = false;
+ setupAllDashboards(store, dashboardPath);
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findActionsMenu().props('addingMetricsAvailable')).toBe(true);
});
- },
- );
+ });
- const nonDuplicableCases = [
- dashboardGitResponse[1].path,
- selfMonitoringDashboardGitResponse[1].path,
- ];
+ it.each(customDashboards)(
+ 'gets passed false if current dashboard is custom',
+ dashboardPath => {
+ createShallowWrapper({ customMetricsAvailable: true });
- describe.each(nonDuplicableCases)(
- 'when the selected dashboard cannot be duplicated',
- dashboardPath => {
- it('contains a "Create New" menu item and no "Duplicate Dashboard" menu item', () => {
- store.state.monitoringDashboard.projectPath = 'https://path/to/project';
+ store.state.monitoringDashboard.emptyState = false;
setupAllDashboards(store, dashboardPath);
return wrapper.vm.$nextTick().then(() => {
- expect(findCreateDashboardMenuItem().exists()).toBe(true);
- expect(findCreateDashboardDuplicateItem().exists()).toBe(false);
+ expect(findActionsMenu().props('addingMetricsAvailable')).toBe(false);
});
+ },
+ );
+
+ it('gets passed false if empty state is shown', () => {
+ createShallowWrapper({ customMetricsAvailable: true });
+
+ store.state.monitoringDashboard.emptyState = true;
+ setupAllDashboards(store, ootbDashboards[0]);
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findActionsMenu().props('addingMetricsAvailable')).toBe(false);
});
- },
- );
- });
+ });
- describe('actions menu modals', () => {
- const url = 'https://path/to/project';
+ it('gets passed false if custom metrics are not available', () => {
+ createShallowWrapper({ customMetricsAvailable: false });
- beforeEach(() => {
- store.state.monitoringDashboard.projectPath = url;
- setupAllDashboards(store);
+ store.state.monitoringDashboard.emptyState = false;
+ setupAllDashboards(store, ootbDashboards[0]);
- createShallowWrapper();
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findActionsMenu().props('addingMetricsAvailable')).toBe(false);
+ });
+ });
});
- it('Clicking on "Create New" opens up a modal', () => {
- const modalId = 'createDashboard';
- const modalTrigger = findCreateDashboardMenuItem();
- const rootEmit = jest.spyOn(wrapper.vm.$root, '$emit');
+ it('custom metrics path gets passed', () => {
+ const path = 'https://path/to/customMetrics';
- modalTrigger.trigger('click');
+ createShallowWrapper({ customMetricsPath: path });
return wrapper.vm.$nextTick().then(() => {
- expect(rootEmit.mock.calls[0]).toContainEqual(modalId);
+ expect(findActionsMenu().props('customMetricsPath')).toBe(path);
});
});
- it('"Create new dashboard" modal contains correct buttons', () => {
- expect(findCreateDashboardModal().props('projectPath')).toBe(url);
+ it('validate query path gets passed', () => {
+ const path = 'https://path/to/validateQuery';
+
+ createShallowWrapper({ validateQueryPath: path });
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findActionsMenu().props('validateQueryPath')).toBe(path);
+ });
});
- it('"Duplicate Dashboard" opens up a modal', () => {
- const modalId = 'duplicateDashboard';
- const modalTrigger = findCreateDashboardDuplicateItem();
- const rootEmit = jest.spyOn(wrapper.vm.$root, '$emit');
+ it('default branch gets passed', () => {
+ const branch = 'branchName';
- modalTrigger.trigger('click');
+ createShallowWrapper({ defaultBranch: branch });
return wrapper.vm.$nextTick().then(() => {
- expect(rootEmit.mock.calls[0]).toContainEqual(modalId);
+ expect(findActionsMenu().props('defaultBranch')).toBe(branch);
});
});
});