diff options
Diffstat (limited to 'spec/frontend/monitoring/store/actions_spec.js')
-rw-r--r-- | spec/frontend/monitoring/store/actions_spec.js | 1167 |
1 files changed, 0 insertions, 1167 deletions
diff --git a/spec/frontend/monitoring/store/actions_spec.js b/spec/frontend/monitoring/store/actions_spec.js deleted file mode 100644 index b3b198d6b51..00000000000 --- a/spec/frontend/monitoring/store/actions_spec.js +++ /dev/null @@ -1,1167 +0,0 @@ -import MockAdapter from 'axios-mock-adapter'; -import { backoffMockImplementation } from 'helpers/backoff_helper'; -import testAction from 'helpers/vuex_action_helper'; -import { createAlert } from '~/alert'; -import axios from '~/lib/utils/axios_utils'; -import * as commonUtils from '~/lib/utils/common_utils'; -import { - HTTP_STATUS_BAD_REQUEST, - HTTP_STATUS_CREATED, - HTTP_STATUS_INTERNAL_SERVER_ERROR, - HTTP_STATUS_OK, - HTTP_STATUS_UNPROCESSABLE_ENTITY, -} from '~/lib/utils/http_status'; -import { ENVIRONMENT_AVAILABLE_STATE } from '~/monitoring/constants'; - -import getAnnotations from '~/monitoring/queries/get_annotations.query.graphql'; -import getDashboardValidationWarnings from '~/monitoring/queries/get_dashboard_validation_warnings.query.graphql'; -import getEnvironments from '~/monitoring/queries/get_environments.query.graphql'; -import { createStore } from '~/monitoring/stores'; -import { - setGettingStartedEmptyState, - setInitialState, - setExpandedPanel, - clearExpandedPanel, - filterEnvironments, - fetchData, - fetchDashboard, - receiveMetricsDashboardSuccess, - fetchDashboardData, - fetchPrometheusMetric, - fetchDeploymentsData, - fetchEnvironmentsData, - fetchAnnotations, - fetchDashboardValidationWarnings, - toggleStarredValue, - duplicateSystemDashboard, - updateVariablesAndFetchData, - fetchVariableMetricLabelValues, - fetchPanelPreview, -} from '~/monitoring/stores/actions'; -import * as getters from '~/monitoring/stores/getters'; -import * as types from '~/monitoring/stores/mutation_types'; -import storeState from '~/monitoring/stores/state'; -import { - gqClient, - parseEnvironmentsResponse, - parseAnnotationsResponse, -} from '~/monitoring/stores/utils'; -import Tracking from '~/tracking'; -import { defaultTimeRange } from '~/vue_shared/constants'; -import { - metricsDashboardResponse, - metricsDashboardViewModel, - metricsDashboardPanelCount, -} from '../fixture_data'; -import { - deploymentData, - environmentData, - annotationsData, - dashboardGitResponse, - mockDashboardsErrorResponse, -} from '../mock_data'; - -jest.mock('~/alert'); - -describe('Monitoring store actions', () => { - const { convertObjectPropsToCamelCase } = commonUtils; - - let mock; - let store; - let state; - - let dispatch; - let commit; - - beforeEach(() => { - store = createStore({ getters }); - state = store.state.monitoringDashboard; - mock = new MockAdapter(axios); - - commit = jest.fn(); - dispatch = jest.fn(); - - jest.spyOn(commonUtils, 'backOff').mockImplementation(backoffMockImplementation); - }); - - afterEach(() => { - mock.reset(); - - commonUtils.backOff.mockReset(); - createAlert.mockReset(); - }); - - // Setup - - describe('setGettingStartedEmptyState', () => { - it('should commit SET_GETTING_STARTED_EMPTY_STATE mutation', () => { - return testAction( - setGettingStartedEmptyState, - null, - state, - [ - { - type: types.SET_GETTING_STARTED_EMPTY_STATE, - }, - ], - [], - ); - }); - }); - - describe('setInitialState', () => { - it('should commit SET_INITIAL_STATE mutation', () => { - return testAction( - setInitialState, - { - currentDashboard: '.gitlab/dashboards/dashboard.yml', - deploymentsEndpoint: 'deployments.json', - }, - state, - [ - { - type: types.SET_INITIAL_STATE, - payload: { - currentDashboard: '.gitlab/dashboards/dashboard.yml', - deploymentsEndpoint: 'deployments.json', - }, - }, - ], - [], - ); - }); - }); - - describe('setExpandedPanel', () => { - it('Sets a panel as expanded', () => { - const group = 'group_1'; - const panel = { title: 'A Panel' }; - - return testAction( - setExpandedPanel, - { group, panel }, - state, - [{ type: types.SET_EXPANDED_PANEL, payload: { group, panel } }], - [], - ); - }); - }); - - describe('clearExpandedPanel', () => { - it('Clears a panel as expanded', () => { - return testAction( - clearExpandedPanel, - undefined, - state, - [{ type: types.SET_EXPANDED_PANEL, payload: { group: null, panel: null } }], - [], - ); - }); - }); - - // All Data - - describe('fetchData', () => { - it('dispatches fetchEnvironmentsData and fetchEnvironmentsData', () => { - return testAction( - fetchData, - null, - state, - [], - [ - { type: 'fetchEnvironmentsData' }, - { type: 'fetchDashboard' }, - { type: 'fetchAnnotations' }, - ], - ); - }); - - it('dispatches when feature metricsDashboardAnnotations is on', () => { - window.gon = { features: { metricsDashboardAnnotations: true } }; - - return testAction( - fetchData, - null, - state, - [], - [ - { type: 'fetchEnvironmentsData' }, - { type: 'fetchDashboard' }, - { type: 'fetchAnnotations' }, - ], - ); - }); - }); - - // Metrics dashboard - - describe('fetchDashboard', () => { - const response = metricsDashboardResponse; - beforeEach(() => { - state.dashboardEndpoint = '/dashboard'; - }); - - it('on success, dispatches receive and success actions, then fetches dashboard warnings', () => { - document.body.dataset.page = 'projects:environments:metrics'; - mock.onGet(state.dashboardEndpoint).reply(HTTP_STATUS_OK, response); - - return testAction( - fetchDashboard, - null, - state, - [], - [ - { type: 'requestMetricsDashboard' }, - { - type: 'receiveMetricsDashboardSuccess', - payload: { response }, - }, - { type: 'fetchDashboardValidationWarnings' }, - ], - ); - }); - - describe('on failure', () => { - let result; - beforeEach(() => { - const params = {}; - const localGetters = { - fullDashboardPath: store.getters['monitoringDashboard/fullDashboardPath'], - }; - result = () => { - mock - .onGet(state.dashboardEndpoint) - .replyOnce(HTTP_STATUS_INTERNAL_SERVER_ERROR, mockDashboardsErrorResponse); - return fetchDashboard({ state, commit, dispatch, getters: localGetters }, params); - }; - }); - - it('dispatches a failure', async () => { - await result(); - expect(commit).toHaveBeenCalledWith( - types.SET_ALL_DASHBOARDS, - mockDashboardsErrorResponse.all_dashboards, - ); - expect(dispatch).toHaveBeenCalledWith( - 'receiveMetricsDashboardFailure', - new Error('Request failed with status code 500'), - ); - expect(createAlert).toHaveBeenCalled(); - }); - - it('dispatches a failure action when a message is returned', async () => { - await result(); - expect(dispatch).toHaveBeenCalledWith( - 'receiveMetricsDashboardFailure', - new Error('Request failed with status code 500'), - ); - expect(createAlert).toHaveBeenCalledWith({ - message: expect.stringContaining(mockDashboardsErrorResponse.message), - }); - }); - - it('does not show an alert when showErrorBanner is disabled', async () => { - state.showErrorBanner = false; - - await result(); - expect(dispatch).toHaveBeenCalledWith( - 'receiveMetricsDashboardFailure', - new Error('Request failed with status code 500'), - ); - expect(createAlert).not.toHaveBeenCalled(); - }); - }); - }); - - describe('receiveMetricsDashboardSuccess', () => { - it('stores groups', () => { - const response = metricsDashboardResponse; - receiveMetricsDashboardSuccess({ state, commit, dispatch }, { response }); - expect(commit).toHaveBeenCalledWith( - types.RECEIVE_METRICS_DASHBOARD_SUCCESS, - - metricsDashboardResponse.dashboard, - ); - expect(dispatch).toHaveBeenCalledWith('fetchDashboardData'); - }); - - it('sets the dashboards loaded from the repository', () => { - const params = {}; - const response = metricsDashboardResponse; - response.all_dashboards = dashboardGitResponse; - receiveMetricsDashboardSuccess( - { - state, - commit, - dispatch, - }, - { - response, - params, - }, - ); - expect(commit).toHaveBeenCalledWith(types.SET_ALL_DASHBOARDS, dashboardGitResponse); - }); - }); - - // Metrics - - describe('fetchDashboardData', () => { - beforeEach(() => { - jest.spyOn(Tracking, 'event'); - - state.timeRange = defaultTimeRange; - }); - - it('commits empty state when state.groups is empty', async () => { - const localGetters = { - metricsWithData: () => [], - }; - await fetchDashboardData({ state, commit, dispatch, getters: localGetters }); - expect(Tracking.event).toHaveBeenCalledWith(document.body.dataset.page, 'dashboard_fetch', { - label: 'custom_metrics_dashboard', - property: 'count', - value: 0, - }); - expect(dispatch).toHaveBeenCalledTimes(2); - expect(dispatch).toHaveBeenCalledWith('fetchDeploymentsData'); - expect(dispatch).toHaveBeenCalledWith('fetchVariableMetricLabelValues', { - defaultQueryParams: { - start_time: expect.any(String), - end_time: expect.any(String), - step: expect.any(Number), - }, - }); - - expect(createAlert).not.toHaveBeenCalled(); - }); - - it('dispatches fetchPrometheusMetric for each panel query', async () => { - state.dashboard.panelGroups = convertObjectPropsToCamelCase( - metricsDashboardResponse.dashboard.panel_groups, - ); - - const [metric] = state.dashboard.panelGroups[0].panels[0].metrics; - const localGetters = { - metricsWithData: () => [metric.id], - }; - - await fetchDashboardData({ state, commit, dispatch, getters: localGetters }); - expect(dispatch).toHaveBeenCalledWith('fetchPrometheusMetric', { - metric, - defaultQueryParams: { - start_time: expect.any(String), - end_time: expect.any(String), - step: expect.any(Number), - }, - }); - - expect(Tracking.event).toHaveBeenCalledWith(document.body.dataset.page, 'dashboard_fetch', { - label: 'custom_metrics_dashboard', - property: 'count', - value: 1, - }); - }); - - it('dispatches fetchPrometheusMetric for each panel query, handles an error', async () => { - state.dashboard.panelGroups = metricsDashboardViewModel.panelGroups; - const metric = state.dashboard.panelGroups[0].panels[0].metrics[0]; - - dispatch.mockResolvedValueOnce(); // fetchDeploymentsData - dispatch.mockResolvedValueOnce(); // fetchVariableMetricLabelValues - // Mock having one out of four metrics failing - dispatch.mockRejectedValueOnce(new Error('Error fetching this metric')); - dispatch.mockResolvedValue(); - - await fetchDashboardData({ state, commit, dispatch }); - const defaultQueryParams = { - start_time: expect.any(String), - end_time: expect.any(String), - step: expect.any(Number), - }; - - expect(dispatch).toHaveBeenCalledTimes(metricsDashboardPanelCount + 2); // plus 1 for deployments - expect(dispatch).toHaveBeenCalledWith('fetchDeploymentsData'); - expect(dispatch).toHaveBeenCalledWith('fetchVariableMetricLabelValues', { - defaultQueryParams, - }); - expect(dispatch).toHaveBeenCalledWith('fetchPrometheusMetric', { - metric, - defaultQueryParams, - }); - - expect(createAlert).toHaveBeenCalledTimes(1); - }); - }); - - describe('fetchPrometheusMetric', () => { - const defaultQueryParams = { - start_time: '2019-08-06T12:40:02.184Z', - end_time: '2019-08-06T20:40:02.184Z', - step: 60, - }; - let metric; - let data; - let prometheusEndpointPath; - - beforeEach(() => { - state = storeState(); - [metric] = metricsDashboardViewModel.panelGroups[0].panels[0].metrics; - - prometheusEndpointPath = metric.prometheusEndpointPath; - - data = { - metricId: metric.metricId, - result: [1582065167.353, 5, 1582065599.353], - }; - }); - - it('commits result', () => { - mock.onGet(prometheusEndpointPath).reply(HTTP_STATUS_OK, { data }); // One attempt - - return testAction( - fetchPrometheusMetric, - { metric, defaultQueryParams }, - state, - [ - { - type: types.REQUEST_METRIC_RESULT, - payload: { - metricId: metric.metricId, - }, - }, - { - type: types.RECEIVE_METRIC_RESULT_SUCCESS, - payload: { - metricId: metric.metricId, - data, - }, - }, - ], - [], - ); - }); - - describe('without metric defined step', () => { - const expectedParams = { - start_time: '2019-08-06T12:40:02.184Z', - end_time: '2019-08-06T20:40:02.184Z', - step: 60, - }; - - it('uses calculated step', async () => { - mock.onGet(prometheusEndpointPath).reply(HTTP_STATUS_OK, { data }); // One attempt - - await testAction( - fetchPrometheusMetric, - { metric, defaultQueryParams }, - state, - [ - { - type: types.REQUEST_METRIC_RESULT, - payload: { - metricId: metric.metricId, - }, - }, - { - type: types.RECEIVE_METRIC_RESULT_SUCCESS, - payload: { - metricId: metric.metricId, - data, - }, - }, - ], - [], - ); - expect(mock.history.get[0].params).toEqual(expectedParams); - }); - }); - - describe('with metric defined step', () => { - beforeEach(() => { - metric.step = 7; - }); - - const expectedParams = { - start_time: '2019-08-06T12:40:02.184Z', - end_time: '2019-08-06T20:40:02.184Z', - step: 7, - }; - - it('uses metric step', async () => { - mock.onGet(prometheusEndpointPath).reply(HTTP_STATUS_OK, { data }); // One attempt - - await testAction( - fetchPrometheusMetric, - { metric, defaultQueryParams }, - state, - [ - { - type: types.REQUEST_METRIC_RESULT, - payload: { - metricId: metric.metricId, - }, - }, - { - type: types.RECEIVE_METRIC_RESULT_SUCCESS, - payload: { - metricId: metric.metricId, - data, - }, - }, - ], - [], - ); - expect(mock.history.get[0].params).toEqual(expectedParams); - }); - }); - - it('commits failure, when waiting for results and getting a server error', async () => { - mock.onGet(prometheusEndpointPath).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR); - - const error = new Error('Request failed with status code 500'); - - await expect( - testAction( - fetchPrometheusMetric, - { metric, defaultQueryParams }, - state, - [ - { - type: types.REQUEST_METRIC_RESULT, - payload: { - metricId: metric.metricId, - }, - }, - { - type: types.RECEIVE_METRIC_RESULT_FAILURE, - payload: { - metricId: metric.metricId, - error, - }, - }, - ], - [], - ), - ).rejects.toEqual(error); - }); - }); - - // Deployments - - describe('fetchDeploymentsData', () => { - it('dispatches receiveDeploymentsDataSuccess on success', () => { - state.deploymentsEndpoint = '/success'; - mock.onGet(state.deploymentsEndpoint).reply(HTTP_STATUS_OK, { - deployments: deploymentData, - }); - - return testAction( - fetchDeploymentsData, - null, - state, - [], - [{ type: 'receiveDeploymentsDataSuccess', payload: deploymentData }], - ); - }); - it('dispatches receiveDeploymentsDataFailure on error', () => { - state.deploymentsEndpoint = '/error'; - mock.onGet(state.deploymentsEndpoint).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR); - - return testAction( - fetchDeploymentsData, - null, - state, - [], - [{ type: 'receiveDeploymentsDataFailure' }], - () => { - expect(createAlert).toHaveBeenCalled(); - }, - ); - }); - }); - - // Environments - - describe('fetchEnvironmentsData', () => { - beforeEach(() => { - state.projectPath = 'gitlab-org/gitlab-test'; - }); - - it('setting SET_ENVIRONMENTS_FILTER should dispatch fetchEnvironmentsData', () => { - jest.spyOn(gqClient, 'mutate').mockReturnValue({ - data: { - project: { - data: { - environments: [], - }, - }, - }, - }); - - return testAction( - filterEnvironments, - {}, - state, - [ - { - type: 'SET_ENVIRONMENTS_FILTER', - payload: {}, - }, - ], - [ - { - type: 'fetchEnvironmentsData', - }, - ], - ); - }); - - it('fetch environments data call takes in search param', () => { - const mockMutate = jest.spyOn(gqClient, 'mutate'); - const searchTerm = 'Something'; - const mutationVariables = { - mutation: getEnvironments, - variables: { - projectPath: state.projectPath, - search: searchTerm, - states: [ENVIRONMENT_AVAILABLE_STATE], - }, - }; - state.environmentsSearchTerm = searchTerm; - mockMutate.mockResolvedValue({}); - - return testAction( - fetchEnvironmentsData, - null, - state, - [], - [ - { type: 'requestEnvironmentsData' }, - { type: 'receiveEnvironmentsDataSuccess', payload: [] }, - ], - () => { - expect(mockMutate).toHaveBeenCalledWith(mutationVariables); - }, - ); - }); - - it('dispatches receiveEnvironmentsDataSuccess on success', () => { - jest.spyOn(gqClient, 'mutate').mockResolvedValue({ - data: { - project: { - data: { - environments: environmentData, - }, - }, - }, - }); - - return testAction( - fetchEnvironmentsData, - null, - state, - [], - [ - { type: 'requestEnvironmentsData' }, - { - type: 'receiveEnvironmentsDataSuccess', - payload: parseEnvironmentsResponse(environmentData, state.projectPath), - }, - ], - ); - }); - - it('dispatches receiveEnvironmentsDataFailure on error', () => { - jest.spyOn(gqClient, 'mutate').mockRejectedValue({}); - - return testAction( - fetchEnvironmentsData, - null, - state, - [], - [{ type: 'requestEnvironmentsData' }, { type: 'receiveEnvironmentsDataFailure' }], - ); - }); - }); - - describe('fetchAnnotations', () => { - beforeEach(() => { - state.timeRange = { - start: '2020-04-15T12:54:32.137Z', - end: '2020-08-15T12:54:32.137Z', - }; - state.projectPath = 'gitlab-org/gitlab-test'; - state.currentEnvironmentName = 'production'; - state.currentDashboard = '.gitlab/dashboards/custom_dashboard.yml'; - // testAction doesn't have access to getters. The state is passed in as getters - // instead of the actual getters inside the testAction method implementation. - // All methods downstream that needs access to getters will throw and error. - // For that reason, the result of the getter is set as a state variable. - state.fullDashboardPath = store.getters['monitoringDashboard/fullDashboardPath']; - }); - - it('fetches annotations data and dispatches receiveAnnotationsSuccess', () => { - const mockMutate = jest.spyOn(gqClient, 'mutate'); - const mutationVariables = { - mutation: getAnnotations, - variables: { - projectPath: state.projectPath, - environmentName: state.currentEnvironmentName, - dashboardPath: state.currentDashboard, - startingFrom: state.timeRange.start, - }, - }; - const parsedResponse = parseAnnotationsResponse(annotationsData); - - mockMutate.mockResolvedValue({ - data: { - project: { - environments: { - nodes: [ - { - metricsDashboard: { - annotations: { - nodes: parsedResponse, - }, - }, - }, - ], - }, - }, - }, - }); - - return testAction( - fetchAnnotations, - null, - state, - [], - [{ type: 'receiveAnnotationsSuccess', payload: parsedResponse }], - () => { - expect(mockMutate).toHaveBeenCalledWith(mutationVariables); - }, - ); - }); - - it('dispatches receiveAnnotationsFailure if the annotations API call fails', () => { - const mockMutate = jest.spyOn(gqClient, 'mutate'); - const mutationVariables = { - mutation: getAnnotations, - variables: { - projectPath: state.projectPath, - environmentName: state.currentEnvironmentName, - dashboardPath: state.currentDashboard, - startingFrom: state.timeRange.start, - }, - }; - - mockMutate.mockRejectedValue({}); - - return testAction( - fetchAnnotations, - null, - state, - [], - [{ type: 'receiveAnnotationsFailure' }], - () => { - expect(mockMutate).toHaveBeenCalledWith(mutationVariables); - }, - ); - }); - }); - - describe('fetchDashboardValidationWarnings', () => { - let mockMutate; - let mutationVariables; - - beforeEach(() => { - state.projectPath = 'gitlab-org/gitlab-test'; - state.currentEnvironmentName = 'production'; - state.currentDashboard = '.gitlab/dashboards/dashboard_with_warnings.yml'; - // testAction doesn't have access to getters. The state is passed in as getters - // instead of the actual getters inside the testAction method implementation. - // All methods downstream that needs access to getters will throw and error. - // For that reason, the result of the getter is set as a state variable. - state.fullDashboardPath = store.getters['monitoringDashboard/fullDashboardPath']; - - mockMutate = jest.spyOn(gqClient, 'mutate'); - mutationVariables = { - mutation: getDashboardValidationWarnings, - variables: { - projectPath: state.projectPath, - environmentName: state.currentEnvironmentName, - dashboardPath: state.fullDashboardPath, - }, - }; - }); - - it('dispatches receiveDashboardValidationWarningsSuccess with true payload when there are warnings', () => { - mockMutate.mockResolvedValue({ - data: { - project: { - id: 'gid://gitlab/Project/29', - environments: { - nodes: [ - { - name: 'production', - metricsDashboard: { - path: '.gitlab/dashboards/dashboard_errors_test.yml', - schemaValidationWarnings: ["unit: can't be blank"], - }, - }, - ], - }, - }, - }, - }); - - return testAction( - fetchDashboardValidationWarnings, - null, - state, - [], - [{ type: 'receiveDashboardValidationWarningsSuccess', payload: true }], - () => { - expect(mockMutate).toHaveBeenCalledWith(mutationVariables); - }, - ); - }); - - it('dispatches receiveDashboardValidationWarningsSuccess with false payload when there are no warnings', () => { - mockMutate.mockResolvedValue({ - data: { - project: { - id: 'gid://gitlab/Project/29', - environments: { - nodes: [ - { - name: 'production', - metricsDashboard: { - path: '.gitlab/dashboards/dashboard_errors_test.yml', - schemaValidationWarnings: [], - }, - }, - ], - }, - }, - }, - }); - - return testAction( - fetchDashboardValidationWarnings, - null, - state, - [], - [{ type: 'receiveDashboardValidationWarningsSuccess', payload: false }], - () => { - expect(mockMutate).toHaveBeenCalledWith(mutationVariables); - }, - ); - }); - - it('dispatches receiveDashboardValidationWarningsSuccess with false payload when the response is empty', () => { - mockMutate.mockResolvedValue({ - data: { - project: null, - }, - }); - - return testAction( - fetchDashboardValidationWarnings, - null, - state, - [], - [{ type: 'receiveDashboardValidationWarningsSuccess', payload: false }], - () => { - expect(mockMutate).toHaveBeenCalledWith(mutationVariables); - }, - ); - }); - - it('dispatches receiveDashboardValidationWarningsFailure if the warnings API call fails', () => { - mockMutate.mockRejectedValue({}); - - return testAction( - fetchDashboardValidationWarnings, - null, - state, - [], - [{ type: 'receiveDashboardValidationWarningsFailure' }], - () => { - expect(mockMutate).toHaveBeenCalledWith(mutationVariables); - }, - ); - }); - }); - - // Dashboard manipulation - - describe('toggleStarredValue', () => { - let unstarredDashboard; - let starredDashboard; - - beforeEach(() => { - state.isUpdatingStarredValue = false; - [unstarredDashboard, starredDashboard] = dashboardGitResponse; - }); - - it('performs no changes if no dashboard is selected', () => { - return testAction(toggleStarredValue, null, state, [], []); - }); - - it('performs no changes if already changing starred value', () => { - state.selectedDashboard = unstarredDashboard; - state.isUpdatingStarredValue = true; - return testAction(toggleStarredValue, null, state, [], []); - }); - - it('stars dashboard if it is not starred', () => { - state.selectedDashboard = unstarredDashboard; - mock.onPost(unstarredDashboard.user_starred_path).reply(HTTP_STATUS_OK); - - return testAction(toggleStarredValue, null, state, [ - { type: types.REQUEST_DASHBOARD_STARRING }, - { - type: types.RECEIVE_DASHBOARD_STARRING_SUCCESS, - payload: { - newStarredValue: true, - selectedDashboard: unstarredDashboard, - }, - }, - ]); - }); - - it('unstars dashboard if it is starred', () => { - state.selectedDashboard = starredDashboard; - mock.onPost(starredDashboard.user_starred_path).reply(HTTP_STATUS_OK); - - return testAction(toggleStarredValue, null, state, [ - { type: types.REQUEST_DASHBOARD_STARRING }, - { type: types.RECEIVE_DASHBOARD_STARRING_FAILURE }, - ]); - }); - }); - - describe('duplicateSystemDashboard', () => { - beforeEach(() => { - state.dashboardsEndpoint = '/dashboards.json'; - }); - - it('Succesful POST request resolves', async () => { - mock.onPost(state.dashboardsEndpoint).reply(HTTP_STATUS_CREATED, { - dashboard: dashboardGitResponse[1], - }); - - await testAction(duplicateSystemDashboard, {}, state, [], []); - expect(mock.history.post).toHaveLength(1); - }); - - it('Succesful POST request resolves to a dashboard', async () => { - const mockCreatedDashboard = dashboardGitResponse[1]; - - const params = { - dashboard: 'my-dashboard', - fileName: 'file-name.yml', - branch: 'my-new-branch', - commitMessage: 'A new commit message', - }; - - const expectedPayload = JSON.stringify({ - dashboard: 'my-dashboard', - file_name: 'file-name.yml', - branch: 'my-new-branch', - commit_message: 'A new commit message', - }); - - mock.onPost(state.dashboardsEndpoint).reply(HTTP_STATUS_CREATED, { - dashboard: mockCreatedDashboard, - }); - - const result = await testAction(duplicateSystemDashboard, params, state, [], []); - expect(mock.history.post).toHaveLength(1); - expect(mock.history.post[0].data).toEqual(expectedPayload); - expect(result).toEqual(mockCreatedDashboard); - }); - - it('Failed POST request throws an error', async () => { - mock.onPost(state.dashboardsEndpoint).reply(HTTP_STATUS_BAD_REQUEST); - - await expect(testAction(duplicateSystemDashboard, {}, state, [], [])).rejects.toEqual( - 'There was an error creating the dashboard.', - ); - expect(mock.history.post).toHaveLength(1); - }); - - it('Failed POST request throws an error with a description', async () => { - const backendErrorMsg = 'This file already exists!'; - - mock.onPost(state.dashboardsEndpoint).reply(HTTP_STATUS_BAD_REQUEST, { - error: backendErrorMsg, - }); - - await expect(testAction(duplicateSystemDashboard, {}, state, [], [])).rejects.toEqual( - `There was an error creating the dashboard. ${backendErrorMsg}`, - ); - expect(mock.history.post).toHaveLength(1); - }); - }); - - // Variables manipulation - - describe('updateVariablesAndFetchData', () => { - it('should commit UPDATE_VARIABLE_VALUE mutation and fetch data', () => { - return testAction( - updateVariablesAndFetchData, - { pod: 'POD' }, - state, - [ - { - type: types.UPDATE_VARIABLE_VALUE, - payload: { pod: 'POD' }, - }, - ], - [ - { - type: 'fetchDashboardData', - }, - ], - ); - }); - }); - - describe('fetchVariableMetricLabelValues', () => { - const variable = { - type: 'metric_label_values', - name: 'label1', - options: { - prometheusEndpointPath: '/series?match[]=metric_name', - label: 'job', - }, - }; - - const defaultQueryParams = { - start_time: '2019-08-06T12:40:02.184Z', - end_time: '2019-08-06T20:40:02.184Z', - }; - - beforeEach(() => { - state = { - ...state, - timeRange: defaultTimeRange, - variables: [variable], - }; - }); - - it('should commit UPDATE_VARIABLE_METRIC_LABEL_VALUES mutation and fetch data', () => { - const data = [ - { - __name__: 'up', - job: 'prometheus', - }, - { - __name__: 'up', - job: 'POD', - }, - ]; - - mock.onGet('/series?match[]=metric_name').reply(HTTP_STATUS_OK, { - status: 'success', - data, - }); - - return testAction( - fetchVariableMetricLabelValues, - { defaultQueryParams }, - state, - [ - { - type: types.UPDATE_VARIABLE_METRIC_LABEL_VALUES, - payload: { variable, label: 'job', data }, - }, - ], - [], - ); - }); - - it('should notify the user that dynamic options were not loaded', () => { - mock.onGet('/series?match[]=metric_name').reply(HTTP_STATUS_INTERNAL_SERVER_ERROR); - - return testAction(fetchVariableMetricLabelValues, { defaultQueryParams }, state, [], []).then( - () => { - expect(createAlert).toHaveBeenCalledTimes(1); - expect(createAlert).toHaveBeenCalledWith({ - message: expect.stringContaining('error getting options for variable "label1"'), - }); - }, - ); - }); - }); - - describe('fetchPanelPreview', () => { - const panelPreviewEndpoint = '/builder.json'; - const mockYmlContent = 'mock yml content'; - - beforeEach(() => { - state.panelPreviewEndpoint = panelPreviewEndpoint; - }); - - it('should not commit or dispatch if payload is empty', () => { - testAction(fetchPanelPreview, '', state, [], []); - }); - - it('should store the panel and fetch metric results', () => { - const mockPanel = { - title: 'Go heap size', - type: 'area-chart', - }; - - mock - .onPost(panelPreviewEndpoint, { panel_yaml: mockYmlContent }) - .reply(HTTP_STATUS_OK, mockPanel); - - testAction( - fetchPanelPreview, - mockYmlContent, - state, - [ - { type: types.SET_PANEL_PREVIEW_IS_SHOWN, payload: true }, - { type: types.REQUEST_PANEL_PREVIEW, payload: mockYmlContent }, - { type: types.RECEIVE_PANEL_PREVIEW_SUCCESS, payload: mockPanel }, - ], - [{ type: 'fetchPanelPreviewMetrics' }], - ); - }); - - it('should display a validation error when the backend cannot process the yml', () => { - const mockErrorMsg = 'Each "metric" must define one of :query or :query_range'; - - mock - .onPost(panelPreviewEndpoint, { panel_yaml: mockYmlContent }) - .reply(HTTP_STATUS_UNPROCESSABLE_ENTITY, { - message: mockErrorMsg, - }); - - testAction(fetchPanelPreview, mockYmlContent, state, [ - { type: types.SET_PANEL_PREVIEW_IS_SHOWN, payload: true }, - { type: types.REQUEST_PANEL_PREVIEW, payload: mockYmlContent }, - { type: types.RECEIVE_PANEL_PREVIEW_FAILURE, payload: mockErrorMsg }, - ]); - }); - - it('should display a generic error when the backend fails', () => { - mock - .onPost(panelPreviewEndpoint, { panel_yaml: mockYmlContent }) - .reply(HTTP_STATUS_INTERNAL_SERVER_ERROR); - - testAction(fetchPanelPreview, mockYmlContent, state, [ - { type: types.SET_PANEL_PREVIEW_IS_SHOWN, payload: true }, - { type: types.REQUEST_PANEL_PREVIEW, payload: mockYmlContent }, - { - type: types.RECEIVE_PANEL_PREVIEW_FAILURE, - payload: 'Request failed with status code 500', - }, - ]); - }); - }); -}); |