diff --git a/src/__test__/components/ContentWrapper.test.jsx b/src/__test__/components/ContentWrapper.test.jsx index 38e4650e9b..08671a2d6d 100644 --- a/src/__test__/components/ContentWrapper.test.jsx +++ b/src/__test__/components/ContentWrapper.test.jsx @@ -14,7 +14,9 @@ import AppRouteProvider from 'utils/AppRouteProvider'; import { makeStore } from 'redux/store'; import { getBackendStatus } from 'redux/selectors'; -import { loadProjects, setActiveProject } from 'redux/actions/projects'; + +import { loadExperiments, setActiveExperiment } from 'redux/actions/experiments'; + import { updateExperimentInfo } from 'redux/actions/experimentSettings'; import generateGem2sParamsHash from 'utils/data-management/generateGem2sParamsHash'; @@ -117,8 +119,8 @@ describe('ContentWrapper', () => { status: null, })); - await store.dispatch(loadProjects()); - await store.dispatch(setActiveProject(experimentId)); + await store.dispatch(loadExperiments()); + await store.dispatch(setActiveExperiment(experimentId)); await store.dispatch(updateExperimentInfo({ experimentId, experimentName, sampleIds })); }); diff --git a/src/__test__/components/NotifyByEmail.test.jsx b/src/__test__/components/NotifyByEmail.test.jsx index bff207db13..e5345fd5a7 100644 --- a/src/__test__/components/NotifyByEmail.test.jsx +++ b/src/__test__/components/NotifyByEmail.test.jsx @@ -8,12 +8,9 @@ import { act } from 'react-dom/test-utils'; import { Provider } from 'react-redux'; import userEvent from '@testing-library/user-event'; import * as updateExperiment from 'redux/actions/experiments/updateExperiment'; -import * as loadProjects from 'redux/actions/projects/loadProjects'; import * as loadExperiments from 'redux/actions/experiments/loadExperiments'; import fetchMock, { enableFetchMocks } from 'jest-fetch-mock'; -import mockAPI, { - generateDefaultMockAPIResponses, -} from '__test__/test-utils/mockAPI'; + import { makeStore } from 'redux/store'; import fake from '__test__/test-utils/constants'; @@ -23,19 +20,18 @@ const experimentId = fake.EXPERIMENT_ID; describe('Notify by email component', () => { let updateExperimentSpy; - let loadProjectsSpy; let loadExperimentsSpy; beforeEach(() => { jest.clearAllMocks(); updateExperimentSpy = jest.spyOn(updateExperiment, 'default'); - loadProjectsSpy = jest.spyOn(loadProjects, 'default'); loadExperimentsSpy = jest.spyOn(loadExperiments, 'default'); enableFetchMocks(); fetchMock.resetMocks(); fetchMock.doMock(); storeState = makeStore(); }); + const renderNotifyByEmail = async () => { await act(async () => (render( @@ -45,11 +41,6 @@ describe('Notify by email component', () => { , ))); }; - it('loads experiments if there is an activeProjectUuid', async () => { - fetchMock.mockIf(/.*/, mockAPI(generateDefaultMockAPIResponses(experimentId, fake.PROJECT_ID))); - await renderNotifyByEmail(); - expect(loadExperimentsSpy).toHaveBeenCalledTimes(1); - }); it('Renders Correctly', async () => { await renderNotifyByEmail(); @@ -67,8 +58,8 @@ describe('Notify by email component', () => { expect(updateExperimentSpy).toHaveBeenCalledTimes(2); }); - it('loads projects if non-existent', async () => { + it('loads experiments if non-existent', async () => { await renderNotifyByEmail(); - expect(loadProjectsSpy).toHaveBeenCalledTimes(1); + expect(loadExperimentsSpy).toHaveBeenCalledTimes(1); }); }); diff --git a/src/__test__/components/data-exploration/heatmap/HeatmapMetadataTrackSettings.test.jsx b/src/__test__/components/data-exploration/heatmap/HeatmapMetadataTrackSettings.test.jsx index ede79f0366..37940c822e 100644 --- a/src/__test__/components/data-exploration/heatmap/HeatmapMetadataTrackSettings.test.jsx +++ b/src/__test__/components/data-exploration/heatmap/HeatmapMetadataTrackSettings.test.jsx @@ -30,7 +30,7 @@ const loadAndRenderDefault = async () => { fetchMock.resetMocks(); fetchMock.doMock(); - fetchMock.mockIf(/.*/, mockAPI(generateDefaultMockAPIResponses(fake.EXPERIMENT_ID, fake.PROJECT_ID))); + fetchMock.mockIf(/.*/, mockAPI(generateDefaultMockAPIResponses(fake.EXPERIMENT_ID))); storeState = makeStore(); diff --git a/src/__test__/components/data-exploration/heatmap/HeatmapPlot.test.jsx b/src/__test__/components/data-exploration/heatmap/HeatmapPlot.test.jsx index 9c68d2095d..9c1d9778f9 100644 --- a/src/__test__/components/data-exploration/heatmap/HeatmapPlot.test.jsx +++ b/src/__test__/components/data-exploration/heatmap/HeatmapPlot.test.jsx @@ -85,7 +85,7 @@ const loadAndRenderDefaultHeatmap = async (storeState) => { }); }; -const mockAPIResponses = generateDefaultMockAPIResponses(experimentId, fake.PROJECT_ID); +const mockAPIResponses = generateDefaultMockAPIResponses(experimentId); const errorResponse = () => Promise.reject(new Error('Some error idk')); diff --git a/src/__test__/components/data-management/DownloadDataButton.test.jsx b/src/__test__/components/data-management/DownloadDataButton.test.jsx index c10124e45c..cb5c42f045 100644 --- a/src/__test__/components/data-management/DownloadDataButton.test.jsx +++ b/src/__test__/components/data-management/DownloadDataButton.test.jsx @@ -13,7 +13,6 @@ import DownloadDataButton from 'components/data-management/DownloadDataButton'; import pushNotificationMessage from 'utils/pushNotificationMessage'; import downloadFromUrl from 'utils/data-management/downloadFromUrl'; -import initialProjectState, { projectTemplate } from 'redux/reducers/projects/initialState'; import initialSamplesState from 'redux/reducers/samples/initialState'; import initialExperimentsState from 'redux/reducers/experiments/initialState'; import initialExperimentSettingsState from 'redux/reducers/experimentSettings/initialState'; @@ -28,32 +27,23 @@ jest.mock('utils/http/fetchAPI'); jest.mock('utils/data-management/downloadFromUrl'); const mockStore = configureMockStore([thunk]); -const projectName = 'Project 1'; -const projectUuid = 'project-1-uuid'; -const projectDescription = 'Some description'; +const experimentName = 'Experiment 1'; +const experimentDescription = 'Some description'; const experimentId = 'my-experiment-🧬'; const sample1Uuid = 'sample-1'; const sample2Uuid = 'sample-2'; const noDataState = { - projects: { - ...initialProjectState, - meta: { - ...initialProjectState.meta, - activeProjectUuid: projectUuid, - loading: false, - }, - ids: [projectUuid], - [projectUuid]: { - ...projectTemplate, - uuid: projectUuid, - name: projectName, - description: projectDescription, - }, - }, experiments: { ...initialExperimentsState, + name: experimentName, + description: experimentDescription, ids: ['experiment-1'], + meta: { + ...initialExperimentsState.meta, + activeExperimentId: experimentId, + loading: false, + }, }, experimentSettings: { ...initialExperimentSettingsState, @@ -65,13 +55,12 @@ const noDataState = { const withDataState = { ...noDataState, - projects: { - ...noDataState.projects, - [projectUuid]: { - ...noDataState.projects[projectUuid], - samples: [sample1Uuid, sample2Uuid], + experiments: { + ...noDataState.experiments, + [experimentId]: { + ...noDataState.experiments[experimentId], + sampleIds: [sample1Uuid, sample2Uuid], metadataKeys: ['metadata-1'], - experiments: [experimentId], }, }, experimentSettings: { @@ -97,7 +86,7 @@ describe('DownloadDataButton', () => { await act(async () => { render( - + , ); }); diff --git a/src/__test__/components/data-management/LaunchAnalysisButton.test.jsx b/src/__test__/components/data-management/LaunchAnalysisButton.test.jsx index 6e0c46b781..b62f0bbb96 100644 --- a/src/__test__/components/data-management/LaunchAnalysisButton.test.jsx +++ b/src/__test__/components/data-management/LaunchAnalysisButton.test.jsx @@ -12,9 +12,8 @@ import { runGem2s } from 'redux/actions/pipeline'; import PipelineStatus from 'utils/pipelineStatusValues'; import LaunchAnalysisButton from 'components/data-management/LaunchAnalysisButton'; -import initialProjectState, { projectTemplate } from 'redux/reducers/projects/initialState'; -import initialSamplesState, { sampleTemplate } from 'redux/reducers/samples/initialState'; import initialExperimentsState, { experimentTemplate } from 'redux/reducers/experiments/initialState'; +import initialSamplesState, { sampleTemplate } from 'redux/reducers/samples/initialState'; import { initialExperimentBackendStatus } from 'redux/reducers/backendStatus/initialState'; import UploadStatus from 'utils/upload/UploadStatus'; @@ -37,37 +36,28 @@ jest.mock('utils/AppRouteProvider', () => ({ const mockStore = configureMockStore([thunk]); -const projectName = 'Project 1'; -const projectUuid = 'project-1-uuid'; -const projectDescription = 'Some description'; -const sample1Name = 'Sample 1'; +const experiment1id = 'experiment-1'; +const experimentName = 'Experiment 1'; +const experimentDescription = 'Some description'; const sample1Uuid = 'sample-1'; -const sample2Name = 'Sample 2'; +const sample1Name = 'Sample 1'; const sample2Uuid = 'sample-2'; -const experiment1id = 'experiment-1'; +const sample2Name = 'Sample 2'; const noDataState = { - projects: { - ...initialProjectState, + experiments: { + ...initialExperimentsState, meta: { - ...initialProjectState.meta, - activeProjectUuid: projectUuid, + ...initialExperimentsState, + activeExperimentId: experiment1id, loading: false, }, - ids: [projectUuid], - [projectUuid]: { - ...projectTemplate, - experiments: [experiment1id], - uuid: projectUuid, - name: projectName, - description: projectDescription, - }, - }, - experiments: { - ...initialExperimentsState, ids: [experiment1id], [experiment1id]: { ...experimentTemplate, + id: experiment1id, + name: experimentName, + description: experimentDescription, }, }, samples: { @@ -90,20 +80,13 @@ const noDataState = { const withDataState = { ...noDataState, - projects: { - ...noDataState.projects, - [projectUuid]: { - ...noDataState.projects[projectUuid], - samples: [sample1Uuid, sample2Uuid], - metadataKeys: ['metadata-1'], - }, - }, experiments: { ...noDataState.experiments, [experiment1id]: { ...experimentTemplate, ...noDataState.experiments[experiment1id], sampleIds: [sample1Uuid, sample2Uuid], + metadataKeys: ['metadata-1'], }, }, samples: { @@ -111,7 +94,7 @@ const withDataState = { [sample1Uuid]: { ...sampleTemplate, name: sample1Name, - projectUuid, + experimentId: experiment1id, uuid: sample1Uuid, type: '10X Chromium', metadata: ['value-1'], @@ -125,7 +108,7 @@ const withDataState = { [sample2Uuid]: { ...sampleTemplate, name: sample2Name, - projectUuid, + experimentId: experiment1id, uuid: sample2Uuid, type: '10X Chromium', metadata: ['value-2'], @@ -239,7 +222,7 @@ describe('LaunchAnalysisButton', () => { expect(button).not.toBeDisabled(); }); - it('Shows Go to Data Processing if there are no changes to the project (same hash)', async () => { + it('Shows Go to Data Processing if there are no changes to the experiment (same hash)', async () => { generateGem2sParamsHash.mockReturnValueOnce('old-params-hash'); await act(async () => { @@ -255,7 +238,7 @@ describe('LaunchAnalysisButton', () => { }); }); - it('Shows Process project if there are changes to the project (different hash)', async () => { + it('Shows Process project if there are changes to the experiment (different hash)', async () => { generateGem2sParamsHash.mockReturnValueOnce('new-params-hash'); await act(async () => { @@ -271,7 +254,7 @@ describe('LaunchAnalysisButton', () => { }); }); - it('Dispatches request for GEM2S if there are changes to the project', async () => { + it('Dispatches request for GEM2S if there are changes to the experiment', async () => { generateGem2sParamsHash.mockReturnValueOnce('new-params-hash'); await act(async () => { @@ -295,7 +278,7 @@ describe('LaunchAnalysisButton', () => { expect(runGem2s).toHaveBeenCalled(); }); - it('Does not dispatch request for GEM2S if there are no changes to the project', async () => { + it('Does not dispatch request for GEM2S if there are no changes to the experiment', async () => { generateGem2sParamsHash.mockReturnValueOnce('old-params-hash'); await act(async () => { diff --git a/src/__test__/components/data-management/NewProjectModal.test.jsx b/src/__test__/components/data-management/NewProjectModal.test.jsx index 2b752090a8..ccdf06a98b 100644 --- a/src/__test__/components/data-management/NewProjectModal.test.jsx +++ b/src/__test__/components/data-management/NewProjectModal.test.jsx @@ -9,25 +9,18 @@ import { ClipLoader } from 'react-spinners'; import NewProjectModal from 'components/data-management/NewProjectModal'; import '__test__/test-utils/setupTests'; +import experimentsInitialState from 'redux/reducers/experiments/initialState'; + const { TextArea } = Input; const { Text } = Typography; const mockStore = configureMockStore([thunk]); -const initialState = { - projects: { - ids: [], - meta: { - loading: true, - saving: false, - error: false, - }, - }, -}; +const initialState = { experiments: experimentsInitialState }; -const storeWithProjects = { - projects: { +const storeWithExperiments = { + experiments: { ids: ['123'], meta: { loading: true, @@ -35,7 +28,7 @@ const storeWithProjects = { error: false, }, 123: { - name: 'my awesome project', + name: 'my awesome experiment', }, }, }; @@ -66,7 +59,7 @@ describe('NewProjectModal', () => { // It has an input expect(component.find(Input).length).toEqual(1); - // It has a project description input + // It has a experiment description input expect(component.find(TextArea).length).toEqual(1); // It has a button @@ -75,7 +68,7 @@ describe('NewProjectModal', () => { it('contains required components for later flows', () => { const component = mount( - + , ); @@ -86,24 +79,24 @@ describe('NewProjectModal', () => { // It has an input expect(component.find(Input).length).toEqual(1); - // It has a project description input + // It has a experiment description input expect(component.find(TextArea).length).toEqual(1); // It has a button expect(component.find(Button).length).toEqual(1); }); - it('disables input and shows loading when project is being saved', () => { + it('disables input and shows loading when experiment is being saved', () => { const savingState = { ...initialState, - projects: { + experiments: { meta: { - ...initialState.projects.meta, + ...initialState.experiments.meta, saving: true, }, ids: ['123'], 123: { - name: 'my awesome project', + name: 'my awesome experiment', }, }, }; @@ -124,19 +117,19 @@ describe('NewProjectModal', () => { expect(component.find(ClipLoader).length).toEqual(1); }); - it('disables input and shows error if project has errors', () => { + it('disables input and shows error if experiment has errors', () => { const errMsg = 'Error message'; const errorState = { ...initialState, - projects: { + experiments: { meta: { - ...initialState.projects.meta, + ...initialState.experiments.meta, error: errMsg, }, ids: ['123'], 123: { - name: 'my awesome project', + name: 'my awesome experiment', }, }, }; diff --git a/src/__test__/components/data-management/ProjectCard.test.jsx b/src/__test__/components/data-management/ProjectCard.test.jsx index cbf82c3a2d..eee9d0136d 100644 --- a/src/__test__/components/data-management/ProjectCard.test.jsx +++ b/src/__test__/components/data-management/ProjectCard.test.jsx @@ -11,28 +11,25 @@ import configureMockStore from 'redux-mock-store'; import { Provider } from 'react-redux'; import thunk from 'redux-thunk'; -import initialState, { projectTemplate } from 'redux/reducers/projects/initialState'; +import initialState, { experimentTemplate } from 'redux/reducers/experiments/initialState'; import ProjectCard from 'components/data-management/ProjectCard'; -const projectUuid = '12345'; -const projectName = 'Test Project'; const experimentId = 'experimentId1'; +const experimentName = 'Test Experiment'; const samplesIdsArray = new Array(13).fill(null).map((_, i) => (`sample-${i}`)); -const createdDate = moment().subtract(30, 'days').format(); -const lastModified = moment().subtract(30, 'minutes').format(); +const createdAt = moment().subtract(30, 'days').format(); +const updatedAt = moment().subtract(30, 'minutes').format(); -const projectState = { - projects: { +const experimentState = { + experiments: { ...initialState, - experiments: [], - [projectUuid]: { - ...projectTemplate, - experiments: [experimentId], - name: projectName, - uuid: projectUuid, - samples: samplesIdsArray, - createdDate, - lastModified, + [experimentId]: { + ...experimentTemplate, + id: experimentId, + name: experimentName, + sampleIds: samplesIdsArray, + createdAt, + updatedAt, }, }, }; @@ -51,28 +48,28 @@ describe('ProjectCard', () => { it('Displays correctly', () => { render( - - + + , ); - // Project name is shown - expect(screen.getByText(new RegExp(projectName, 'i'))).toBeInTheDocument(); + // Experiment name is shown + expect(screen.getByText(new RegExp(experimentName, 'i'))).toBeInTheDocument(); // Number of samples is shown expect(screen.getByText(samplesIdsArray.length)).toBeInTheDocument(); // Created date is shown - expect(screen.getByText(moment(createdDate).fromNow())).toBeInTheDocument(); + expect(screen.getByText(moment(createdAt).fromNow())).toBeInTheDocument(); // Last modified is shown - expect(screen.getByText(moment(lastModified).fromNow())).toBeInTheDocument(); + expect(screen.getByText(moment(updatedAt).fromNow())).toBeInTheDocument(); }); - it('Displays the delete project modal when delete project is clicked', async () => { + it('Displays the delete project modal when delete experiment is clicked', async () => { render( - - + + , ); @@ -86,8 +83,8 @@ describe('ProjectCard', () => { it('Updates project name when clicked', async () => { render( - - + + , ); @@ -98,7 +95,7 @@ describe('ProjectCard', () => { // Write the new name userEvent.clear(screen.getByTestId('editableFieldInput')); - userEvent.type(screen.getByTestId('editableFieldInput'), 'new project name'); + userEvent.type(screen.getByTestId('editableFieldInput'), 'new experiment name'); // Click save changes button userEvent.click(screen.getByRole('button', { name: 'Save' })); @@ -108,7 +105,7 @@ describe('ProjectCard', () => { expect(fetchMock).toHaveBeenCalledWith( `http://localhost:3000/v2/experiments/${experimentId}`, { - body: JSON.stringify({ name: 'new project name' }), + body: JSON.stringify({ name: 'new experiment name' }), headers: { 'Content-Type': 'application/json' }, method: 'PATCH', }, diff --git a/src/__test__/components/data-management/ProjectDeleteModal.test.jsx b/src/__test__/components/data-management/ProjectDeleteModal.test.jsx index 79272a1581..a65ed0e3a8 100644 --- a/src/__test__/components/data-management/ProjectDeleteModal.test.jsx +++ b/src/__test__/components/data-management/ProjectDeleteModal.test.jsx @@ -6,21 +6,21 @@ import { screen, render, fireEvent, waitFor, } from '@testing-library/react'; import configureMockStore from 'redux-mock-store'; -import initialProjectState from 'redux/reducers/projects/initialState'; +import initialExperimentState from 'redux/reducers/experiments/initialState'; import ProjectDeleteModal from 'components/data-management/ProjectDeleteModal'; const mockStore = configureMockStore([thunk]); -const projectName = 'super cool project'; -const projectId = 'iamid'; +const experimentName = 'super cool experiment'; +const experimentId = 'iamid'; const state = { - projects: { - ...initialProjectState, - ids: [projectId], - [projectId]: { - name: projectName, + experiments: { + ...initialExperimentState, + ids: [experimentId], + [experimentId]: { + name: experimentName, }, meta: { - ...initialProjectState.meta, + ...initialExperimentState.meta, loading: false, }, }, @@ -37,7 +37,7 @@ describe('Delete Project Modal tests', () => { render( @@ -59,14 +59,14 @@ describe('Delete Project Modal tests', () => { it('ok button is not disabled if project name is typed in', () => { renderProjectDeleteModal(); const nameField = screen.getByRole('textbox'); - fireEvent.change(nameField, { target: { value: projectName } }); + fireEvent.change(nameField, { target: { value: experimentName } }); expect(screen.getByText('Permanently delete project').parentElement).not.toBeDisabled(); }); it('Calls delete on deletion', async () => { renderProjectDeleteModal(); const nameField = screen.getByRole('textbox'); - fireEvent.change(nameField, { target: { value: projectName } }); + fireEvent.change(nameField, { target: { value: experimentName } }); fireEvent.click(screen.getByText('Permanently delete project').parentElement); await waitFor(() => expect(deleteProjectSpy).toHaveBeenCalled()); }); diff --git a/src/__test__/components/data-management/ProjectDetails.test.jsx b/src/__test__/components/data-management/ProjectDetails.test.jsx index ef7099437e..e431fa44be 100644 --- a/src/__test__/components/data-management/ProjectDetails.test.jsx +++ b/src/__test__/components/data-management/ProjectDetails.test.jsx @@ -13,8 +13,7 @@ import { fireEvent } from '@testing-library/dom'; import userEvent from '@testing-library/user-event'; import { screen, render, waitFor } from '@testing-library/react'; -import * as createMetadataTrack from 'redux/actions/projects/createMetadataTrack'; -import initialProjectState, { projectTemplate } from 'redux/reducers/projects/initialState'; +import * as createMetadataTrack from 'redux/actions/experiments/createMetadataTrack'; import initialSamplesState, { sampleTemplate } from 'redux/reducers/samples/initialState'; import initialExperimentsState from 'redux/reducers/experiments/initialState'; import initialExperimentSettingsState from 'redux/reducers/experimentSettings/initialState'; @@ -36,38 +35,31 @@ jest.mock('utils/AppRouteProvider', () => ({ const mockStore = configureStore([thunk]); const width = 600; const height = 400; -const projectName = 'Project 1'; -const projectUuid = 'project-1-uuid'; -const projectDescription = 'Some description'; +const experiment1id = 'experiment-1'; +const experimentName = 'Experiment 1'; +const experimentDescription = 'Some description'; const sample1Name = 'Sample 1'; const sample1Uuid = 'sample-1'; const sample2Name = 'Sample 2'; const sample2Uuid = 'sample-2'; -const experiment1id = 'experiment-1'; const noDataState = { - backendStatus: { - 'experiment-1': initialExperimentBackendStatus, - }, - projects: { - ...initialProjectState, - meta: { - ...initialProjectState.meta, - activeProjectUuid: projectUuid, - loading: false, - }, - ids: [projectUuid], - [projectUuid]: { - ...projectTemplate, - experiments: [experiment1id], - uuid: projectUuid, - name: projectName, - description: projectDescription, - }, - }, experiments: { ...initialExperimentsState, ids: [experiment1id], + meta: { + activeExperimentId: experiment1id, + }, + [experiment1id]: { + id: experiment1id, + name: experimentName, + description: experimentDescription, + notifyByEmail: true, + createdAt: '2022-06-29 17:06:10.683568+00', + updatedAt: '2022-06-29 17:06:10.683568+00', + metadataKeys: [], + sampleIds: [], + }, }, experimentSettings: { ...initialExperimentSettingsState, @@ -76,6 +68,7 @@ const noDataState = { ...initialSamplesState, }, backendStatus: { + 'experiment-1': initialExperimentBackendStatus, [experiment1id]: { ...initialExperimentBackendStatus, status: { @@ -92,11 +85,11 @@ const noDataState = { const withDataState = { ...noDataState, - projects: { - ...noDataState.projects, - [projectUuid]: { - ...noDataState.projects[projectUuid], - samples: [sample1Uuid, sample2Uuid], + experiments: { + ...noDataState.experiments, + [experiment1id]: { + ...noDataState.experiments[experiment1id], + sampleIds: [sample1Uuid, sample2Uuid], metadataKeys: ['metadata-1'], }, }, @@ -105,7 +98,7 @@ const withDataState = { [sample1Uuid]: { ...sampleTemplate, name: sample1Name, - projectUuid, + experimentId: experiment1id, uuid: sample1Uuid, type: '10X Chromium', metadata: ['value-1'], @@ -120,7 +113,7 @@ const withDataState = { [sample2Uuid]: { ...sampleTemplate, name: sample2Name, - projectUuid, + experimentId: experiment1id, uuid: sample2Uuid, type: '10X Chromium', metadata: ['value-2'], @@ -154,6 +147,7 @@ describe('ProjectDetails', () => { jest.clearAllMocks(); metadataCreated = jest.spyOn(createMetadataTrack, 'default'); }); + it('Has a title, project ID and description', () => { render( @@ -162,13 +156,13 @@ describe('ProjectDetails', () => { ); // Project name - expect(screen.getByText(projectName)).toBeDefined(); + expect(screen.getByText(experimentName)).toBeDefined(); // Project uuid - expect(screen.queryByText(projectUuid)).toBeDefined(); + expect(screen.queryByText(experiment1id)).toBeDefined(); // Description - expect(screen.queryByText(projectDescription)).toBeDefined(); + expect(screen.queryByText(experimentDescription)).toBeDefined(); }); it('Has 4 buttons', () => { @@ -260,6 +254,7 @@ describe('ProjectDetails', () => { const field = screen.getByRole('textbox'); userEvent.type(field, 'somenewMeta'); fireEvent.keyDown(field, { key: 'Escape', code: 'Escape' }); - expect(store.getState().projects[projectUuid].metadataKeys).toEqual(['metadata-1']); + + expect(store.getState().experiments[experiment1id].metadataKeys).toEqual(['metadata-1']); }); }); diff --git a/src/__test__/components/data-management/ProjectMenu.test.jsx b/src/__test__/components/data-management/ProjectMenu.test.jsx index 2db1179365..3781a10322 100644 --- a/src/__test__/components/data-management/ProjectMenu.test.jsx +++ b/src/__test__/components/data-management/ProjectMenu.test.jsx @@ -9,17 +9,17 @@ import _ from 'lodash'; import '@testing-library/jest-dom'; import '__test__/test-utils/mockWorkerBackend'; +import fetchMock, { enableFetchMocks } from 'jest-fetch-mock'; + import { makeStore } from 'redux/store'; import fake from '__test__/test-utils/constants'; -import fetchMock, { enableFetchMocks } from 'jest-fetch-mock'; - +import { experiments } from '__test__/test-utils/mockData'; import createTestComponentFactory from '__test__/test-utils/testComponentFactory'; import mockAPI, { generateDefaultMockAPIResponses } from '__test__/test-utils/mockAPI'; -import { loadProjects, setActiveProject } from 'redux/actions/projects'; -import { experiments } from '__test__/test-utils/mockData'; import ProjectMenu from 'components/data-management/ProjectMenu'; +import { loadExperiments, setActiveExperiment } from 'redux/actions/experiments'; const mockNavigateTo = jest.fn(); jest.mock('@aws-amplify/auth', () => ({ @@ -81,8 +81,8 @@ describe('ProjectMenu', () => { storeState = makeStore(); - await storeState.dispatch(loadProjects()); - await storeState.dispatch(setActiveProject(experimentWithoutSamplesId)); + await storeState.dispatch(loadExperiments()); + await storeState.dispatch(setActiveExperiment(experimentWithoutSamplesId)); }); it('Renders correctly when there is a project', async () => { diff --git a/src/__test__/components/data-management/ProjectsList.test.jsx b/src/__test__/components/data-management/ProjectsList.test.jsx index 93f918bf81..1c0762e1d8 100644 --- a/src/__test__/components/data-management/ProjectsList.test.jsx +++ b/src/__test__/components/data-management/ProjectsList.test.jsx @@ -4,84 +4,81 @@ import { Provider } from 'react-redux'; import configureMockStore from 'redux-mock-store'; import thunk from 'redux-thunk'; import '@testing-library/jest-dom'; -import initialState, { projectTemplate } from 'redux/reducers/projects/initialState'; +import initialState, { experimentTemplate } from 'redux/reducers/experiments/initialState'; import ProjectsList from 'components/data-management/ProjectsList'; import ProjectCard from 'components/data-management/ProjectCard'; import '__test__/test-utils/setupTests'; const mockStore = configureMockStore([thunk]); -const project1 = { - ...projectTemplate, - name: 'project 1', - uuid: '12345', - experiments: ['experiment-1'], - createdDate: '01-01-2021', - lastModified: '01-01-2021', +const experiment1 = { + ...experimentTemplate, + name: 'experiment 1', + id: '12345', + createdAt: '01-01-2021', + updatedAt: '01-01-2021', }; -const project2 = { - ...project1, - name: 'project 2', - uuid: '67890', - experiments: ['experiment-2'], +const experiment2 = { + ...experiment1, + name: 'experiment 2', + id: '67890', }; -const project3 = { - ...project1, +const experiment3 = { + ...experiment1, name: 'testing', - uuid: '45678', - experiments: ['experiment-3'], + id: '45678', }; const initialStore = mockStore({ - projects: { + experiments: { ...initialState, }, }); const emptyStore = mockStore({ - projects: { + experiments: { ...initialState, ids: [], meta: { - activeProjectUuid: null, + activeExperimentId: null, }, }, }); -const createMockStore = (projectNames) => { - const newProjects = projectNames.reduce((acc, name, idx) => { +const createMockStore = (experimentNames) => { + const newExperiments = experimentNames.reduce((acc, name, idx) => { acc[idx] = { - ...projectTemplate, + ...experimentTemplate, name, - uuid: idx, + id: idx, }; return acc; }, {}); return mockStore({ - projects: { + experiments: { ...initialState, - ids: Object.keys(newProjects), + ids: Object.keys(newExperiments), meta: { - activeProjectUuid: Object.keys(newProjects)[0], + activeExperimentId: Object.keys(newExperiments)[0], }, - ...newProjects, + ...newExperiments, }, }); }; const filledStore = mockStore({ - projects: { + experiments: { ...initialState, - ids: [project1.uuid, project2.uuid, project3.uuid], + ids: [experiment1.id, experiment2.id, experiment3.id], meta: { - activeProjectUuid: project1.uuid, + activeExperimentId: experiment1.id, }, - [project1.uuid]: project1, - [project2.uuid]: project2, - [project3.uuid]: project3, + [experiment1.id]: experiment1, + [experiment2.id]: experiment2, + [experiment3.id]: experiment3, }, }); @@ -96,8 +93,8 @@ describe('ProjectsList', () => { expect(component.exists()).toEqual(true); }); - it('has no project if there is no project', () => { - const projects = initialStore.getState().projects.ids; + it('has no experiment if there is no experiment', () => { + const experiments = initialStore.getState().experiments.ids; const component = mount( @@ -105,12 +102,12 @@ describe('ProjectsList', () => { , ); - // expect the number of projects to be the same as the one in the list - expect(component.find(ProjectCard).length).toEqual(projects.length); + // expect the number of experiments to be the same as the one in the list + expect(component.find(ProjectCard).length).toEqual(experiments.length); }); - it('contains components if there are projects', () => { - const projects = filledStore.getState().projects.ids; + it('contains components if there are experiments', () => { + const experiments = filledStore.getState().experiments.ids; const component = mount( @@ -118,12 +115,12 @@ describe('ProjectsList', () => { , ); - // expect the number of projects to be the same as the one in the list - expect(component.find(ProjectCard).length).toEqual(projects.length); + // expect the number of experiments to be the same as the one in the list + expect(component.find(ProjectCard).length).toEqual(experiments.length); }); - it('Shows all projects if not given a filter', () => { - const projects = filledStore.getState().projects.ids; + it('Shows all experiments if not given a filter', () => { + const experiments = filledStore.getState().experiments.ids; const component = mount( @@ -131,46 +128,46 @@ describe('ProjectsList', () => { , ); - // Expect all projects to be shown - expect(component.find(ProjectCard).length).toEqual(projects.length); + // Expect all experiments to be shown + expect(component.find(ProjectCard).length).toEqual(experiments.length); }); - it('Filters the correct project given a filter', () => { + it('Filters the correct experiment given a filter', () => { const testCases = [ - // Filter for one project + // Filter for one experiment { filterText: 'test', - projectNames: ['testing', 'new project', 'misc'], - matchingProjects: ['testing'], + experimentNames: ['testing', 'new experiment', 'misc'], + matchingExperiments: ['testing'], }, - // Filter for more than one project + // Filter for more than one experiment { filterText: 'test', - projectNames: ['testing', 'project1', 'testing2'], - matchingProjects: ['testing', 'testing2'], + experimentNames: ['testing', 'project1', 'testing2'], + matchingExperiments: ['testing', 'testing2'], }, - // Filter for projects with the same name + // Filter for experiments with the same name { filterText: 'test', - projectNames: ['testing', 'project1', 'testing', 'testing'], - matchingProjects: ['testing', 'testing', 'testing'], + experimentNames: ['testing', 'project1', 'testing', 'testing'], + matchingExperiments: ['testing', 'testing', 'testing'], }, // Check that filter works for names beginning, containing and ending the filter { filterText: 'test', - projectNames: ['testing-project', 'beta-testing', 'project', 'no-test'], - matchingProjects: ['testing-project', 'beta-testing', 'no-test'], + experimentNames: ['testing-project', 'beta-testing', 'project', 'no-test'], + matchingExperiments: ['testing-project', 'beta-testing', 'no-test'], }, // If no projects match, expect no projects to be shown { filterText: 'test', - projectNames: ['project1', 'project2', 'project3'], - matchingProjects: [], + experimentNames: ['experiment1', 'project2', 'project3'], + matchingExperiments: [], }, ]; @@ -178,45 +175,45 @@ describe('ProjectsList', () => { const filter = new RegExp(testCase.filterText, 'i'); const component = mount( - + , ); - const projects = component.find(ProjectCard); + const experiments = component.find(ProjectCard); - expect(projects.length).toEqual(testCase.matchingProjects.length); + expect(experiments.length).toEqual(testCase.matchingExperiments.length); - testCase.matchingProjects.forEach((projectName, idx) => { - expect(projects.at(idx).text()).toMatch(projectName); + testCase.matchingExperiments.forEach((experimentName, idx) => { + expect(experiments.at(idx).text()).toMatch(experimentName); }); }); }); - it('Filter should not break if there is no project and no filter', () => { + it('Filter should not break if there is no experiment and no filter', () => { const component = mount( , ); - // Expect there to be no project + // Expect there to be no experiment expect(component.find(ProjectCard).length).toEqual(0); }); - it('Filter should not break if there is no project and the filter is input', () => { + it('Filter should not break if there is no experiment and the filter is input', () => { const component = mount( , ); - // Expect there to be no project + // Expect there to be no experiment expect(component.find(ProjectCard).length).toEqual(0); }); - it('Filter should work when searching using projectUuid', () => { - const filterText = project3.uuid; + it('Filter should work when searching using experimentId', () => { + const filterText = experiment3.id; const filter = new RegExp(filterText, 'i'); const component = mount( @@ -225,15 +222,14 @@ describe('ProjectsList', () => { , ); - const filteredProjects = component.find(ProjectCard); + const filteredExperiments = component.find(ProjectCard); - expect(filteredProjects.length).toEqual(1); - expect(filteredProjects.text()).toMatch(project3.name); + expect(filteredExperiments.length).toEqual(1); + expect(filteredExperiments.text()).toMatch(experiment3.name); }); it('Filter should work when searching using experimentId', () => { - const filterText = project3.experiments[0]; - const filter = new RegExp(filterText, 'i'); + const filter = new RegExp(experiment3.id, 'i'); const component = mount( @@ -241,9 +237,9 @@ describe('ProjectsList', () => { , ); - const filteredProjects = component.find(ProjectCard); + const filteredExperiments = component.find(ProjectCard); - expect(filteredProjects.length).toEqual(1); - expect(filteredProjects.text()).toMatch(project3.name); + expect(filteredExperiments.length).toEqual(1); + expect(filteredExperiments.text()).toMatch(experiment3.name); }); }); diff --git a/src/__test__/components/data-management/SamplesTable.test.jsx b/src/__test__/components/data-management/SamplesTable.test.jsx index f9137d87e0..90d83dc85a 100644 --- a/src/__test__/components/data-management/SamplesTable.test.jsx +++ b/src/__test__/components/data-management/SamplesTable.test.jsx @@ -18,10 +18,8 @@ import configureMockStore from 'redux-mock-store'; import thunk from 'redux-thunk'; import createTestComponentFactory from '__test__/test-utils/testComponentFactory'; -import { loadProjects, setActiveProject } from 'redux/actions/projects'; - +import { loadExperiments, setActiveExperiment } from 'redux/actions/experiments'; import loadEnvironment from 'redux/actions/networkResources/loadEnvironment'; -import { loadExperiments } from 'redux/actions/experiments'; import { loadSamples } from 'redux/actions/samples'; import mockDemoExperiments from '__test__/test-utils/mockData/mockDemoExperiments.json'; @@ -98,15 +96,13 @@ describe('Samples table', () => { storeState = makeStore(); - await storeState.dispatch(loadProjects()); + await storeState.dispatch(loadExperiments()); // Loading experiment is usually called in Data Management, so we have to load them manually - await storeState.dispatch(loadExperiments(experimentWithSamplesId)); - await storeState.dispatch(loadExperiments(experimentWithoutSamplesId)); await storeState.dispatch(loadSamples(experimentWithSamplesId)); // Defaults to project with samples - await storeState.dispatch(setActiveProject(experimentWithSamplesId)); + await storeState.dispatch(setActiveExperiment(experimentWithSamplesId)); await storeState.dispatch(loadEnvironment('test')); }); @@ -240,7 +236,7 @@ describe('Samples table', () => { // Load project without samples await act(async () => { - await storeState.dispatch(setActiveProject(experimentWithoutSamplesId)); + await storeState.dispatch(setActiveExperiment(experimentWithoutSamplesId)); }); }); diff --git a/src/__test__/components/data-management/ShareExperimentModal.test.jsx b/src/__test__/components/data-management/ShareExperimentModal.test.jsx index b17ad48902..d7073c2f6a 100644 --- a/src/__test__/components/data-management/ShareExperimentModal.test.jsx +++ b/src/__test__/components/data-management/ShareExperimentModal.test.jsx @@ -49,10 +49,9 @@ describe('Share expeirment modal', () => { await act(async () => render( , )); @@ -61,7 +60,7 @@ describe('Share expeirment modal', () => { it('Renders correctly', async () => { await renderShareExperimentModal(); expect(screen.getByText('Share with collaborators')).toBeInTheDocument(); - expect(screen.getByText(fake.PROJECT_NAME)).toBeInTheDocument(); + expect(screen.getByText(fake.EXPERIMENT_NAME)).toBeInTheDocument(); expect(screen.getByText('Input an email address. Add multiple addresses with enter.')).toBeInTheDocument(); expect(screen.getAllByRole('combobox').length).toEqual(2); expect(screen.getByText('bob@bob.com')).toBeInTheDocument(); diff --git a/src/__test__/components/data-management/__snapshots__/ShareExperimentModal.test.jsx.snap b/src/__test__/components/data-management/__snapshots__/ShareExperimentModal.test.jsx.snap index e2468c41cb..ce6e5a3259 100644 --- a/src/__test__/components/data-management/__snapshots__/ShareExperimentModal.test.jsx.snap +++ b/src/__test__/components/data-management/__snapshots__/ShareExperimentModal.test.jsx.snap @@ -4,7 +4,7 @@ exports[`Share expeirment modal Inviting users works 1`] = ` Array [ "http://localhost:3000/v2/access/testae48e318dab9a1bd0bexperiment", Object { - "body": "{\\"projectUuid\\":\\"test24b6-8600-test-mock-63822d2fmock\\",\\"role\\":\\"explorer\\",\\"userEmail\\":\\"asd@asd.com\\"}", + "body": "{\\"projectUuid\\":\\"testae48e318dab9a1bd0bexperiment\\",\\"role\\":\\"explorer\\",\\"userEmail\\":\\"asd@asd.com\\"}", "headers": Object { "Content-Type": "application/json", }, diff --git a/src/__test__/components/plots/styling/heatmap/HeatmapControls.test.jsx b/src/__test__/components/plots/styling/heatmap/HeatmapControls.test.jsx index 2a17bb6214..f30ebb4b1f 100644 --- a/src/__test__/components/plots/styling/heatmap/HeatmapControls.test.jsx +++ b/src/__test__/components/plots/styling/heatmap/HeatmapControls.test.jsx @@ -11,7 +11,7 @@ describe('Heatmap Controls test', () => { const renderHeatmapControls = (selectedGenes) => { render(); diff --git a/src/__test__/pages/__snapshots__/_error.test.jsx.snap b/src/__test__/pages/__snapshots__/_error.test.jsx.snap index 6dba9960cf..aa4ec46aab 100644 --- a/src/__test__/pages/__snapshots__/_error.test.jsx.snap +++ b/src/__test__/pages/__snapshots__/_error.test.jsx.snap @@ -89,6 +89,7 @@ Array [ "experiments": Object { "ids": Array [], "meta": Object { + "activeExperimentId": null, "error": false, "loading": false, "saving": false, @@ -135,15 +136,6 @@ Array [ "networkResources": Object { "environment": "production", }, - "projects": Object { - "ids": Array [], - "meta": Object { - "activeProjectUuid": null, - "error": false, - "loading": true, - "saving": false, - }, - }, "samples": Object { "meta": Object { "error": false, @@ -244,6 +236,7 @@ Array [ "experiments": Object { "ids": Array [], "meta": Object { + "activeExperimentId": null, "error": false, "loading": false, "saving": false, @@ -290,15 +283,6 @@ Array [ "networkResources": Object { "environment": "staging", }, - "projects": Object { - "ids": Array [], - "meta": Object { - "activeProjectUuid": null, - "error": false, - "loading": true, - "saving": false, - }, - }, "samples": Object { "meta": Object { "error": false, diff --git a/src/__test__/pages/experiments/[experimentId]/data-management/index.test.jsx b/src/__test__/pages/experiments/[experimentId]/data-management/index.test.jsx index 3c480bed09..412dba3f34 100644 --- a/src/__test__/pages/experiments/[experimentId]/data-management/index.test.jsx +++ b/src/__test__/pages/experiments/[experimentId]/data-management/index.test.jsx @@ -16,13 +16,11 @@ import { samples, } from '__test__/test-utils/mockData'; -import downloadFromUrl from 'utils/data-management/downloadFromUrl'; - import DataManagementPage from 'pages/data-management'; import userEvent from '@testing-library/user-event'; +import { setActiveExperiment } from 'redux/actions/experiments'; import loadEnvironment from 'redux/actions/networkResources/loadEnvironment'; -import { setActiveProject } from 'redux/actions/projects'; jest.mock('utils/data-management/downloadFromUrl'); jest.mock('react-resize-detector', () => (props) => props.children({ width: 100, height: 100 })); @@ -138,7 +136,7 @@ describe('Data Management page', () => { // Select the project with samples await act(async () => { - storeState.dispatch(setActiveProject(experimentWithSamplesId)); + storeState.dispatch(setActiveExperiment(experimentWithSamplesId)); }); expect(screen.getAllByText(/Project Details/i).length).toBeGreaterThan(0); diff --git a/src/__test__/redux/actions/experiments/__snapshots__/createExperiment.test.js.snap b/src/__test__/redux/actions/experiments/__snapshots__/createExperiment.test.js.snap index 45f5b10a36..eda2fd4764 100644 --- a/src/__test__/redux/actions/experiments/__snapshots__/createExperiment.test.js.snap +++ b/src/__test__/redux/actions/experiments/__snapshots__/createExperiment.test.js.snap @@ -3,12 +3,12 @@ exports[`createExperiment Works correctly 1`] = ` Object { "experiment": Object { - "createdDate": "2020-01-01T00:00:00.000Z", - "description": undefined, + "createdAt": "2020-01-01T00:00:00.000Z", + "description": "description", "id": "b3f6c0ca86ec045c84f380cd5016972e", - "name": "project-1", + "name": "name", }, } `; -exports[`createExperiment Works correctly 2`] = `"{\\"id\\":\\"b3f6c0ca86ec045c84f380cd5016972e\\",\\"name\\":\\"project-1\\"}"`; +exports[`createExperiment Works correctly 2`] = `"{\\"id\\":\\"b3f6c0ca86ec045c84f380cd5016972e\\",\\"name\\":\\"name\\",\\"description\\":\\"description\\"}"`; diff --git a/src/__test__/redux/actions/projects/__snapshots__/createMetadataTrack.test.js.snap b/src/__test__/redux/actions/experiments/__snapshots__/createMetadataTrack.test.js.snap similarity index 89% rename from src/__test__/redux/actions/projects/__snapshots__/createMetadataTrack.test.js.snap rename to src/__test__/redux/actions/experiments/__snapshots__/createMetadataTrack.test.js.snap index a8489a77c1..b38efafb16 100644 --- a/src/__test__/redux/actions/projects/__snapshots__/createMetadataTrack.test.js.snap +++ b/src/__test__/redux/actions/experiments/__snapshots__/createMetadataTrack.test.js.snap @@ -3,8 +3,8 @@ exports[`createMetadataTrack action Works correctly 1`] = ` Array [ Object { + "experimentId": "expeirment-1", "key": "Test_track", - "projectUuid": "project1", }, Object { "sample": Object { diff --git a/src/__test__/redux/actions/projects/__snapshots__/deleteMetadataTrack.test.js.snap b/src/__test__/redux/actions/experiments/__snapshots__/deleteMetadataTrack.test.js.snap similarity index 85% rename from src/__test__/redux/actions/projects/__snapshots__/deleteMetadataTrack.test.js.snap rename to src/__test__/redux/actions/experiments/__snapshots__/deleteMetadataTrack.test.js.snap index 96d9f8e8ca..e0fcd7f5c1 100644 --- a/src/__test__/redux/actions/projects/__snapshots__/deleteMetadataTrack.test.js.snap +++ b/src/__test__/redux/actions/experiments/__snapshots__/deleteMetadataTrack.test.js.snap @@ -3,8 +3,8 @@ exports[`deleteMetadataTrack action Works correctly 1`] = ` Array [ Object { + "experimentId": "experiment-1234", "key": "Test", - "projectUuid": "project-1234", }, Object { "metadataKey": "Test", diff --git a/src/__test__/redux/actions/experiments/__snapshots__/setActiveExperiment.test.js.snap b/src/__test__/redux/actions/experiments/__snapshots__/setActiveExperiment.test.js.snap new file mode 100644 index 0000000000..c562aba39e --- /dev/null +++ b/src/__test__/redux/actions/experiments/__snapshots__/setActiveExperiment.test.js.snap @@ -0,0 +1,10 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`setActiveExperiment action Dispatches event correctly 1`] = ` +Object { + "payload": Object { + "experimentId": "67890", + }, + "type": "experiments/setActive", +} +`; diff --git a/src/__test__/redux/actions/experiments/__snapshots__/switchExperiment.test.js.snap b/src/__test__/redux/actions/experiments/__snapshots__/switchExperiment.test.js.snap index d871c43451..02b43dc3d0 100644 --- a/src/__test__/redux/actions/experiments/__snapshots__/switchExperiment.test.js.snap +++ b/src/__test__/redux/actions/experiments/__snapshots__/switchExperiment.test.js.snap @@ -92,57 +92,56 @@ Object { "testae48e318dab9a1bd0bexperiment-1", ], "meta": Object { + "activeExperimentId": "testae48e318dab9a1bd0bexperiment-1", "error": false, "loading": false, "saving": false, }, "testae48e318dab9a1bd0bexperiment-0": Object { - "createdDate": "0000-00-00T00:00:00.000Z", + "createdAt": "0000-00-00T00:00:00.000Z", "description": "Mock experiment 0", "id": "testae48e318dab9a1bd0bexperiment-0", - "meta": Object { + "metadataKeys": Array [], + "name": "Test Experiment-0", + "notifyByEmail": true, + "pipelines": Object { "gem2s": Object { "executionArn": "arn:aws:states:eu-west-1:000000000000:execution:biomage-gem2s-development-mock997586f1bae0a6d5c5beed65663ec1519de4:5f273383-f093-4112-95b0-d76db896test", "paramsHash": "mock57f90e94eeaa82ee6fb7627110828f2etest", "stateMachineArn": "arn:aws:states:eu-west-1:000000000000:stateMachine:biomage-gem2s-development-mock997586f1bae0a6d5c5beed65663ec151test", }, - "organism": null, - "pipeline": Object { + "qc": Object { "executionArn": "arn:aws:states:eu-west-1:000000000000:execution:biomage-qc-development-mock997586f1bae0a6d5c5beed65663ec1519de4:422493f3-68a0-4ecb-8b17-0e8cd7a3test", "stateMachineArn": "arn:aws:states:eu-west-1:000000000000:stateMachine:biomage-qc-development-mock997586f1bae0a6d5c5beed65663ec151test", }, - "type": "10x", }, - "name": "Test Experiment-0", - "notifyByEmail": true, - "projectUuid": "testae48e318dab9a1bd0bexperiment-0", "sampleIds": Array [ "test9188-d682-test-mock-cb6d644cmock-0", "test9188-d682-test-mock-cb6d644cmock-1", "test9188-d682-test-mock-cb6d644cmock-2", ], + "updatedAt": "0000-00-00T00:00:00.000Z", }, "testae48e318dab9a1bd0bexperiment-1": Object { - "createdDate": "0000-00-00T00:00:00.000Z", + "createdAt": "0000-00-00T00:00:00.000Z", "description": "Mock experiment 1", "id": "testae48e318dab9a1bd0bexperiment-1", - "meta": Object { + "metadataKeys": Array [], + "name": "Test Experiment-1", + "notifyByEmail": true, + "pipelines": Object { "gem2s": Object { "executionArn": "arn:aws:states:eu-west-1:000000000000:execution:biomage-gem2s-development-mock997586f1bae0a6d5c5beed65663ec1519de4:5f273383-f093-4112-95b0-d76db896test", "paramsHash": "mock57f90e94eeaa82ee6fb7627110828f2etest", "stateMachineArn": "arn:aws:states:eu-west-1:000000000000:stateMachine:biomage-gem2s-development-mock997586f1bae0a6d5c5beed65663ec151test", }, - "organism": null, - "pipeline": Object { + "qc": Object { "executionArn": "arn:aws:states:eu-west-1:000000000000:execution:biomage-qc-development-mock997586f1bae0a6d5c5beed65663ec1519de4:422493f3-68a0-4ecb-8b17-0e8cd7a3test", "stateMachineArn": "arn:aws:states:eu-west-1:000000000000:stateMachine:biomage-qc-development-mock997586f1bae0a6d5c5beed65663ec151test", }, - "type": "10x", }, - "name": "Test Experiment-1", - "notifyByEmail": true, - "projectUuid": "testae48e318dab9a1bd0bexperiment-1", "sampleIds": Array [], + "updatedAt": "0000-00-00T00:00:00.000Z", }, }, "genes": Object { @@ -186,68 +185,6 @@ Object { "networkResources": Object { "environment": undefined, }, - "projects": Object { - "ids": Array [ - "testae48e318dab9a1bd0bexperiment-0", - "testae48e318dab9a1bd0bexperiment-1", - ], - "loading": false, - "meta": Object { - "activeProjectUuid": "testae48e318dab9a1bd0bexperiment-1", - }, - "testae48e318dab9a1bd0bexperiment-0": Object { - "createdDate": "0000-00-00T00:00:00.000Z", - "description": "Mock experiment 0", - "experiments": Array [ - "testae48e318dab9a1bd0bexperiment-0", - ], - "lastModified": "0000-00-00T00:00:00.000Z", - "metadataKeys": Array [], - "name": "Test Experiment-0", - "notifyByEmail": true, - "pipelines": Object { - "gem2s": Object { - "executionArn": "arn:aws:states:eu-west-1:000000000000:execution:biomage-gem2s-development-mock997586f1bae0a6d5c5beed65663ec1519de4:5f273383-f093-4112-95b0-d76db896test", - "paramsHash": "mock57f90e94eeaa82ee6fb7627110828f2etest", - "stateMachineArn": "arn:aws:states:eu-west-1:000000000000:stateMachine:biomage-gem2s-development-mock997586f1bae0a6d5c5beed65663ec151test", - }, - "qc": Object { - "executionArn": "arn:aws:states:eu-west-1:000000000000:execution:biomage-qc-development-mock997586f1bae0a6d5c5beed65663ec1519de4:422493f3-68a0-4ecb-8b17-0e8cd7a3test", - "stateMachineArn": "arn:aws:states:eu-west-1:000000000000:stateMachine:biomage-qc-development-mock997586f1bae0a6d5c5beed65663ec151test", - }, - }, - "samples": Array [ - "test9188-d682-test-mock-cb6d644cmock-0", - "test9188-d682-test-mock-cb6d644cmock-1", - "test9188-d682-test-mock-cb6d644cmock-2", - ], - "uuid": "testae48e318dab9a1bd0bexperiment-0", - }, - "testae48e318dab9a1bd0bexperiment-1": Object { - "createdDate": "0000-00-00T00:00:00.000Z", - "description": "Mock experiment 1", - "experiments": Array [ - "testae48e318dab9a1bd0bexperiment-1", - ], - "lastModified": "0000-00-00T00:00:00.000Z", - "metadataKeys": Array [], - "name": "Test Experiment-1", - "notifyByEmail": true, - "pipelines": Object { - "gem2s": Object { - "executionArn": "arn:aws:states:eu-west-1:000000000000:execution:biomage-gem2s-development-mock997586f1bae0a6d5c5beed65663ec1519de4:5f273383-f093-4112-95b0-d76db896test", - "paramsHash": "mock57f90e94eeaa82ee6fb7627110828f2etest", - "stateMachineArn": "arn:aws:states:eu-west-1:000000000000:stateMachine:biomage-gem2s-development-mock997586f1bae0a6d5c5beed65663ec151test", - }, - "qc": Object { - "executionArn": "arn:aws:states:eu-west-1:000000000000:execution:biomage-qc-development-mock997586f1bae0a6d5c5beed65663ec1519de4:422493f3-68a0-4ecb-8b17-0e8cd7a3test", - "stateMachineArn": "arn:aws:states:eu-west-1:000000000000:stateMachine:biomage-qc-development-mock997586f1bae0a6d5c5beed65663ec151test", - }, - }, - "samples": Array [], - "uuid": "testae48e318dab9a1bd0bexperiment-1", - }, - }, "samples": Object { "meta": Object { "error": false, @@ -256,6 +193,7 @@ Object { }, "test9188-d682-test-mock-cb6d644cmock-0": Object { "createdDate": "2021-12-07 17:36:27.773+00", + "experimentId": "testae48e318dab9a1bd0bexperiment-0", "fileNames": Array [ "matrix.mtx.gz", "barcodes.tsv.gz", @@ -293,12 +231,12 @@ Object { "timePoint": "BL", }, "name": "Mock sample 0", - "projectUuid": "testae48e318dab9a1bd0bexperiment-0", "type": "10X Chromium", "uuid": "test9188-d682-test-mock-cb6d644cmock-0", }, "test9188-d682-test-mock-cb6d644cmock-1": Object { "createdDate": "2021-12-07 17:36:27.773+00", + "experimentId": "testae48e318dab9a1bd0bexperiment-0", "fileNames": Array [ "matrix.mtx.gz", "barcodes.tsv.gz", @@ -336,12 +274,12 @@ Object { "timePoint": "BL", }, "name": "Mock sample 1", - "projectUuid": "testae48e318dab9a1bd0bexperiment-0", "type": "10X Chromium", "uuid": "test9188-d682-test-mock-cb6d644cmock-1", }, "test9188-d682-test-mock-cb6d644cmock-2": Object { "createdDate": "2021-12-07 17:36:27.773+00", + "experimentId": "testae48e318dab9a1bd0bexperiment-0", "fileNames": Array [ "matrix.mtx.gz", "barcodes.tsv.gz", @@ -379,7 +317,6 @@ Object { "timePoint": "BL", }, "name": "Mock sample 2", - "projectUuid": "testae48e318dab9a1bd0bexperiment-0", "type": "10X Chromium", "uuid": "test9188-d682-test-mock-cb6d644cmock-2", }, @@ -479,57 +416,56 @@ Object { "testae48e318dab9a1bd0bexperiment-1", ], "meta": Object { + "activeExperimentId": "testae48e318dab9a1bd0bexperiment-1", "error": false, "loading": false, "saving": false, }, "testae48e318dab9a1bd0bexperiment-0": Object { - "createdDate": "0000-00-00T00:00:00.000Z", + "createdAt": "0000-00-00T00:00:00.000Z", "description": "Mock experiment 0", "id": "testae48e318dab9a1bd0bexperiment-0", - "meta": Object { + "metadataKeys": Array [], + "name": "Test Experiment-0", + "notifyByEmail": true, + "pipelines": Object { "gem2s": Object { "executionArn": "arn:aws:states:eu-west-1:000000000000:execution:biomage-gem2s-development-mock997586f1bae0a6d5c5beed65663ec1519de4:5f273383-f093-4112-95b0-d76db896test", "paramsHash": "mock57f90e94eeaa82ee6fb7627110828f2etest", "stateMachineArn": "arn:aws:states:eu-west-1:000000000000:stateMachine:biomage-gem2s-development-mock997586f1bae0a6d5c5beed65663ec151test", }, - "organism": null, - "pipeline": Object { + "qc": Object { "executionArn": "arn:aws:states:eu-west-1:000000000000:execution:biomage-qc-development-mock997586f1bae0a6d5c5beed65663ec1519de4:422493f3-68a0-4ecb-8b17-0e8cd7a3test", "stateMachineArn": "arn:aws:states:eu-west-1:000000000000:stateMachine:biomage-qc-development-mock997586f1bae0a6d5c5beed65663ec151test", }, - "type": "10x", }, - "name": "Test Experiment-0", - "notifyByEmail": true, - "projectUuid": "testae48e318dab9a1bd0bexperiment-0", "sampleIds": Array [ "test9188-d682-test-mock-cb6d644cmock-0", "test9188-d682-test-mock-cb6d644cmock-1", "test9188-d682-test-mock-cb6d644cmock-2", ], + "updatedAt": "0000-00-00T00:00:00.000Z", }, "testae48e318dab9a1bd0bexperiment-1": Object { - "createdDate": "0000-00-00T00:00:00.000Z", + "createdAt": "0000-00-00T00:00:00.000Z", "description": "Mock experiment 1", "id": "testae48e318dab9a1bd0bexperiment-1", - "meta": Object { + "metadataKeys": Array [], + "name": "Test Experiment-1", + "notifyByEmail": true, + "pipelines": Object { "gem2s": Object { "executionArn": "arn:aws:states:eu-west-1:000000000000:execution:biomage-gem2s-development-mock997586f1bae0a6d5c5beed65663ec1519de4:5f273383-f093-4112-95b0-d76db896test", "paramsHash": "mock57f90e94eeaa82ee6fb7627110828f2etest", "stateMachineArn": "arn:aws:states:eu-west-1:000000000000:stateMachine:biomage-gem2s-development-mock997586f1bae0a6d5c5beed65663ec151test", }, - "organism": null, - "pipeline": Object { + "qc": Object { "executionArn": "arn:aws:states:eu-west-1:000000000000:execution:biomage-qc-development-mock997586f1bae0a6d5c5beed65663ec1519de4:422493f3-68a0-4ecb-8b17-0e8cd7a3test", "stateMachineArn": "arn:aws:states:eu-west-1:000000000000:stateMachine:biomage-qc-development-mock997586f1bae0a6d5c5beed65663ec151test", }, - "type": "10x", }, - "name": "Test Experiment-1", - "notifyByEmail": true, - "projectUuid": "testae48e318dab9a1bd0bexperiment-1", "sampleIds": Array [], + "updatedAt": "0000-00-00T00:00:00.000Z", }, }, "genes": Object { @@ -573,68 +509,6 @@ Object { "networkResources": Object { "environment": undefined, }, - "projects": Object { - "ids": Array [ - "testae48e318dab9a1bd0bexperiment-0", - "testae48e318dab9a1bd0bexperiment-1", - ], - "loading": false, - "meta": Object { - "activeProjectUuid": "testae48e318dab9a1bd0bexperiment-1", - }, - "testae48e318dab9a1bd0bexperiment-0": Object { - "createdDate": "0000-00-00T00:00:00.000Z", - "description": "Mock experiment 0", - "experiments": Array [ - "testae48e318dab9a1bd0bexperiment-0", - ], - "lastModified": "0000-00-00T00:00:00.000Z", - "metadataKeys": Array [], - "name": "Test Experiment-0", - "notifyByEmail": true, - "pipelines": Object { - "gem2s": Object { - "executionArn": "arn:aws:states:eu-west-1:000000000000:execution:biomage-gem2s-development-mock997586f1bae0a6d5c5beed65663ec1519de4:5f273383-f093-4112-95b0-d76db896test", - "paramsHash": "mock57f90e94eeaa82ee6fb7627110828f2etest", - "stateMachineArn": "arn:aws:states:eu-west-1:000000000000:stateMachine:biomage-gem2s-development-mock997586f1bae0a6d5c5beed65663ec151test", - }, - "qc": Object { - "executionArn": "arn:aws:states:eu-west-1:000000000000:execution:biomage-qc-development-mock997586f1bae0a6d5c5beed65663ec1519de4:422493f3-68a0-4ecb-8b17-0e8cd7a3test", - "stateMachineArn": "arn:aws:states:eu-west-1:000000000000:stateMachine:biomage-qc-development-mock997586f1bae0a6d5c5beed65663ec151test", - }, - }, - "samples": Array [ - "test9188-d682-test-mock-cb6d644cmock-0", - "test9188-d682-test-mock-cb6d644cmock-1", - "test9188-d682-test-mock-cb6d644cmock-2", - ], - "uuid": "testae48e318dab9a1bd0bexperiment-0", - }, - "testae48e318dab9a1bd0bexperiment-1": Object { - "createdDate": "0000-00-00T00:00:00.000Z", - "description": "Mock experiment 1", - "experiments": Array [ - "testae48e318dab9a1bd0bexperiment-1", - ], - "lastModified": "0000-00-00T00:00:00.000Z", - "metadataKeys": Array [], - "name": "Test Experiment-1", - "notifyByEmail": true, - "pipelines": Object { - "gem2s": Object { - "executionArn": "arn:aws:states:eu-west-1:000000000000:execution:biomage-gem2s-development-mock997586f1bae0a6d5c5beed65663ec1519de4:5f273383-f093-4112-95b0-d76db896test", - "paramsHash": "mock57f90e94eeaa82ee6fb7627110828f2etest", - "stateMachineArn": "arn:aws:states:eu-west-1:000000000000:stateMachine:biomage-gem2s-development-mock997586f1bae0a6d5c5beed65663ec151test", - }, - "qc": Object { - "executionArn": "arn:aws:states:eu-west-1:000000000000:execution:biomage-qc-development-mock997586f1bae0a6d5c5beed65663ec1519de4:422493f3-68a0-4ecb-8b17-0e8cd7a3test", - "stateMachineArn": "arn:aws:states:eu-west-1:000000000000:stateMachine:biomage-qc-development-mock997586f1bae0a6d5c5beed65663ec151test", - }, - }, - "samples": Array [], - "uuid": "testae48e318dab9a1bd0bexperiment-1", - }, - }, "samples": Object { "meta": Object { "error": false, @@ -643,6 +517,7 @@ Object { }, "test9188-d682-test-mock-cb6d644cmock-0": Object { "createdDate": "2021-12-07 17:36:27.773+00", + "experimentId": "testae48e318dab9a1bd0bexperiment-0", "fileNames": Array [ "matrix.mtx.gz", "barcodes.tsv.gz", @@ -680,12 +555,12 @@ Object { "timePoint": "BL", }, "name": "Mock sample 0", - "projectUuid": "testae48e318dab9a1bd0bexperiment-0", "type": "10X Chromium", "uuid": "test9188-d682-test-mock-cb6d644cmock-0", }, "test9188-d682-test-mock-cb6d644cmock-1": Object { "createdDate": "2021-12-07 17:36:27.773+00", + "experimentId": "testae48e318dab9a1bd0bexperiment-0", "fileNames": Array [ "matrix.mtx.gz", "barcodes.tsv.gz", @@ -723,12 +598,12 @@ Object { "timePoint": "BL", }, "name": "Mock sample 1", - "projectUuid": "testae48e318dab9a1bd0bexperiment-0", "type": "10X Chromium", "uuid": "test9188-d682-test-mock-cb6d644cmock-1", }, "test9188-d682-test-mock-cb6d644cmock-2": Object { "createdDate": "2021-12-07 17:36:27.773+00", + "experimentId": "testae48e318dab9a1bd0bexperiment-0", "fileNames": Array [ "matrix.mtx.gz", "barcodes.tsv.gz", @@ -766,7 +641,6 @@ Object { "timePoint": "BL", }, "name": "Mock sample 2", - "projectUuid": "testae48e318dab9a1bd0bexperiment-0", "type": "10X Chromium", "uuid": "test9188-d682-test-mock-cb6d644cmock-2", }, diff --git a/src/__test__/redux/actions/projects/__snapshots__/updateMetadataTrack.test.js.snap b/src/__test__/redux/actions/experiments/__snapshots__/updateMetadataTrack.test.js.snap similarity index 91% rename from src/__test__/redux/actions/projects/__snapshots__/updateMetadataTrack.test.js.snap rename to src/__test__/redux/actions/experiments/__snapshots__/updateMetadataTrack.test.js.snap index 2cdcff878e..ba32ce124e 100644 --- a/src/__test__/redux/actions/projects/__snapshots__/updateMetadataTrack.test.js.snap +++ b/src/__test__/redux/actions/experiments/__snapshots__/updateMetadataTrack.test.js.snap @@ -3,9 +3,9 @@ exports[`updateMetadataTrack action Works correctly 1`] = ` Array [ Object { + "experimentId": "experiment-1234", "newKey": "New_track", "oldKey": "Old_track", - "projectUuid": "project-1234", }, Object { "sample": Object { diff --git a/src/__test__/redux/actions/projects/__snapshots__/updateValueInMetadataTrack.test.js.snap b/src/__test__/redux/actions/experiments/__snapshots__/updateValueInMetadataTrack.test.js.snap similarity index 100% rename from src/__test__/redux/actions/projects/__snapshots__/updateValueInMetadataTrack.test.js.snap rename to src/__test__/redux/actions/experiments/__snapshots__/updateValueInMetadataTrack.test.js.snap diff --git a/src/__test__/redux/actions/experiments/createExperiment.test.js b/src/__test__/redux/actions/experiments/createExperiment.test.js index cbd0b57e6c..31aeff4807 100644 --- a/src/__test__/redux/actions/experiments/createExperiment.test.js +++ b/src/__test__/redux/actions/experiments/createExperiment.test.js @@ -4,27 +4,21 @@ import fetchMock, { enableFetchMocks } from 'jest-fetch-mock'; import { EXPERIMENTS_SAVING, EXPERIMENTS_CREATED } from 'redux/actionTypes/experiments'; import { createExperiment } from 'redux/actions/experiments'; -import initialExperimentState from 'redux/reducers/experiments/initialState'; -import initialProjectState, { projectTemplate } from 'redux/reducers/projects/initialState'; +import initialExperimentState, { experimentTemplate } from 'redux/reducers/experiments/initialState'; const mockStore = configureStore([thunk]); enableFetchMocks(); describe('createExperiment', () => { - const projectUuid = 'project-1'; + const experimentId = 'experiment-1'; const mockState = { - projects: { - ...initialProjectState, - [projectUuid]: { - ...projectTemplate, - uuid: projectUuid, - experiments: [], - }, - }, experiments: { ...initialExperimentState, + [experimentId]: { + ...experimentTemplate, + }, }, }; @@ -41,7 +35,7 @@ describe('createExperiment', () => { it('Works correctly', async () => { const store = mockStore(mockState); - await store.dispatch(createExperiment(projectUuid)); + await store.dispatch(createExperiment('name', 'description')); const actions = store.getActions(); diff --git a/src/__test__/redux/actions/projects/createMetadataTrack.test.js b/src/__test__/redux/actions/experiments/createMetadataTrack.test.js similarity index 57% rename from src/__test__/redux/actions/projects/createMetadataTrack.test.js rename to src/__test__/redux/actions/experiments/createMetadataTrack.test.js index 403bd2a8d2..860159789c 100644 --- a/src/__test__/redux/actions/projects/createMetadataTrack.test.js +++ b/src/__test__/redux/actions/experiments/createMetadataTrack.test.js @@ -4,12 +4,13 @@ import thunk from 'redux-thunk'; import fetchMock, { enableFetchMocks } from 'jest-fetch-mock'; -import createMetadataTrack from 'redux/actions/projects/createMetadataTrack'; -import initialProjectState, { projectTemplate } from 'redux/reducers/projects/initialState'; +import createMetadataTrack from 'redux/actions/experiments/createMetadataTrack'; +import initialExperimentState, { experimentTemplate } from 'redux/reducers/experiments/initialState'; import initialSamplesState, { sampleTemplate } from 'redux/reducers/samples/initialState'; + import { - PROJECTS_METADATA_CREATE, -} from 'redux/actionTypes/projects'; + EXPERIMENTS_METADATA_CREATE, +} from 'redux/actionTypes/experiments'; import '__test__/test-utils/setupTests'; @@ -18,30 +19,30 @@ import { SAMPLES_UPDATE } from 'redux/actionTypes/samples'; const mockStore = configureStore([thunk]); describe('createMetadataTrack action', () => { - const project1uuid = 'project1'; + const experiment1Id = 'expeirment-1'; const sample1uuid = 'sample1'; - const project1 = { - ...projectTemplate, - name: 'Project 1', - uuid: 'project1', + const experiment1 = { + ...experimentTemplate, + name: 'Experiment 1', + id: experiment1Id, createdDate: '01-01-2021', lastModified: '01-01-2021', - samples: [sample1uuid], + sampleIds: [sample1uuid], }; const sample1 = { ...sampleTemplate, name: 'Sample 1', - projectUuid: project1uuid, + experimentId: experiment1Id, uuid: 'sample1', }; - const oneProjectState = { - projects: { - ...initialProjectState, - ids: [project1.uuid], - [project1.uuid]: project1, + const oneExperimentState = { + experiments: { + ...initialExperimentState, + ids: [experiment1.id], + [experiment1.id]: experiment1, }, samples: { ...initialSamplesState, @@ -56,20 +57,20 @@ describe('createMetadataTrack action', () => { }); it('Works correctly', async () => { - const store = mockStore(oneProjectState); + const store = mockStore(oneExperimentState); fetchMock.mockResolvedValue(new Response(JSON.stringify({}))); - await store.dispatch(createMetadataTrack('Test track', project1.uuid)); + await store.dispatch(createMetadataTrack('Test track', experiment1.id)); const trackKeyRCompatible = 'Test_track'; const actions = store.getActions(); - expect(_.map(actions, 'type')).toEqual([PROJECTS_METADATA_CREATE, SAMPLES_UPDATE]); + expect(_.map(actions, 'type')).toEqual([EXPERIMENTS_METADATA_CREATE, SAMPLES_UPDATE]); expect(_.map(actions, 'payload')).toMatchSnapshot(); expect(fetchMock).toHaveBeenCalledWith( - `http://localhost:3000/v2/experiments/${project1.uuid}/metadataTracks/${trackKeyRCompatible}`, + `http://localhost:3000/v2/experiments/${experiment1.id}/metadataTracks/${trackKeyRCompatible}`, { headers: { 'Content-Type': 'application/json' }, method: 'POST', diff --git a/src/__test__/redux/actions/experiments/deleteExperiment.test.js b/src/__test__/redux/actions/experiments/deleteExperiment.test.js new file mode 100644 index 0000000000..050d275ae1 --- /dev/null +++ b/src/__test__/redux/actions/experiments/deleteExperiment.test.js @@ -0,0 +1,134 @@ +import _ from 'lodash'; + +import configureStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; +import fetchMock, { enableFetchMocks } from 'jest-fetch-mock'; +import deleteExperiment from 'redux/actions/experiments/deleteExperiment'; + +import initialSampleState, { sampleTemplate } from 'redux/reducers/samples/initialState'; +import initialExperimentState, { experimentTemplate } from 'redux/reducers/experiments/initialState'; + +import { EXPERIMENTS_SET_ACTIVE, EXPERIMENTS_DELETED, EXPERIMENTS_SAVING } from 'redux/actionTypes/experiments'; +import { SAMPLES_DELETE } from 'redux/actionTypes/samples'; + +enableFetchMocks(); + +const mockStore = configureStore([thunk]); + +describe('deleteExperiment action', () => { + const mockSampleUuid1 = 'sample-1'; + const mockSampleUuid2 = 'sample-2'; + const mockExperimentId1 = 'experiment-1'; + const mockExperimentId2 = 'experiment-2'; + + const mockSample = { + ...sampleTemplate, + name: 'test sample', + experimentId: mockExperimentId1, + uuid: mockSampleUuid1, + }; + + const mockExperiment = { + ...experimentTemplate, + name: 'test experiment', + sampleIds: [mockSampleUuid1], + }; + + const initialStateUniSample = { + samples: { + ...initialSampleState, + ids: [mockSampleUuid1], + [mockSampleUuid1]: mockSample, + }, + experiments: { + ...initialExperimentState, + [mockExperimentId1]: mockExperiment, + ids: [mockExperimentId1], + }, + }; + + const initialStateMultipleSamples = { + samples: { + ...initialSampleState, + ids: [mockSampleUuid1], + [mockSampleUuid1]: mockSample, + [mockSampleUuid2]: { + mockSample, + uuid: mockSampleUuid2, + }, + }, + experiments: { + ...initialExperimentState, + ids: [mockExperimentId1], + [mockExperimentId1]: { + ...mockExperiment, + sampleIds: [ + mockExperiment.sampleIds, + mockSampleUuid2, + ], + }, + }, + }; + + const initialStateMultipleExperiments = { + experiments: { + ...initialExperimentState, + meta: { activeExperimentId: mockExperimentId1 }, + ids: [mockExperimentId1, mockExperimentId2], + [mockExperimentId1]: mockExperiment, + [mockExperimentId2]: { + ...mockExperiment, + id: mockExperimentId2, + }, + }, + }; + + beforeEach(async () => { + fetchMock.resetMocks(); + fetchMock.doMock(); + fetchMock.mockResponse(JSON.stringify({})); + }); + + it('Dispatches event correctly for one sample', async () => { + const store = mockStore(initialStateUniSample); + await store.dispatch(deleteExperiment(mockExperimentId1)); + + // Sets up loading state for saving experiment + const actions = store.getActions(); + expect(_.map(actions, 'type')).toEqual([ + EXPERIMENTS_SAVING, SAMPLES_DELETE, EXPERIMENTS_DELETED, + ]); + + expect(fetchMock).toHaveBeenCalledWith( + `http://localhost:3000/v2/experiments/${mockExperimentId1}`, + { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json', + }, + }, + ); + }); + + it('Dispatches event correctly for multiple samples', async () => { + const store = mockStore(initialStateMultipleSamples); + await store.dispatch(deleteExperiment(mockExperimentId1)); + + // Sets up loading state for saving experiment + const actions = store.getActions(); + expect(_.map(actions, 'type')).toEqual([ + EXPERIMENTS_SAVING, SAMPLES_DELETE, EXPERIMENTS_DELETED, + ]); + }); + + it('Switches to activeExperimentId to another experiment if multiple experiment exists', async () => { + const store = mockStore(initialStateMultipleExperiments); + await store.dispatch(deleteExperiment(mockExperimentId1)); + + // Sets up loading state for saving experiment + const actions = store.getActions(); + expect(_.map(actions, 'type')).toEqual([ + EXPERIMENTS_SAVING, EXPERIMENTS_SET_ACTIVE, SAMPLES_DELETE, EXPERIMENTS_DELETED, + ]); + }); +}); diff --git a/src/__test__/redux/actions/projects/deleteMetadataTrack.test.js b/src/__test__/redux/actions/experiments/deleteMetadataTrack.test.js similarity index 70% rename from src/__test__/redux/actions/projects/deleteMetadataTrack.test.js rename to src/__test__/redux/actions/experiments/deleteMetadataTrack.test.js index 80b005a178..3306974059 100644 --- a/src/__test__/redux/actions/projects/deleteMetadataTrack.test.js +++ b/src/__test__/redux/actions/experiments/deleteMetadataTrack.test.js @@ -6,36 +6,36 @@ import fetchMock, { enableFetchMocks } from 'jest-fetch-mock'; import { metadataNameToKey } from 'utils/data-management/metadataUtils'; import pushNotificationMessage from 'utils/pushNotificationMessage'; -import deleteMetadataTrack from 'redux/actions/projects/deleteMetadataTrack'; -import initialProjectState from 'redux/reducers/projects'; +import deleteMetadataTrack from 'redux/actions/experiments/deleteMetadataTrack'; +import initialExperimentState from 'redux/reducers/experiments'; import initialSampleState from 'redux/reducers/samples'; import '__test__/test-utils/setupTests'; -import { PROJECTS_METADATA_DELETE } from 'redux/actionTypes/projects'; +import { EXPERIMENTS_METADATA_DELETE } from 'redux/actionTypes/experiments'; import { SAMPLES_METADATA_DELETE } from 'redux/actionTypes/samples'; const mockStore = configureStore([thunk]); -const mockProjectUuid = 'project-1234'; +const mockExperimentId = 'experiment-1234'; const mockSampleUuid = 'sample-1234'; const metadataTrack = 'Test'; const metadataTrackKey = metadataNameToKey(metadataTrack); -const mockProject = { - ...initialProjectState, - name: 'test project', - uuid: mockProjectUuid, - createdDate: '01-01-2021', - lastModified: '01-01-2021', +const mockExperiment = { + ...initialExperimentState, + name: 'test experiment', + id: mockExperimentId, + createdAt: '01-01-2021', + updatedAt: '01-01-2021', metadataKeys: [metadataTrackKey], - samples: [mockSampleUuid], + sampleIds: [mockSampleUuid], }; const mockSample = { ...initialSampleState, name: 'test sample', - projectUuid: mockProjectUuid, + experimentId: mockExperimentId, uuid: mockSampleUuid, metadata: { [metadataTrackKey]: 'value', @@ -43,9 +43,9 @@ const mockSample = { }; const initialState = { - projects: { - ids: [mockProject.uuid], - [mockProject.uuid]: mockProject, + experiments: { + ids: [mockExperiment.id], + [mockExperiment.id]: mockExperiment, }, samples: { ids: [mockSample.uuid], @@ -65,14 +65,14 @@ describe('deleteMetadataTrack action', () => { fetchMock.mockResolvedValue(new Response(JSON.stringify({}))); - await store.dispatch(deleteMetadataTrack(metadataTrack, mockProject.uuid)); + await store.dispatch(deleteMetadataTrack(metadataTrack, mockExperiment.id)); const actions = store.getActions(); - expect(_.map(actions, 'type')).toEqual([PROJECTS_METADATA_DELETE, SAMPLES_METADATA_DELETE]); + expect(_.map(actions, 'type')).toEqual([EXPERIMENTS_METADATA_DELETE, SAMPLES_METADATA_DELETE]); expect(_.map(actions, 'payload')).toMatchSnapshot(); expect(fetchMock).toHaveBeenCalledWith( - `http://localhost:3000/v2/experiments/${mockProject.uuid}/metadataTracks/${metadataTrack}`, + `http://localhost:3000/v2/experiments/${mockExperiment.id}/metadataTracks/${metadataTrack}`, { headers: { 'Content-Type': 'application/json' }, method: 'DELETE', @@ -82,7 +82,7 @@ describe('deleteMetadataTrack action', () => { it('Does not update metadata if save fails', async () => { const store = mockStore(initialState); - await store.dispatch(deleteMetadataTrack(metadataTrack, mockProject.uuid)); + await store.dispatch(deleteMetadataTrack(metadataTrack, mockExperiment.id)); const actions = store.getActions(); expect(actions).toHaveLength(0); diff --git a/src/__test__/redux/actions/experiments/loadExperiments.test.js b/src/__test__/redux/actions/experiments/loadExperiments.test.js index a31a391a11..8dd8d67260 100644 --- a/src/__test__/redux/actions/experiments/loadExperiments.test.js +++ b/src/__test__/redux/actions/experiments/loadExperiments.test.js @@ -15,35 +15,7 @@ enableFetchMocks(); const mockStore = configureStore([thunk]); -const v1Experiment = [ - { - experimentId: '03a9af8d-17ae-9caf-ace5-1152f4241eb2', - projectId: '03a9af8d-17ae-9caf-ace5-1152f4241eb2', - description: '', - experimentName: 'Bone marrow analysis', - createdDate: '2021-06-29 09:34:48.793+00', - notifyByEmail: true, - sampleIds: [ - '51ffbd1e-a156-46e7-a380-039c2999a5b5', - ], - meta: { - organism: null, - type: '10x', - gem2s: { - paramsHash: 'paramsHash', - executionArn: 'executionArnGem2s', - stateMachineArn: 'stateMachineArnGem2s', - }, - pipeline: { - paramsHash: null, - executionArn: 'executionArnPipeline', - stateMachineArn: 'stateMachineArnPipeline', - }, - }, - }, -]; - -const v2Experiment = { +const experiment = { id: '03a9af8d-17ae-9caf-ace5-1152f4241eb2', name: 'Bone marrow analysis', description: '', @@ -53,21 +25,19 @@ const v2Experiment = { notifyByEmail: true, createdAt: '2021-06-29 09:34:48.793+00', updatedAt: '2022-01-17 15:06:22.267+00', - pipelines: { - qc: { - paramsHash: null, - executionArn: 'executionArnPipeline', - stateMachineArn: 'stateMachineArnPipeline', - }, - gem2s: { - paramsHash: 'paramsHash', - executionArn: 'executionArnGem2s', - stateMachineArn: 'stateMachineArnGem2s', - }, - }, }; -describe('loadExperiment', () => { +const dispatchedExperiment = { + id: experiment.id, + name: experiment.name, + description: experiment.description, + sampleIds: experiment.samplesOrder, + notifyByEmail: experiment.notifyByEmail, + createdAt: experiment.createdAt, + updatedAt: experiment.updatedAt, +}; + +describe('loadExperiments', () => { beforeEach(() => { jest.clearAllMocks(); @@ -78,7 +48,7 @@ describe('loadExperiment', () => { it('Dispatches the correct actions when called', async () => { const experimentId = 'experiment-1'; - fetchMock.mockResolvedValue(new Response(JSON.stringify(v2Experiment))); + fetchMock.mockResolvedValue(new Response(JSON.stringify([experiment]))); const store = mockStore(); await store.dispatch(loadExperiments(experimentId)); @@ -87,7 +57,7 @@ describe('loadExperiment', () => { expect(actions[0].type).toEqual(EXPERIMENTS_LOADING); expect(actions[1].type).toEqual(EXPERIMENTS_LOADED); - expect(actions[1].payload.experiments).toEqual(v1Experiment); + expect(actions[1].payload.experiments).toEqual([dispatchedExperiment]); }); it('Dispatches notifications when error', async () => { @@ -99,8 +69,8 @@ describe('loadExperiment', () => { await store.dispatch(loadExperiments(experimentId)); const actions = store.getActions(); - expect(actions[0].type).toEqual(EXPERIMENTS_LOADING); + expect(actions[0].type).toEqual(EXPERIMENTS_LOADING); expect(actions[1].type).toEqual(EXPERIMENTS_ERROR); expect(pushNotificationMessage).toHaveBeenCalled(); diff --git a/src/__test__/redux/actions/experiments/setActiveExperiment.test.js b/src/__test__/redux/actions/experiments/setActiveExperiment.test.js new file mode 100644 index 0000000000..486a10c837 --- /dev/null +++ b/src/__test__/redux/actions/experiments/setActiveExperiment.test.js @@ -0,0 +1,55 @@ +import configureStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; +import setActiveExperiment from 'redux/actions/experiments/setActiveExperiment'; +import initialExperimentState, { experimentTemplate } from 'redux/reducers/experiments/initialState'; + +import { EXPERIMENTS_SET_ACTIVE } from 'redux/actionTypes/experiments'; + +const mockStore = configureStore([thunk]); + +describe('setActiveExperiment action', () => { + const activeExperiment = { + ...experimentTemplate, + name: 'experiment 1', + id: '12345', + createdAt: '01-01-2021', + updatedAt: '01-01-2021', + }; + + const otherExperiment = { + ...experimentTemplate, + name: 'experiment 2', + id: '67890', + createdAt: '01-01-2021', + updatedAt: '01-01-2021', + }; + + const mockState = { + experiments: { + ...initialExperimentState, + ids: [...initialExperimentState.ids, activeExperiment.id, otherExperiment.uuid], + meta: { + ...initialExperimentState.meta, + activeExperimentId: activeExperiment.id, + }, + [activeExperiment.id]: activeExperiment, + [otherExperiment.id]: otherExperiment, + }, + }; + + it('Dispatches event correctly', async () => { + const store = mockStore(mockState); + await store.dispatch(setActiveExperiment(otherExperiment.id)); + + const firstAction = store.getActions()[0]; + expect(firstAction.type).toEqual(EXPERIMENTS_SET_ACTIVE); + expect(firstAction).toMatchSnapshot(); + }); + + it('Does not dispatch if project is the same', async () => { + const store = mockStore(mockState); + await store.dispatch(setActiveExperiment(activeExperiment.id)); + + expect(store.getActions().length).toEqual(0); + }); +}); diff --git a/src/__test__/redux/actions/experiments/switchExperiment.test.js b/src/__test__/redux/actions/experiments/switchExperiment.test.js index 17272f91d5..dcf5a2e897 100644 --- a/src/__test__/redux/actions/experiments/switchExperiment.test.js +++ b/src/__test__/redux/actions/experiments/switchExperiment.test.js @@ -1,15 +1,17 @@ -import { loadExperiments, switchExperiment } from 'redux/actions/experiments'; import _ from 'lodash'; -import mockAPI, { - generateDefaultMockAPIResponses, +import fetchMock, { enableFetchMocks } from 'jest-fetch-mock'; -} from '__test__/test-utils/mockAPI'; import { makeStore } from 'redux/store'; -import { loadProjects, setActiveProject } from 'redux/actions/projects'; -import { responseData } from '__test__/test-utils/mockData'; -import fetchMock, { enableFetchMocks } from 'jest-fetch-mock'; +import { + loadExperiments, setActiveExperiment, switchExperiment, +} from 'redux/actions/experiments'; import { loadSamples } from 'redux/actions/samples'; +import { responseData } from '__test__/test-utils/mockData'; +import mockAPI, { + generateDefaultMockAPIResponses, +} from '__test__/test-utils/mockAPI'; + let store = null; const { experiments } = responseData; @@ -36,11 +38,9 @@ describe('switch experiment ', () => { fetchMock.mockIf(/.*/, mockAPI(mockAPIResponses)); store = makeStore(); - await store.dispatch(loadProjects()); - await store.dispatch(loadExperiments(experimentWithSamplesId)); + await store.dispatch(loadExperiments()); await store.dispatch(loadSamples(experimentWithSamplesId)); - await store.dispatch(loadExperiments(experimentWithoutSamplesId)); - await store.dispatch(setActiveProject(experimentWithoutSamplesId)); + await store.dispatch(setActiveExperiment(experimentWithoutSamplesId)); }); it('switches the experiment to its initial values', async () => { diff --git a/src/__test__/redux/actions/projects/updateMetadataTrack.test.js b/src/__test__/redux/actions/experiments/updateMetadataTrack.test.js similarity index 66% rename from src/__test__/redux/actions/projects/updateMetadataTrack.test.js rename to src/__test__/redux/actions/experiments/updateMetadataTrack.test.js index 5c9e5b2ac4..504552df6d 100644 --- a/src/__test__/redux/actions/projects/updateMetadataTrack.test.js +++ b/src/__test__/redux/actions/experiments/updateMetadataTrack.test.js @@ -5,20 +5,20 @@ import thunk from 'redux-thunk'; import fetchMock, { enableFetchMocks } from 'jest-fetch-mock'; import { metadataNameToKey } from 'utils/data-management/metadataUtils'; -import updateMetadataTrack from 'redux/actions/projects/updateMetadataTrack'; -import initialProjectState from 'redux/reducers/projects'; +import updateMetadataTrack from 'redux/actions/experiments/updateMetadataTrack'; +import initialExperimentState from 'redux/reducers/experiments'; import initialSampleState from 'redux/reducers/samples'; import { - PROJECTS_METADATA_UPDATE, -} from 'redux/actionTypes/projects'; + EXPERIMENTS_METADATA_UPDATE, +} from 'redux/actionTypes/experiments'; import '__test__/test-utils/setupTests'; import { SAMPLES_METADATA_DELETE, SAMPLES_UPDATE } from 'redux/actionTypes/samples'; const mockStore = configureStore([thunk]); -const mockProjectUuid = 'project-1234'; +const mockExperimentId = 'experiment-1234'; const mockSampleUuid = 'sample-1234'; const oldMetadataTrack = 'Old track'; @@ -27,20 +27,20 @@ const oldMetadataTrackKey = metadataNameToKey(oldMetadataTrack); const newMetadataTrack = 'New track'; const newMetadataTrackKey = metadataNameToKey(newMetadataTrack); -const mockProject = { - ...initialProjectState, - name: 'test project', - uuid: mockProjectUuid, +const mockExperiment = { + ...initialExperimentState, + name: 'test experiment', + id: mockExperimentId, createdDate: '01-01-2021', lastModified: '01-01-2021', metadataKeys: [oldMetadataTrackKey], - samples: [mockSampleUuid], + sampleIds: [mockSampleUuid], }; const mockSample = { ...initialSampleState, name: 'test sample', - projectUuid: mockProjectUuid, + experimentId: mockExperimentId, uuid: mockSampleUuid, metadata: { [oldMetadataTrackKey]: 'value', @@ -48,9 +48,9 @@ const mockSample = { }; const initialState = { - projects: { - ids: [mockProject.uuid], - [mockProject.uuid]: mockProject, + experiments: { + ids: [mockExperiment.id], + [mockExperiment.id]: mockExperiment, }, samples: { ids: [mockSample.uuid], @@ -70,14 +70,16 @@ describe('updateMetadataTrack action', () => { fetchMock.mockResolvedValue(new Response(JSON.stringify({}))); - await store.dispatch(updateMetadataTrack(oldMetadataTrack, newMetadataTrack, mockProject.uuid)); + await store.dispatch( + updateMetadataTrack(oldMetadataTrack, newMetadataTrack, mockExperiment.id), + ); const actions = store.getActions(); - expect(_.map(actions, 'type')).toEqual([PROJECTS_METADATA_UPDATE, SAMPLES_UPDATE, SAMPLES_METADATA_DELETE]); + expect(_.map(actions, 'type')).toEqual([EXPERIMENTS_METADATA_UPDATE, SAMPLES_UPDATE, SAMPLES_METADATA_DELETE]); expect(_.map(actions, 'payload')).toMatchSnapshot(); expect(fetchMock).toHaveBeenCalledWith( - `http://localhost:3000/v2/experiments/${mockProject.uuid}/metadataTracks/${oldMetadataTrackKey}`, + `http://localhost:3000/v2/experiments/${mockExperiment.id}/metadataTracks/${oldMetadataTrackKey}`, { body: JSON.stringify({ key: newMetadataTrackKey }), headers: { 'Content-Type': 'application/json' }, diff --git a/src/__test__/redux/actions/projects/updateValueInMetadataTrack.test.js b/src/__test__/redux/actions/experiments/updateValueInMetadataTrack.test.js similarity index 96% rename from src/__test__/redux/actions/projects/updateValueInMetadataTrack.test.js rename to src/__test__/redux/actions/experiments/updateValueInMetadataTrack.test.js index 468e8b4bbd..ea9911ebc6 100644 --- a/src/__test__/redux/actions/projects/updateValueInMetadataTrack.test.js +++ b/src/__test__/redux/actions/experiments/updateValueInMetadataTrack.test.js @@ -4,7 +4,7 @@ import thunk from 'redux-thunk'; import fetchMock, { enableFetchMocks } from 'jest-fetch-mock'; -import { updateValueInMetadataTrack } from 'redux/actions/projects'; +import { updateValueInMetadataTrack } from 'redux/actions/experiments'; import '__test__/test-utils/setupTests'; diff --git a/src/__test__/redux/actions/pipelines/runGem2s.test.js b/src/__test__/redux/actions/pipelines/runGem2s.test.js index f1967b16f8..1b8059c32d 100644 --- a/src/__test__/redux/actions/pipelines/runGem2s.test.js +++ b/src/__test__/redux/actions/pipelines/runGem2s.test.js @@ -33,7 +33,7 @@ const initialState = { ...experimentTemplate, name: 'Mock experiment', id: experimentId, - projectUuid: projectId, + experimentId: projectId, sampleIds: ['sample-1', 'sample-2'], }, }, diff --git a/src/__test__/redux/actions/projects/__snapshots__/createProject.test.js.snap b/src/__test__/redux/actions/projects/__snapshots__/createProject.test.js.snap deleted file mode 100644 index 4b103e87e2..0000000000 --- a/src/__test__/redux/actions/projects/__snapshots__/createProject.test.js.snap +++ /dev/null @@ -1,19 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`createProject action Creates a project when there are no errors 1`] = ` -Object { - "project": Object { - "createdDate": "2020-01-01T00:00:00.000Z", - "description": "test project description", - "experiments": Array [ - "random-experiment-uuid", - ], - "lastAnalyzed": null, - "lastModified": "2020-01-01T00:00:00.000Z", - "metadataKeys": Array [], - "name": "test project", - "samples": Array [], - "uuid": "random-experiment-uuid", - }, -} -`; diff --git a/src/__test__/redux/actions/projects/__snapshots__/loadProjects.test.js.snap b/src/__test__/redux/actions/projects/__snapshots__/loadProjects.test.js.snap deleted file mode 100644 index 16f4f90244..0000000000 --- a/src/__test__/redux/actions/projects/__snapshots__/loadProjects.test.js.snap +++ /dev/null @@ -1,64 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`load projects Works correctly 1`] = ` -Object { - "ids": Array [ - "testae48e318dab9a1bd0bexperiment-0", - "testae48e318dab9a1bd0bexperiment-1", - ], - "projects": Array [ - Object { - "createdDate": "0000-00-00T00:00:00.000Z", - "description": "Mock experiment 0", - "experiments": Array [ - "testae48e318dab9a1bd0bexperiment-0", - ], - "lastModified": "0000-00-00T00:00:00.000Z", - "metadataKeys": Array [], - "name": "Test Experiment-0", - "notifyByEmail": true, - "pipelines": Object { - "gem2s": Object { - "executionArn": "arn:aws:states:eu-west-1:000000000000:execution:biomage-gem2s-development-mock997586f1bae0a6d5c5beed65663ec1519de4:5f273383-f093-4112-95b0-d76db896test", - "paramsHash": "mock57f90e94eeaa82ee6fb7627110828f2etest", - "stateMachineArn": "arn:aws:states:eu-west-1:000000000000:stateMachine:biomage-gem2s-development-mock997586f1bae0a6d5c5beed65663ec151test", - }, - "qc": Object { - "executionArn": "arn:aws:states:eu-west-1:000000000000:execution:biomage-qc-development-mock997586f1bae0a6d5c5beed65663ec1519de4:422493f3-68a0-4ecb-8b17-0e8cd7a3test", - "stateMachineArn": "arn:aws:states:eu-west-1:000000000000:stateMachine:biomage-qc-development-mock997586f1bae0a6d5c5beed65663ec151test", - }, - }, - "samples": Array [ - "test9188-d682-test-mock-cb6d644cmock-0", - "test9188-d682-test-mock-cb6d644cmock-1", - "test9188-d682-test-mock-cb6d644cmock-2", - ], - "uuid": "testae48e318dab9a1bd0bexperiment-0", - }, - Object { - "createdDate": "0000-00-00T00:00:00.000Z", - "description": "Mock experiment 1", - "experiments": Array [ - "testae48e318dab9a1bd0bexperiment-1", - ], - "lastModified": "0000-00-00T00:00:00.000Z", - "metadataKeys": Array [], - "name": "Test Experiment-1", - "notifyByEmail": true, - "pipelines": Object { - "gem2s": Object { - "executionArn": "arn:aws:states:eu-west-1:000000000000:execution:biomage-gem2s-development-mock997586f1bae0a6d5c5beed65663ec1519de4:5f273383-f093-4112-95b0-d76db896test", - "paramsHash": "mock57f90e94eeaa82ee6fb7627110828f2etest", - "stateMachineArn": "arn:aws:states:eu-west-1:000000000000:stateMachine:biomage-gem2s-development-mock997586f1bae0a6d5c5beed65663ec151test", - }, - "qc": Object { - "executionArn": "arn:aws:states:eu-west-1:000000000000:execution:biomage-qc-development-mock997586f1bae0a6d5c5beed65663ec1519de4:422493f3-68a0-4ecb-8b17-0e8cd7a3test", - "stateMachineArn": "arn:aws:states:eu-west-1:000000000000:stateMachine:biomage-qc-development-mock997586f1bae0a6d5c5beed65663ec151test", - }, - }, - "samples": Array [], - "uuid": "testae48e318dab9a1bd0bexperiment-1", - }, - ], -} -`; diff --git a/src/__test__/redux/actions/projects/__snapshots__/setActiveProject.test.js.snap b/src/__test__/redux/actions/projects/__snapshots__/setActiveProject.test.js.snap deleted file mode 100644 index b161fa791f..0000000000 --- a/src/__test__/redux/actions/projects/__snapshots__/setActiveProject.test.js.snap +++ /dev/null @@ -1,10 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`setActiveProject action Dispatches event correctly 1`] = ` -Object { - "payload": Object { - "projectUuid": "67890", - }, - "type": "projects/setActive", -} -`; diff --git a/src/__test__/redux/actions/projects/createProject.test.js b/src/__test__/redux/actions/projects/createProject.test.js deleted file mode 100644 index acd5a903fe..0000000000 --- a/src/__test__/redux/actions/projects/createProject.test.js +++ /dev/null @@ -1,86 +0,0 @@ -import configureStore from 'redux-mock-store'; -import thunk from 'redux-thunk'; -import fetchMock, { enableFetchMocks } from 'jest-fetch-mock'; - -import handleError from 'utils/http/handleError'; -import createProject from 'redux/actions/projects/createProject'; -import initialProjectsState from 'redux/reducers/projects'; - -import { createExperiment } from 'redux/actions/experiments'; -import { - PROJECTS_CREATE, PROJECTS_SAVING, PROJECTS_ERROR, -} from 'redux/actionTypes/projects'; -import '__test__/test-utils/setupTests'; - -jest.mock('utils/http/handleError'); - -const mockStore = configureStore([thunk]); - -const experimentId = 'random-experiment-uuid'; -jest.mock('redux/actions/experiments/createExperiment'); -createExperiment.mockImplementation(() => async () => (experimentId)); - -enableFetchMocks(); - -describe('createProject action', () => { - let store; - - beforeEach(() => { - jest.clearAllMocks(); - jest.useFakeTimers('modern').setSystemTime(new Date('2020-01-01').getTime()); - - fetchMock.resetMocks(); - fetchMock.doMock(); - - store = mockStore({ - projects: initialProjectsState, - }); - }); - - const projectName = 'test project'; - const projectDescription = 'test project description'; - const experimentName = 'mockExperimentName'; - - it('Creates a project when there are no errors', async () => { - fetchMock.mockResponse(JSON.stringify({})); - - await store.dispatch( - createProject(projectName, projectDescription, experimentName), - ); - - expect(createExperiment).toHaveBeenCalledWith(experimentName, projectDescription); - - // Sends correct actions - const actions = store.getActions(); - expect(actions[0].type).toEqual(PROJECTS_SAVING); - expect(actions[1].type).toEqual(PROJECTS_CREATE); - - // No other action was sent - expect(actions).toHaveLength(2); - - expect(actions[1].payload).toMatchSnapshot(); - }); - - it('Shows error when there was an experiment error', async () => { - const fetchErrorMessage = 'some error'; - - createExperiment.mockImplementationOnce(() => { throw new Error(fetchErrorMessage); }); - - await store.dispatch( - createProject(projectName, projectDescription, experimentName), - ); - - expect(createExperiment).toHaveBeenCalledWith(experimentName, projectDescription); - - // Sends correct actions - const actions = store.getActions(); - - expect(actions[0].type).toEqual(PROJECTS_SAVING); - expect(actions[1].type).toEqual(PROJECTS_ERROR); - - // Check no other action was sent - expect(actions).toHaveLength(2); - - expect(handleError).toHaveBeenCalledTimes(1); - }); -}); diff --git a/src/__test__/redux/actions/projects/deleteProject.test.js b/src/__test__/redux/actions/projects/deleteProject.test.js deleted file mode 100644 index 99f0afc0f6..0000000000 --- a/src/__test__/redux/actions/projects/deleteProject.test.js +++ /dev/null @@ -1,139 +0,0 @@ -import _ from 'lodash'; - -import configureStore from 'redux-mock-store'; -import thunk from 'redux-thunk'; -import fetchMock, { enableFetchMocks } from 'jest-fetch-mock'; -import deleteProject from 'redux/actions/projects/deleteProject'; - -import initialSampleState, { sampleTemplate } from 'redux/reducers/samples/initialState'; -import initialProjectState, { projectTemplate } from 'redux/reducers/projects/initialState'; - -import { - PROJECTS_DELETE, PROJECTS_SAVED, PROJECTS_SAVING, PROJECTS_SET_ACTIVE, -} from 'redux/actionTypes/projects'; -import { EXPERIMENTS_DELETED } from 'redux/actionTypes/experiments'; -import { SAMPLES_DELETE } from 'redux/actionTypes/samples'; - -enableFetchMocks(); - -const mockStore = configureStore([thunk]); - -describe('deleteProject action', () => { - const mockSampleUuid1 = 'sample-1'; - const mockSampleUuid2 = 'sample-2'; - const mockProjectUuid1 = 'project-1'; - const mockProjectUuid2 = 'project-2'; - - const mockSample = { - ...sampleTemplate, - name: 'test sample', - projectUuid: mockProjectUuid1, - uuid: mockSampleUuid1, - }; - - const mockProject = { - ...projectTemplate, - name: 'test project', - uuid: mockProjectUuid1, - samples: [mockSampleUuid1], - }; - - const initialStateUniSample = { - samples: { - ...initialSampleState, - ids: [mockSampleUuid1], - [mockSampleUuid1]: mockSample, - }, - projects: { - ...initialProjectState, - ids: [mockProjectUuid1], - [mockProjectUuid1]: mockProject, - }, - }; - - const initialStateMultipleSamples = { - samples: { - ...initialSampleState, - ids: [mockSampleUuid1], - [mockSampleUuid1]: mockSample, - [mockSampleUuid2]: { - mockSample, - uuid: mockSampleUuid2, - }, - }, - projects: { - ...initialProjectState, - ids: [mockProjectUuid1], - [mockProjectUuid1]: { - ...mockProject, - samples: [ - ...mockProject.samples, - mockSampleUuid2, - ], - }, - }, - }; - - const initialStateMultipleProjects = { - projects: { - ...initialProjectState, - meta: { activeProjectUuid: mockProjectUuid1 }, - ids: [mockProjectUuid1, mockProjectUuid2], - [mockProjectUuid1]: mockProject, - [mockProjectUuid2]: { - ...mockProject, - uuid: mockProjectUuid2, - }, - }, - }; - - beforeEach(async () => { - fetchMock.resetMocks(); - fetchMock.doMock(); - fetchMock.mockResponse(JSON.stringify({})); - }); - - it('Dispatches event correctly for one sample', async () => { - const store = mockStore(initialStateUniSample); - await store.dispatch(deleteProject(mockProjectUuid1)); - - // Sets up loading state for saving project - const actions = store.getActions(); - expect(_.map(actions, 'type')).toEqual([ - PROJECTS_SAVING, SAMPLES_DELETE, EXPERIMENTS_DELETED, PROJECTS_DELETE, PROJECTS_SAVED, - ]); - - expect(fetchMock).toHaveBeenCalledWith( - `http://localhost:3000/v2/experiments/${mockProject.uuid}`, - { - method: 'DELETE', - headers: { - 'Content-Type': 'application/json', - }, - }, - ); - }); - - it('Dispatches event correctly for multiple samples', async () => { - const store = mockStore(initialStateMultipleSamples); - await store.dispatch(deleteProject(mockProjectUuid1)); - - // Sets up loading state for saving project - const actions = store.getActions(); - expect(_.map(actions, 'type')).toEqual([ - PROJECTS_SAVING, SAMPLES_DELETE, EXPERIMENTS_DELETED, PROJECTS_DELETE, PROJECTS_SAVED, - ]); - }); - - it('Switches to activeProjectUuid to another project if multiple project exists', async () => { - const store = mockStore(initialStateMultipleProjects); - await store.dispatch(deleteProject(mockProjectUuid1)); - - // Sets up loading state for saving project - const actions = store.getActions(); - expect(_.map(actions, 'type')).toEqual([ - PROJECTS_SAVING, PROJECTS_SET_ACTIVE, SAMPLES_DELETE, - EXPERIMENTS_DELETED, PROJECTS_DELETE, PROJECTS_SAVED, - ]); - }); -}); diff --git a/src/__test__/redux/actions/projects/loadProjects.test.js b/src/__test__/redux/actions/projects/loadProjects.test.js deleted file mode 100644 index 01133d3178..0000000000 --- a/src/__test__/redux/actions/projects/loadProjects.test.js +++ /dev/null @@ -1,50 +0,0 @@ -import configureStore from 'redux-mock-store'; -import thunk from 'redux-thunk'; -import fetchMock, { enableFetchMocks } from 'jest-fetch-mock'; -import { PROJECTS_LOADED, PROJECTS_ERROR } from 'redux/actionTypes/projects'; -import { projectTemplate } from 'redux/reducers/projects/initialState'; -import { loadProjects } from 'redux/actions/projects'; - -import fake from '__test__/test-utils/constants'; -import mockAPI, { generateDefaultMockAPIResponses } from '__test__/test-utils/mockAPI'; - -enableFetchMocks(); - -const mockStore = configureStore([thunk]); - -describe('load projects ', () => { - const initialState = { - projects: { - ...projectTemplate, - }, - }; - - beforeEach(() => { - const mockAPIResponse = generateDefaultMockAPIResponses(fake.EXPERIMENT_ID); - - fetchMock.resetMocks(); - fetchMock.mockIf(/.*/, mockAPI(mockAPIResponse)); - - jest.clearAllMocks(); - }); - - it('Works correctly', async () => { - const store = mockStore(initialState); - - await store.dispatch(loadProjects()); - - const actions = store.getActions(); - - const lastAction = actions[actions.length - 1]; - expect(lastAction.type).toEqual(PROJECTS_LOADED); - expect(lastAction.payload).toMatchSnapshot(); - }); - - it('Dispatches error correctly', async () => { - fetchMock.mockReject(new Error('Something went wrong :/')); - const store = mockStore(initialState); - await store.dispatch(loadProjects()); - const action = store.getActions()[1]; - expect(action.type).toEqual(PROJECTS_ERROR); - }); -}); diff --git a/src/__test__/redux/actions/projects/setActiveProject.test.js b/src/__test__/redux/actions/projects/setActiveProject.test.js deleted file mode 100644 index 7bfd9eda9e..0000000000 --- a/src/__test__/redux/actions/projects/setActiveProject.test.js +++ /dev/null @@ -1,55 +0,0 @@ -import configureStore from 'redux-mock-store'; -import thunk from 'redux-thunk'; -import setActiveProject from 'redux/actions/projects/setActiveProject'; -import initialState, { projectTemplate } from 'redux/reducers/projects/initialState'; - -import { PROJECTS_SET_ACTIVE } from 'redux/actionTypes/projects'; - -const mockStore = configureStore([thunk]); - -describe('setActiveProject action', () => { - const activeProject = { - ...projectTemplate, - name: 'project 1', - uuid: '12345', - createdDate: '01-01-2021', - lastModified: '01-01-2021', - }; - - const otherProject = { - ...projectTemplate, - name: 'project 2', - uuid: '67890', - createdDate: '01-01-2021', - lastModified: '01-01-2021', - }; - - const mockState = { - projects: { - ...initialState, - ids: [...initialState.ids, activeProject.uuid, otherProject.uuid], - meta: { - ...initialState.meta, - activeProjectUuid: activeProject.uuid, - }, - [activeProject.uuid]: activeProject, - [otherProject.uuid]: otherProject, - }, - }; - - it('Dispatches event correctly', async () => { - const store = mockStore(mockState); - await store.dispatch(setActiveProject(otherProject.uuid)); - - const firstAction = store.getActions()[0]; - expect(firstAction.type).toEqual(PROJECTS_SET_ACTIVE); - expect(firstAction).toMatchSnapshot(); - }); - - it('Does not dispatch if project is the same', async () => { - const store = mockStore(mockState); - await store.dispatch(setActiveProject(activeProject.uuid)); - - expect(store.getActions().length).toEqual(0); - }); -}); diff --git a/src/__test__/redux/actions/projects/updateProject.test.js b/src/__test__/redux/actions/projects/updateProject.test.js deleted file mode 100644 index 2ccd99d78f..0000000000 --- a/src/__test__/redux/actions/projects/updateProject.test.js +++ /dev/null @@ -1,47 +0,0 @@ -import configureStore from 'redux-mock-store'; -import thunk from 'redux-thunk'; -import updateProject from 'redux/actions/projects/updateProject'; -import initialState, { projectTemplate } from 'redux/reducers/projects/initialState'; - -import { PROJECTS_UPDATE } from 'redux/actionTypes/projects'; - -const mockStore = configureStore([thunk]); - -const mockUuid = 'abc123'; - -const mockProject = { - ...projectTemplate, - name: 'test project', - uuid: mockUuid, - createdDate: '01-01-2021', - lastModified: '01-01-2021', -}; - -const updatedProject = { - ...mockProject, - name: 'updated name', - lastModified: '02-01-2021', -}; - -const mockState = { - projects: { - ...initialState, - ids: [...initialState.ids, mockProject.uuid], - [mockProject.uuid]: mockProject, - }, -}; - -let store = null; - -describe('updateProject action', () => { - beforeEach(() => { - store = mockStore(mockState); - }); - - it('Dispatches event correctly', async () => { - await store.dispatch(updateProject(mockUuid, updatedProject)); - - const firstAction = store.getActions()[0]; - expect(firstAction.type).toEqual(PROJECTS_UPDATE); - }); -}); diff --git a/src/__test__/redux/actions/samples/__snapshots__/createSample.test.js.snap b/src/__test__/redux/actions/samples/__snapshots__/createSample.test.js.snap index d8233ad80e..64e7b31c7a 100644 --- a/src/__test__/redux/actions/samples/__snapshots__/createSample.test.js.snap +++ b/src/__test__/redux/actions/samples/__snapshots__/createSample.test.js.snap @@ -29,6 +29,7 @@ Array [ "complete": false, "createdDate": "2020-01-01T00:00:00.000Z", "error": false, + "experimentId": "exp234", "fileNames": Array [], "files": Object { "barcodes.tsv.gz": Object { @@ -50,7 +51,6 @@ Array [ "lastModified": "2020-01-01T00:00:00.000Z", "metadata": Object {}, "name": "test sample", - "projectUuid": "qwe234", "type": "10X Chromium", "uuid": "abc123", }, @@ -61,6 +61,7 @@ Array [ "complete": false, "createdDate": "2020-01-01T00:00:00.000Z", "error": false, + "experimentId": "exp234", "fileNames": Array [], "files": Object { "barcodes.tsv.gz": Object { @@ -82,7 +83,6 @@ Array [ "lastModified": "2020-01-01T00:00:00.000Z", "metadata": Object {}, "name": "test sample", - "projectUuid": "qwe234", "type": "10X Chromium", "uuid": "abc123", }, @@ -108,6 +108,7 @@ Array [ "complete": false, "createdDate": "2020-01-01T00:00:00.000Z", "error": false, + "experimentId": "exp234", "fileNames": Array [], "files": Object { "matrix.tsv.gz": Object { @@ -119,7 +120,6 @@ Array [ "lastModified": "2020-01-01T00:00:00.000Z", "metadata": Object {}, "name": "test sample", - "projectUuid": "qwe234", "type": "10X Chromium", "uuid": "abc123", }, @@ -130,6 +130,7 @@ Array [ "complete": false, "createdDate": "2020-01-01T00:00:00.000Z", "error": false, + "experimentId": "exp234", "fileNames": Array [], "files": Object { "matrix.tsv.gz": Object { @@ -141,7 +142,6 @@ Array [ "lastModified": "2020-01-01T00:00:00.000Z", "metadata": Object {}, "name": "test sample", - "projectUuid": "qwe234", "type": "10X Chromium", "uuid": "abc123", }, diff --git a/src/__test__/redux/actions/samples/__snapshots__/loadSamples.test.js.snap b/src/__test__/redux/actions/samples/__snapshots__/loadSamples.test.js.snap index 18b391df18..ecc9a3fe98 100644 --- a/src/__test__/redux/actions/samples/__snapshots__/loadSamples.test.js.snap +++ b/src/__test__/redux/actions/samples/__snapshots__/loadSamples.test.js.snap @@ -14,6 +14,7 @@ Object { "samples": Object { "e03ef6ea-5014-4e57-aecd-59964ac9172c": Object { "createdDate": "2021-12-07 17:36:27.773+00", + "experimentId": "1234", "fileNames": Array [ "matrix.mtx.gz", "barcodes.tsv.gz", @@ -51,7 +52,6 @@ Object { "timePoint": "BL", }, "name": "BLp7", - "projectUuid": "1234", "type": "10X Chromium", "uuid": "e03ef6ea-5014-4e57-aecd-59964ac9172c", }, diff --git a/src/__test__/redux/actions/samples/createSample.test.js b/src/__test__/redux/actions/samples/createSample.test.js index 8810837055..db00081996 100644 --- a/src/__test__/redux/actions/samples/createSample.test.js +++ b/src/__test__/redux/actions/samples/createSample.test.js @@ -6,7 +6,6 @@ import { v4 as uuidv4 } from 'uuid'; import createSample from 'redux/actions/samples/createSample'; import initialSampleState from 'redux/reducers/samples/initialState'; -import initialProjectState, { projectTemplate } from 'redux/reducers/projects/initialState'; import initialExperimentState, { experimentTemplate } from 'redux/reducers/experiments/initialState'; import { @@ -29,18 +28,10 @@ uuidv4.mockImplementation(() => sampleUuid); const sampleName = 'test sample'; describe('createSample action', () => { - const projectUuid = 'qwe234'; const experimentId = 'exp234'; const mockType = '10X Chromium'; - const mockProject = { - ...projectTemplate, - name: 'test project', - uuid: projectUuid, - experiments: [experimentId], - }; - const mockExperiment = { ...experimentTemplate, name: 'Experiment 1', @@ -52,11 +43,7 @@ describe('createSample action', () => { experiments: { ...initialExperimentState, [experimentId]: mockExperiment, - }, - projects: { - ...initialProjectState, - ids: [projectUuid], - [projectUuid]: mockProject, + ids: [mockExperiment.id], }, }; @@ -75,7 +62,7 @@ describe('createSample action', () => { it('Works correctly with one file being uploaded', async () => { fetchMock.mockResponse(JSON.stringify({}), { url: 'mockedUrl', status: 200 }); - const newUuid = await store.dispatch(createSample(projectUuid, sampleName, mockType, ['matrix.tsv.gz'])); + const newUuid = await store.dispatch(createSample(experimentId, sampleName, mockType, ['matrix.tsv.gz'])); // Returns a new sampleUuid expect(newUuid).toEqual(sampleUuid); @@ -84,7 +71,7 @@ describe('createSample action', () => { 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(fetchMockFirstCall[0]).toEqual(`http://localhost:3000/v2/experiments/${mockExperiment.id}/samples/${sampleUuid}`); expect(fetchMethod).toEqual('POST'); expect(JSON.parse(fetchBody)).toMatchSnapshot(); @@ -98,7 +85,7 @@ describe('createSample action', () => { it('Works correctly with many files being uploaded', async () => { fetchMock.mockResponse(JSON.stringify({}), { url: 'mockedUrl', status: 200 }); - const newUuid = await store.dispatch(createSample(projectUuid, sampleName, mockType, ['matrix.tsv.gz', 'features.tsv.gz', 'barcodes.tsv.gz'])); + const newUuid = await store.dispatch(createSample(experimentId, sampleName, mockType, ['matrix.tsv.gz', 'features.tsv.gz', 'barcodes.tsv.gz'])); // Returns a new sampleUuid expect(newUuid).toEqual(sampleUuid); @@ -107,7 +94,7 @@ describe('createSample action', () => { 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(fetchMockFirstCall[0]).toEqual(`http://localhost:3000/v2/experiments/${mockExperiment.id}/samples/${sampleUuid}`); expect(fetchMethod).toEqual('POST'); expect(JSON.parse(fetchBody)).toMatchSnapshot(); @@ -123,7 +110,7 @@ describe('createSample action', () => { await expect( store.dispatch( - createSample(projectUuid, sampleName, mockType, ['matrix.tsv.gz']), + createSample(experimentId, sampleName, mockType, ['matrix.tsv.gz']), ), ).rejects.toThrow(endUserMessages.ERROR_CREATING_SAMPLE); @@ -138,7 +125,7 @@ describe('createSample action', () => { await expect( store.dispatch( - createSample(projectUuid, sampleName, 'unrecognizable type', ['matrix.tsv.gz', 'features.tsv.gz', 'barcodes.tsv.gz']), + createSample(experimentId, sampleName, 'unrecognizable type', ['matrix.tsv.gz', 'features.tsv.gz', 'barcodes.tsv.gz']), ), ).rejects.toThrow('Sample technology unrecognizable type is not recognized'); }); diff --git a/src/__test__/redux/actions/samples/deleteSamples.test.js b/src/__test__/redux/actions/samples/deleteSamples.test.js index 16718c0d55..ff3a1c3e63 100644 --- a/src/__test__/redux/actions/samples/deleteSamples.test.js +++ b/src/__test__/redux/actions/samples/deleteSamples.test.js @@ -4,7 +4,7 @@ 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 initialExperimentState, { experimentTemplate } from 'redux/reducers/experiments/initialState'; import { SAMPLES_DELETE, SAMPLES_SAVED, SAMPLES_SAVING, SAMPLES_ERROR, @@ -21,14 +21,14 @@ const mockSample = { ...sampleTemplate, name: 'test sample', uuid: mockSampleUuid, - projectUuid: mockExperimentId, + experimentId: mockExperimentId, }; -const mockProject = { - ...projectTemplate, - name: 'test project', +const mockExperiment = { + ...experimentTemplate, + name: 'test experiment', + id: mockExperimentId, samples: [mockSampleUuid], - experiments: [mockExperimentId], }; const initialState = { @@ -36,10 +36,10 @@ const initialState = { ...initialSampleState, [mockSampleUuid]: mockSample, }, - projects: { - ...initialProjectState, + experiments: { + ...initialExperimentState, ids: [mockExperimentId], - [mockExperimentId]: mockProject, + [mockExperimentId]: mockExperiment, }, }; diff --git a/src/__test__/redux/reducers/__snapshots__/experimentsReducer.test.js.snap b/src/__test__/redux/reducers/__snapshots__/experimentsReducer.test.js.snap index 63a0a78d96..060606324c 100644 --- a/src/__test__/redux/reducers/__snapshots__/experimentsReducer.test.js.snap +++ b/src/__test__/redux/reducers/__snapshots__/experimentsReducer.test.js.snap @@ -3,19 +3,16 @@ exports[`experimentsReducer Adds new sampleId when sample is created 1`] = ` Object { "experiment-1": Object { - "createdDate": "01-01-2021", + "createdAt": "2021-01-01", "description": "this is a test description", "id": "experiment-1", - "meta": Object { - "organism": null, - "type": "10x", - }, + "metadataKeys": Array [], "name": "experiment 1", "notifyByEmail": true, - "projectUuid": "experiment-1", "sampleIds": Array [ "testSampleId", ], + "updatedAt": "2022-01-17", }, "ids": Array [ "experiment-1", @@ -31,20 +28,136 @@ Object { exports[`experimentsReducer Adds new sampleId when sample is created and we already have one sample 1`] = ` Object { "experiment-1": Object { - "createdDate": "01-01-2021", + "createdAt": "2021-01-01", "description": "this is a test description", "id": "experiment-1", - "meta": Object { - "organism": null, - "type": "10x", - }, + "metadataKeys": Array [], "name": "experiment 1", "notifyByEmail": true, - "projectUuid": "experiment-1", "sampleIds": Array [ "testSampleId", "testAnotherSampleId", ], + "updatedAt": "2022-01-17", + }, + "ids": Array [ + "experiment-1", + ], + "meta": Object { + "error": false, + "loading": false, + "saving": false, + }, +} +`; + +exports[`experimentsReducer Correctly creates project metadata 1`] = ` +Object { + "[object Object]": Object { + "createdAt": "2021-01-01", + "description": "this is a test description", + "id": "experiment-1", + "metadataKeys": Array [], + "name": "experiment 1", + "notifyByEmail": true, + "sampleIds": Array [ + "testSampleId", + ], + "updatedAt": "2022-01-17", + }, + "experiment-1": Object { + "createdAt": "2021-01-01", + "description": "this is a test description", + "id": "experiment-1", + "metadataKeys": Array [ + "metadata-test", + ], + "name": "experiment 1", + "notifyByEmail": true, + "sampleIds": Array [ + "testSampleId", + ], + "updatedAt": "2022-01-17", + }, + "ids": Array [ + "experiment-1", + ], + "meta": Object { + "error": false, + "loading": false, + "saving": false, + }, +} +`; + +exports[`experimentsReducer Correctly deletes project metadata 1`] = ` +Object { + "[object Object]": Object { + "createdAt": "2021-01-01", + "description": "this is a test description", + "id": "experiment-1", + "metadataKeys": Array [ + "metadata-old", + ], + "name": "experiment 1", + "notifyByEmail": true, + "sampleIds": Array [ + "testSampleId", + ], + "updatedAt": "2022-01-17", + }, + "experiment-1": Object { + "createdAt": "2021-01-01", + "description": "this is a test description", + "id": "experiment-1", + "metadataKeys": Array [], + "name": "experiment 1", + "notifyByEmail": true, + "sampleIds": Array [ + "testSampleId", + ], + "updatedAt": "2022-01-17", + }, + "ids": Array [ + "experiment-1", + ], + "meta": Object { + "error": false, + "loading": false, + "saving": false, + }, +} +`; + +exports[`experimentsReducer Correctly updates project metadata 1`] = ` +Object { + "[object Object]": Object { + "createdAt": "2021-01-01", + "description": "this is a test description", + "id": "experiment-1", + "metadataKeys": Array [ + "metadata-old", + ], + "name": "experiment 1", + "notifyByEmail": true, + "sampleIds": Array [ + "testSampleId", + ], + "updatedAt": "2022-01-17", + }, + "experiment-1": Object { + "createdAt": "2021-01-01", + "description": "this is a test description", + "id": "experiment-1", + "metadataKeys": Array [ + "metadata-new", + ], + "name": "experiment 1", + "notifyByEmail": true, + "sampleIds": Array [ + "testSampleId", + ], + "updatedAt": "2022-01-17", }, "ids": Array [ "experiment-1", @@ -60,17 +173,14 @@ Object { exports[`experimentsReducer Deletes an experiment correctly 1`] = ` Object { "experiment-1": Object { - "createdDate": "01-01-2021", + "createdAt": "2021-01-01", "description": "this is a test description", "id": "experiment-1", - "meta": Object { - "organism": null, - "type": "10x", - }, + "metadataKeys": Array [], "name": "experiment 1", "notifyByEmail": true, - "projectUuid": "experiment-1", "sampleIds": Array [], + "updatedAt": "2022-01-17", }, "ids": Array [ "experiment-1", @@ -83,20 +193,17 @@ Object { } `; -exports[`experimentsReducer Deletes samples in v2 correctly 1`] = ` +exports[`experimentsReducer Deletes samples correctly 1`] = ` Object { "experiment-1": Object { - "createdDate": "01-01-2021", + "createdAt": "2021-01-01", "description": "this is a test description", "id": "experiment-1", - "meta": Object { - "organism": null, - "type": "10x", - }, + "metadataKeys": Array [], "name": "experiment 1", "notifyByEmail": true, - "projectUuid": "experiment-1", "sampleIds": Array [], + "updatedAt": "2022-01-17", }, "ids": Array [ "experiment-1", @@ -113,6 +220,7 @@ exports[`experimentsReducer Error state inserts error correctly 1`] = ` Object { "ids": Array [], "meta": Object { + "activeExperimentId": null, "error": "Error message", "loading": false, "saving": false, @@ -123,22 +231,24 @@ Object { exports[`experimentsReducer Inserts a new experiment correctly 1`] = ` Object { "experiment-1": Object { - "createdDate": "01-01-2021", + "createdAt": "2021-01-01", "description": "this is a test description", "id": "experiment-1", "meta": Object { "organism": null, "type": "10x", }, + "metadataKeys": Array [], "name": "experiment 1", "notifyByEmail": true, - "projectUuid": "experiment-1", "sampleIds": Array [], + "updatedAt": null, }, "ids": Array [ "experiment-1", ], "meta": Object { + "activeExperimentId": "experiment-1", "error": false, "loading": false, "saving": false, @@ -150,6 +260,7 @@ exports[`experimentsReducer Loading state changes meta state 1`] = ` Object { "ids": Array [], "meta": Object { + "activeExperimentId": null, "error": false, "loading": true, "saving": false, @@ -160,22 +271,20 @@ Object { exports[`experimentsReducer Loads an experiment correctly 1`] = ` Object { "experiment-1": Object { - "createdDate": "01-01-2021", + "createdAt": "2021-01-01", "description": "this is a test description", "id": "experiment-1", - "meta": Object { - "organism": null, - "type": "10x", - }, + "metadataKeys": Array [], "name": "experiment 1", "notifyByEmail": true, - "projectUuid": "experiment-1", "sampleIds": Array [], + "updatedAt": "2022-01-17", }, "ids": Array [ "experiment-1", ], "meta": Object { + "activeExperimentId": "experiment-1", "error": false, "loading": false, "saving": false, @@ -183,39 +292,68 @@ Object { } `; -exports[`experimentsReducer Loads experiment correctly on existing state 1`] = ` +exports[`experimentsReducer Loads experiments correctly 1`] = ` Object { "experiment-1": Object { - "createdDate": "01-01-2021", + "createdAt": "2021-01-01", "description": "this is a test description", "id": "experiment-1", - "meta": Object { - "organism": null, - "type": "10x", - }, + "metadataKeys": Array [], "name": "experiment 1", "notifyByEmail": true, - "projectUuid": "experiment-1", "sampleIds": Array [], + "updatedAt": "2022-01-17", }, "experiment-2": Object { - "createdDate": "01-01-2021", + "createdAt": "2021-01-01", "description": "this is a test description", "id": "experiment-2", - "meta": Object { - "organism": null, - "type": "10x", - }, + "metadataKeys": Array [], "name": "experiment 2", "notifyByEmail": true, - "projectUuid": "experiment-2", "sampleIds": Array [], + "updatedAt": "2022-01-17", }, "ids": Array [ "experiment-1", "experiment-2", ], "meta": Object { + "activeExperimentId": "experiment-1", + "error": false, + "loading": false, + "saving": false, + }, +} +`; + +exports[`experimentsReducer Overwrites existing state on loading experiments 1`] = ` +Object { + "experiment-1": Object { + "createdAt": "2021-01-01", + "description": "this is a test description", + "id": "experiment-1", + "metadataKeys": Array [], + "name": "experiment 1", + "notifyByEmail": true, + "sampleIds": Array [], + "updatedAt": "2022-01-17", + }, + "experiment-2": Object { + "createdAt": "2021-01-01", + "description": "this is a test description", + "id": "experiment-2", + "metadataKeys": Array [], + "name": "experiment 2", + "notifyByEmail": true, + "sampleIds": Array [], + "updatedAt": "2022-01-17", + }, + "ids": Array [ + "experiment-2", + ], + "meta": Object { + "activeExperimentId": "experiment-2", "error": false, "loading": false, "saving": false, @@ -223,21 +361,42 @@ Object { } `; +exports[`experimentsReducer Sets up saving state correctly 1`] = ` +Object { + "experiment-1": Object { + "createdAt": "2021-01-01", + "description": "this is a test description", + "id": "experiment-1", + "metadataKeys": Array [], + "name": "experiment 1", + "notifyByEmail": true, + "sampleIds": Array [ + "testSampleId", + ], + "updatedAt": "2022-01-17", + }, + "ids": Array [ + "experiment-1", + ], + "meta": Object { + "error": false, + "loading": false, + "saving": true, + }, +} +`; + exports[`experimentsReducer Updates an experiment correctly 1`] = ` Object { "experiment-1": Object { - "createdDate": "01-01-2021", + "createdAt": "2021-01-01", "description": "this is a test description", "id": "experiment-1", - "lastModified": "02-01-2021", - "meta": Object { - "organism": null, - "type": "10x", - }, + "metadataKeys": Array [], "name": "updated name", "notifyByEmail": true, - "projectUuid": "experiment-1", "sampleIds": Array [], + "updatedAt": "02-01-2021", }, "ids": Array [ "experiment-1", diff --git a/src/__test__/redux/reducers/__snapshots__/projectsReducer.test.js.snap b/src/__test__/redux/reducers/__snapshots__/projectsReducer.test.js.snap deleted file mode 100644 index bcdf978915..0000000000 --- a/src/__test__/redux/reducers/__snapshots__/projectsReducer.test.js.snap +++ /dev/null @@ -1,353 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`projectsReducer Adds a new project correctly 1`] = ` -Object { - "ids": Array [ - "project-1", - "project-2", - ], - "meta": Object { - "activeProjectUuid": "project-2", - "saving": false, - }, - "project-1": Object { - "createdDate": "01-01-2021", - "description": "this is a test description", - "experiments": Array [], - "lastAnalyzed": null, - "lastModified": "01-01-2021", - "metadataKeys": Array [], - "name": "test project", - "samples": Array [], - "uuid": "project-1", - }, - "project-2": Object { - "createdDate": "01-01-2021", - "description": "This is another test description :)", - "experiments": Array [], - "lastAnalyzed": null, - "lastModified": "01-01-2021", - "metadataKeys": Array [], - "name": "test project 2", - "samples": Array [], - "uuid": "project-2", - }, -} -`; - -exports[`projectsReducer Correctly creates project metadata 1`] = ` -Object { - "[object Object]": Object { - "createdDate": "01-01-2021", - "description": "this is a test description", - "experiments": Array [], - "lastAnalyzed": null, - "lastModified": "01-01-2021", - "metadataKeys": Array [], - "name": "test project", - "samples": Array [], - "uuid": "project-1", - }, - "ids": Array [ - "project-1", - ], - "meta": Object { - "activeProjectUuid": "project-1", - }, - "project-1": Object { - "createdDate": "01-01-2021", - "description": "this is a test description", - "experiments": Array [], - "lastAnalyzed": null, - "lastModified": "01-01-2021", - "metadataKeys": Array [ - "metadata-test", - ], - "name": "test project", - "samples": Array [], - "uuid": "project-1", - }, -} -`; - -exports[`projectsReducer Correctly deletes project metadata 1`] = ` -Object { - "[object Object]": Object { - "createdDate": "01-01-2021", - "description": "this is a test description", - "experiments": Array [], - "lastAnalyzed": null, - "lastModified": "01-01-2021", - "metadataKeys": Array [ - "metadata-old", - ], - "name": "test project", - "samples": Array [], - "uuid": "project-1", - }, - "ids": Array [ - "project-1", - ], - "meta": Object { - "activeProjectUuid": "project-1", - }, - "project-1": Object { - "createdDate": "01-01-2021", - "description": "this is a test description", - "experiments": Array [], - "lastAnalyzed": null, - "lastModified": "01-01-2021", - "metadataKeys": Array [], - "name": "test project", - "samples": Array [], - "uuid": "project-1", - }, -} -`; - -exports[`projectsReducer Correctly updates project metadata 1`] = ` -Object { - "[object Object]": Object { - "createdDate": "01-01-2021", - "description": "this is a test description", - "experiments": Array [], - "lastAnalyzed": null, - "lastModified": "01-01-2021", - "metadataKeys": Array [ - "metadata-old", - ], - "name": "test project", - "samples": Array [], - "uuid": "project-1", - }, - "ids": Array [ - "project-1", - ], - "meta": Object { - "activeProjectUuid": "project-1", - }, - "project-1": Object { - "createdDate": "01-01-2021", - "description": "this is a test description", - "experiments": Array [], - "lastAnalyzed": null, - "lastModified": "01-01-2021", - "metadataKeys": Array [ - "metadata-new", - ], - "name": "test project", - "samples": Array [], - "uuid": "project-1", - }, -} -`; - -exports[`projectsReducer Deletes projects correctly 1`] = ` -Object { - "ids": Array [ - "project-1", - ], - "meta": Object { - "activeProjectUuid": "project-2", - }, - "project-1": Object { - "createdDate": "01-01-2021", - "description": "this is a test description", - "experiments": Array [], - "lastAnalyzed": null, - "lastModified": "01-01-2021", - "metadataKeys": Array [], - "name": "test project", - "samples": Array [], - "uuid": "project-1", - }, -} -`; - -exports[`projectsReducer Inserts a new project correctly 1`] = ` -Object { - "ids": Array [ - "project-1", - ], - "meta": Object { - "activeProjectUuid": "project-1", - "error": false, - "loading": true, - "saving": false, - }, - "project-1": Object { - "createdDate": "01-01-2021", - "description": "this is a test description", - "experiments": Array [], - "lastAnalyzed": null, - "lastModified": "01-01-2021", - "metadataKeys": Array [], - "name": "test project", - "samples": Array [], - "uuid": "project-1", - }, -} -`; - -exports[`projectsReducer Loads projects correctly 1`] = ` -Object { - "ids": Array [ - "project-1", - "project-2", - ], - "loading": false, - "meta": Object { - "activeProjectUuid": "project-1", - }, - "project-1": Object { - "createdDate": "01-01-2021", - "description": "this is a test description", - "experiments": Array [], - "lastAnalyzed": null, - "lastModified": "01-01-2021", - "metadataKeys": Array [], - "name": "test project", - "samples": Array [], - "uuid": "project-1", - }, - "project-2": Object { - "createdDate": "01-01-2021", - "description": "This is another test description :)", - "experiments": Array [], - "lastAnalyzed": null, - "lastModified": "01-01-2021", - "metadataKeys": Array [], - "name": "test project 2", - "samples": Array [], - "uuid": "project-2", - }, -} -`; - -exports[`projectsReducer Sets an active project correctly 1`] = ` -Object { - "ids": Array [ - "project-1", - "project-2", - ], - "meta": Object { - "activeProjectUuid": "project-2", - }, - "project-1": Object { - "createdDate": "01-01-2021", - "description": "this is a test description", - "experiments": Array [], - "lastAnalyzed": null, - "lastModified": "01-01-2021", - "metadataKeys": Array [], - "name": "test project", - "samples": Array [], - "uuid": "project-1", - }, - "project-2": Object { - "createdDate": "01-01-2021", - "description": "This is another test description :)", - "experiments": Array [], - "lastAnalyzed": null, - "lastModified": "01-01-2021", - "metadataKeys": Array [], - "name": "test project 2", - "samples": Array [], - "uuid": "project-2", - }, -} -`; - -exports[`projectsReducer Sets up saved state correctly 1`] = ` -Object { - "ids": Array [ - "project-1", - ], - "meta": Object { - "error": false, - "loading": false, - "saving": false, - }, - "project-1": Object { - "createdDate": "01-01-2021", - "description": "this is a test description", - "experiments": Array [], - "lastAnalyzed": null, - "lastModified": "01-01-2021", - "metadataKeys": Array [], - "name": "test project", - "samples": Array [], - "uuid": "project-1", - }, -} -`; - -exports[`projectsReducer Sets up saving state correctly 1`] = ` -Object { - "ids": Array [ - "project-1", - ], - "meta": Object { - "error": false, - "loading": false, - "saving": "Saving", - }, - "project-1": Object { - "createdDate": "01-01-2021", - "description": "this is a test description", - "experiments": Array [], - "lastAnalyzed": null, - "lastModified": "01-01-2021", - "metadataKeys": Array [], - "name": "test project", - "samples": Array [], - "uuid": "project-1", - }, -} -`; - -exports[`projectsReducer Stores error state correctly 1`] = ` -Object { - "ids": Array [ - "project-1", - ], - "meta": Object { - "error": "Error message", - "loading": false, - "saving": false, - }, - "project-1": Object { - "createdDate": "01-01-2021", - "description": "this is a test description", - "experiments": Array [], - "lastAnalyzed": null, - "lastModified": "01-01-2021", - "metadataKeys": Array [], - "name": "test project", - "samples": Array [], - "uuid": "project-1", - }, -} -`; - -exports[`projectsReducer Updates a project correctly 1`] = ` -Object { - "ids": Array [ - "project-1", - ], - "meta": Object { - "activeProjectUuid": "project-1", - }, - "project-1": Object { - "createdDate": "01-01-2021", - "description": "this is a test description", - "experiments": Array [], - "lastAnalyzed": null, - "lastModified": "02-01-2021", - "metadataKeys": Array [], - "name": "updated name", - "samples": Array [], - "uuid": "project-1", - }, -} -`; diff --git a/src/__test__/redux/reducers/__snapshots__/samplesReducer.test.js.snap b/src/__test__/redux/reducers/__snapshots__/samplesReducer.test.js.snap index e55a94da4b..7fe9d2725b 100644 --- a/src/__test__/redux/reducers/__snapshots__/samplesReducer.test.js.snap +++ b/src/__test__/redux/reducers/__snapshots__/samplesReducer.test.js.snap @@ -6,12 +6,12 @@ Object { "complete": false, "createdDate": "2021-01-01T14:48:00.000Z", "error": false, + "experimentId": null, "fileNames": Array [], "files": Object {}, "lastModified": "2021-01-01T14:48:00.000Z", "metadata": Object {}, "name": "test sample", - "projectUuid": null, "type": null, "uuid": "asd123", }, @@ -24,12 +24,12 @@ Object { "complete": false, "createdDate": "2021-01-02T14:48:00.000Z", "error": false, + "experimentId": null, "fileNames": Array [], "files": Object {}, "lastModified": "2021-01-02T14:48:00.000Z", "metadata": Object {}, "name": "test sample 2", - "projectUuid": null, "type": null, "uuid": "qwe234", }, @@ -42,12 +42,12 @@ Object { "complete": false, "createdDate": "2021-01-01T14:48:00.000Z", "error": false, + "experimentId": null, "fileNames": Array [], "files": Object {}, "lastModified": "2021-01-01T14:48:00.000Z", "metadata": Object {}, "name": "test sample", - "projectUuid": null, "type": null, "uuid": "asd123", }, @@ -70,12 +70,12 @@ Object { "complete": false, "createdDate": "2021-01-01T14:48:00.000Z", "error": false, + "experimentId": null, "fileNames": Array [], "files": Object {}, "lastModified": "2021-01-01T14:48:00.000Z", "metadata": Object {}, "name": "test sample", - "projectUuid": null, "type": null, "uuid": "asd123", }, @@ -108,12 +108,12 @@ Object { "complete": false, "createdDate": "2021-01-01T14:48:00.000Z", "error": false, + "experimentId": null, "fileNames": Array [], "files": Object {}, "lastModified": "2021-01-01T14:48:00.000Z", "metadata": Object {}, "name": "test sample", - "projectUuid": null, "type": null, "uuid": "asd123", }, @@ -134,6 +134,7 @@ Object { "complete": false, "createdDate": "2021-01-01T14:48:00.000Z", "error": false, + "experimentId": null, "fileNames": Array [], "files": Object {}, "lastModified": "2021-01-01T14:48:00.000Z", @@ -141,7 +142,6 @@ Object { "metadata-test": "value", }, "name": "test sample", - "projectUuid": null, "type": null, "uuid": "asd123", }, @@ -159,12 +159,12 @@ Object { "complete": false, "createdDate": "2021-01-01T14:48:00.000Z", "error": false, + "experimentId": null, "fileNames": Array [], "files": Object {}, "lastModified": "2021-01-01T14:48:00.000Z", "metadata": Object {}, "name": "test sample", - "projectUuid": null, "type": null, "uuid": "asd123", }, @@ -181,12 +181,12 @@ Object { "complete": false, "createdDate": "2021-01-02T14:48:00.000Z", "error": false, + "experimentId": null, "fileNames": Array [], "files": Object {}, "lastModified": "2021-01-02T14:48:00.000Z", "metadata": Object {}, "name": "test sample 2", - "projectUuid": null, "type": null, "uuid": "qwe234", }, @@ -199,12 +199,12 @@ Object { "complete": false, "createdDate": "2021-01-01T14:48:00.000Z", "error": false, + "experimentId": null, "fileNames": Array [], "files": Object {}, "lastModified": "2021-01-01T14:48:00.000Z", "metadata": Object {}, "name": "test sample", - "projectUuid": null, "type": null, "uuid": "asd123", }, @@ -222,12 +222,12 @@ Object { "complete": false, "createdDate": "2021-01-01T14:48:00.000Z", "error": false, + "experimentId": null, "fileNames": Array [], "files": Object {}, "lastModified": "2021-01-01T14:48:00.000Z", "metadata": Object {}, "name": "test sample", - "projectUuid": null, "type": null, "uuid": "asd123", }, @@ -245,12 +245,12 @@ Object { "complete": false, "createdDate": "2021-01-01T14:48:00.000Z", "error": false, + "experimentId": null, "fileNames": Array [], "files": Object {}, "lastModified": "2021-01-01T14:48:00.000Z", "metadata": Object {}, "name": "test sample", - "projectUuid": null, "type": null, "uuid": "asd123", }, @@ -268,12 +268,12 @@ Object { "complete": false, "createdDate": "2021-01-01T14:48:00.000Z", "error": false, + "experimentId": null, "fileNames": Array [], "files": Object {}, "lastModified": "2021-01-01T14:48:00.000Z", "metadata": Object {}, "name": "updated name", - "projectUuid": null, "type": null, "uuid": "asd123", }, @@ -291,6 +291,7 @@ Object { "complete": false, "createdDate": "2021-01-01T14:48:00.000Z", "error": false, + "experimentId": null, "fileNames": Array [ "features.tsv", ], @@ -313,7 +314,6 @@ Object { "lastModified": "newLastModified", "metadata": Object {}, "name": "test sample", - "projectUuid": null, "type": null, "uuid": "asd123", }, @@ -336,6 +336,7 @@ Object { "complete": false, "createdDate": "2021-01-01T14:48:00.000Z", "error": false, + "experimentId": null, "fileNames": Array [], "files": Object {}, "lastModified": "2021-01-01T14:48:00.000Z", @@ -343,7 +344,6 @@ Object { "metadata-test": "new-value", }, "name": "test sample", - "projectUuid": null, "type": null, "uuid": "asd123", }, diff --git a/src/__test__/redux/reducers/experimentsReducer.test.js b/src/__test__/redux/reducers/experimentsReducer.test.js index 263c5ab061..7146f649ea 100644 --- a/src/__test__/redux/reducers/experimentsReducer.test.js +++ b/src/__test__/redux/reducers/experimentsReducer.test.js @@ -1,5 +1,6 @@ -import experimentsReducer from 'redux/reducers/experiments'; import initialState, { experimentTemplate } from 'redux/reducers/experiments/initialState'; + +import experimentsReducer from 'redux/reducers/experiments'; import { sampleTemplate } from 'redux/reducers/samples/initialState'; import { @@ -9,6 +10,10 @@ import { EXPERIMENTS_UPDATED, EXPERIMENTS_ERROR, EXPERIMENTS_DELETED, + EXPERIMENTS_SAVING, + EXPERIMENTS_METADATA_CREATE, + EXPERIMENTS_METADATA_UPDATE, + EXPERIMENTS_METADATA_DELETE, } from 'redux/actionTypes/experiments'; import { SAMPLES_CREATE, SAMPLES_DELETE } from 'redux/actionTypes/samples'; @@ -17,54 +22,26 @@ describe('experimentsReducer', () => { const experimentId1 = 'experiment-1'; const experimentId2 = 'experiment-2'; - const rawExperiment1 = { - experimentId: experimentId1, - experimentName: 'experiment 1', - projectId: experimentId1, - description: 'this is a test description', - createdDate: '01-01-2021', - meta: { - organism: null, - type: '10x', - }, - sampleIds: [], - notifyByEmail: true, - }; - - const rawExperiment2 = { - experimentId: experimentId2, - experimentName: 'experiment 2', - projectId: experimentId2, - description: 'this is a test description', - createdDate: '01-01-2021', - meta: { - organism: null, - type: '10x', - }, - sampleIds: [], - notifyByEmail: true, - }; - const experiment1 = { - ...experimentTemplate, - projectUuid: experimentId1, - name: 'experiment 1', id: experimentId1, + name: 'experiment 1', description: 'this is a test description', - createdDate: '01-01-2021', sampleIds: [], - meta: experimentTemplate.meta, + metadataKeys: [], + notifyByEmail: true, + createdAt: '2021-01-01', + updatedAt: '2022-01-17', }; const experiment2 = { - ...experimentTemplate, - projectUuid: experimentId2, - name: 'experiment 2', id: experimentId2, + name: 'experiment 2', description: 'this is a test description', - createdDate: '01-01-2021', sampleIds: [], - meta: experimentTemplate.meta, + metadataKeys: [], + notifyByEmail: true, + createdAt: '2021-01-01', + updatedAt: '2022-01-17', }; const sampleId = 'testSampleId'; @@ -76,13 +53,18 @@ describe('experimentsReducer', () => { const updatedExperiment = { ...experiment1, name: 'updated name', - lastModified: '02-01-2021', + updatedAt: '02-01-2021', }; const oneExperimentState = { ...initialState, ids: [experimentId1], [experimentId1]: experiment1, + meta: { + loading: false, + saving: false, + error: false, + }, }; const twoExperimentsState = { @@ -90,20 +72,30 @@ describe('experimentsReducer', () => { ids: [experimentId1, experimentId2], [experimentId1]: experiment1, [experimentId2]: experiment2, + meta: { + loading: false, + saving: false, + error: false, + }, }; const oneExperimentWithSampleState = { ...initialState, ids: [experimentId1], [experimentId1]: experiment1WithSample, + meta: { + loading: false, + saving: false, + error: false, + }, }; const sample = { ...sampleTemplate, name: 'test sample', uuid: sampleId, - createdDate: '2021-01-01T14:48:00.000Z', - lastModified: '2021-01-01T14:48:00.000Z', + createdAt: '2021-01-01T14:48:00.000Z', + updatedAt: '2021-01-01T14:48:00.000Z', }; it('Reduces identical state on unknown action', () => expect( @@ -117,7 +109,7 @@ describe('experimentsReducer', () => { const newState = experimentsReducer(initialState, { type: EXPERIMENTS_LOADED, payload: { - experiments: [rawExperiment1], + experiments: [experiment1], }, }); @@ -126,19 +118,33 @@ describe('experimentsReducer', () => { expect(newState).toMatchSnapshot(); }); - it('Loads experiment correctly on existing state', () => { + it('Overwrites existing state on loading experiments', () => { const newState = experimentsReducer(oneExperimentState, { type: EXPERIMENTS_LOADED, payload: { - experiments: [rawExperiment2], + experiments: [experiment2], }, }); - expect(newState.ids).toEqual([experiment1.id, experiment2.id]); + expect(newState.ids).toEqual([experiment2.id]); expect(newState[experiment2.id]).toEqual(experiment2); expect(newState).toMatchSnapshot(); }); + it('Loads experiments correctly', () => { + const newState = experimentsReducer(initialState, { + type: EXPERIMENTS_LOADED, + payload: { + experiments: [ + experiment1, experiment2, + ], + }, + }); + expect(newState.ids).toEqual([experiment1.id, experiment2.id]); + expect(newState.meta.activeExperimentId).toEqual(experiment1.id); + expect(newState).toMatchSnapshot(); + }); + it('Loading state changes meta state', () => { const newState = experimentsReducer(initialState, { type: EXPERIMENTS_LOADING, @@ -161,15 +167,25 @@ describe('experimentsReducer', () => { }); it('Inserts a new experiment correctly', () => { + const createdExperimentData = { + id: experiment1.id, + name: experiment1.name, + description: experiment1.description, + createdAt: experiment1.createdAt, + }; + const newState = experimentsReducer(initialState, { type: EXPERIMENTS_CREATED, - payload: { - experiment: experiment1, - }, + payload: { experiment: createdExperimentData }, }); expect(newState.ids).toEqual([experiment1.id]); - expect(newState[experiment1.id]).toEqual(experiment1); + expect(newState[experiment1.id]).toEqual( + { + ...experimentTemplate, + ...createdExperimentData, + }, + ); expect(newState).toMatchSnapshot(); }); @@ -218,8 +234,8 @@ describe('experimentsReducer', () => { ...sampleTemplate, name: 'another test sample', uuid: 'testAnotherSampleId', - createdDate: '2021-01-01T14:48:00.000Z', - lastModified: '2021-01-01T14:48:00.000Z', + createdAt: '2021-01-01T14:48:00.000Z', + updatedAt: '2021-01-01T14:48:00.000Z', }; const newState = experimentsReducer(oneExperimentWithSampleState, { @@ -234,7 +250,26 @@ describe('experimentsReducer', () => { expect(newState).toMatchSnapshot(); }); - it('Deletes samples in v2 correctly', () => { + it('Sets up saving state correctly', () => { + const newState = experimentsReducer({ + ...oneExperimentWithSampleState, + meta: { + ...oneExperimentWithSampleState.meta, + loading: false, + saving: false, + error: true, + }, + }, { + type: EXPERIMENTS_SAVING, + }); + + expect(newState.meta.error).toBe(false); + expect(newState.meta.loading).toBe(false); + expect(newState.meta.saving).toBe(true); + expect(newState).toMatchSnapshot(); + }); + + it('Deletes samples correctly', () => { const newState = experimentsReducer(oneExperimentWithSampleState, { type: SAMPLES_DELETE, payload: { @@ -246,4 +281,73 @@ describe('experimentsReducer', () => { expect(newState[experiment1.id].sampleIds).toHaveLength(0); expect(newState).toMatchSnapshot(); }); + + it('Correctly creates project metadata', () => { + const newMetadataKey = 'metadata-test'; + + const stateWithMetadata = { + ...oneExperimentWithSampleState, + [oneExperimentWithSampleState[experiment1.id]]: { + ...oneExperimentWithSampleState[experiment1.id], + metadataKeys: [], + }, + }; + + const newState = experimentsReducer(stateWithMetadata, { + type: EXPERIMENTS_METADATA_CREATE, + payload: { + key: newMetadataKey, + experimentId: experiment1.id, + }, + }); + + expect(newState[experiment1.id].metadataKeys).toEqual([newMetadataKey]); + expect(newState).toMatchSnapshot(); + }); + + it('Correctly updates project metadata', () => { + const oldMetadataKey = 'metadata-old'; + const newMetadataKey = 'metadata-new'; + const stateWithMetadata = { + ...oneExperimentWithSampleState, + [oneExperimentWithSampleState[experiment1.id]]: { + ...oneExperimentWithSampleState[experiment1.id], + metadataKeys: [oldMetadataKey], + }, + }; + + const newState = experimentsReducer(stateWithMetadata, { + type: EXPERIMENTS_METADATA_UPDATE, + payload: { + oldKey: oldMetadataKey, + newKey: newMetadataKey, + experimentId: experiment1.id, + }, + }); + + expect(newState[experiment1.id].metadataKeys).toEqual([newMetadataKey]); + expect(newState).toMatchSnapshot(); + }); + + it('Correctly deletes project metadata', () => { + const metadataKey = 'metadata-old'; + const stateWithMetadata = { + ...oneExperimentWithSampleState, + [oneExperimentWithSampleState[experiment1.id]]: { + ...oneExperimentWithSampleState[experiment1.id], + metadataKeys: [metadataKey], + }, + }; + + const newState = experimentsReducer(stateWithMetadata, { + type: EXPERIMENTS_METADATA_DELETE, + payload: { + key: metadataKey, + experimentId: experiment1.id, + }, + }); + + expect(newState[experiment1.id].metadataKeys).toEqual([]); + expect(newState).toMatchSnapshot(); + }); }); diff --git a/src/__test__/redux/reducers/projects/__snapshots__/samplesCreate.test.js.snap b/src/__test__/redux/reducers/projects/__snapshots__/samplesCreate.test.js.snap deleted file mode 100644 index 2c8def3c3d..0000000000 --- a/src/__test__/redux/reducers/projects/__snapshots__/samplesCreate.test.js.snap +++ /dev/null @@ -1,49 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`samplesCreate returns correct state if previous state was initial 1`] = ` -Object { - "ids": Array [ - "project-1", - ], - "meta": Object { - "activeProjectUuid": "project-1", - }, - "project-1": Object { - "createdDate": "01-01-2021", - "description": "this is a test description", - "experiments": Array [], - "lastAnalyzed": null, - "lastModified": "01-01-2021", - "metadataKeys": Array [], - "name": "test project", - "samples": Array [ - "uuid", - ], - "uuid": "project-1", - }, -} -`; - -exports[`samplesCreate returns correct state when project already had a sample 1`] = ` -Object { - "ids": Array [ - "project-1", - ], - "meta": Object { - "activeProjectUuid": "project-1", - }, - "project-1": Object { - "createdDate": "01-01-2021", - "description": "this is a test description", - "experiments": Array [], - "lastAnalyzed": null, - "lastModified": "01-01-2021", - "metadataKeys": Array [], - "name": "test project", - "samples": Array [ - "uuid", - ], - "uuid": "project-1", - }, -} -`; diff --git a/src/__test__/redux/reducers/projects/samplesCreate.test.js b/src/__test__/redux/reducers/projects/samplesCreate.test.js deleted file mode 100644 index aa90feddd9..0000000000 --- a/src/__test__/redux/reducers/projects/samplesCreate.test.js +++ /dev/null @@ -1,51 +0,0 @@ -import _ from 'lodash'; - -import samplesCreateReducer from 'redux/reducers/projects/samplesCreate'; - -import { sampleTemplate } from 'redux/reducers/samples/initialState'; -import initialState, { projectTemplate } from 'redux/reducers/projects/initialState'; - -const projectUuid = 'project-1'; - -const newSample = { - ...sampleTemplate, - name: 'sampleName', - uuid: 'uuid', - projectUuid, - type: '10x', -}; - -const project = { - ...projectTemplate, - name: 'test project', - uuid: projectUuid, - description: 'this is a test description', - createdDate: '01-01-2021', - lastModified: '01-01-2021', -}; - -const oneProjectState = { - ...initialState, - ids: [...initialState.ids, projectUuid], - meta: { - activeProjectUuid: projectUuid, - }, - [project.uuid]: project, -}; - -describe('samplesCreate', () => { - it('returns correct state if previous state was initial', () => { - const newState = samplesCreateReducer(oneProjectState, { payload: { sample: newSample } }); - - expect(newState).toMatchSnapshot(); - }); - - it('returns correct state when project already had a sample', () => { - const projectWithSampleState = _.cloneDeep(oneProjectState); - projectWithSampleState[projectUuid].samples.push('oldSampleUuid'); - - const newState = samplesCreateReducer(oneProjectState, { payload: { sample: newSample } }); - - expect(newState).toMatchSnapshot(); - }); -}); diff --git a/src/__test__/redux/reducers/projectsReducer.test.js b/src/__test__/redux/reducers/projectsReducer.test.js deleted file mode 100644 index 1f54a0139f..0000000000 --- a/src/__test__/redux/reducers/projectsReducer.test.js +++ /dev/null @@ -1,288 +0,0 @@ -import projectsReducer from 'redux/reducers/projects'; -import initialState, { projectTemplate } from 'redux/reducers/projects/initialState'; - -import { - PROJECTS_CREATE, - PROJECTS_UPDATE, - PROJECTS_SET_ACTIVE, - PROJECTS_DELETE, - PROJECTS_SAVING, - PROJECTS_SAVED, - PROJECTS_ERROR, - PROJECTS_METADATA_CREATE, - PROJECTS_METADATA_UPDATE, - PROJECTS_METADATA_DELETE, - PROJECTS_LOADED, -} from 'redux/actionTypes/projects'; - -describe('projectsReducer', () => { - const projectUuid1 = 'project-1'; - const projectUuid2 = 'project-2'; - - const project1 = { - ...projectTemplate, - name: 'test project', - uuid: projectUuid1, - description: 'this is a test description', - createdDate: '01-01-2021', - lastModified: '01-01-2021', - }; - - const project2 = { - ...projectTemplate, - name: 'test project 2', - description: 'This is another test description :)', - uuid: projectUuid2, - createdDate: '01-01-2021', - lastModified: '01-01-2021', - }; - - const updatedProject1 = { - ...project1, - name: 'updated name', - lastModified: '02-01-2021', - }; - - const oneProjectState = { - ...initialState, - ids: [...initialState.ids, project1.uuid], - meta: { - activeProjectUuid: project1.uuid, - }, - [project1.uuid]: project1, - }; - - const twoProjectsState = { - ...oneProjectState, - ids: [...oneProjectState.ids, project2.uuid], - meta: { - activeProjectUuid: project2.uuid, - }, - [project2.uuid]: project2, - }; - - it('Reduces identical state on unknown action', () => expect( - projectsReducer(undefined, { - action: 'well/this/is/not/a/valid/action', - payload: {}, - }), - ).toEqual(initialState)); - - it('Inserts a new project correctly', () => { - const newState = projectsReducer(initialState, { - type: PROJECTS_CREATE, - payload: { - project: project1, - }, - }); - - expect(newState.ids).toEqual([project1.uuid]); - expect(newState.meta.activeProjectUuid).toEqual(project1.uuid); - expect(newState[project1.uuid]).toEqual(project1); - expect(newState).toMatchSnapshot(); - }); - - it('Adds a new project correctly', () => { - const newState = projectsReducer(oneProjectState, { - type: PROJECTS_CREATE, - payload: { - project: project2, - }, - }); - - expect(newState.ids).toEqual([project1.uuid, project2.uuid]); - expect(newState.meta.activeProjectUuid).toEqual(project2.uuid); - expect(newState[project1.uuid]).toEqual(project1); - expect(newState[project2.uuid]).toEqual(project2); - expect(newState).toMatchSnapshot(); - }); - - it('Loads projects correctly', () => { - const newState = projectsReducer(initialState, { - type: PROJECTS_LOADED, - payload: { - projects: [ - project1, project2, - ], - ids: [project1.uuid, project2.uuid], - }, - }); - expect(newState.ids).toEqual([project1.uuid, project2.uuid]); - expect(newState.meta.activeProjectUuid).toEqual(project1.uuid); - expect(newState).toMatchSnapshot(); - }); - - it('Updates a project correctly', () => { - const newState = projectsReducer(oneProjectState, { - type: PROJECTS_UPDATE, - payload: { - projectUuid: projectUuid1, - project: updatedProject1, - }, - }); - - expect(newState.ids).toEqual(oneProjectState.ids); - expect(newState.meta.activeProjectUuid).toEqual(oneProjectState.meta.activeProjectUuid); - expect(newState[project1.uuid]).toEqual(updatedProject1); - expect(newState).toMatchSnapshot(); - }); - - it('Sets an active project correctly', () => { - const newState = projectsReducer(twoProjectsState, { - type: PROJECTS_SET_ACTIVE, - payload: { - projectUuid: project2.uuid, - }, - }); - - expect(newState.ids).toEqual(twoProjectsState.ids); - expect(newState.meta.activeProjectUuid).toEqual(project2.uuid); - expect(newState).toMatchSnapshot(); - }); - - it('Deletes projects correctly', () => { - const newState = projectsReducer(twoProjectsState, { - type: PROJECTS_DELETE, - payload: { projectUuid: projectUuid2 }, - }); - - expect(newState.ids).toEqual([project1.uuid]); - expect(newState[project2.uuid]).toBeUndefined(); - expect(newState).toMatchSnapshot(); - }); - - it('Correctly creates project metadata', () => { - const newMetadataKey = 'metadata-test'; - - const stateWithMetadata = { - ...oneProjectState, - [oneProjectState[project1.uuid]]: { - ...oneProjectState[project1.uuid], - metadataKeys: [], - }, - }; - - const newState = projectsReducer(stateWithMetadata, { - type: PROJECTS_METADATA_CREATE, - payload: { - key: newMetadataKey, - projectUuid: projectUuid1, - }, - }); - - expect(newState[project1.uuid].metadataKeys).toEqual([newMetadataKey]); - expect(newState).toMatchSnapshot(); - }); - - it('Correctly updates project metadata', () => { - const oldMetadataKey = 'metadata-old'; - const newMetadataKey = 'metadata-new'; - - const stateWithMetadata = { - ...oneProjectState, - [oneProjectState[project1.uuid]]: { - ...oneProjectState[project1.uuid], - metadataKeys: [oldMetadataKey], - }, - }; - - const newState = projectsReducer(stateWithMetadata, { - type: PROJECTS_METADATA_UPDATE, - payload: { - oldKey: oldMetadataKey, - newKey: newMetadataKey, - projectUuid: projectUuid1, - }, - }); - - expect(newState[project1.uuid].metadataKeys).toEqual([newMetadataKey]); - expect(newState).toMatchSnapshot(); - }); - - it('Correctly deletes project metadata', () => { - const metadataKey = 'metadata-old'; - - const stateWithMetadata = { - ...oneProjectState, - [oneProjectState[project1.uuid]]: { - ...oneProjectState[project1.uuid], - metadataKeys: [metadataKey], - }, - }; - - const newState = projectsReducer(stateWithMetadata, { - type: PROJECTS_METADATA_DELETE, - payload: { - key: metadataKey, - projectUuid: projectUuid1, - }, - }); - - expect(newState[project1.uuid].metadataKeys).toEqual([]); - expect(newState).toMatchSnapshot(); - }); - - it('Sets up saving state correctly', () => { - const savingMsg = 'Saving'; - - const newState = projectsReducer({ - ...oneProjectState, - meta: { - ...oneProjectState[projectUuid1].meta, - loading: false, - saving: savingMsg, - error: true, - }, - }, { - type: PROJECTS_SAVING, - payload: { message: savingMsg }, - }); - - expect(newState.meta.error).toBe(false); - expect(newState.meta.loading).toBe(false); - expect(newState.meta.saving).toBe(savingMsg); - expect(newState).toMatchSnapshot(); - }); - - it('Sets up saved state correctly', () => { - const newState = projectsReducer({ - ...oneProjectState, - meta: { - ...oneProjectState[projectUuid1].meta, - loading: false, - saving: true, - error: false, - }, - }, { type: PROJECTS_SAVED }); - - expect(newState.meta.error).toBe(false); - expect(newState.meta.loading).toBe(false); - expect(newState.meta.saving).toBe(false); - expect(newState).toMatchSnapshot(); - }); - - it('Stores error state correctly', () => { - const errMsg = 'Error message'; - - const newState = projectsReducer({ - ...oneProjectState, - meta: { - ...oneProjectState[projectUuid1].meta, - loading: false, - saving: true, - error: false, - }, - }, { - type: PROJECTS_ERROR, - payload: { - error: errMsg, - }, - }); - - expect(newState.meta.error).not.toBe(false); - expect(newState.meta.error).toBe(errMsg); - expect(newState.meta.loading).toBe(false); - expect(newState.meta.saving).toBe(false); - expect(newState).toMatchSnapshot(); - }); -}); diff --git a/src/__test__/redux/reducers/samples/__snapshots__/samplesCreate.test.js.snap b/src/__test__/redux/reducers/samples/__snapshots__/samplesCreate.test.js.snap index 812cacc02b..a6f94f76cc 100644 --- a/src/__test__/redux/reducers/samples/__snapshots__/samplesCreate.test.js.snap +++ b/src/__test__/redux/reducers/samples/__snapshots__/samplesCreate.test.js.snap @@ -11,12 +11,12 @@ Object { "complete": false, "createdDate": null, "error": false, + "experimentId": "experimentId", "fileNames": Array [], "files": Object {}, "lastModified": null, "metadata": Object {}, "name": "oldSampleName", - "projectUuid": "projectUuid", "type": "10x", "uuid": "oldUuid", }, @@ -24,12 +24,12 @@ Object { "complete": false, "createdDate": null, "error": false, + "experimentId": "experimentId", "fileNames": Array [], "files": Object {}, "lastModified": null, "metadata": Object {}, "name": "sampleName", - "projectUuid": "projectUuid", "type": "10x", "uuid": "uuid", }, @@ -47,12 +47,12 @@ Object { "complete": false, "createdDate": null, "error": false, + "experimentId": "experimentId", "fileNames": Array [], "files": Object {}, "lastModified": null, "metadata": Object {}, "name": "sampleName", - "projectUuid": "projectUuid", "type": "10x", "uuid": "uuid", }, diff --git a/src/__test__/redux/reducers/samples/samplesCreate.test.js b/src/__test__/redux/reducers/samples/samplesCreate.test.js index dd3cf1e18b..7b9d5de431 100644 --- a/src/__test__/redux/reducers/samples/samplesCreate.test.js +++ b/src/__test__/redux/reducers/samples/samplesCreate.test.js @@ -2,13 +2,13 @@ import samplesCreateReducer from 'redux/reducers/samples/samplesCreate'; import initialState, { sampleTemplate } from 'redux/reducers/samples/initialState'; -const projectUuid = 'projectUuid'; +const experimentId = 'experimentId'; const newSample = { ...sampleTemplate, name: 'sampleName', uuid: 'uuid', - projectUuid, + experimentId, type: '10x', }; @@ -24,7 +24,7 @@ describe('samplesCreate', () => { ...sampleTemplate, name: 'oldSampleName', uuid: 'oldUuid', - projectUuid, + experimentId, type: '10x', }; diff --git a/src/__test__/test-utils/constants.js b/src/__test__/test-utils/constants.js index b5757d4a97..43bbe90dae 100644 --- a/src/__test__/test-utils/constants.js +++ b/src/__test__/test-utils/constants.js @@ -4,7 +4,6 @@ export default { PROJECT_WITHOUT_SAMPLE_UUID: '4761594b-mock-test-ba89-c2c812d39bb5', EXPERIMENT_NAME: 'Test Experiment', PROJECT_ID: 'test24b6-8600-test-mock-63822d2fmock', - PROJECT_NAME: 'Mock project', SAMPLE_ID: 'test9188-d682-test-mock-cb6d644cmock', API_ENDPOINT: /^http?:\/\/localhost:3000.*$/, S3_ENDPOINT: 'http://mock.s3.amazonaws.com', diff --git a/src/__test__/test-utils/mockData/mockProjects.js b/src/__test__/test-utils/mockData/mockProjects.js deleted file mode 100644 index 5e87b415f6..0000000000 --- a/src/__test__/test-utils/mockData/mockProjects.js +++ /dev/null @@ -1,32 +0,0 @@ -import _ from 'lodash'; -import fake from '__test__/test-utils/constants'; - -const mockProjectTemplate = (idx) => ({ - uuid: `${fake.PROJECT_ID}-${idx}`, - name: `${fake.PROJECT_NAME}-${idx}`, - experiments: [`${fake.EXPERIMENT_ID}-${idx}`], - samples: [], - metadataKeys: [], - createdDate: fake.MOCK_DATETIME, - description: `Mock project ${idx}`, - lastAnalyzed: fake.MOCK_DATETIME, - lastModified: fake.MOCK_DATETIME, -}); - -const generateMockProjects = (numProjects = 1, attrs = []) => { - const mockProject = []; - - for (let idx = 0; idx < numProjects; idx += 1) { - const newProject = _.merge( - {}, - mockProjectTemplate(idx), - attrs[idx] ?? {}, - ); - - mockProject.push(newProject); - } - - return mockProject; -}; - -export default generateMockProjects; diff --git a/src/__test__/utils/AppRouteProvider.test.jsx b/src/__test__/utils/AppRouteProvider.test.jsx index 4765344ae0..4a4c58827a 100644 --- a/src/__test__/utils/AppRouteProvider.test.jsx +++ b/src/__test__/utils/AppRouteProvider.test.jsx @@ -17,8 +17,9 @@ import AppRouteProvider, { useAppRouter, PATHS } from 'utils/AppRouteProvider'; import DataProcessingIntercept from 'components/data-processing/DataProcessingIntercept'; import addChangedQCFilter from 'redux/actions/experimentSettings/processingConfig/addChangedQCFilter'; -import { loadProjects, updateProject } from 'redux/actions/projects'; -import { switchExperiment, updateExperiment } from 'redux/actions/experiments'; +import { + updateExperiment, loadExperiments, switchExperiment, +} from 'redux/actions/experiments'; jest.mock('next/router', () => ({ __esModule: true, @@ -29,11 +30,9 @@ jest.mock('components/data-processing/DataProcessingIntercept', () => jest.fn(() => <>Data Processing Intercept)); jest.mock('redux/actions/experiments/switchExperiment'); -jest.mock('redux/actions/projects/updateProject'); jest.mock('redux/actions/experiments/updateExperiment'); switchExperiment.mockImplementation(() => ({ type: 'MOCK_ACTION ' })); -updateProject.mockImplementation(() => ({ type: 'MOCK_ACTION ' })); updateExperiment.mockImplementation(() => ({ type: 'MOCK_ACTION ' })); enableFetchMocks(); @@ -62,7 +61,7 @@ const TestComponent = (props) => { const testParams = { experimentId, - projectUuid: experimentId, + experimentId, ...params, }; @@ -112,7 +111,7 @@ describe('AppRouteProvider', () => { }); it('Switch experiment when navigating from DataManagement', async () => { - await storeState.dispatch(loadProjects()); + await storeState.dispatch(loadExperiments()); render( diff --git a/src/__test__/utils/upload/processUpload.test.js b/src/__test__/utils/upload/processUpload.test.js index 29c1464948..e58bbbf324 100644 --- a/src/__test__/utils/upload/processUpload.test.js +++ b/src/__test__/utils/upload/processUpload.test.js @@ -3,10 +3,11 @@ import thunk from 'redux-thunk'; import waitForActions from 'redux-mock-store-await-actions'; import axios from 'axios'; import fetchMock, { enableFetchMocks } from 'jest-fetch-mock'; + import { SAMPLES_FILE_UPDATE } from 'redux/actionTypes/samples'; import initialSampleState, { sampleTemplate } from 'redux/reducers/samples/initialState'; -import initialProjectState, { projectTemplate } from 'redux/reducers/projects/initialState'; import initialExperimentState, { experimentTemplate } from 'redux/reducers/experiments/initialState'; + import UploadStatus from 'utils/upload/UploadStatus'; import { waitFor } from '@testing-library/dom'; @@ -64,27 +65,13 @@ const getValidFiles = (cellrangerVersion) => { const sampleType = '10X Chromium'; const mockSampleUuid = 'sample-uuid'; -const mockProjectUuid = 'project-uuid'; -const mockExperimentId = 'experiment-id'; +const mockExperimentId = 'project-uuid'; +const sampleName = 'mockSampleName'; + +const mockUnrelatedSampleUuid = 'unrelated-sample-uuid'; +const mockUnrelatedExperimentId = 'unrelated-experiment-id'; const initialState = { - projects: { - ...initialProjectState, - ids: [mockProjectUuid], - meta: { - activeProjectUuid: mockProjectUuid, - }, - [mockProjectUuid]: { - ...projectTemplate, - samples: [mockSampleUuid], - experiments: [mockExperimentId], - }, - errorProjectUuid: { - ...projectTemplate, - samples: [mockSampleUuid], - experiments: [mockExperimentId], - }, - }, experiments: { ...initialExperimentState, [mockExperimentId]: { @@ -101,8 +88,15 @@ const initialState = { }, [mockSampleUuid]: { ...sampleTemplate, - uuid: [mockSampleUuid], - projectUuid: mockProjectUuid, + uuid: mockSampleUuid, + name: sampleName, + experimentId: mockExperimentId, + }, + [mockUnrelatedSampleUuid]: { + ...sampleTemplate, + uuid: mockUnrelatedSampleUuid, + name: sampleName, + experimentId: mockUnrelatedExperimentId, }, }, }; @@ -160,7 +154,7 @@ describe('processUpload', () => { getValidFiles('v3'), sampleType, store.getState().samples, - mockProjectUuid, + mockExperimentId, store.dispatch, ); @@ -247,7 +241,7 @@ describe('processUpload', () => { getValidFiles('v2'), sampleType, store.getState().samples, - mockProjectUuid, + mockExperimentId, store.dispatch, ); @@ -326,7 +320,7 @@ describe('processUpload', () => { invalidFiles, sampleType, store.getState().samples, - mockProjectUuid, + mockExperimentId, store.dispatch, ); @@ -426,7 +420,7 @@ describe('processUpload', () => { getValidFiles('v3'), sampleType, store.getState().samples, - mockProjectUuid, + mockExperimentId, store.dispatch, ); diff --git a/src/components/ContentWrapper.jsx b/src/components/ContentWrapper.jsx index a28be5033d..0730db2cfe 100644 --- a/src/components/ContentWrapper.jsx +++ b/src/components/ContentWrapper.jsx @@ -51,26 +51,23 @@ const ContentWrapper = (props) => { const { navigateTo, currentModule } = useAppRouter(); const currentExperimentIdRef = useRef(routeExperimentId); - const activeProjectUuid = useSelector((state) => state?.projects?.meta?.activeProjectUuid); - const activeProjectExperimentID = useSelector((state) => ( - state?.projects[activeProjectUuid]?.experiments[0])); + const activeExperimentId = useSelector((state) => state?.experiments?.meta?.activeExperimentId); + const activeExperiment = useSelector((state) => state.experiments[activeExperimentId]); - const activeProject = useSelector((state) => state.projects[activeProjectUuid]); const samples = useSelector((state) => state.samples); - // Use the project's experiment ID in data management useEffect(() => { - if (!activeProjectExperimentID && !routeExperimentId) return; + if (!activeExperimentId && !routeExperimentId) return; if (currentModule === modules.DATA_MANAGEMENT) { - currentExperimentIdRef.current = activeProjectExperimentID; + currentExperimentIdRef.current = activeExperimentId; return; } if (currentExperimentIdRef.current === routeExperimentId) return; currentExperimentIdRef.current = routeExperimentId; - }, [currentModule, activeProjectExperimentID, routeExperimentId]); + }, [currentModule, activeExperimentId, routeExperimentId]); const currentExperimentId = currentExperimentIdRef.current; const experiment = useSelector((state) => state?.experiments[currentExperimentId]); @@ -131,12 +128,14 @@ const ContentWrapper = (props) => { const [gem2sRerunStatus, setGem2sRerunStatus] = useState(null); useEffect(() => { + if (!activeExperiment) return; + const gem2sStatus = calculateGem2sRerunStatus( - gem2sBackendStatus, activeProject, samples, experiment, + gem2sBackendStatus, activeExperiment, samples, experiment, ); setGem2sRerunStatus(gem2sStatus); - }, [gem2sBackendStatus, activeProject, samples, experiment]); + }, [gem2sBackendStatus, activeExperiment, samples, experiment]); useEffect(() => { Auth.currentAuthenticatedUser() diff --git a/src/components/NotifyByEmail.jsx b/src/components/NotifyByEmail.jsx index 4dadf003c7..63caff13d3 100644 --- a/src/components/NotifyByEmail.jsx +++ b/src/components/NotifyByEmail.jsx @@ -3,7 +3,6 @@ import { Switch, Typography, Space } from 'antd'; import { useDispatch, useSelector } from 'react-redux'; import { updateExperiment, loadExperiments } from 'redux/actions/experiments'; import PropTypes from 'prop-types'; -import { loadProjects } from 'redux/actions/projects'; const { Text } = Typography; const NotifyByEmail = (props) => { @@ -13,20 +12,14 @@ const NotifyByEmail = (props) => { const changeEmailNotification = (value) => { dispatch(updateExperiment(experimentId, { notifyByEmail: value })); }; - const { activeProjectUuid } = useSelector((state) => state?.projects?.meta) || false; + const { activeExperimentId } = useSelector((state) => state?.experiments?.meta) || false; useEffect(() => { - if (!activeProjectUuid) { - dispatch(loadProjects()); + if (!activeExperimentId) { + dispatch(loadExperiments()); } }, []); - useEffect(() => { - if (!experiment && activeProjectUuid) { - dispatch(loadExperiments(activeProjectUuid)); - } - }, [activeProjectUuid]); - return ( Get notified about your pipeline status via email diff --git a/src/components/data-management/DownloadDataButton.jsx b/src/components/data-management/DownloadDataButton.jsx index ba5264f5dc..ab998407fa 100644 --- a/src/components/data-management/DownloadDataButton.jsx +++ b/src/components/data-management/DownloadDataButton.jsx @@ -21,56 +21,56 @@ import handleError from 'utils/http/handleError'; const DownloadDataButton = () => { const dispatch = useDispatch(); - const { activeProjectUuid } = useSelector((state) => state.projects.meta); const experimentSettings = useSelector((state) => state.experimentSettings); - const activeProject = useSelector((state) => state.projects[activeProjectUuid]); - // Change if we have more than one experiment per project - const experimentId = activeProject?.experiments[0]; + const experiments = useSelector((state) => state.experiments); + const { activeExperimentId } = experiments.meta; + const activeExperiment = experiments[activeExperimentId]; const { status: backendStatuses, loading: backendLoading, - } = useSelector(getBackendStatus(experimentId)); + } = useSelector(getBackendStatus(activeExperimentId)); const samples = useSelector((state) => state.samples); - const projects = useSelector((state) => state.projects); const [qcHasRun, setQcHasRun] = useState(false); const [gem2sHasRun, setGem2sHasRun] = useState(false); const [allSamplesAnalysed, setAllSamplesAnalysed] = useState(false); useEffect(() => { - if (experimentId && !backendLoading && !backendStatuses) { - dispatch(loadBackendStatus(experimentId)); + if (activeExperimentId && !backendLoading && !backendStatuses) { + dispatch(loadBackendStatus(activeExperimentId)); } - }, [experimentId]); + }, [activeExperimentId]); useEffect(() => { - setQcHasRun(experimentId - && (backendStatuses?.pipeline?.status === pipelineStatus.SUCCEEDED)); - setGem2sHasRun(experimentId - && (backendStatuses?.gem2s?.status === pipelineStatus.SUCCEEDED)); + setQcHasRun( + activeExperimentId && (backendStatuses?.pipeline?.status === pipelineStatus.SUCCEEDED), + ); + setGem2sHasRun( + activeExperimentId && (backendStatuses?.gem2s?.status === pipelineStatus.SUCCEEDED), + ); }, [backendStatuses]); useEffect(() => { setAllSamplesAnalysed(getAllSamplesAnalysed()); - }, [activeProject, experimentSettings]); + }, [activeExperiment, experimentSettings]); const getAllSamplesAnalysed = () => { // Returns true only if there is at least one sample in the currently active // project AND all samples in the project have been analysed. - if (!activeProject?.samples?.length) { + if (!activeExperiment?.sampleIds?.length) { return false; } const steps = Object.values(_.omit(experimentSettings?.processing, ['meta'])); return steps.length > 0 // eslint-disable-next-line no-prototype-builtins - && activeProject?.samples?.every((s) => steps[0].hasOwnProperty(s)); + && activeExperiment?.sampleIds?.every((s) => steps[0].hasOwnProperty(s)); }; const downloadExperimentData = async (type) => { try { - if (!experimentId) throw new Error('No experimentId specified'); + if (!activeExperimentId) throw new Error('No experimentId specified'); if (!downloadTypes.has(type)) throw new Error('Invalid download type'); - const signedUrl = await fetchAPI(`/v2/experiments/${experimentId}/download/${type}`); + const signedUrl = await fetchAPI(`/v2/experiments/${activeExperimentId}/download/${type}`); downloadFromUrl(signedUrl); } catch (e) { @@ -123,9 +123,9 @@ const DownloadDataButton = () => { key='download-processing-settings' onClick={() => { const config = _.omit(experimentSettings.processing, ['meta']); - const filteredConfig = filterQCParameters(config, activeProject.samples, samples); + const filteredConfig = filterQCParameters(config, activeExperiment.sampleIds, samples); const blob = exportQCParameters(filteredConfig); - saveAs(blob, `${activeProjectUuid.split('-')[0]}_settings.txt`); + saveAs(blob, `${activeExperimentId.split('-')[0]}_settings.txt`); }} > { @@ -143,8 +143,8 @@ const DownloadDataButton = () => { trigger={['click']} placement='bottomRight' disabled={ - projects.ids.length === 0 - || activeProject.samples.length === 0 + experiments.ids.length === 0 + || activeExperiment.sampleIds.length === 0 } >