Skip to content

Commit

Permalink
Merge pull request #676 from hms-dbmi-cellenics/sample-create-delete-v2
Browse files Browse the repository at this point in the history
Sample create delete api v2
  • Loading branch information
cosa65 authored Apr 12, 2022
2 parents cc277f6 + 9e32f8e commit 8368ddd
Show file tree
Hide file tree
Showing 18 changed files with 347 additions and 130 deletions.
8 changes: 4 additions & 4 deletions src/__test__/redux/actions/projects/deleteProject.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import deleteProject from 'redux/actions/projects/deleteProject';
import initialSampleState, { sampleTemplate } from 'redux/reducers/samples/initialState';
import initialProjectState, { projectTemplate } from 'redux/reducers/projects/initialState';

import { SAMPLES_DELETE } from 'redux/actionTypes/samples';
import { SAMPLES_DELETE_API_V1 } from 'redux/actionTypes/samples';
import {
PROJECTS_DELETE, PROJECTS_SAVED, PROJECTS_SAVING, PROJECTS_SET_ACTIVE,
} from 'redux/actionTypes/projects';
Expand Down Expand Up @@ -105,7 +105,7 @@ describe('deleteProject action', () => {
expect(actions[1].type).toEqual(EXPERIMENTS_DELETED);

// Delete sample
expect(actions[2].type).toEqual(SAMPLES_DELETE);
expect(actions[2].type).toEqual(SAMPLES_DELETE_API_V1);

// Delete project
expect(actions[3].type).toEqual(PROJECTS_DELETE);
Expand All @@ -126,7 +126,7 @@ describe('deleteProject action', () => {
expect(actions[1].type).toEqual(EXPERIMENTS_DELETED);

// Delete sample
expect(actions[2].type).toEqual(SAMPLES_DELETE);
expect(actions[2].type).toEqual(SAMPLES_DELETE_API_V1);

// Delete project
expect(actions[3].type).toEqual(PROJECTS_DELETE);
Expand All @@ -150,7 +150,7 @@ describe('deleteProject action', () => {
expect(actions[2].type).toEqual(EXPERIMENTS_DELETED);

// Delete sample
expect(actions[3].type).toEqual(SAMPLES_DELETE);
expect(actions[3].type).toEqual(SAMPLES_DELETE_API_V1);

// Delete project
expect(actions[4].type).toEqual(PROJECTS_DELETE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,14 @@ Object {
"metadata": Object {},
"name": "test sample",
"projectUuid": "qwe234",
"type": "10x Chromium",
"type": "10X Chromium",
"uuid": "abc123",
}
`;

exports[`createSample action Works correctly for api v2 1`] = `
Object {
"name": "test sample",
"sampleTechnology": "10x",
}
`;
32 changes: 31 additions & 1 deletion src/__test__/redux/actions/samples/createSample.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ import { SAMPLES_CREATE, SAMPLES_SAVING, SAMPLES_ERROR } from 'redux/actionTypes

import pushNotificationMessage from 'utils/pushNotificationMessage';

import config from 'config';
import { api } from 'utils/constants';

jest.mock('config');

pushNotificationMessage.mockImplementation(() => async () => { });

enableFetchMocks();
Expand All @@ -29,7 +34,7 @@ describe('createSample action', () => {
const projectUuid = 'qwe234';
const experimentId = 'exp234';

const mockType = '10x Chromium';
const mockType = '10X Chromium';

const mockProject = {
...projectTemplate,
Expand Down Expand Up @@ -118,4 +123,29 @@ describe('createSample action', () => {
// It should not return a uuid
expect(newUuid).toBeUndefined();
});

it('Works correctly for api v2', async () => {
config.currentApiVersion = api.V2;
fetchMock.mockResponse(JSON.stringify({}), { url: 'mockedUrl', status: 200 });

const newUuid = await store.dispatch(createSample(projectUuid, sampleName, mockType));

// Fetch call is made
const fetchMockFirstCall = fetchMock.mock.calls[0];

const { body: fetchBody, method: fetchMethod } = fetchMockFirstCall[1];
expect(fetchMockFirstCall[0]).toEqual(`http://localhost:3000/v2/experiments/${mockProject.experiments[0]}/samples/${sampleUuid}`);

expect(fetchMethod).toEqual('POST');
expect(JSON.parse(fetchBody)).toMatchSnapshot();

// Sends correct actions
const actions = store.getActions();

expect(actions[0].type).toEqual(SAMPLES_SAVING);
expect(actions[1].type).toEqual(SAMPLES_CREATE);

// Returns a new sampleUuid
expect(newUuid).toEqual(sampleUuid);
});
});
78 changes: 0 additions & 78 deletions src/__test__/redux/actions/samples/deleteSample.test.js

This file was deleted.

163 changes: 163 additions & 0 deletions src/__test__/redux/actions/samples/deleteSamples.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import configureStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import fetchMock, { enableFetchMocks } from 'jest-fetch-mock';

import deleteSamples from 'redux/actions/samples/deleteSamples';
import initialSampleState, { sampleTemplate } from 'redux/reducers/samples/initialState';
import initialProjectState, { projectTemplate } from 'redux/reducers/projects/initialState';

import { saveProject } from 'redux/actions/projects';

import {
SAMPLES_DELETE_API_V2, SAMPLES_DELETE_API_V1, SAMPLES_SAVED, SAMPLES_SAVING, SAMPLES_ERROR,
} from 'redux/actionTypes/samples';
import { PROJECTS_UPDATE } from 'redux/actionTypes/projects';
import { EXPERIMENTS_SAVING } from 'redux/actionTypes/experiments';

import config from 'config';
import { api } from 'utils/constants';

jest.mock('config');

enableFetchMocks();

jest.mock('redux/actions/projects/saveProject');
saveProject.mockImplementation(() => async () => { });

const mockStore = configureStore([thunk]);

const mockSampleUuid = 'sample-1';
const mockProjectUuid = 'project-1';
const mockExperimentId = 'experimentId';

const mockSample = {
...sampleTemplate,
name: 'test sample',
projectUuid: mockProjectUuid,
uuid: mockSampleUuid,
};

const mockProject = {
...projectTemplate,
name: 'test project',
uuid: mockProjectUuid,
samples: [mockSampleUuid],
experiments: [mockExperimentId],
};

const initialState = {
samples: {
...initialSampleState,
[mockSampleUuid]: mockSample,
},
projects: {
...initialProjectState,
ids: [mockProjectUuid],
[mockProjectUuid]: mockProject,
},
};

describe('deleteSamples', () => {
beforeEach(() => {
jest.clearAllMocks();

fetchMock.resetMocks();
fetchMock.doMock();
fetchMock.mockResolvedValue(new Response(JSON.stringify({})));
});

it('Dispatches event correctly', async () => {
const store = mockStore(initialState);
await store.dispatch(deleteSamples([mockSampleUuid]));

// Sets up loading state for saving project
const actions = store.getActions();

expect(saveProject).toHaveBeenCalled();

expect(actions[0].type).toEqual(SAMPLES_SAVING);

// Update project
expect(actions[1].type).toEqual(PROJECTS_UPDATE);

// Delete sample
expect(actions[2].type).toEqual(SAMPLES_DELETE_API_V1);

// Experiments being saved
expect(actions[3].type).toEqual(EXPERIMENTS_SAVING);

// Resolve loading state
expect(actions[4].type).toEqual(SAMPLES_SAVED);

expect(fetchMock).toHaveBeenCalledWith(
'http://localhost:3000/v1/projects/project-1/experimentId/samples',
{
body: '{"ids":["sample-1"]}',
headers: {
'Content-Type': 'application/json',
},
method: 'DELETE',
},
);

expect(fetchMock).toHaveBeenCalledWith(
'http://localhost:3000/v1/experiments/experimentId',
{
body: '{"sampleIds":[]}',
headers: {
'Content-Type': 'application/json',
},
method: 'PUT',
},
);
});

it('Dispatches event correctly for api v2', async () => {
config.currentApiVersion = api.V2;

const store = mockStore(initialState);
await store.dispatch(deleteSamples([mockSampleUuid]));

const actions = store.getActions();

expect(actions[0].type).toEqual(SAMPLES_SAVING);

// Delete sample
expect(actions[1].type).toEqual(SAMPLES_DELETE_API_V2);

// Resolve loading state
expect(actions[2].type).toEqual(SAMPLES_SAVED);

expect(fetchMock).toHaveBeenCalledWith(
`http://localhost:3000/v2/experiments/${mockExperimentId}/samples/sample-1`,
{
headers: { 'Content-Type': 'application/json' },
method: 'DELETE',
},
);
});

it('Dispatches error correctly for api v2 if fetch fails', async () => {
config.currentApiVersion = api.V2;

fetchMock.mockReject(new Error('Api error'));

const store = mockStore(initialState);
await store.dispatch(deleteSamples([mockSampleUuid]));

const actions = store.getActions();

expect(actions[0].type).toEqual(SAMPLES_SAVING);

// Delete sample
expect(actions[1].type).toEqual(SAMPLES_ERROR);

expect(fetchMock).toHaveBeenCalledWith(
`http://localhost:3000/v2/experiments/${mockExperimentId}/samples/sample-1`,
{
headers: { 'Content-Type': 'application/json' },
method: 'DELETE',
},
);
});
});
4 changes: 2 additions & 2 deletions src/__test__/redux/reducers/samplesReducer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
SAMPLES_FILE_UPDATE,
SAMPLES_LOADED,
SAMPLES_ERROR,
SAMPLES_DELETE,
SAMPLES_DELETE_API_V2,
SAMPLES_SAVING,
SAMPLES_SAVED,
SAMPLES_METADATA_DELETE,
Expand Down Expand Up @@ -117,7 +117,7 @@ describe('samplesReducer', () => {

it('Delete samples correctly', () => {
const newState = samplesReducer(twoSamplesState, {
type: SAMPLES_DELETE,
type: SAMPLES_DELETE_API_V2,
payload: {
sampleUuids: [sample2.uuid],
},
Expand Down
10 changes: 8 additions & 2 deletions src/redux/actionTypes/samples.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ const SAMPLES_UPDATE = `${SAMPLES}/update`;
/**
* Delete sample.
*/
const SAMPLES_DELETE = `${SAMPLES}/delete`;
const SAMPLES_DELETE_API_V2 = `${SAMPLES}/deleteApiV2`;

/**
* Delete sample following apiv1 version, remove when doing the final step of cleaning up v1 code.
*/
const SAMPLES_DELETE_API_V1 = `${SAMPLES}/deleteApiV1`;

/**
* Update files in sample.
Expand Down Expand Up @@ -49,7 +54,8 @@ const SAMPLES_LOADING = `${SAMPLES}/loading`;
export {
SAMPLES_CREATE,
SAMPLES_UPDATE,
SAMPLES_DELETE,
SAMPLES_DELETE_API_V2,
SAMPLES_DELETE_API_V1,
SAMPLES_FILE_UPDATE,
SAMPLES_LOADED,
SAMPLES_SAVING,
Expand Down
Loading

0 comments on commit 8368ddd

Please sign in to comment.