Skip to content

Commit

Permalink
Add tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
codyml committed Jun 30, 2022
1 parent 813cfeb commit faa7bf4
Show file tree
Hide file tree
Showing 2 changed files with 262 additions and 36 deletions.
16 changes: 8 additions & 8 deletions superset-frontend/src/explore/actions/saveModalActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export function removeSaveModalAlert() {
return { type: REMOVE_SAVE_MODAL_ALERT };
}

const getSlicePayload = (sliceName, formData) => {
export const getSlicePayload = (sliceName, formData) => {
const [datasourceId, datasourceType] = formData.datasource.split('__');
const payload = {
params: JSON.stringify(formData),
Expand All @@ -88,15 +88,15 @@ const addDashboardSuccessToast = (addedToDashboard, sliceName) => {
if (addedToDashboard) {
if (addedToDashboard.new) {
addSuccessToast(
`${t('Chart')} [${sliceName}] ${t('was added to dashboard')} [${
addedToDashboard.title
}]`,
`${t('Dashboard')} [${addedToDashboard.title}] ${t(
'just got created and chart',
)} [${sliceName}] ${t('was added to it')}`,
);
} else {
addSuccessToast(
`${t('Dashboard')} ${addedToDashboard.title}] ${t(
'just got created and chart',
)} [${sliceName}] ${t('was added to it')}`,
`${t('Chart')} [${sliceName}] ${t('was added to dashboard')} [${
addedToDashboard.title
}]`,
);
}
}
Expand Down Expand Up @@ -136,7 +136,7 @@ export const createSlice =
});

dispatch(saveSliceSuccess());
addSuccessToast(`${t('Chart')} ${sliceName} ${t('has been saved')}`);
addSuccessToast(`${t('Chart')} [${sliceName}] ${t('has been saved')}`);
addDashboardSuccessToast(addedToDashboard, sliceName);
return response.json;
} catch (error) {
Expand Down
282 changes: 254 additions & 28 deletions superset-frontend/src/explore/actions/saveModalActions.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,59 +19,285 @@

import sinon from 'sinon';
import fetchMock from 'fetch-mock';
import { addSuccessToast } from 'src/components/MessageToasts/actions';
import {
createDashboard,
createSlice,
fetchDashboards,
FETCH_DASHBOARDS_FAILED,
FETCH_DASHBOARDS_SUCCEEDED,
getDashboard,
SAVE_SLICE_FAILED,
SAVE_SLICE_SUCCESS,
updateSlice,
} from './saveModalActions';

/**
* Tests fetchDashboards action
*/

const userId = 1;
const fetchDashboardsEndpoint = `glob:*/dashboardasync/api/read?_flt_0_owners=${1}`;
const mockDashboardData = {
pks: ['id'],
result: [{ id: 'id', dashboard_title: 'dashboard title' }],
};

test('fetchDashboards makes the correct fetch request', () => {
fetchMock.restore();
test('fetchDashboards handles success', async () => {
fetchMock.reset();
fetchMock.get(fetchDashboardsEndpoint, mockDashboardData);
const dispatch = sinon.spy();
return fetchDashboards(userId)(dispatch).then(() => {
expect(fetchMock.calls(fetchDashboardsEndpoint)).toHaveLength(1);
await fetchDashboards(userId)(dispatch);
expect(fetchMock.calls(fetchDashboardsEndpoint)).toHaveLength(1);
expect(dispatch.callCount).toBe(1);
expect(dispatch.getCall(0).args[0].type).toBe(FETCH_DASHBOARDS_SUCCEEDED);
});

return Promise.resolve();
});
test('fetchDashboards handles failure', async () => {
fetchMock.reset();
fetchMock.get(fetchDashboardsEndpoint, { throws: 'error' });
const dispatch = sinon.spy();
await fetchDashboards(userId)(dispatch);
expect(fetchMock.calls(fetchDashboardsEndpoint)).toHaveLength(4); // 3 retries
expect(dispatch.callCount).toBe(1);
expect(dispatch.getCall(0).args[0].type).toBe(FETCH_DASHBOARDS_FAILED);
});

test('fetchDashboards calls correct actions on success', () => {
fetchMock.restore();
fetchMock.get(fetchDashboardsEndpoint, mockDashboardData);
const sliceId = 10;
const sliceName = 'New chart';
const vizType = 'sample_viz_type';
const datasourceId = 11;
const datasourceType = 'sample_datasource_type';
const dashboards = [12, 13];
const queryContext = { sampleKey: 'sampleValue' };
const formData = {
viz_type: vizType,
datasource: `${datasourceId}__${datasourceType}`,
dashboards,
};

const sliceResponsePayload = {
id: 10,
};

const sampleError = new Error('sampleError');

jest.mock('../exploreUtils', () => ({
buildV1ChartDataPayload: jest.fn(() => queryContext),
}));

jest.mock('src/components/MessageToasts/actions', () => ({
addSuccessToast: jest.fn(),
}));

/**
* Tests updateSlice action
*/

const updateSliceEndpoint = `glob:*/api/v1/chart/${sliceId}`;
test('updateSlice handles success', async () => {
addSuccessToast.mockClear();
fetchMock.reset();
fetchMock.put(updateSliceEndpoint, sliceResponsePayload);
const dispatch = sinon.spy();
const slice = await updateSlice(sliceId, sliceName, formData)(dispatch);
expect(fetchMock.calls(updateSliceEndpoint)).toHaveLength(1);
expect(dispatch.callCount).toBe(1);
expect(dispatch.getCall(0).args[0].type).toBe(SAVE_SLICE_SUCCESS);
expect(addSuccessToast).toHaveBeenNthCalledWith(
1,
'Chart [New chart] has been overwritten',
);

expect(slice).toEqual(sliceResponsePayload);
});

test('updateSlice handles failure', async () => {
addSuccessToast.mockClear();
fetchMock.reset();
fetchMock.put(updateSliceEndpoint, { throws: sampleError });
const dispatch = sinon.spy();
let caughtError;
try {
await updateSlice(sliceId, sliceName, formData)(dispatch);
} catch (error) {
caughtError = error;
}

expect(caughtError).toEqual(sampleError);
expect(fetchMock.calls(updateSliceEndpoint)).toHaveLength(4);
expect(dispatch.callCount).toBe(1);
expect(dispatch.getCall(0).args[0].type).toBe(SAVE_SLICE_FAILED);
expect(addSuccessToast).not.toHaveBeenCalled();
});

/**
* Tests createSlice action
*/

const createSliceEndpoint = `glob:*/api/v1/chart/`;
test('createSlice handles success', async () => {
addSuccessToast.mockClear();
fetchMock.reset();
fetchMock.post(createSliceEndpoint, sliceResponsePayload);
const dispatch = sinon.spy();
const slice = await createSlice(sliceName, formData)(dispatch);
expect(fetchMock.calls(createSliceEndpoint)).toHaveLength(1);
expect(dispatch.callCount).toBe(1);
expect(dispatch.getCall(0).args[0].type).toBe(SAVE_SLICE_SUCCESS);
expect(addSuccessToast).toHaveBeenNthCalledWith(
1,
'Chart [New chart] has been saved',
);

expect(slice).toEqual(sliceResponsePayload);
});

test('createSlice handles failure', async () => {
addSuccessToast.mockClear();
fetchMock.reset();
fetchMock.post(createSliceEndpoint, { throws: sampleError });
const dispatch = sinon.spy();
let caughtError;
try {
await createSlice(sliceName, formData)(dispatch);
} catch (error) {
caughtError = error;
}

expect(caughtError).toEqual(sampleError);
expect(fetchMock.calls(createSliceEndpoint)).toHaveLength(4);
expect(dispatch.callCount).toBe(1);
expect(dispatch.getCall(0).args[0].type).toBe(SAVE_SLICE_FAILED);
expect(addSuccessToast).not.toHaveBeenCalled();
});

const dashboardId = 14;
const dashboardName = 'New dashboard';
const dashboardResponsePayload = {
id: 14,
};

/**
* Tests createDashboard action
*/

const createDashboardEndpoint = `glob:*/api/v1/dashboard/`;
test('createDashboard handles success', async () => {
addSuccessToast.mockClear();
fetchMock.reset();
fetchMock.post(createDashboardEndpoint, dashboardResponsePayload);
const dispatch = sinon.spy();
const dashboard = await createDashboard(dashboardName)(dispatch);
expect(fetchMock.calls(createDashboardEndpoint)).toHaveLength(1);
expect(dispatch.callCount).toBe(0);
expect(addSuccessToast).not.toHaveBeenCalled();
expect(dashboard).toEqual(dashboardResponsePayload);
});

test('createDashboard handles failure', async () => {
addSuccessToast.mockClear();
fetchMock.reset();
fetchMock.post(createDashboardEndpoint, { throws: sampleError });
const dispatch = sinon.spy();
let caughtError;
try {
await createDashboard(dashboardName)(dispatch);
} catch (error) {
caughtError = error;
}

expect(caughtError).toEqual(sampleError);
expect(fetchMock.calls(createDashboardEndpoint)).toHaveLength(4);
expect(dispatch.callCount).toBe(1);
expect(dispatch.getCall(0).args[0].type).toBe(SAVE_SLICE_FAILED);
expect(addSuccessToast).not.toHaveBeenCalled();
});

/**
* Tests getDashboard action
*/

const getDashboardEndpoint = `glob:*/api/v1/dashboard/${dashboardId}`;
test('getDashboard handles success', async () => {
addSuccessToast.mockClear();
fetchMock.reset();
fetchMock.get(getDashboardEndpoint, dashboardResponsePayload);
const dispatch = sinon.spy();
return fetchDashboards(userId)(dispatch).then(() => {
expect(dispatch.callCount).toBe(1);
expect(dispatch.getCall(0).args[0].type).toBe(FETCH_DASHBOARDS_SUCCEEDED);
const dashboard = await getDashboard(dashboardId)(dispatch);
expect(fetchMock.calls(getDashboardEndpoint)).toHaveLength(1);
expect(dispatch.callCount).toBe(0);
expect(addSuccessToast).not.toHaveBeenCalled();
expect(dashboard).toEqual(dashboardResponsePayload);
});

test('getDashboard handles failure', async () => {
addSuccessToast.mockClear();
fetchMock.reset();
fetchMock.get(getDashboardEndpoint, { throws: sampleError });
const dispatch = sinon.spy();
let caughtError;
try {
await getDashboard(dashboardId)(dispatch);
} catch (error) {
caughtError = error;
}

return Promise.resolve();
});
expect(caughtError).toEqual(sampleError);
expect(fetchMock.calls(getDashboardEndpoint)).toHaveLength(4);
expect(dispatch.callCount).toBe(1);
expect(dispatch.getCall(0).args[0].type).toBe(SAVE_SLICE_FAILED);
expect(addSuccessToast).not.toHaveBeenCalled();
});

test('fetchDashboards calls correct actions on error', () => {
fetchMock.restore();
fetchMock.get(
fetchDashboardsEndpoint,
{ throws: 'error' },
{ overwriteRoutes: true },
test('updateSlice with add to new dashboard handles success', async () => {
addSuccessToast.mockClear();
fetchMock.reset();
fetchMock.put(updateSliceEndpoint, sliceResponsePayload);
const dispatch = sinon.spy();
const slice = await updateSlice(sliceId, sliceName, formData, {
new: true,
title: dashboardName,
})(dispatch);

expect(fetchMock.calls(updateSliceEndpoint)).toHaveLength(1);
expect(dispatch.callCount).toBe(1);
expect(dispatch.getCall(0).args[0].type).toBe(SAVE_SLICE_SUCCESS);
expect(addSuccessToast).toHaveBeenNthCalledWith(
1,
'Chart [New chart] has been overwritten',
);

expect(addSuccessToast).toHaveBeenNthCalledWith(
2,
'Dashboard [New dashboard] just got created and chart [New chart] was added to it',
);

expect(slice).toEqual(sliceResponsePayload);
});

test('updateSlice with add to existing dashboard handles success', async () => {
addSuccessToast.mockClear();
fetchMock.reset();
fetchMock.put(updateSliceEndpoint, sliceResponsePayload);
const dispatch = sinon.spy();
return fetchDashboards(userId)(dispatch).then(() => {
expect(dispatch.callCount).toBe(1);
expect(dispatch.getCall(0).args[0].type).toBe(FETCH_DASHBOARDS_FAILED);
const slice = await updateSlice(sliceId, sliceName, formData, {
new: false,
title: dashboardName,
})(dispatch);

expect(fetchMock.calls(updateSliceEndpoint)).toHaveLength(1);
expect(dispatch.callCount).toBe(1);
expect(dispatch.getCall(0).args[0].type).toBe(SAVE_SLICE_SUCCESS);
expect(addSuccessToast).toHaveBeenNthCalledWith(
1,
'Chart [New chart] has been overwritten',
);

fetchMock.get(fetchDashboardsEndpoint, mockDashboardData, {
overwriteRoutes: true,
});
expect(addSuccessToast).toHaveBeenNthCalledWith(
2,
'Chart [New chart] was added to dashboard [New dashboard]',
);

return Promise.resolve();
});
expect(slice).toEqual(sliceResponsePayload);
});

0 comments on commit faa7bf4

Please sign in to comment.