Commit a12f10d7 authored by Mike Greiling's avatar Mike Greiling

Merge branch 'reorder-actions-spec-to-match' into 'master'

Reorder specs to match actions implementation

See merge request gitlab-org/gitlab!34908
parents dd858cbc 06edcc35
...@@ -12,21 +12,21 @@ import { ENVIRONMENT_AVAILABLE_STATE } from '~/monitoring/constants'; ...@@ -12,21 +12,21 @@ import { ENVIRONMENT_AVAILABLE_STATE } from '~/monitoring/constants';
import { createStore } from '~/monitoring/stores'; import { createStore } from '~/monitoring/stores';
import * as types from '~/monitoring/stores/mutation_types'; import * as types from '~/monitoring/stores/mutation_types';
import { import {
setGettingStartedEmptyState,
setInitialState,
setExpandedPanel,
clearExpandedPanel,
filterEnvironments,
fetchData, fetchData,
fetchDashboard, fetchDashboard,
receiveMetricsDashboardSuccess, receiveMetricsDashboardSuccess,
fetchDashboardData,
fetchPrometheusMetric,
fetchDeploymentsData, fetchDeploymentsData,
fetchEnvironmentsData, fetchEnvironmentsData,
fetchDashboardData,
fetchAnnotations, fetchAnnotations,
fetchDashboardValidationWarnings, fetchDashboardValidationWarnings,
toggleStarredValue, toggleStarredValue,
fetchPrometheusMetric,
setInitialState,
filterEnvironments,
setExpandedPanel,
clearExpandedPanel,
setGettingStartedEmptyState,
duplicateSystemDashboard, duplicateSystemDashboard,
updateVariablesAndFetchData, updateVariablesAndFetchData,
} from '~/monitoring/stores/actions'; } from '~/monitoring/stores/actions';
...@@ -81,6 +81,7 @@ describe('Monitoring store actions', () => { ...@@ -81,6 +81,7 @@ describe('Monitoring store actions', () => {
return q; return q;
}); });
}); });
afterEach(() => { afterEach(() => {
mock.reset(); mock.reset();
...@@ -88,665 +89,313 @@ describe('Monitoring store actions', () => { ...@@ -88,665 +89,313 @@ describe('Monitoring store actions', () => {
createFlash.mockReset(); createFlash.mockReset();
}); });
describe('fetchData', () => { // Setup
it('dispatches fetchEnvironmentsData and fetchEnvironmentsData', () => {
return testAction( describe('setGettingStartedEmptyState', () => {
fetchData, it('should commit SET_GETTING_STARTED_EMPTY_STATE mutation', done => {
testAction(
setGettingStartedEmptyState,
null, null,
state, state,
[],
[ [
{ type: 'fetchEnvironmentsData' }, {
{ type: 'fetchDashboard' }, type: types.SET_GETTING_STARTED_EMPTY_STATE,
{ type: 'fetchAnnotations' }, },
], ],
[],
done,
); );
}); });
});
it('dispatches when feature metricsDashboardAnnotations is on', () => { describe('setInitialState', () => {
const origGon = window.gon; it('should commit SET_INITIAL_STATE mutation', done => {
window.gon = { features: { metricsDashboardAnnotations: true } }; testAction(
setInitialState,
return testAction( {
fetchData, currentDashboard: '.gitlab/dashboards/dashboard.yml',
null, deploymentsEndpoint: 'deployments.json',
},
state, state,
[],
[ [
{ type: 'fetchEnvironmentsData' }, {
{ type: 'fetchDashboard' }, type: types.SET_INITIAL_STATE,
{ type: 'fetchAnnotations' }, payload: {
currentDashboard: '.gitlab/dashboards/dashboard.yml',
deploymentsEndpoint: 'deployments.json',
},
},
], ],
).then(() => { [],
window.gon = origGon; done,
}); );
}); });
}); });
describe('fetchDeploymentsData', () => { describe('setExpandedPanel', () => {
it('dispatches receiveDeploymentsDataSuccess on success', () => { it('Sets a panel as expanded', () => {
state.deploymentsEndpoint = '/success'; const group = 'group_1';
mock.onGet(state.deploymentsEndpoint).reply(200, { const panel = { title: 'A Panel' };
deployments: deploymentData,
});
return testAction( return testAction(
fetchDeploymentsData, setExpandedPanel,
null, { group, panel },
state, state,
[{ type: types.SET_EXPANDED_PANEL, payload: { group, panel } }],
[], [],
[{ type: 'receiveDeploymentsDataSuccess', payload: deploymentData }],
); );
}); });
it('dispatches receiveDeploymentsDataFailure on error', () => { });
state.deploymentsEndpoint = '/error';
mock.onGet(state.deploymentsEndpoint).reply(500);
describe('clearExpandedPanel', () => {
it('Clears a panel as expanded', () => {
return testAction( return testAction(
fetchDeploymentsData, clearExpandedPanel,
null, undefined,
state, state,
[{ type: types.SET_EXPANDED_PANEL, payload: { group: null, panel: null } }],
[], [],
[{ type: 'receiveDeploymentsDataFailure' }],
() => {
expect(createFlash).toHaveBeenCalled();
},
); );
}); });
}); });
describe('fetchEnvironmentsData', () => { // All Data
beforeEach(() => {
state.projectPath = 'gitlab-org/gitlab-test';
});
it('setting SET_ENVIRONMENTS_FILTER should dispatch fetchEnvironmentsData', () => {
jest.spyOn(gqClient, 'mutate').mockReturnValue({
data: {
project: {
data: {
environments: [],
},
},
},
});
describe('fetchData', () => {
it('dispatches fetchEnvironmentsData and fetchEnvironmentsData', () => {
return testAction( return testAction(
filterEnvironments, fetchData,
{}, null,
state, state,
[],
[ [
{ { type: 'fetchEnvironmentsData' },
type: 'SET_ENVIRONMENTS_FILTER', { type: 'fetchDashboard' },
payload: {}, { type: 'fetchAnnotations' },
},
],
[
{
type: 'fetchEnvironmentsData',
},
], ],
); );
}); });
it('fetch environments data call takes in search param', () => { it('dispatches when feature metricsDashboardAnnotations is on', () => {
const mockMutate = jest.spyOn(gqClient, 'mutate'); const origGon = window.gon;
const searchTerm = 'Something'; window.gon = { features: { metricsDashboardAnnotations: true } };
const mutationVariables = {
mutation: getEnvironments,
variables: {
projectPath: state.projectPath,
search: searchTerm,
states: [ENVIRONMENT_AVAILABLE_STATE],
},
};
state.environmentsSearchTerm = searchTerm;
mockMutate.mockResolvedValue({});
return testAction( return testAction(
fetchEnvironmentsData, fetchData,
null, null,
state, state,
[], [],
[ [
{ type: 'requestEnvironmentsData' }, { type: 'fetchEnvironmentsData' },
{ type: 'receiveEnvironmentsDataSuccess', payload: [] }, { type: 'fetchDashboard' },
{ type: 'fetchAnnotations' },
], ],
() => { ).then(() => {
expect(mockMutate).toHaveBeenCalledWith(mutationVariables); window.gon = origGon;
}, });
);
}); });
});
it('dispatches receiveEnvironmentsDataSuccess on success', () => { // Metrics dashboard
jest.spyOn(gqClient, 'mutate').mockResolvedValue({
data: { describe('fetchDashboard', () => {
project: { let dispatch;
data: { let commit;
environments: environmentData, const response = metricsDashboardResponse;
}, beforeEach(() => {
}, dispatch = jest.fn();
}, commit = jest.fn();
}); 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(200, response);
return testAction( return testAction(
fetchEnvironmentsData, fetchDashboard,
null, null,
state, state,
[], [],
[ [
{ type: 'requestEnvironmentsData' }, { type: 'requestMetricsDashboard' },
{ {
type: 'receiveEnvironmentsDataSuccess', type: 'receiveMetricsDashboardSuccess',
payload: parseEnvironmentsResponse(environmentData, state.projectPath), payload: { response },
}, },
{ type: 'fetchDashboardValidationWarnings' },
], ],
); );
}); });
it('dispatches receiveEnvironmentsDataFailure on error', () => { describe('on failure', () => {
jest.spyOn(gqClient, 'mutate').mockRejectedValue({}); let result;
beforeEach(() => {
return testAction( const params = {};
fetchEnvironmentsData, const localGetters = {
null, fullDashboardPath: store.getters['monitoringDashboard/fullDashboardPath'],
state, };
[], result = () => {
[{ type: 'requestEnvironmentsData' }, { type: 'receiveEnvironmentsDataFailure' }], mock.onGet(state.dashboardEndpoint).replyOnce(500, mockDashboardsErrorResponse);
); return fetchDashboard({ state, commit, dispatch, getters: localGetters }, params);
}); };
}); });
describe('fetchAnnotations', () => { it('dispatches a failure', done => {
beforeEach(() => { result()
state.timeRange = { .then(() => {
start: '2020-04-15T12:54:32.137Z', expect(commit).toHaveBeenCalledWith(
end: '2020-08-15T12:54:32.137Z', types.SET_ALL_DASHBOARDS,
}; mockDashboardsErrorResponse.all_dashboards,
state.projectPath = 'gitlab-org/gitlab-test'; );
state.currentEnvironmentName = 'production'; expect(dispatch).toHaveBeenCalledWith(
state.currentDashboard = '.gitlab/dashboards/custom_dashboard.yml'; 'receiveMetricsDashboardFailure',
// testAction doesn't have access to getters. The state is passed in as getters new Error('Request failed with status code 500'),
// instead of the actual getters inside the testAction method implementation. );
// All methods downstream that needs access to getters will throw and error. expect(createFlash).toHaveBeenCalled();
// For that reason, the result of the getter is set as a state variable. done();
state.fullDashboardPath = store.getters['monitoringDashboard/fullDashboardPath']; })
}); .catch(done.fail);
});
it('fetches annotations data and dispatches receiveAnnotationsSuccess', () => { it('dispatches a failure action when a message is returned', done => {
const mockMutate = jest.spyOn(gqClient, 'mutate'); result()
const mutationVariables = { .then(() => {
mutation: getAnnotations, expect(dispatch).toHaveBeenCalledWith(
variables: { 'receiveMetricsDashboardFailure',
projectPath: state.projectPath, new Error('Request failed with status code 500'),
environmentName: state.currentEnvironmentName, );
dashboardPath: state.currentDashboard, expect(createFlash).toHaveBeenCalledWith(
startingFrom: state.timeRange.start, expect.stringContaining(mockDashboardsErrorResponse.message),
}, );
}; done();
const parsedResponse = parseAnnotationsResponse(annotationsData); })
.catch(done.fail);
mockMutate.mockResolvedValue({
data: {
project: {
environments: {
nodes: [
{
metricsDashboard: {
annotations: {
nodes: parsedResponse,
},
},
},
],
},
},
},
}); });
return testAction( it('does not show a flash error when showErrorBanner is disabled', done => {
fetchAnnotations, state.showErrorBanner = false;
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( result()
fetchAnnotations, .then(() => {
null, expect(dispatch).toHaveBeenCalledWith(
state, 'receiveMetricsDashboardFailure',
[], new Error('Request failed with status code 500'),
[{ type: 'receiveAnnotationsFailure' }], );
() => { expect(createFlash).not.toHaveBeenCalled();
expect(mockMutate).toHaveBeenCalledWith(mutationVariables); done();
}, })
); .catch(done.fail);
});
}); });
}); });
describe('fetchDashboardValidationWarnings', () => { describe('receiveMetricsDashboardSuccess', () => {
let mockMutate; let commit;
let mutationVariables; let dispatch;
beforeEach(() => { beforeEach(() => {
state.projectPath = 'gitlab-org/gitlab-test'; commit = jest.fn();
state.currentEnvironmentName = 'production'; dispatch = jest.fn();
state.currentDashboard = '.gitlab/dashboards/dashboard_with_warnings.yml';
mockMutate = jest.spyOn(gqClient, 'mutate');
mutationVariables = {
mutation: getDashboardValidationWarnings,
variables: {
projectPath: state.projectPath,
environmentName: state.currentEnvironmentName,
dashboardPath: state.currentDashboard,
},
};
}); });
it('dispatches receiveDashboardValidationWarningsSuccess with true payload when there are warnings', () => { it('stores groups', () => {
mockMutate.mockResolvedValue({ const response = metricsDashboardResponse;
data: { receiveMetricsDashboardSuccess({ state, commit, dispatch }, { response });
project: { expect(commit).toHaveBeenCalledWith(
id: 'gid://gitlab/Project/29', types.RECEIVE_METRICS_DASHBOARD_SUCCESS,
environments: {
nodes: [
{
name: 'production',
metricsDashboard: {
path: '.gitlab/dashboards/dashboard_errors_test.yml',
schemaValidationWarnings: ["unit: can't be blank"],
},
},
],
},
},
},
});
return testAction( metricsDashboardResponse.dashboard,
fetchDashboardValidationWarnings,
null,
state,
[],
[{ type: 'receiveDashboardValidationWarningsSuccess', payload: true }],
() => {
expect(mockMutate).toHaveBeenCalledWith(mutationVariables);
},
); );
expect(dispatch).toHaveBeenCalledWith('fetchDashboardData');
}); });
it('dispatches receiveDashboardValidationWarningsSuccess with false payload when there are no warnings', () => { it('stores templating variables', () => {
mockMutate.mockResolvedValue({ const response = {
data: { ...metricsDashboardResponse.dashboard,
project: { ...mockTemplatingData.allVariableTypes.dashboard,
id: 'gid://gitlab/Project/29', };
environments: {
nodes: [ receiveMetricsDashboardSuccess(
{ { state, commit, dispatch },
name: 'production', {
metricsDashboard: { response: {
path: '.gitlab/dashboards/dashboard_errors_test.yml', ...metricsDashboardResponse,
schemaValidationWarnings: [], dashboard: {
}, ...metricsDashboardResponse.dashboard,
}, ...mockTemplatingData.allVariableTypes.dashboard,
],
}, },
}, },
}, },
}); );
return testAction( expect(commit).toHaveBeenCalledWith(
fetchDashboardValidationWarnings, types.RECEIVE_METRICS_DASHBOARD_SUCCESS,
null,
state, response,
[],
[{ type: 'receiveDashboardValidationWarningsSuccess', payload: false }],
() => {
expect(mockMutate).toHaveBeenCalledWith(mutationVariables);
},
); );
}); });
it('dispatches receiveDashboardValidationWarningsFailure if the warnings API call fails', () => { it('sets the dashboards loaded from the repository', () => {
mockMutate.mockRejectedValue({}); const params = {};
const response = metricsDashboardResponse;
return testAction( response.all_dashboards = dashboardGitResponse;
fetchDashboardValidationWarnings, receiveMetricsDashboardSuccess(
null, {
state, state,
[], commit,
[{ type: 'receiveDashboardValidationWarningsFailure' }], dispatch,
() => { },
expect(mockMutate).toHaveBeenCalledWith(mutationVariables); {
response,
params,
}, },
); );
expect(commit).toHaveBeenCalledWith(types.SET_ALL_DASHBOARDS, dashboardGitResponse);
}); });
}); });
describe('Toggles starred value of current dashboard', () => { // Metrics
let unstarredDashboard;
let starredDashboard;
beforeEach(() => {
state.isUpdatingStarredValue = false;
[unstarredDashboard, starredDashboard] = dashboardGitResponse;
});
describe('toggleStarredValue', () => { describe('fetchDashboardData', () => {
it('performs no changes if no dashboard is selected', () => { let commit;
return testAction(toggleStarredValue, null, state, [], []); let dispatch;
});
it('performs no changes if already changing starred value', () => { beforeEach(() => {
state.selectedDashboard = unstarredDashboard; jest.spyOn(Tracking, 'event');
state.isUpdatingStarredValue = true; commit = jest.fn();
return testAction(toggleStarredValue, null, state, [], []); dispatch = jest.fn();
});
it('stars dashboard if it is not starred', () => { state.timeRange = defaultTimeRange;
state.selectedDashboard = unstarredDashboard; });
mock.onPost(unstarredDashboard.user_starred_path).reply(200);
return testAction(toggleStarredValue, null, state, [ it('commits empty state when state.groups is empty', done => {
{ type: types.REQUEST_DASHBOARD_STARRING }, const localGetters = {
{ metricsWithData: () => [],
type: types.RECEIVE_DASHBOARD_STARRING_SUCCESS, };
payload: { fetchDashboardData({ state, commit, dispatch, getters: localGetters })
newStarredValue: true, .then(() => {
selectedDashboard: unstarredDashboard, expect(Tracking.event).toHaveBeenCalledWith(
document.body.dataset.page,
'dashboard_fetch',
{
label: 'custom_metrics_dashboard',
property: 'count',
value: 0,
}, },
}, );
]); expect(dispatch).toHaveBeenCalledTimes(1);
}); expect(dispatch).toHaveBeenCalledWith('fetchDeploymentsData');
it('unstars dashboard if it is starred', () => {
state.selectedDashboard = starredDashboard;
mock.onPost(starredDashboard.user_starred_path).reply(200);
return testAction(toggleStarredValue, null, state, [ expect(createFlash).not.toHaveBeenCalled();
{ type: types.REQUEST_DASHBOARD_STARRING }, done();
{ type: types.RECEIVE_DASHBOARD_STARRING_FAILURE }, })
]); .catch(done.fail);
});
}); });
}); it('dispatches fetchPrometheusMetric for each panel query', done => {
state.dashboard.panelGroups = convertObjectPropsToCamelCase(
describe('Set initial state', () => { metricsDashboardResponse.dashboard.panel_groups,
it('should commit SET_INITIAL_STATE mutation', done => { );
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',
},
},
],
[],
done,
);
});
});
describe('Set empty states', () => {
it('should commit SET_METRICS_ENDPOINT mutation', done => {
testAction(
setGettingStartedEmptyState,
null,
state,
[
{
type: types.SET_GETTING_STARTED_EMPTY_STATE,
},
],
[],
done,
);
});
});
describe('updateVariablesAndFetchData', () => {
it('should commit UPDATE_VARIABLES mutation and fetch data', done => {
testAction(
updateVariablesAndFetchData,
{ pod: 'POD' },
state,
[
{
type: types.UPDATE_VARIABLES,
payload: { pod: 'POD' },
},
],
[
{
type: 'fetchDashboardData',
},
],
done,
);
});
});
describe('fetchDashboard', () => {
let dispatch;
let commit;
const response = metricsDashboardResponse;
beforeEach(() => {
dispatch = jest.fn();
commit = jest.fn();
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(200, 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(500, mockDashboardsErrorResponse);
return fetchDashboard({ state, commit, dispatch, getters: localGetters }, params);
};
});
it('dispatches a failure', done => {
result()
.then(() => {
expect(commit).toHaveBeenCalledWith(
types.SET_ALL_DASHBOARDS,
mockDashboardsErrorResponse.all_dashboards,
);
expect(dispatch).toHaveBeenCalledWith(
'receiveMetricsDashboardFailure',
new Error('Request failed with status code 500'),
);
expect(createFlash).toHaveBeenCalled();
done();
})
.catch(done.fail);
});
it('dispatches a failure action when a message is returned', done => {
result()
.then(() => {
expect(dispatch).toHaveBeenCalledWith(
'receiveMetricsDashboardFailure',
new Error('Request failed with status code 500'),
);
expect(createFlash).toHaveBeenCalledWith(
expect.stringContaining(mockDashboardsErrorResponse.message),
);
done();
})
.catch(done.fail);
});
it('does not show a flash error when showErrorBanner is disabled', done => {
state.showErrorBanner = false;
result()
.then(() => {
expect(dispatch).toHaveBeenCalledWith(
'receiveMetricsDashboardFailure',
new Error('Request failed with status code 500'),
);
expect(createFlash).not.toHaveBeenCalled();
done();
})
.catch(done.fail);
});
});
});
describe('receiveMetricsDashboardSuccess', () => {
let commit;
let dispatch;
beforeEach(() => {
commit = jest.fn();
dispatch = jest.fn();
});
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('stores templating variables', () => {
const response = {
...metricsDashboardResponse.dashboard,
...mockTemplatingData.allVariableTypes.dashboard,
};
receiveMetricsDashboardSuccess(
{ state, commit, dispatch },
{
response: {
...metricsDashboardResponse,
dashboard: {
...metricsDashboardResponse.dashboard,
...mockTemplatingData.allVariableTypes.dashboard,
},
},
},
);
expect(commit).toHaveBeenCalledWith(
types.RECEIVE_METRICS_DASHBOARD_SUCCESS,
response,
);
});
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);
});
});
describe('fetchDashboardData', () => {
let commit;
let dispatch;
beforeEach(() => {
jest.spyOn(Tracking, 'event');
commit = jest.fn();
dispatch = jest.fn();
state.timeRange = defaultTimeRange;
});
it('commits empty state when state.groups is empty', done => {
const localGetters = {
metricsWithData: () => [],
};
fetchDashboardData({ state, commit, dispatch, getters: localGetters })
.then(() => {
expect(Tracking.event).toHaveBeenCalledWith(
document.body.dataset.page,
'dashboard_fetch',
{
label: 'custom_metrics_dashboard',
property: 'count',
value: 0,
},
);
expect(dispatch).toHaveBeenCalledTimes(1);
expect(dispatch).toHaveBeenCalledWith('fetchDeploymentsData');
expect(createFlash).not.toHaveBeenCalled();
done();
})
.catch(done.fail);
});
it('dispatches fetchPrometheusMetric for each panel query', done => {
state.dashboard.panelGroups = convertObjectPropsToCamelCase(
metricsDashboardResponse.dashboard.panel_groups,
);
const [metric] = state.dashboard.panelGroups[0].panels[0].metrics; const [metric] = state.dashboard.panelGroups[0].panels[0].metrics;
const localGetters = { const localGetters = {
...@@ -810,6 +459,7 @@ describe('Monitoring store actions', () => { ...@@ -810,6 +459,7 @@ describe('Monitoring store actions', () => {
done(); done();
}); });
}); });
describe('fetchPrometheusMetric', () => { describe('fetchPrometheusMetric', () => {
const defaultQueryParams = { const defaultQueryParams = {
start_time: '2019-08-06T12:40:02.184Z', start_time: '2019-08-06T12:40:02.184Z',
...@@ -826,190 +476,562 @@ describe('Monitoring store actions', () => { ...@@ -826,190 +476,562 @@ describe('Monitoring store actions', () => {
prometheusEndpointPath = metric.prometheusEndpointPath; prometheusEndpointPath = metric.prometheusEndpointPath;
data = { data = {
metricId: metric.metricId, metricId: metric.metricId,
result: [1582065167.353, 5, 1582065599.353], result: [1582065167.353, 5, 1582065599.353],
}; };
});
it('commits result', done => {
mock.onGet(prometheusEndpointPath).reply(200, { data }); // One attempt
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).toHaveLength(1);
done();
},
).catch(done.fail);
});
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', done => {
mock.onGet(prometheusEndpointPath).reply(200, { data }); // One attempt
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);
done();
},
).catch(done.fail);
});
});
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', done => {
mock.onGet(prometheusEndpointPath).reply(200, { data }); // One attempt
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);
done();
},
).catch(done.fail);
});
});
it('commits result, when waiting for results', done => {
// Mock multiple attempts while the cache is filling up
mock.onGet(prometheusEndpointPath).replyOnce(statusCodes.NO_CONTENT);
mock.onGet(prometheusEndpointPath).replyOnce(statusCodes.NO_CONTENT);
mock.onGet(prometheusEndpointPath).replyOnce(statusCodes.NO_CONTENT);
mock.onGet(prometheusEndpointPath).reply(200, { data }); // 4th attempt
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).toHaveLength(4);
done();
},
).catch(done.fail);
});
it('commits failure, when waiting for results and getting a server error', done => {
// Mock multiple attempts while the cache is filling up and fails
mock.onGet(prometheusEndpointPath).replyOnce(statusCodes.NO_CONTENT);
mock.onGet(prometheusEndpointPath).replyOnce(statusCodes.NO_CONTENT);
mock.onGet(prometheusEndpointPath).replyOnce(statusCodes.NO_CONTENT);
mock.onGet(prometheusEndpointPath).reply(500); // 4th attempt
const error = new Error('Request failed with status code 500');
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,
},
},
],
[],
).catch(e => {
expect(mock.history.get).toHaveLength(4);
expect(e).toEqual(error);
done();
});
});
});
// Deployments
describe('fetchDeploymentsData', () => {
it('dispatches receiveDeploymentsDataSuccess on success', () => {
state.deploymentsEndpoint = '/success';
mock.onGet(state.deploymentsEndpoint).reply(200, {
deployments: deploymentData,
});
return testAction(
fetchDeploymentsData,
null,
state,
[],
[{ type: 'receiveDeploymentsDataSuccess', payload: deploymentData }],
);
});
it('dispatches receiveDeploymentsDataFailure on error', () => {
state.deploymentsEndpoint = '/error';
mock.onGet(state.deploymentsEndpoint).reply(500);
return testAction(
fetchDeploymentsData,
null,
state,
[],
[{ type: 'receiveDeploymentsDataFailure' }],
() => {
expect(createFlash).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';
mockMutate = jest.spyOn(gqClient, 'mutate');
mutationVariables = {
mutation: getDashboardValidationWarnings,
variables: {
projectPath: state.projectPath,
environmentName: state.currentEnvironmentName,
dashboardPath: state.currentDashboard,
},
};
});
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('commits result', done => { it('dispatches receiveDashboardValidationWarningsSuccess with false payload when there are no warnings', () => {
mock.onGet(prometheusEndpointPath).reply(200, { data }); // One attempt mockMutate.mockResolvedValue({
data: {
testAction( project: {
fetchPrometheusMetric, id: 'gid://gitlab/Project/29',
{ metric, defaultQueryParams }, environments: {
state, nodes: [
[ {
{ name: 'production',
type: types.REQUEST_METRIC_RESULT, metricsDashboard: {
payload: { path: '.gitlab/dashboards/dashboard_errors_test.yml',
metricId: metric.metricId, schemaValidationWarnings: [],
}, },
}, },
{ ],
type: types.RECEIVE_METRIC_RESULT_SUCCESS,
payload: {
metricId: metric.metricId,
data,
}, },
}, },
], },
});
return testAction(
fetchDashboardValidationWarnings,
null,
state,
[], [],
[{ type: 'receiveDashboardValidationWarningsSuccess', payload: false }],
() => { () => {
expect(mock.history.get).toHaveLength(1); expect(mockMutate).toHaveBeenCalledWith(mutationVariables);
done();
}, },
).catch(done.fail); );
}); });
describe('without metric defined step', () => { it('dispatches receiveDashboardValidationWarningsFailure if the warnings API call fails', () => {
const expectedParams = { mockMutate.mockRejectedValue({});
start_time: '2019-08-06T12:40:02.184Z',
end_time: '2019-08-06T20:40:02.184Z',
step: 60,
};
it('uses calculated step', done => {
mock.onGet(prometheusEndpointPath).reply(200, { data }); // One attempt
testAction( return testAction(
fetchPrometheusMetric, fetchDashboardValidationWarnings,
{ metric, defaultQueryParams }, null,
state, state,
[ [],
{ [{ type: 'receiveDashboardValidationWarningsFailure' }],
type: types.REQUEST_METRIC_RESULT, () => {
payload: { expect(mockMutate).toHaveBeenCalledWith(mutationVariables);
metricId: metric.metricId, },
}, );
},
{
type: types.RECEIVE_METRIC_RESULT_SUCCESS,
payload: {
metricId: metric.metricId,
data,
},
},
],
[],
() => {
expect(mock.history.get[0].params).toEqual(expectedParams);
done();
},
).catch(done.fail);
});
}); });
});
describe('with metric defined step', () => { // Dashboard manipulation
beforeEach(() => {
metric.step = 7;
});
const expectedParams = { describe('toggleStarredValue', () => {
start_time: '2019-08-06T12:40:02.184Z', let unstarredDashboard;
end_time: '2019-08-06T20:40:02.184Z', let starredDashboard;
step: 7,
};
it('uses metric step', done => { beforeEach(() => {
mock.onGet(prometheusEndpointPath).reply(200, { data }); // One attempt state.isUpdatingStarredValue = false;
[unstarredDashboard, starredDashboard] = dashboardGitResponse;
});
testAction( it('performs no changes if no dashboard is selected', () => {
fetchPrometheusMetric, return testAction(toggleStarredValue, null, state, [], []);
{ 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);
done();
},
).catch(done.fail);
});
}); });
it('commits result, when waiting for results', done => { it('performs no changes if already changing starred value', () => {
// Mock multiple attempts while the cache is filling up state.selectedDashboard = unstarredDashboard;
mock.onGet(prometheusEndpointPath).replyOnce(statusCodes.NO_CONTENT); state.isUpdatingStarredValue = true;
mock.onGet(prometheusEndpointPath).replyOnce(statusCodes.NO_CONTENT); return testAction(toggleStarredValue, null, state, [], []);
mock.onGet(prometheusEndpointPath).replyOnce(statusCodes.NO_CONTENT); });
mock.onGet(prometheusEndpointPath).reply(200, { data }); // 4th attempt
testAction( it('stars dashboard if it is not starred', () => {
fetchPrometheusMetric, state.selectedDashboard = unstarredDashboard;
{ metric, defaultQueryParams }, mock.onPost(unstarredDashboard.user_starred_path).reply(200);
state,
[ return testAction(toggleStarredValue, null, state, [
{ { type: types.REQUEST_DASHBOARD_STARRING },
type: types.REQUEST_METRIC_RESULT, {
payload: { type: types.RECEIVE_DASHBOARD_STARRING_SUCCESS,
metricId: metric.metricId, payload: {
}, newStarredValue: true,
}, selectedDashboard: unstarredDashboard,
{
type: types.RECEIVE_METRIC_RESULT_SUCCESS,
payload: {
metricId: metric.metricId,
data,
},
}, },
],
[],
() => {
expect(mock.history.get).toHaveLength(4);
done();
}, },
).catch(done.fail); ]);
}); });
it('commits failure, when waiting for results and getting a server error', done => { it('unstars dashboard if it is starred', () => {
// Mock multiple attempts while the cache is filling up and fails state.selectedDashboard = starredDashboard;
mock.onGet(prometheusEndpointPath).replyOnce(statusCodes.NO_CONTENT); mock.onPost(starredDashboard.user_starred_path).reply(200);
mock.onGet(prometheusEndpointPath).replyOnce(statusCodes.NO_CONTENT);
mock.onGet(prometheusEndpointPath).replyOnce(statusCodes.NO_CONTENT);
mock.onGet(prometheusEndpointPath).reply(500); // 4th attempt
const error = new Error('Request failed with status code 500');
testAction( return testAction(toggleStarredValue, null, state, [
fetchPrometheusMetric, { type: types.REQUEST_DASHBOARD_STARRING },
{ metric, defaultQueryParams }, { type: types.RECEIVE_DASHBOARD_STARRING_FAILURE },
state, ]);
[
{
type: types.REQUEST_METRIC_RESULT,
payload: {
metricId: metric.metricId,
},
},
{
type: types.RECEIVE_METRIC_RESULT_FAILURE,
payload: {
metricId: metric.metricId,
error,
},
},
],
[],
).catch(e => {
expect(mock.history.get).toHaveLength(4);
expect(e).toEqual(error);
done();
});
}); });
}); });
...@@ -1091,29 +1113,26 @@ describe('Monitoring store actions', () => { ...@@ -1091,29 +1113,26 @@ describe('Monitoring store actions', () => {
}); });
}); });
describe('setExpandedPanel', () => { // Variables manipulation
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', () => { describe('updateVariablesAndFetchData', () => {
it('Clears a panel as expanded', () => { it('should commit UPDATE_VARIABLES mutation and fetch data', done => {
return testAction( testAction(
clearExpandedPanel, updateVariablesAndFetchData,
undefined, { pod: 'POD' },
state, state,
[{ type: types.SET_EXPANDED_PANEL, payload: { group: null, panel: null } }], [
[], {
type: types.UPDATE_VARIABLES,
payload: { pod: 'POD' },
},
],
[
{
type: 'fetchDashboardData',
},
],
done,
); );
}); });
}); });
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment