Skip to content

Commit 2cc1194

Browse files
committed
tests and cleanup
1 parent faa9cdc commit 2cc1194

File tree

6 files changed

+56
-35
lines changed

6 files changed

+56
-35
lines changed

packages/compass-data-modeling/src/components/diagram-editor.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,6 @@ const DiagramContent: React.FunctionComponent<{
133133
isNewlyCreatedDiagram?: boolean;
134134
model: StaticModel | null;
135135
isInRelationshipDrawingMode: boolean;
136-
editErrors?: string[];
137136
newCollection?: string;
138137
onAddFieldToObjectField: (ns: string, parentPath: string[]) => void;
139138
onAddNewFieldToCollection: (ns: string) => void;
@@ -561,7 +560,6 @@ export default connect(
561560
const { diagram, step } = state;
562561
return {
563562
step: step,
564-
editErrors: diagram?.editErrors,
565563
diagramId: diagram?.id,
566564
};
567565
},

packages/compass-data-modeling/src/store/diagram.spec.ts

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import type {
1818
StaticModel,
1919
} from '../services/data-model-storage';
2020
import { UUID } from 'bson';
21+
import Sinon from 'sinon';
2122

2223
const model: StaticModel = {
2324
collections: [
@@ -69,9 +70,11 @@ const loadedDiagram: MongoDBDataModelDescription = {
6970

7071
describe('Data Modeling store', function () {
7172
let store: DataModelingStore;
73+
let openToastSpy: Sinon.SinonSpy;
7274

7375
beforeEach(function () {
74-
store = setupStore();
76+
openToastSpy = Sinon.spy();
77+
store = setupStore({}, undefined, openToastSpy);
7578
});
7679

7780
describe('New Diagram', function () {
@@ -160,7 +163,7 @@ describe('Data Modeling store', function () {
160163

161164
const state = store.getState();
162165
const diagram = getCurrentDiagramFromState(state);
163-
expect(state.diagram?.editErrors).to.be.undefined;
166+
expect(openToastSpy).not.to.have.been.called;
164167
expect(diagram.edits).to.have.length(2);
165168
expect(diagram.edits[0]).to.deep.equal(loadedDiagram.edits[0]);
166169
expect(diagram.edits[1]).to.deep.include(edit);
@@ -196,7 +199,7 @@ describe('Data Modeling store', function () {
196199

197200
const state = store.getState();
198201
const diagram = getCurrentDiagramFromState(state);
199-
expect(state.diagram?.editErrors).to.be.undefined;
202+
expect(openToastSpy).not.to.have.been.called;
200203
expect(diagram.edits).to.have.length(2);
201204
expect(diagram.edits[0]).to.deep.equal(loadedDiagram.edits[0]);
202205
expect(diagram.edits[1]).to.deep.include({
@@ -220,9 +223,8 @@ describe('Data Modeling store', function () {
220223
} as unknown as Edit;
221224
store.dispatch(applyEdit(edit));
222225

223-
const editErrors = store.getState().diagram?.editErrors;
224-
expect(editErrors).to.have.length(1);
225-
expect(editErrors && editErrors[0]).to.equal(
226+
expect(openToastSpy).to.have.been.calledOnce;
227+
expect(openToastSpy.firstCall.args[1].description).to.include(
226228
"'relationship,relationship' is required"
227229
);
228230
const diagram = getCurrentDiagramFromState(store.getState());
@@ -356,7 +358,7 @@ describe('Data Modeling store', function () {
356358

357359
const state = store.getState();
358360
const diagram = getCurrentDiagramFromState(state);
359-
expect(state.diagram?.editErrors).to.be.undefined;
361+
expect(openToastSpy).not.to.have.been.called;
360362
expect(diagram.edits).to.have.length(2);
361363
expect(diagram.edits[0]).to.deep.equal(loadedDiagram.edits[0]);
362364
expect(diagram.edits[1]).to.deep.include(edit);
@@ -376,12 +378,22 @@ describe('Data Modeling store', function () {
376378
} as unknown as Edit;
377379
store.dispatch(applyEdit(edit));
378380

379-
const editErrors = store.getState().diagram?.editErrors;
380-
expect(editErrors).to.have.length(1);
381-
expect(editErrors && editErrors[0]).to.equal("'newPosition' is required");
381+
expect(openToastSpy).to.have.been.calledOnce;
382+
expect(openToastSpy.firstCall.args[1].description).to.include(
383+
"'newPosition' is required"
384+
);
382385
const diagram = getCurrentDiagramFromState(store.getState());
383386
expect(diagram.edits).to.deep.equal(loadedDiagram.edits);
384387
});
388+
389+
it('should handle an invalid RenameCollection edit', function () {
390+
store.dispatch(openDiagram(loadedDiagram));
391+
store.dispatch(renameCollection('nonExisting', 'newName'));
392+
expect(openToastSpy).to.have.been.calledOnce;
393+
expect(openToastSpy.firstCall.args[1].description).to.include(
394+
"Collection 'nonExisting' not found"
395+
);
396+
});
385397
});
386398

387399
it('undo & redo', function () {

packages/compass-data-modeling/src/store/diagram.ts

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { memoize } from 'lodash';
1818
import type { DataModelingState, DataModelingThunkAction } from './reducer';
1919
import {
2020
getCoordinatesForNewNode,
21-
openToast,
21+
type openToast as _openToast,
2222
showConfirmation,
2323
showPrompt,
2424
} from '@mongodb-js/compass-components';
@@ -229,7 +229,6 @@ export const diagramReducer: Reducer<DiagramState> = (
229229
state.draftCollection,
230230
action.edit.toNS
231231
),
232-
editErrors: undefined,
233232
updatedAt: new Date().toISOString(),
234233
selectedItems: {
235234
type: 'collection',
@@ -246,7 +245,6 @@ export const diagramReducer: Reducer<DiagramState> = (
246245
current: [...state.edits.current, action.edit] as [Edit, ...Edit[]],
247246
next: [],
248247
},
249-
editErrors: undefined,
250248
updatedAt: new Date().toISOString(),
251249
selectedItems: updateSelectedItemsFromAppliedEdit(
252250
state.selectedItems,
@@ -509,7 +507,7 @@ export function redoEdit(): DataModelingThunkAction<void, RedoEditAction> {
509507
export function onAddNestedField(
510508
ns: string,
511509
parentFieldPath: string[]
512-
): DataModelingThunkAction<void, ApplyEditAction | ApplyEditFailedAction> {
510+
): DataModelingThunkAction<void, ApplyEditAction | RevertFailedEditAction> {
513511
return (dispatch, getState) => {
514512
const modelState = selectCurrentModelFromState(getState());
515513

@@ -540,7 +538,7 @@ export function onAddNestedField(
540538

541539
export function addNewFieldToCollection(
542540
ns: string
543-
): DataModelingThunkAction<void, ApplyEditAction | ApplyEditFailedAction> {
541+
): DataModelingThunkAction<void, ApplyEditAction | RevertFailedEditAction> {
544542
return (dispatch, getState) => {
545543
const modelState = selectCurrentModelFromState(getState());
546544

@@ -569,7 +567,7 @@ export function addNewFieldToCollection(
569567
export function moveCollection(
570568
ns: string,
571569
newPosition: [number, number]
572-
): DataModelingThunkAction<void, ApplyEditAction | ApplyEditFailedAction> {
570+
): DataModelingThunkAction<void, ApplyEditAction | RevertFailedEditAction> {
573571
const edit: Omit<
574572
Extract<Edit, { type: 'MoveCollection' }>,
575573
'id' | 'timestamp'
@@ -586,7 +584,7 @@ export function renameCollection(
586584
toNS: string
587585
): DataModelingThunkAction<
588586
void,
589-
ApplyEditAction | ApplyEditFailedAction | CollectionSelectedAction
587+
ApplyEditAction | RevertFailedEditAction | CollectionSelectedAction
590588
> {
591589
const edit: Omit<
592590
Extract<Edit, { type: 'RenameCollection' }>,
@@ -600,18 +598,21 @@ export function renameCollection(
600598
return applyEdit(edit);
601599
}
602600

603-
function handleError(messages: string[]) {
601+
function handleError(openToast: typeof _openToast, messages: string[]) {
604602
openToast('data-modeling-error', {
605603
variant: 'warning',
606604
title: 'Error opening diagram',
607605
description: messages.join(' '),
608606
});
609607
}
610608

609+
/**
610+
* Not intended to be called directly, only exported for testing.
611+
*/
611612
export function applyEdit(
612613
rawEdit: EditAction
613614
): DataModelingThunkAction<boolean, ApplyEditAction | RevertFailedEditAction> {
614-
return (dispatch, getState, { dataModelStorage }) => {
615+
return (dispatch, getState, { dataModelStorage, openToast }) => {
615616
const edit = {
616617
...rawEdit,
617618
id: new UUID().toString(),
@@ -620,7 +621,7 @@ export function applyEdit(
620621
const { result, errors } = validateEdit(edit);
621622
let isValid = result;
622623
if (!result) {
623-
handleError(errors);
624+
handleError(openToast, errors);
624625
return isValid;
625626
}
626627
dispatch({
@@ -632,7 +633,7 @@ export function applyEdit(
632633
try {
633634
selectCurrentModelFromState(getState());
634635
} catch (e) {
635-
handleError([
636+
handleError(openToast, [
636637
'Something went wrong when applying the changes.',
637638
(e as Error).message,
638639
]);
@@ -697,7 +698,7 @@ export function renameDiagram(
697698
export function openDiagramFromFile(
698699
file: File
699700
): DataModelingThunkAction<Promise<void>, OpenDiagramAction> {
700-
return async (dispatch, getState, { dataModelStorage, track }) => {
701+
return async (dispatch, getState, { dataModelStorage, track, openToast }) => {
701702
try {
702703
const { name, edits } = await getDiagramContentsFromFile(file);
703704

@@ -728,7 +729,7 @@ export function openDiagramFromFile(
728729

729730
export function updateRelationship(
730731
relationship: Relationship
731-
): DataModelingThunkAction<boolean, ApplyEditAction | ApplyEditFailedAction> {
732+
): DataModelingThunkAction<boolean, ApplyEditAction | RevertFailedEditAction> {
732733
return applyEdit({
733734
type: 'UpdateRelationship',
734735
relationship,
@@ -756,7 +757,7 @@ export function deleteRelationship(
756757

757758
export function deleteCollection(
758759
ns: string
759-
): DataModelingThunkAction<void, ApplyEditAction | ApplyEditFailedAction> {
760+
): DataModelingThunkAction<void, ApplyEditAction | RevertFailedEditAction> {
760761
return (dispatch, getState, { track }) => {
761762
track('Data Modeling Collection Removed', {
762763
source: 'side_panel',
@@ -769,14 +770,14 @@ export function deleteCollection(
769770
export function updateCollectionNote(
770771
ns: string,
771772
note: string
772-
): DataModelingThunkAction<void, ApplyEditAction | ApplyEditFailedAction> {
773+
): DataModelingThunkAction<void, ApplyEditAction | RevertFailedEditAction> {
773774
return applyEdit({ type: 'UpdateCollectionNote', ns, note });
774775
}
775776

776777
export function removeField(
777778
ns: string,
778779
field: FieldPath
779-
): DataModelingThunkAction<void, ApplyEditAction | ApplyEditFailedAction> {
780+
): DataModelingThunkAction<void, ApplyEditAction | RevertFailedEditAction> {
780781
return (dispatch, getState, { track }) => {
781782
track('Data Modeling Field Removed', {
782783
source: 'side_panel',
@@ -790,7 +791,7 @@ export function renameField(
790791
ns: string,
791792
field: FieldPath,
792793
newName: string
793-
): DataModelingThunkAction<void, ApplyEditAction | ApplyEditFailedAction> {
794+
): DataModelingThunkAction<void, ApplyEditAction | RevertFailedEditAction> {
794795
return (dispatch, getState, { track }) => {
795796
track('Data Modeling Field Renamed', {
796797
source: 'side_panel',
@@ -826,7 +827,7 @@ export function changeFieldType(
826827
ns: string,
827828
fieldPath: FieldPath,
828829
newTypes: string[]
829-
): DataModelingThunkAction<void, ApplyEditAction | ApplyEditFailedAction> {
830+
): DataModelingThunkAction<void, ApplyEditAction | RevertFailedEditAction> {
830831
return (dispatch, getState, { track }) => {
831832
const collectionSchema = selectCurrentModelFromState(
832833
getState()
@@ -895,7 +896,7 @@ export function addCollection(
895896
position?: [number, number]
896897
): DataModelingThunkAction<
897898
void,
898-
ApplyEditAction | ApplyEditFailedAction | CollectionSelectedAction
899+
ApplyEditAction | RevertFailedEditAction | CollectionSelectedAction
899900
> {
900901
return (dispatch, getState, { track }) => {
901902
const existingCollections = selectCurrentModelFromState(

packages/compass-data-modeling/src/store/index.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@ import reducer from './reducer';
99
import type { DataModelingExtraArgs } from './reducer';
1010
import thunk from 'redux-thunk';
1111
import type { ActivateHelpers } from '@mongodb-js/compass-app-registry';
12+
import { openToast as _openToast } from '@mongodb-js/compass-components';
1213

13-
export type DataModelingStoreOptions = Record<string, unknown>;
14+
export type DataModelingStoreOptions = {
15+
openToast?: typeof _openToast;
16+
};
1417

1518
export type DataModelingStoreServices = {
1619
preferences: PreferencesAccess;
@@ -22,7 +25,7 @@ export type DataModelingStoreServices = {
2225
};
2326

2427
export function activateDataModelingStore(
25-
_: DataModelingStoreOptions,
28+
{ openToast = _openToast }: DataModelingStoreOptions,
2629
services: DataModelingStoreServices,
2730
{ cleanup }: ActivateHelpers
2831
) {
@@ -35,6 +38,7 @@ export function activateDataModelingStore(
3538
...services,
3639
cancelAnalysisControllerRef,
3740
cancelExportControllerRef,
41+
openToast,
3842
})
3943
)
4044
);

packages/compass-data-modeling/src/store/reducer.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import type {
2020
ExportDiagramActions,
2121
} from './export-diagram';
2222
import { exportDiagramReducer } from './export-diagram';
23+
import { type openToast as _openToast } from '@mongodb-js/compass-components';
2324

2425
const reducer = combineReducers({
2526
step: stepReducer,
@@ -46,6 +47,7 @@ export type DataModelingState = ReturnType<typeof reducer>;
4647
export type DataModelingExtraArgs = DataModelingStoreServices & {
4748
cancelAnalysisControllerRef: { current: AbortController | null };
4849
cancelExportControllerRef: { current: AbortController | null };
50+
openToast: typeof _openToast;
4951
};
5052

5153
export type DataModelingThunkAction<R, A extends AnyAction> = ThunkAction<

packages/compass-data-modeling/test/setup-store.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { activateDataModelingStore } from '../src/store';
1010
import type { DataModelingStoreServices } from '../src/store';
1111
import { noopDataModelStorageService } from '../src/provider';
1212
import { Provider } from 'react-redux';
13+
import { openToast as _openToast } from '@mongodb-js/compass-components';
1314

1415
type ConnectionInfoWithMockData = ConnectionInfo & {
1516
databases: Array<{
@@ -136,10 +137,13 @@ const testConnections = [
136137

137138
export const setupStore = (
138139
services: Partial<DataModelingStoreServices> = {},
139-
connections: ConnectionInfoWithMockData[] = testConnections
140+
connections: ConnectionInfoWithMockData[] = testConnections,
141+
openToast: typeof _openToast = _openToast
140142
) => {
141143
return activateDataModelingStore(
142-
{},
144+
{
145+
openToast,
146+
},
143147
{
144148
logger: createNoopLogger('TEST'),
145149
track: createNoopTrack(),

0 commit comments

Comments
 (0)