diff --git a/client/src/app/metamodel/effects/attribute.effects.ts b/client/src/app/metamodel/effects/attribute.effects.ts
index 855fe3301ff2a861979aeea5d3b851e64673e473..59e6c66114e1ce62e7b1bac1aa3b0f24452b7d08 100644
--- a/client/src/app/metamodel/effects/attribute.effects.ts
+++ b/client/src/app/metamodel/effects/attribute.effects.ts
@@ -18,7 +18,7 @@ import { ToastrService } from 'ngx-toastr';
 import * as attributeActions from '../actions/attribute.actions';
 import { AttributeService } from '../services/attribute.service';
 import * as datasetSelector from '../selectors/dataset.selector';
- 
+
 @Injectable()
 export class AttributeEffects {
     loadAttributes$ = createEffect(() =>
@@ -33,8 +33,8 @@ export class AttributeEffects {
             )
         )
     );
-    
-    addAttribute$ = createEffect(() => 
+
+    addAttribute$ = createEffect(() =>
         this.actions$.pipe(
             ofType(attributeActions.addAttribute),
             concatLatestFrom(() => this.store.select(datasetSelector.selectDatasetNameByRoute)),
@@ -47,23 +47,23 @@ export class AttributeEffects {
         )
     );
 
-    addAttributeSuccess$ = createEffect(() => 
+    addAttributeSuccess$ = createEffect(() =>
         this.actions$.pipe(
             ofType(attributeActions.addAttributeSuccess),
             tap(() => {
                 this.toastr.success('Attribute successfully added', 'The new attribute was added into the database')
             })
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
 
-    addAttributeFail$ = createEffect(() => 
+    addAttributeFail$ = createEffect(() =>
         this.actions$.pipe(
             ofType(attributeActions.addAttributeFail),
             tap(() => this.toastr.error('Failure to add attribute', 'The new attribute could not be added into the database'))
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
 
-    editAttribute$ = createEffect(() => 
+    editAttribute$ = createEffect(() =>
         this.actions$.pipe(
             ofType(attributeActions.editAttribute),
             concatLatestFrom(() => this.store.select(datasetSelector.selectDatasetNameByRoute)),
@@ -76,14 +76,14 @@ export class AttributeEffects {
         )
     );
 
-    editAttributeFail$ = createEffect(() => 
+    editAttributeFail$ = createEffect(() =>
         this.actions$.pipe(
             ofType(attributeActions.editAttributeFail),
             tap(() => this.toastr.error('Failure to edit attribute', 'The existing attribute could not be edited into the database'))
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
 
-    deleteAttribute$ = createEffect(() => 
+    deleteAttribute$ = createEffect(() =>
         this.actions$.pipe(
             ofType(attributeActions.deleteAttribute),
             concatLatestFrom(() => this.store.select(datasetSelector.selectDatasetNameByRoute)),
@@ -96,20 +96,20 @@ export class AttributeEffects {
         )
     );
 
-    deleteAttributeSuccess$ = createEffect(() => 
+    deleteAttributeSuccess$ = createEffect(() =>
         this.actions$.pipe(
             ofType(attributeActions.deleteAttributeSuccess),
             tap(() => this.toastr.success('Attribute successfully deleted', 'The existing attribute has been deleted'))
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
 
-    deleteAttributeFail$ = createEffect(() => 
+    deleteAttributeFail$ = createEffect(() =>
         this.actions$.pipe(
             ofType(attributeActions.deleteAttributeFail),
             tap(() => this.toastr.error('Failure to delete attribute', 'The existing attribute could not be deleted from the database'))
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
- 
+
     constructor(
         private actions$: Actions,
         private attributeService: AttributeService,
diff --git a/client/src/app/metamodel/effects/column.effects.spec.ts b/client/src/app/metamodel/effects/column.effects.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ef28d818d0c4adcd08c1e4236eadeeef5ce242d4
--- /dev/null
+++ b/client/src/app/metamodel/effects/column.effects.spec.ts
@@ -0,0 +1,88 @@
+import { TestBed } from '@angular/core/testing';
+import { Router } from '@angular/router';
+
+import { provideMockActions } from '@ngrx/effects/testing';
+import { MockStore, provideMockStore } from '@ngrx/store/testing';
+import { EffectsMetadata, getEffectsMetadata } from '@ngrx/effects';
+import { Observable } from 'rxjs';
+import { cold, hot } from 'jasmine-marbles';
+import { ToastrService } from 'ngx-toastr';
+
+import { ColumnEffects } from './column.effects';
+import { ColumnService } from '../services/column.service';
+import * as columnActions from '../actions/column.actions';
+import { COLUMN_LIST } from '../../../test-data';
+import * as datasetSelector from '../selectors/dataset.selector';
+
+describe('[Metamodel][Effects] ColumnEffects', () => {
+    let actions = new Observable();
+    let effects: ColumnEffects;
+    let metadata: EffectsMetadata<ColumnEffects>;
+    let service: ColumnService;
+    let toastr: ToastrService;
+    let store: MockStore;
+    const initialState = { metamodel: { } };
+    let mockDatasetSelectorSelectDatasetNameByRoute;
+    let router: Router;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            providers: [
+                ColumnEffects,
+                { provide: ColumnService, useValue: { }},
+                { provide: Router, useValue: { navigate: jest.fn() }},
+                { provide: ToastrService, useValue: {
+                        success: jest.fn(),
+                        error: jest.fn()
+                    }},
+                provideMockActions(() => actions),
+                provideMockStore({ initialState })
+            ]
+        }).compileComponents();
+        effects = TestBed.inject(ColumnEffects);
+        metadata = getEffectsMetadata(effects);
+        service = TestBed.inject(ColumnService);
+        toastr = TestBed.inject(ToastrService);
+        router = TestBed.inject(Router);
+        store = TestBed.inject(MockStore);
+        mockDatasetSelectorSelectDatasetNameByRoute = store.overrideSelector(
+            datasetSelector.selectDatasetNameByRoute,''
+        );
+    });
+
+    it('should be created', () => {
+        expect(effects).toBeTruthy();
+    });
+
+    describe('loadOutputFamilies$ effect', () => {
+        it('should dispatch the loadColumnListSuccess action on success', () => {
+            mockDatasetSelectorSelectDatasetNameByRoute = store.overrideSelector(
+                datasetSelector.selectDatasetNameByRoute, 'myDataset'
+            );
+
+            const action = columnActions.loadColumnList();
+            const outcome = columnActions.loadColumnListSuccess({ columns: COLUMN_LIST });
+
+            actions = hot('-a', { a: action });
+            const response = cold('-a|', { a: COLUMN_LIST });
+            const expected = cold('--b', { b: outcome });
+            service.retrieveColumns = jest.fn(() => response);
+
+            expect(effects.loadColumns$).toBeObservable(expected);
+            expect(service.retrieveColumns).toHaveBeenCalledWith('myDataset');
+        });
+
+        it('should dispatch the loadColumnListFail action on HTTP failure', () => {
+            const action = columnActions.loadColumnList();
+            const error = new Error();
+            const outcome = columnActions.loadColumnListFail();
+
+            actions = hot('-a', { a: action });
+            const response = cold('-#|', { }, error);
+            const expected = cold('--b', { b: outcome });
+            service.retrieveColumns = jest.fn(() => response);
+
+            expect(effects.loadColumns$).toBeObservable(expected);
+        });
+    });
+});
diff --git a/client/src/app/metamodel/effects/column.effects.ts b/client/src/app/metamodel/effects/column.effects.ts
index 53399092ae075c8302d67a01ed281cd5d35b6fd3..0e11b28f27add041602baf97520a2e0c021eb6fc 100644
--- a/client/src/app/metamodel/effects/column.effects.ts
+++ b/client/src/app/metamodel/effects/column.effects.ts
@@ -17,10 +17,18 @@ import { map, mergeMap, catchError } from 'rxjs/operators';
 import * as columnActions from '../actions/column.actions';
 import { ColumnService } from '../services/column.service';
 import * as datasetSelector from '../selectors/dataset.selector';
- 
+
+/**
+ * @class
+ * @classdesc Column effects.
+ */
 @Injectable()
 export class ColumnEffects {
-    loadColumns$ = createEffect(() =>
+
+    /**
+     * Calls action to retrieve survey list.
+     */
+    loadColumns$ = createEffect((): any =>
         this.actions$.pipe(
             ofType(columnActions.loadColumnList),
             concatLatestFrom(() => this.store.select(datasetSelector.selectDatasetNameByRoute)),
@@ -32,7 +40,7 @@ export class ColumnEffects {
             )
         )
     );
- 
+
     constructor(
         private actions$: Actions,
         private columnService: ColumnService,
diff --git a/client/src/app/metamodel/effects/criteria-family.effects.spec.ts b/client/src/app/metamodel/effects/criteria-family.effects.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..10ac482fdfe156d74aab60854e244b8b47628691
--- /dev/null
+++ b/client/src/app/metamodel/effects/criteria-family.effects.spec.ts
@@ -0,0 +1,312 @@
+import { TestBed } from '@angular/core/testing';
+import { Router } from '@angular/router';
+
+import { provideMockActions } from '@ngrx/effects/testing';
+import { MockStore, provideMockStore } from '@ngrx/store/testing';
+import { EffectsMetadata, getEffectsMetadata } from '@ngrx/effects';
+import { Observable } from 'rxjs';
+import { cold, hot } from 'jasmine-marbles';
+
+import { ToastrService } from 'ngx-toastr';
+import { CriteriaFamilyEffects } from './criteria-family.effects';
+import { CriteriaFamilyService } from '../services/criteria-family.service';
+import * as criteriaFamilyActions from '../actions/criteria-family.actions';
+import { CRITERIA_FAMILY, CRITERIA_FAMILY_LIST } from '../../../test-data';
+import * as datasetSelector from '../selectors/dataset.selector';
+
+describe('[Metamodel][Effects] CriteriaFamilyEffects', () => {
+    let actions = new Observable();
+    let effects: CriteriaFamilyEffects;
+    let metadata: EffectsMetadata<CriteriaFamilyEffects>;
+    let service: CriteriaFamilyService;
+    let toastr: ToastrService;
+    let store: MockStore;
+    const initialState = { metamodel: { } };
+    let mockDatasetSelectorSelectDatasetNameByRoute;
+    let router: Router;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            providers: [
+                CriteriaFamilyEffects,
+                { provide: CriteriaFamilyService, useValue: { }},
+                { provide: Router, useValue: { navigate: jest.fn() }},
+                { provide: ToastrService, useValue: {
+                        success: jest.fn(),
+                        error: jest.fn()
+                    }},
+                provideMockActions(() => actions),
+                provideMockStore({ initialState })
+            ]
+        }).compileComponents();
+        effects = TestBed.inject(CriteriaFamilyEffects);
+        metadata = getEffectsMetadata(effects);
+        service = TestBed.inject(CriteriaFamilyService);
+        toastr = TestBed.inject(ToastrService);
+        router = TestBed.inject(Router);
+        store = TestBed.inject(MockStore);
+        mockDatasetSelectorSelectDatasetNameByRoute = store.overrideSelector(
+            datasetSelector.selectDatasetNameByRoute,''
+        );
+    });
+
+    it('should be created', () => {
+        expect(effects).toBeTruthy();
+    });
+
+    describe('loadCriteriaFamilies$ effect', () => {
+        it('should dispatch the loadCriteriaFamilyListSuccess action on success', () => {
+            mockDatasetSelectorSelectDatasetNameByRoute = store.overrideSelector(
+                datasetSelector.selectDatasetNameByRoute, 'myDataset'
+            );
+
+            const action = criteriaFamilyActions.loadCriteriaFamilyList();
+            const outcome = criteriaFamilyActions.loadCriteriaFamilyListSuccess({ criteriaFamilies: CRITERIA_FAMILY_LIST });
+
+            actions = hot('-a', { a: action });
+            const response = cold('-a|', { a: CRITERIA_FAMILY_LIST });
+            const expected = cold('--b', { b: outcome });
+            service.retrieveCriteriaFamilyList = jest.fn(() => response);
+
+            expect(effects.loadCriteriaFamilies$).toBeObservable(expected);
+            expect(service.retrieveCriteriaFamilyList).toHaveBeenCalledWith('myDataset');
+        });
+
+        it('should dispatch the loadCriteriaFamilyListFail action on HTTP failure', () => {
+            const action = criteriaFamilyActions.loadCriteriaFamilyList();
+            const error = new Error();
+            const outcome = criteriaFamilyActions.loadCriteriaFamilyListFail();
+
+            actions = hot('-a', { a: action });
+            const response = cold('-#|', { }, error);
+            const expected = cold('--b', { b: outcome });
+            service.retrieveCriteriaFamilyList = jest.fn(() => response);
+
+            expect(effects.loadCriteriaFamilies$).toBeObservable(expected);
+        });
+    });
+
+    describe('addCriteriaFamilies$ effect', () => {
+        it('should dispatch the addCriteriaFamilySuccess action on success', () => {
+            mockDatasetSelectorSelectDatasetNameByRoute = store.overrideSelector(
+                datasetSelector.selectDatasetNameByRoute, 'myDataset'
+            );
+
+            const action = criteriaFamilyActions.addCriteriaFamily({ criteriaFamily: CRITERIA_FAMILY });
+            const outcome = criteriaFamilyActions.addCriteriaFamilySuccess({ criteriaFamily: CRITERIA_FAMILY });
+
+            actions = hot('-a', { a: action });
+            const response = cold('-a|', { a: CRITERIA_FAMILY });
+            const expected = cold('--b', { b: outcome });
+            service.addCriteriaFamily = jest.fn(() => response);
+
+            expect(effects.addCriteriaFamily$).toBeObservable(expected);
+            expect(service.addCriteriaFamily).toHaveBeenCalledWith('myDataset', CRITERIA_FAMILY);
+        });
+
+        it('should dispatch the addCriteriaFamilyFail action on HTTP failure', () => {
+            const action = criteriaFamilyActions.addCriteriaFamily({ criteriaFamily: CRITERIA_FAMILY });
+            const error = new Error();
+            const outcome = criteriaFamilyActions.addCriteriaFamilyFail();
+
+            actions = hot('-a', { a: action });
+            const response = cold('-#|', { }, error);
+            const expected = cold('--b', { b: outcome });
+            service.addCriteriaFamily = jest.fn(() => response);
+
+            expect(effects.addCriteriaFamily$).toBeObservable(expected);
+        });
+    });
+
+    describe('addCriteriaFamilySuccess$ effect', () => {
+        it('should not dispatch', () => {
+            expect(metadata.addCriteriaFamilySuccess$).toEqual(
+                expect.objectContaining({ dispatch: false })
+            );
+        });
+
+        it('should display a success notification', () => {
+            const spy = jest.spyOn(toastr, 'success');
+            const action = criteriaFamilyActions.addCriteriaFamilySuccess({ criteriaFamily: CRITERIA_FAMILY });
+
+            actions = hot('a', { a: action });
+            const expected = cold('a', { a: action });
+
+            expect(effects.addCriteriaFamilySuccess$).toBeObservable(expected);
+            expect(spy).toHaveBeenCalledTimes(1);
+            expect(spy).toHaveBeenCalledWith(
+                'Criteria family successfully added',
+                'The new criteria family was added into the database'
+            );
+        });
+    });
+
+    describe('addCriteriaFamilyFail$ effect', () => {
+        it('should not dispatch', () => {
+            expect(metadata.addCriteriaFamilyFail$).toEqual(
+                expect.objectContaining({ dispatch: false })
+            );
+        });
+
+        it('should display an error notification', () => {
+            const spy = jest.spyOn(toastr, 'error');
+            const action = criteriaFamilyActions.addCriteriaFamilyFail();
+
+            actions = hot('a', { a: action });
+            const expected = cold('a', { a: action });
+
+            expect(effects.addCriteriaFamilyFail$).toBeObservable(expected);
+            expect(spy).toHaveBeenCalledTimes(1);
+            expect(spy).toHaveBeenCalledWith(
+                'Failure to add criteria family',
+                'The new criteria family could not be added into the database'
+            );
+        });
+    });
+
+    describe('editCriteriaFamily$ effect', () => {
+        it('should dispatch the editCriteriaFamilySuccess action on success', () => {
+            const action = criteriaFamilyActions.editCriteriaFamily({ criteriaFamily: CRITERIA_FAMILY });
+            const outcome = criteriaFamilyActions.editCriteriaFamilySuccess({ criteriaFamily: CRITERIA_FAMILY });
+
+            actions = hot('-a', { a: action });
+            const response = cold('-a|', { a: CRITERIA_FAMILY });
+            const expected = cold('--b', { b: outcome });
+            service.editCriteriaFamily = jest.fn(() => response);
+
+            expect(effects.editCriteriaFamily$).toBeObservable(expected);
+        });
+
+        it('should dispatch the editCriteriaFamilyFail action on HTTP failure', () => {
+            const action = criteriaFamilyActions.editCriteriaFamily({ criteriaFamily: CRITERIA_FAMILY });
+            const error = new Error();
+            const outcome = criteriaFamilyActions.editCriteriaFamilyFail();
+
+            actions = hot('-a', { a: action });
+            const response = cold('-#|', { }, error);
+            const expected = cold('--b', { b: outcome });
+            service.editCriteriaFamily = jest.fn(() => response);
+
+            expect(effects.editCriteriaFamily$).toBeObservable(expected);
+        });
+    });
+
+    describe('editCriteriaFamilySuccess$ effect', () => {
+        it('should not dispatch', () => {
+            expect(metadata.editCriteriaFamilySuccess$).toEqual(
+                expect.objectContaining({ dispatch: false })
+            );
+        });
+
+        it('should display a success notification', () => {
+            const spy = jest.spyOn(toastr, 'success');
+            const action = criteriaFamilyActions.editCriteriaFamilySuccess({ criteriaFamily: CRITERIA_FAMILY });
+
+            actions = hot('a', { a: action });
+            const expected = cold('a', { a: action });
+
+            expect(effects.editCriteriaFamilySuccess$).toBeObservable(expected);
+            expect(spy).toHaveBeenCalledTimes(1);
+            expect(spy).toHaveBeenCalledWith(
+                'Criteria family successfully edited',
+                'The existing criteria family has been edited into the database'
+            );
+        });
+    });
+
+    describe('editCriteriaFamilyFail$ effect', () => {
+        it('should not dispatch', () => {
+            expect(metadata.editCriteriaFamilyFail$).toEqual(
+                expect.objectContaining({ dispatch: false })
+            );
+        });
+
+        it('should display an error notification', () => {
+            const spy = jest.spyOn(toastr, 'error');
+            const action = criteriaFamilyActions.editCriteriaFamilyFail();
+
+            actions = hot('a', { a: action });
+            const expected = cold('a', { a: action });
+
+            expect(effects.editCriteriaFamilyFail$).toBeObservable(expected);
+            expect(spy).toHaveBeenCalledTimes(1);
+            expect(spy).toHaveBeenCalledWith(
+                'Failure to edit criteria family',
+                'The existing criteria family could not be edited into the database'
+            );
+        });
+    });
+
+    describe('deleteCriteriaFamily$ effect', () => {
+        it('should dispatch the deleteSurveySuccess action on success', () => {
+            const action = criteriaFamilyActions.deleteCriteriaFamily({ criteriaFamily: CRITERIA_FAMILY });
+            const outcome = criteriaFamilyActions.deleteCriteriaFamilySuccess({ criteriaFamily: CRITERIA_FAMILY });
+
+            actions = hot('-a', { a: action });
+            const response = cold('-a|', { a: CRITERIA_FAMILY });
+            const expected = cold('--b', { b: outcome });
+            service.deleteCriteriaFamily = jest.fn(() => response);
+
+            expect(effects.deleteCriteriaFamily$).toBeObservable(expected);
+        });
+
+        it('should dispatch the deleteCriteriaFamilyFail action on HTTP failure', () => {
+            const action = criteriaFamilyActions.deleteCriteriaFamily({ criteriaFamily: CRITERIA_FAMILY });
+            const error = new Error();
+            const outcome = criteriaFamilyActions.deleteCriteriaFamilyFail();
+
+            actions = hot('-a', { a: action });
+            const response = cold('-#|', { }, error);
+            const expected = cold('--b', { b: outcome });
+            service.deleteCriteriaFamily = jest.fn(() => response);
+
+            expect(effects.deleteCriteriaFamily$).toBeObservable(expected);
+        });
+    });
+
+    describe('deleteCriteriaFamilySuccess$ effect', () => {
+        it('should not dispatch', () => {
+            expect(metadata.deleteCriteriaFamilySuccess$).toEqual(
+                expect.objectContaining({ dispatch: false })
+            );
+        });
+
+        it('should display a success notification', () => {
+            const spy = jest.spyOn(toastr, 'success');
+            const action = criteriaFamilyActions.deleteCriteriaFamilySuccess({ criteriaFamily: CRITERIA_FAMILY });
+
+            actions = hot('a', { a: action });
+            const expected = cold('a', { a: action });
+
+            expect(effects.deleteCriteriaFamilySuccess$).toBeObservable(expected);
+            expect(spy).toHaveBeenCalledTimes(1);
+            expect(spy).toHaveBeenCalledWith(
+                'Criteria family successfully deleted',
+                'The existing criteria family has been deleted'
+            );
+        });
+    });
+
+    describe('deleteCriteriaFamilyFail$ effect', () => {
+        it('should not dispatch', () => {
+            expect(metadata.deleteCriteriaFamilyFail$).toEqual(
+                expect.objectContaining({ dispatch: false })
+            );
+        });
+
+        it('should display an error notification', () => {
+            const spy = jest.spyOn(toastr, 'error');
+            const action = criteriaFamilyActions.deleteCriteriaFamilyFail();
+
+            actions = hot('a', { a: action });
+            const expected = cold('a', { a: action });
+
+            expect(effects.deleteCriteriaFamilyFail$).toBeObservable(expected);
+            expect(spy).toHaveBeenCalledTimes(1);
+            expect(spy).toHaveBeenCalledWith(
+                'Failure to delete criteria family',
+                'The existing criteria family could not be deleted from the database'
+            );
+        });
+    });
+});
diff --git a/client/src/app/metamodel/effects/criteria-family.effects.ts b/client/src/app/metamodel/effects/criteria-family.effects.ts
index 95894f4cf924558bf1f2fb125c6eebece5d65237..e72d3178a3aa9d1ddac4032d69cfa1a741d96035 100644
--- a/client/src/app/metamodel/effects/criteria-family.effects.ts
+++ b/client/src/app/metamodel/effects/criteria-family.effects.ts
@@ -18,10 +18,18 @@ import { ToastrService } from 'ngx-toastr';
 import * as criteriaFamilyActions from '../actions/criteria-family.actions';
 import { CriteriaFamilyService } from '../services/criteria-family.service';
 import * as datasetSelector from '../selectors/dataset.selector';
- 
+
+/**
+ * @class
+ * @classdesc Criteria family effects.
+ */
 @Injectable()
 export class CriteriaFamilyEffects {
-    loadCriteriaFamilys$ = createEffect(() =>
+
+    /**
+     * Calls action to retrieve criteria family list.
+     */
+    loadCriteriaFamilies$ = createEffect((): any =>
         this.actions$.pipe(
             ofType(criteriaFamilyActions.loadCriteriaFamilyList),
             concatLatestFrom(() => this.store.select(datasetSelector.selectDatasetNameByRoute)),
@@ -34,7 +42,10 @@ export class CriteriaFamilyEffects {
         )
     );
 
-    addCriteriaFamily$ = createEffect(() => 
+    /**
+     * Calls action to add a criteria family.
+     */
+    addCriteriaFamily$ = createEffect((): any =>
         this.actions$.pipe(
             ofType(criteriaFamilyActions.addCriteriaFamily),
             concatLatestFrom(() => this.store.select(datasetSelector.selectDatasetNameByRoute)),
@@ -47,21 +58,30 @@ export class CriteriaFamilyEffects {
         )
     );
 
-    addCriteriaFamilySuccess$ = createEffect(() => 
+    /**
+     * Displays add criteria family success notification.
+     */
+    addCriteriaFamilySuccess$ = createEffect(() =>
         this.actions$.pipe(
             ofType(criteriaFamilyActions.addCriteriaFamilySuccess),
             tap(() => this.toastr.success('Criteria family successfully added', 'The new criteria family was added into the database'))
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
 
-    addCriteriaFamilyFail$ = createEffect(() => 
+    /**
+     * Displays add criteria family error notification.
+     */
+    addCriteriaFamilyFail$ = createEffect(() =>
         this.actions$.pipe(
             ofType(criteriaFamilyActions.addCriteriaFamilyFail),
             tap(() => this.toastr.error('Failure to add criteria family', 'The new criteria family could not be added into the database'))
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
 
-    editCriteriaFamily$ = createEffect(() => 
+    /**
+     * Calls action to modify a criteria family.
+     */
+    editCriteriaFamily$ = createEffect((): any =>
         this.actions$.pipe(
             ofType(criteriaFamilyActions.editCriteriaFamily),
             mergeMap(action => this.criteriaFamilyService.editCriteriaFamily(action.criteriaFamily)
@@ -73,21 +93,30 @@ export class CriteriaFamilyEffects {
         )
     );
 
-    editCriteriaFamilySuccess$ = createEffect(() => 
+    /**
+     * Displays edit criteria family success notification.
+     */
+    editCriteriaFamilySuccess$ = createEffect(() =>
         this.actions$.pipe(
             ofType(criteriaFamilyActions.editCriteriaFamilySuccess),
             tap(() => this.toastr.success('Criteria family successfully edited', 'The existing criteria family has been edited into the database'))
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
 
-    editCriteriaFamilyFail$ = createEffect(() => 
+    /**
+     * Displays edit criteria family error notification.
+     */
+    editCriteriaFamilyFail$ = createEffect(() =>
         this.actions$.pipe(
             ofType(criteriaFamilyActions.editCriteriaFamilyFail),
             tap(() => this.toastr.error('Failure to edit criteria family', 'The existing criteria family could not be edited into the database'))
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
 
-    deleteCriteriaFamily$ = createEffect(() => 
+    /**
+     * Calls action to remove a criteria family.
+     */
+    deleteCriteriaFamily$ = createEffect((): any =>
         this.actions$.pipe(
             ofType(criteriaFamilyActions.deleteCriteriaFamily),
             mergeMap(action => this.criteriaFamilyService.deleteCriteriaFamily(action.criteriaFamily.id)
@@ -99,20 +128,26 @@ export class CriteriaFamilyEffects {
         )
     );
 
-    deleteCriteriaFamilySuccess$ = createEffect(() => 
+    /**
+     * Displays delete criteria family success notification.
+     */
+    deleteCriteriaFamilySuccess$ = createEffect(() =>
         this.actions$.pipe(
             ofType(criteriaFamilyActions.deleteCriteriaFamilySuccess),
             tap(() => this.toastr.success('Criteria family successfully deleted', 'The existing criteria family has been deleted'))
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
 
-    deleteCriteriaFamilyFail$ = createEffect(() => 
+    /**
+     * Displays delete criteria family error notification.
+     */
+    deleteCriteriaFamilyFail$ = createEffect(() =>
         this.actions$.pipe(
             ofType(criteriaFamilyActions.deleteCriteriaFamilyFail),
             tap(() => this.toastr.error('Failure to delete criteria family', 'The existing criteria family could not be deleted from the database'))
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
- 
+
     constructor(
         private actions$: Actions,
         private criteriaFamilyService: CriteriaFamilyService,
diff --git a/client/src/app/metamodel/effects/database.effects.spec.ts b/client/src/app/metamodel/effects/database.effects.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..65326e24aa2d975960b63f61662f57a8254f0c90
--- /dev/null
+++ b/client/src/app/metamodel/effects/database.effects.spec.ts
@@ -0,0 +1,298 @@
+import { TestBed } from '@angular/core/testing';
+import { Router } from '@angular/router';
+
+import { provideMockActions } from '@ngrx/effects/testing';
+import { EffectsMetadata, getEffectsMetadata } from '@ngrx/effects';
+import { Observable } from 'rxjs';
+import { cold, hot } from 'jasmine-marbles';
+import { ToastrService } from 'ngx-toastr';
+
+import { DatabaseEffects } from './database.effects';
+import { DatabaseService } from '../services/database.service';
+import * as databaseActions from '../actions/database.actions';
+import { DATABASE, DATABASE_LIST } from '../../../test-data';
+
+describe('[Metamodel][Effects] DatabaseEffects', () => {
+    let actions = new Observable();
+    let effects: DatabaseEffects;
+    let metadata: EffectsMetadata<DatabaseEffects>;
+    let service: DatabaseService;
+    let toastr: ToastrService;
+    let router: Router;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            providers: [
+                DatabaseEffects,
+                { provide: DatabaseService, useValue: { }},
+                { provide: Router, useValue: { navigate: jest.fn() }},
+                { provide: ToastrService, useValue: {
+                        success: jest.fn(),
+                        error: jest.fn()
+                    }},
+                provideMockActions(() => actions)
+            ]
+        }).compileComponents();
+        effects = TestBed.inject(DatabaseEffects);
+        metadata = getEffectsMetadata(effects);
+        service = TestBed.inject(DatabaseService);
+        toastr = TestBed.inject(ToastrService);
+        router = TestBed.inject(Router);
+    });
+
+    it('should be created', () => {
+        expect(effects).toBeTruthy();
+    });
+
+    describe('loadDatabases$ effect', () => {
+        it('should dispatch the loadDatabaseListSuccess action on success', () => {
+            const action = databaseActions.loadDatabaseList();
+            const outcome = databaseActions.loadDatabaseListSuccess({ databases: DATABASE_LIST });
+
+            actions = hot('-a', { a: action });
+            const response = cold('-a|', { a: DATABASE_LIST });
+            const expected = cold('--b', { b: outcome });
+            service.retrieveDatabaseList = jest.fn(() => response);
+
+            expect(effects.loadDatabases$).toBeObservable(expected);
+        });
+
+        it('should dispatch the loadDatabaseListFail action on HTTP failure', () => {
+            const action = databaseActions.loadDatabaseList();
+            const error = new Error();
+            const outcome = databaseActions.loadDatabaseListFail();
+
+            actions = hot('-a', { a: action });
+            const response = cold('-#|', { }, error);
+            const expected = cold('--b', { b: outcome });
+            service.retrieveDatabaseList = jest.fn(() => response);
+
+            expect(effects.loadDatabases$).toBeObservable(expected);
+        });
+    });
+
+    describe('addDatabase$ effect', () => {
+        it('should dispatch the addDatabaseSuccess action on success', () => {
+            const action = databaseActions.addDatabase({ database: DATABASE });
+            const outcome = databaseActions.addDatabaseSuccess({ database: DATABASE });
+
+            actions = hot('-a', { a: action });
+            const response = cold('-a|', { a: DATABASE });
+            const expected = cold('--b', { b: outcome });
+            service.addDatabase = jest.fn(() => response);
+
+            expect(effects.addDatabase$).toBeObservable(expected);
+        });
+
+        it('should dispatch the addDatabaseFail action on HTTP failure', () => {
+            const action = databaseActions.addDatabase({ database: DATABASE });
+            const error = new Error();
+            const outcome = databaseActions.addDatabaseFail();
+
+            actions = hot('-a', { a: action });
+            const response = cold('-#|', { }, error);
+            const expected = cold('--b', { b: outcome });
+            service.addDatabase = jest.fn(() => response);
+
+            expect(effects.addDatabase$).toBeObservable(expected);
+        });
+    });
+
+    describe('addDatabaseSuccess$ effect', () => {
+        it('should not dispatch', () => {
+            expect(metadata.addDatabaseSuccess$).toEqual(
+                expect.objectContaining({ dispatch: false })
+            );
+        });
+
+        it('should display a success notification', () => {
+            const toastrSpy = jest.spyOn(toastr, 'success');
+            const routerSpy = jest.spyOn(router, 'navigate');
+            const action = databaseActions.addDatabaseSuccess({ database: DATABASE });
+
+            actions = hot('a', { a: action });
+            const expected = cold('a', { a: action });
+
+            expect(effects.addDatabaseSuccess$).toBeObservable(expected);
+            expect(toastrSpy).toHaveBeenCalledTimes(1);
+            expect(toastrSpy).toHaveBeenCalledWith(
+                'Database successfully added',
+                'The new database was added into the database'
+            );
+            expect(routerSpy).toHaveBeenCalledTimes(1);
+            expect(routerSpy).toHaveBeenCalledWith(['/admin/database/database-list']);
+        });
+    });
+
+    describe('addDatabaseFail$ effect', () => {
+        it('should not dispatch', () => {
+            expect(metadata.addDatabaseFail$).toEqual(
+                expect.objectContaining({ dispatch: false })
+            );
+        });
+
+        it('should display an error notification', () => {
+            const spy = jest.spyOn(toastr, 'error');
+            const action = databaseActions.addDatabaseFail();
+
+            actions = hot('a', { a: action });
+            const expected = cold('a', { a: action });
+
+            expect(effects.addDatabaseFail$).toBeObservable(expected);
+            expect(spy).toHaveBeenCalledTimes(1);
+            expect(spy).toHaveBeenCalledWith(
+                'Failure to add database',
+                'The new database could not be added into the database'
+            );
+        });
+    });
+
+    describe('editDatabase$ effect', () => {
+        it('should dispatch the editDatabaseSuccess action on success', () => {
+            const action = databaseActions.editDatabase({ database: DATABASE });
+            const outcome = databaseActions.editDatabaseSuccess({ database: DATABASE });
+
+            actions = hot('-a', { a: action });
+            const response = cold('-a|', { a: DATABASE });
+            const expected = cold('--b', { b: outcome });
+            service.editDatabase = jest.fn(() => response);
+
+            expect(effects.editDatabase$).toBeObservable(expected);
+        });
+
+        it('should dispatch the editDatabaseFail action on HTTP failure', () => {
+            const action = databaseActions.editDatabase({ database: DATABASE });
+            const error = new Error();
+            const outcome = databaseActions.editDatabaseFail();
+
+            actions = hot('-a', { a: action });
+            const response = cold('-#|', { }, error);
+            const expected = cold('--b', { b: outcome });
+            service.editDatabase = jest.fn(() => response);
+
+            expect(effects.editDatabase$).toBeObservable(expected);
+        });
+    });
+
+    describe('editDatabaseSuccess$ effect', () => {
+        it('should not dispatch', () => {
+            expect(metadata.editDatabaseSuccess$).toEqual(
+                expect.objectContaining({ dispatch: false })
+            );
+        });
+
+        it('should display a success notification', () => {
+            const toastrSpy = jest.spyOn(toastr, 'success');
+            const routerSpy = jest.spyOn(router, 'navigate');
+            const action = databaseActions.editDatabaseSuccess({ database: DATABASE });
+
+            actions = hot('a', { a: action });
+            const expected = cold('a', { a: action });
+
+            expect(effects.editDatabaseSuccess$).toBeObservable(expected);
+            expect(toastrSpy).toHaveBeenCalledTimes(1);
+            expect(toastrSpy).toHaveBeenCalledWith(
+                'Database successfully edited',
+                'The existing database has been edited into the database'
+            );
+            expect(routerSpy).toHaveBeenCalledTimes(1);
+            expect(routerSpy).toHaveBeenCalledWith(['/admin/database/database-list']);
+        });
+    });
+
+    describe('editDatabaseFail$ effect', () => {
+        it('should not dispatch', () => {
+            expect(metadata.editDatabaseFail$).toEqual(
+                expect.objectContaining({ dispatch: false })
+            );
+        });
+
+        it('should display an error notification', () => {
+            const spy = jest.spyOn(toastr, 'error');
+            const action = databaseActions.editDatabaseFail();
+
+            actions = hot('a', { a: action });
+            const expected = cold('a', { a: action });
+
+            expect(effects.editDatabaseFail$).toBeObservable(expected);
+            expect(spy).toHaveBeenCalledTimes(1);
+            expect(spy).toHaveBeenCalledWith(
+                'Failure to edit database',
+                'The existing database could not be edited into the database'
+            );
+        });
+    });
+
+    describe('deleteDatabase$ effect', () => {
+        it('should dispatch the deleteDatabaseSuccess action on success', () => {
+            const action = databaseActions.deleteDatabase({ database: DATABASE });
+            const outcome = databaseActions.deleteDatabaseSuccess({ database: DATABASE });
+
+            actions = hot('-a', { a: action });
+            const response = cold('-a|', { a: DATABASE });
+            const expected = cold('--b', { b: outcome });
+            service.deleteDatabase = jest.fn(() => response);
+
+            expect(effects.deleteDatabase$).toBeObservable(expected);
+        });
+
+        it('should dispatch the deleteDatabaseFail action on HTTP failure', () => {
+            const action = databaseActions.deleteDatabase({ database: DATABASE });
+            const error = new Error();
+            const outcome = databaseActions.deleteDatabaseFail();
+
+            actions = hot('-a', { a: action });
+            const response = cold('-#|', { }, error);
+            const expected = cold('--b', { b: outcome });
+            service.deleteDatabase = jest.fn(() => response);
+
+            expect(effects.deleteDatabase$).toBeObservable(expected);
+        });
+    });
+
+    describe('deleteDatabaseSuccess$ effect', () => {
+        it('should not dispatch', () => {
+            expect(metadata.deleteDatabaseSuccess$).toEqual(
+                expect.objectContaining({ dispatch: false })
+            );
+        });
+
+        it('should display a success notification', () => {
+            const toastrSpy = jest.spyOn(toastr, 'success');
+            const action = databaseActions.deleteDatabaseSuccess({ database: DATABASE });
+
+            actions = hot('a', { a: action });
+            const expected = cold('a', { a: action });
+
+            expect(effects.deleteDatabaseSuccess$).toBeObservable(expected);
+            expect(toastrSpy).toHaveBeenCalledTimes(1);
+            expect(toastrSpy).toHaveBeenCalledWith(
+                'Database successfully deleted',
+                'The existing database has been deleted'
+            );
+        });
+    });
+
+    describe('deleteDatabaseFail$ effect', () => {
+        it('should not dispatch', () => {
+            expect(metadata.deleteDatabaseFail$).toEqual(
+                expect.objectContaining({ dispatch: false })
+            );
+        });
+
+        it('should display an error notification', () => {
+            const spy = jest.spyOn(toastr, 'error');
+            const action = databaseActions.deleteDatabaseFail();
+
+            actions = hot('a', { a: action });
+            const expected = cold('a', { a: action });
+
+            expect(effects.deleteDatabaseFail$).toBeObservable(expected);
+            expect(spy).toHaveBeenCalledTimes(1);
+            expect(spy).toHaveBeenCalledWith(
+                'Failure to delete database',
+                'The existing database could not be deleted from the database'
+            );
+        });
+    });
+});
diff --git a/client/src/app/metamodel/effects/database.effects.ts b/client/src/app/metamodel/effects/database.effects.ts
index 0d2b2add88347833596b69248b8edf08bd5737e7..7be7fa4755703a9518afc3007ff579f64c930aec 100644
--- a/client/src/app/metamodel/effects/database.effects.ts
+++ b/client/src/app/metamodel/effects/database.effects.ts
@@ -17,10 +17,18 @@ import { ToastrService } from 'ngx-toastr';
 
 import * as databaseActions from '../actions/database.actions';
 import { DatabaseService } from '../services/database.service';
- 
+
+/**
+ * @class
+ * @classdesc Database effects.
+ */
 @Injectable()
 export class DatabaseEffects {
-    loadDatabases$ = createEffect(() =>
+
+    /**
+     * Calls action to retrieve database list.
+     */
+    loadDatabases$ = createEffect((): any =>
         this.actions$.pipe(
             ofType(databaseActions.loadDatabaseList),
             mergeMap(() => this.databaseService.retrieveDatabaseList()
@@ -32,7 +40,10 @@ export class DatabaseEffects {
         )
     );
 
-    addDatabase$ = createEffect(() => 
+    /**
+     * Calls action to add a database.
+     */
+    addDatabase$ = createEffect((): any =>
         this.actions$.pipe(
             ofType(databaseActions.addDatabase),
             mergeMap(action => this.databaseService.addDatabase(action.database)
@@ -44,24 +55,33 @@ export class DatabaseEffects {
         )
     );
 
-    addDatabaseSuccess$ = createEffect(() => 
+    /**
+     * Displays add database success notification.
+     */
+    addDatabaseSuccess$ = createEffect(() =>
         this.actions$.pipe(
             ofType(databaseActions.addDatabaseSuccess),
             tap(() => {
                 this.router.navigate(['/admin/database/database-list']);
                 this.toastr.success('Database successfully added', 'The new database was added into the database')
             })
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
 
-    addDatabaseFail$ = createEffect(() => 
+    /**
+     * Displays add database error notification.
+     */
+    addDatabaseFail$ = createEffect(() =>
         this.actions$.pipe(
             ofType(databaseActions.addDatabaseFail),
             tap(() => this.toastr.error('Failure to add database', 'The new database could not be added into the database'))
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
 
-    editDatabase$ = createEffect(() => 
+    /**
+     * Calls action to modify a database.
+     */
+    editDatabase$ = createEffect((): any =>
         this.actions$.pipe(
             ofType(databaseActions.editDatabase),
             mergeMap(action => this.databaseService.editDatabase(action.database)
@@ -73,24 +93,33 @@ export class DatabaseEffects {
         )
     );
 
-    editDatabaseSuccess$ = createEffect(() => 
+    /**
+     * Displays edit database success notification.
+     */
+    editDatabaseSuccess$ = createEffect(() =>
         this.actions$.pipe(
             ofType(databaseActions.editDatabaseSuccess),
             tap(() => {
                 this.router.navigate(['/admin/database/database-list']);
                 this.toastr.success('Database successfully edited', 'The existing database has been edited into the database')
             })
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
 
-    editDatabaseFail$ = createEffect(() => 
+    /**
+     * Displays edit database error notification.
+     */
+    editDatabaseFail$ = createEffect(() =>
         this.actions$.pipe(
             ofType(databaseActions.editDatabaseFail),
             tap(() => this.toastr.error('Failure to edit database', 'The existing database could not be edited into the database'))
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
 
-    deleteDatabase$ = createEffect(() => 
+    /**
+     * Calls action to remove a database.
+     */
+    deleteDatabase$ = createEffect((): any =>
         this.actions$.pipe(
             ofType(databaseActions.deleteDatabase),
             mergeMap(action => this.databaseService.deleteDatabase(action.database.id)
@@ -102,20 +131,26 @@ export class DatabaseEffects {
         )
     );
 
-    deleteDatabaseSuccess$ = createEffect(() => 
+    /**
+     * Displays delete database success notification.
+     */
+    deleteDatabaseSuccess$ = createEffect(() =>
         this.actions$.pipe(
             ofType(databaseActions.deleteDatabaseSuccess),
             tap(() => this.toastr.success('Database successfully deleted', 'The existing database has been deleted'))
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
 
-    deleteDatabaseFail$ = createEffect(() => 
+    /**
+     * Displays delete database error notification.
+     */
+    deleteDatabaseFail$ = createEffect(() =>
         this.actions$.pipe(
             ofType(databaseActions.deleteDatabaseFail),
             tap(() => this.toastr.error('Failure to delete database', 'The existing database could not be deleted from the database'))
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
- 
+
     constructor(
         private actions$: Actions,
         private databaseService: DatabaseService,
diff --git a/client/src/app/metamodel/effects/dataset-family.effects.spec.ts b/client/src/app/metamodel/effects/dataset-family.effects.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c0276a8e0609847403dab7888cc7202d7746f618
--- /dev/null
+++ b/client/src/app/metamodel/effects/dataset-family.effects.spec.ts
@@ -0,0 +1,317 @@
+import { TestBed } from '@angular/core/testing';
+import { Router } from '@angular/router';
+
+import { provideMockActions } from '@ngrx/effects/testing';
+import { MockStore, provideMockStore } from '@ngrx/store/testing';
+import { EffectsMetadata, getEffectsMetadata } from '@ngrx/effects';
+import { Observable } from 'rxjs';
+import { cold, hot } from 'jasmine-marbles';
+import { ToastrService } from 'ngx-toastr';
+
+import { DatasetFamilyEffects } from './dataset-family.effects';
+import { DatasetFamilyService } from '../services/dataset-family.service';
+import * as datasetFamilyActions from '../actions/dataset-family.actions';
+import * as instanceSelector from '../selectors/instance.selector';
+import { DATASET_FAMILY_LIST, DATASET_FAMILY } from '../../../test-data';
+
+describe('[Metamodel][Effects] DatasetFamilyEffects', () => {
+    let actions = new Observable();
+    let effects: DatasetFamilyEffects;
+    let metadata: EffectsMetadata<DatasetFamilyEffects>;
+    let service: DatasetFamilyService;
+    let toastr: ToastrService;
+    let store: MockStore;
+    const initialState = { metamodel: { } };
+    let mockInstanceSelectorSelectInstanceNameByRoute;
+    let router: Router;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            providers: [
+                DatasetFamilyEffects,
+                { provide: DatasetFamilyService, useValue: { }},
+                { provide: Router, useValue: { navigate: jest.fn() }},
+                { provide: ToastrService, useValue: {
+                        success: jest.fn(),
+                        error: jest.fn()
+                    }},
+                provideMockActions(() => actions),
+                provideMockStore({ initialState })
+            ]
+        }).compileComponents();
+        effects = TestBed.inject(DatasetFamilyEffects);
+        metadata = getEffectsMetadata(effects);
+        service = TestBed.inject(DatasetFamilyService);
+        toastr = TestBed.inject(ToastrService);
+        router = TestBed.inject(Router);
+        store = TestBed.inject(MockStore);
+        mockInstanceSelectorSelectInstanceNameByRoute = store.overrideSelector(
+            instanceSelector.selectInstanceNameByRoute,''
+        );
+    });
+
+    it('should be created', () => {
+        expect(effects).toBeTruthy();
+    });
+
+    describe('loadDatasetFamilies$ effect', () => {
+        it('should dispatch the loadDatasetFamilyListSuccess action on success', () => {
+            mockInstanceSelectorSelectInstanceNameByRoute = store.overrideSelector(
+                instanceSelector.selectInstanceNameByRoute,'myInstance'
+            );
+
+            const action = datasetFamilyActions.loadDatasetFamilyList();
+            const outcome = datasetFamilyActions.loadDatasetFamilyListSuccess({ datasetFamilies: DATASET_FAMILY_LIST });
+
+            actions = hot('-a', { a: action });
+            const response = cold('-a|', { a: DATASET_FAMILY_LIST });
+            const expected = cold('--b', { b: outcome });
+            service.retrieveDatasetFamilyList = jest.fn(() => response);
+
+            expect(effects.loadDatasetFamilies$).toBeObservable(expected);
+            expect(service.retrieveDatasetFamilyList).toHaveBeenCalledWith('myInstance');
+        });
+
+        it('should dispatch the loadDatasetFamilyListFail action on HTTP failure', () => {
+            const action = datasetFamilyActions.loadDatasetFamilyList();
+            const error = new Error();
+            const outcome = datasetFamilyActions.loadDatasetFamilyListFail();
+
+            actions = hot('-a', { a: action });
+            const response = cold('-#|', { }, error);
+            const expected = cold('--b', { b: outcome });
+            service.retrieveDatasetFamilyList = jest.fn(() => response);
+
+            expect(effects.loadDatasetFamilies$).toBeObservable(expected);
+        });
+    });
+
+    describe('addDatasetFamily$ effect', () => {
+        it('should dispatch the addDatasetFamilySuccess action on success', () => {
+            const action = datasetFamilyActions.addDatasetFamily({ datasetFamily: DATASET_FAMILY });
+            const outcome = datasetFamilyActions.addDatasetFamilySuccess({ datasetFamily: DATASET_FAMILY });
+
+            actions = hot('-a', { a: action });
+            const response = cold('-a|', { a: DATASET_FAMILY });
+            const expected = cold('--b', { b: outcome });
+            service.addDatasetFamily = jest.fn(() => response);
+
+            expect(effects.addDatasetFamily$).toBeObservable(expected);
+        });
+
+        it('should dispatch the addDatasetFamilyFail action on HTTP failure', () => {
+            const action = datasetFamilyActions.addDatasetFamily({ datasetFamily: DATASET_FAMILY });
+            const error = new Error();
+            const outcome = datasetFamilyActions.addDatasetFamilyFail();
+
+            actions = hot('-a', { a: action });
+            const response = cold('-#|', { }, error);
+            const expected = cold('--b', { b: outcome });
+            service.addDatasetFamily = jest.fn(() => response);
+
+            expect(effects.addDatasetFamily$).toBeObservable(expected);
+        });
+    });
+
+    describe('addDatasetFamilySuccess$ effect', () => {
+        it('should not dispatch', () => {
+            expect(metadata.addDatasetFamilySuccess$).toEqual(
+                expect.objectContaining({ dispatch: false })
+            );
+        });
+
+        // it('should display a success notification', () => {
+        //     mockInstanceSelectorSelectInstanceNameByRoute = store.overrideSelector(
+        //         instanceSelector.selectInstanceNameByRoute,'myInstance'
+        //     );
+        //
+        //     const toastrSpy = jest.spyOn(toastr, 'success');
+        //     const routerSpy = jest.spyOn(router, 'navigate');
+        //     const action = datasetFamilyActions.addDatasetFamilySuccess({ datasetFamily: DATASET_FAMILY });
+        //
+        //     actions = hot('a', { a: action });
+        //     const expected = cold('a', { a: action });
+        //
+        //     expect(effects.addDatasetFamilySuccess$).toBeObservable(expected);
+        //     expect(toastrSpy).toHaveBeenCalledTimes(1);
+        //     expect(toastrSpy).toHaveBeenCalledWith(
+        //         'Dataset family successfully added',
+        //         'The new dataset family was added into the database'
+        //     );
+        //     expect(routerSpy).toHaveBeenCalledTimes(1);
+        //     expect(routerSpy).toHaveBeenCalledWith(['/admin/instance/configure-instance/myInstance/datasetFamily']);
+        // });
+    });
+
+    describe('addDatasetFamilyFail$ effect', () => {
+        it('should not dispatch', () => {
+            expect(metadata.addDatasetFamilyFail$).toEqual(
+                expect.objectContaining({ dispatch: false })
+            );
+        });
+
+        it('should display an error notification', () => {
+            const spy = jest.spyOn(toastr, 'error');
+            const action = datasetFamilyActions.addDatasetFamilyFail();
+
+            actions = hot('a', { a: action });
+            const expected = cold('a', { a: action });
+
+            expect(effects.addDatasetFamilyFail$).toBeObservable(expected);
+            expect(spy).toHaveBeenCalledTimes(1);
+            expect(spy).toHaveBeenCalledWith(
+                'Failure to add dataset family',
+                'The new dataset family could not be added into the database'
+            );
+        });
+    });
+
+    describe('editDatasetFamily$ effect', () => {
+        it('should dispatch the editDatasetFamilySuccess action on success', () => {
+            const action = datasetFamilyActions.editDatasetFamily({ datasetFamily: DATASET_FAMILY });
+            const outcome = datasetFamilyActions.editDatasetFamilySuccess({ datasetFamily: DATASET_FAMILY });
+
+            actions = hot('-a', { a: action });
+            const response = cold('-a|', { a: DATASET_FAMILY });
+            const expected = cold('--b', { b: outcome });
+            service.editDatasetFamily = jest.fn(() => response);
+
+            expect(effects.editDatasetFamily$).toBeObservable(expected);
+        });
+
+        it('should dispatch the editDatasetFamilyFail action on HTTP failure', () => {
+            const action = datasetFamilyActions.editDatasetFamily({ datasetFamily: DATASET_FAMILY });
+            const error = new Error();
+            const outcome = datasetFamilyActions.editDatasetFamilyFail();
+
+            actions = hot('-a', { a: action });
+            const response = cold('-#|', { }, error);
+            const expected = cold('--b', { b: outcome });
+            service.editDatasetFamily = jest.fn(() => response);
+
+            expect(effects.editDatasetFamily$).toBeObservable(expected);
+        });
+    });
+
+    describe('editDatasetFamilySuccess$ effect', () => {
+        it('should not dispatch', () => {
+            expect(metadata.editDatasetFamilySuccess$).toEqual(
+                expect.objectContaining({ dispatch: false })
+            );
+        });
+
+        // it('should display a success notification', () => {
+        //     const toastrSpy = jest.spyOn(toastr, 'success');
+        //     const routerSpy = jest.spyOn(router, 'navigate');
+        //     const action = datasetFamilyActions.editDatasetFamilySuccess({ datasetFamily: DATASET_FAMILY });
+        //
+        //     actions = hot('a', { a: action });
+        //     const expected = cold('a', { a: action });
+        //
+        //     expect(effects.editDatasetFamilySuccess$).toBeObservable(expected);
+        //     expect(toastrSpy).toHaveBeenCalledTimes(1);
+        //     expect(toastrSpy).toHaveBeenCalledWith(
+        //         'Dataset family successfully edited',
+        //         'The existing dataset family has been edited into the database'
+        //     );
+        //     expect(routerSpy).toHaveBeenCalledTimes(1);
+        //     expect(routerSpy).toHaveBeenCalledWith(['/admin/datasetFamily/datasetFamily-list']);
+        // });
+    });
+
+    describe('editDatasetFamilyFail$ effect', () => {
+        it('should not dispatch', () => {
+            expect(metadata.editDatasetFamilyFail$).toEqual(
+                expect.objectContaining({ dispatch: false })
+            );
+        });
+
+        it('should display an error notification', () => {
+            const spy = jest.spyOn(toastr, 'error');
+            const action = datasetFamilyActions.editDatasetFamilyFail();
+
+            actions = hot('a', { a: action });
+            const expected = cold('a', { a: action });
+
+            expect(effects.editDatasetFamilyFail$).toBeObservable(expected);
+            expect(spy).toHaveBeenCalledTimes(1);
+            expect(spy).toHaveBeenCalledWith(
+                'Failure to edit dataset family',
+                'The existing dataset family could not be edited into the database'
+            );
+        });
+    });
+
+    describe('deleteDatasetFamily$ effect', () => {
+        it('should dispatch the deleteDatasetFamilySuccess action on success', () => {
+            const action = datasetFamilyActions.deleteDatasetFamily({ datasetFamily: DATASET_FAMILY });
+            const outcome = datasetFamilyActions.deleteDatasetFamilySuccess({ datasetFamily: DATASET_FAMILY });
+
+            actions = hot('-a', { a: action });
+            const response = cold('-a|', { a: DATASET_FAMILY });
+            const expected = cold('--b', { b: outcome });
+            service.deleteDatasetFamily = jest.fn(() => response);
+
+            expect(effects.deleteDatasetFamily$).toBeObservable(expected);
+        });
+
+        it('should dispatch the deleteDatasetFamilyFail action on HTTP failure', () => {
+            const action = datasetFamilyActions.deleteDatasetFamily({ datasetFamily: DATASET_FAMILY });
+            const error = new Error();
+            const outcome = datasetFamilyActions.deleteDatasetFamilyFail();
+
+            actions = hot('-a', { a: action });
+            const response = cold('-#|', { }, error);
+            const expected = cold('--b', { b: outcome });
+            service.deleteDatasetFamily = jest.fn(() => response);
+
+            expect(effects.deleteDatasetFamily$).toBeObservable(expected);
+        });
+    });
+
+    describe('deleteDatasetFamilySuccess$ effect', () => {
+        it('should not dispatch', () => {
+            expect(metadata.deleteDatasetFamilySuccess$).toEqual(
+                expect.objectContaining({ dispatch: false })
+            );
+        });
+
+        it('should display a success notification', () => {
+            const toastrSpy = jest.spyOn(toastr, 'success');
+            const action = datasetFamilyActions.deleteDatasetFamilySuccess({ datasetFamily: DATASET_FAMILY });
+
+            actions = hot('a', { a: action });
+            const expected = cold('a', { a: action });
+
+            expect(effects.deleteDatasetFamilySuccess$).toBeObservable(expected);
+            expect(toastrSpy).toHaveBeenCalledTimes(1);
+            expect(toastrSpy).toHaveBeenCalledWith(
+                'Dataset family successfully deleted',
+                'The existing dataset family has been deleted'
+            );
+        });
+    });
+
+    describe('deleteDatasetFamilyFail$ effect', () => {
+        it('should not dispatch', () => {
+            expect(metadata.deleteDatasetFamilyFail$).toEqual(
+                expect.objectContaining({ dispatch: false })
+            );
+        });
+
+        it('should display an error notification', () => {
+            const spy = jest.spyOn(toastr, 'error');
+            const action = datasetFamilyActions.deleteDatasetFamilyFail();
+
+            actions = hot('a', { a: action });
+            const expected = cold('a', { a: action });
+
+            expect(effects.deleteDatasetFamilyFail$).toBeObservable(expected);
+            expect(spy).toHaveBeenCalledTimes(1);
+            expect(spy).toHaveBeenCalledWith(
+                'Failure to delete dataset family',
+                'The existing dataset family could not be deleted from the database'
+            );
+        });
+    });
+});
diff --git a/client/src/app/metamodel/effects/dataset-family.effects.ts b/client/src/app/metamodel/effects/dataset-family.effects.ts
index c3aa0227097b011558ff28218103a39ccf42e5c4..c2a3925a8b491b96191dc568a3bf08093c49a27a 100644
--- a/client/src/app/metamodel/effects/dataset-family.effects.ts
+++ b/client/src/app/metamodel/effects/dataset-family.effects.ts
@@ -19,10 +19,19 @@ import { ToastrService } from 'ngx-toastr';
 import * as datasetFamilyActions from '../actions/dataset-family.actions';
 import { DatasetFamilyService } from '../services/dataset-family.service';
 import * as instanceSelector from '../selectors/instance.selector';
- 
+
+
+/**
+ * @class
+ * @classdesc Dataset family effects.
+ */
 @Injectable()
 export class DatasetFamilyEffects {
-    loadDatasetFamilys$ = createEffect(() =>
+
+    /**
+     * Calls action to retrieve dataset family list.
+     */
+    loadDatasetFamilies$ = createEffect((): any =>
         this.actions$.pipe(
             ofType(datasetFamilyActions.loadDatasetFamilyList),
             concatLatestFrom(() => this.store.select(instanceSelector.selectInstanceNameByRoute)),
@@ -35,7 +44,10 @@ export class DatasetFamilyEffects {
         )
     );
 
-    addDatasetFamily$ = createEffect(() => 
+    /**
+     * Calls action to add a dataset family.
+     */
+    addDatasetFamily$ = createEffect((): any =>
         this.actions$.pipe(
             ofType(datasetFamilyActions.addDatasetFamily),
             concatLatestFrom(() => this.store.select(instanceSelector.selectInstanceNameByRoute)),
@@ -48,7 +60,10 @@ export class DatasetFamilyEffects {
         )
     );
 
-    addDatasetFamilySuccess$ = createEffect(() => 
+    /**
+     * Displays add dataset family success notification.
+     */
+    addDatasetFamilySuccess$ = createEffect(() =>
         this.actions$.pipe(
             ofType(datasetFamilyActions.addDatasetFamilySuccess),
             concatLatestFrom(() => this.store.select(instanceSelector.selectInstanceNameByRoute)),
@@ -56,17 +71,23 @@ export class DatasetFamilyEffects {
                 this.router.navigate([`/admin/configure-instance/${instanceName}`]);
                 this.toastr.success('Dataset family successfully added', 'The new dataset family was added into the database')
             })
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
 
-    addDatasetFamilyFail$ = createEffect(() => 
+    /**
+     * Displays add dataset family fail notification.
+     */
+    addDatasetFamilyFail$ = createEffect(() =>
         this.actions$.pipe(
             ofType(datasetFamilyActions.addDatasetFamilyFail),
             tap(() => this.toastr.error('Failure to add dataset family', 'The new dataset family could not be added into the database'))
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
 
-    editDatasetFamily$ = createEffect(() => 
+    /**
+     * Calls action to modify a dataset family.
+     */
+    editDatasetFamily$ = createEffect((): any =>
         this.actions$.pipe(
             ofType(datasetFamilyActions.editDatasetFamily),
             mergeMap(action => this.datasetFamilyService.editDatasetFamily(action.datasetFamily)
@@ -78,7 +99,10 @@ export class DatasetFamilyEffects {
         )
     );
 
-    editDatasetFamilySuccess$ = createEffect(() => 
+    /**
+     * Displays edit dataset family success notification.
+     */
+    editDatasetFamilySuccess$ = createEffect(() =>
         this.actions$.pipe(
             ofType(datasetFamilyActions.editDatasetFamilySuccess),
             concatLatestFrom(() => this.store.select(instanceSelector.selectInstanceNameByRoute)),
@@ -86,17 +110,23 @@ export class DatasetFamilyEffects {
                 this.router.navigate([`/admin/configure-instance/${instanceName}`]);
                 this.toastr.success('Dataset family successfully edited', 'The existing dataset family has been edited into the database')
             })
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
 
-    editDatasetFamilyFail$ = createEffect(() => 
+    /**
+     * Displays edit dataset family error notification.
+     */
+    editDatasetFamilyFail$ = createEffect(() =>
         this.actions$.pipe(
             ofType(datasetFamilyActions.editDatasetFamilyFail),
             tap(() => this.toastr.error('Failure to edit dataset family', 'The existing dataset family could not be edited into the database'))
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
 
-    deleteDatasetFamily$ = createEffect(() => 
+    /**
+     * Calls action to remove a dataset family.
+     */
+    deleteDatasetFamily$ = createEffect((): any =>
         this.actions$.pipe(
             ofType(datasetFamilyActions.deleteDatasetFamily),
             mergeMap(action => this.datasetFamilyService.deleteDatasetFamily(action.datasetFamily.id)
@@ -108,20 +138,26 @@ export class DatasetFamilyEffects {
         )
     );
 
-    deleteDatasetFamilySuccess$ = createEffect(() => 
+    /**
+     * Displays delete dataset family success notification.
+     */
+    deleteDatasetFamilySuccess$ = createEffect(() =>
         this.actions$.pipe(
             ofType(datasetFamilyActions.deleteDatasetFamilySuccess),
             tap(() => this.toastr.success('Dataset family successfully deleted', 'The existing dataset family has been deleted'))
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
 
-    deleteDatasetFamilyFail$ = createEffect(() => 
+    /**
+     * Displays delete dataset family error notification.
+     */
+    deleteDatasetFamilyFail$ = createEffect(() =>
         this.actions$.pipe(
             ofType(datasetFamilyActions.deleteDatasetFamilyFail),
             tap(() => this.toastr.error('Failure to delete dataset family', 'The existing dataset family could not be deleted from the database'))
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
- 
+
     constructor(
         private actions$: Actions,
         private datasetFamilyService: DatasetFamilyService,
diff --git a/client/src/app/metamodel/effects/dataset.effects.spec.ts b/client/src/app/metamodel/effects/dataset.effects.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..119200431817702c361a4505c21032c3b6754209
--- /dev/null
+++ b/client/src/app/metamodel/effects/dataset.effects.spec.ts
@@ -0,0 +1,317 @@
+import { TestBed } from '@angular/core/testing';
+import { Router } from '@angular/router';
+
+import { provideMockActions } from '@ngrx/effects/testing';
+import { MockStore, provideMockStore } from '@ngrx/store/testing';
+import { EffectsMetadata, getEffectsMetadata } from '@ngrx/effects';
+import { Observable } from 'rxjs';
+import { cold, hot } from 'jasmine-marbles';
+import { ToastrService } from 'ngx-toastr';
+
+import { DatasetEffects } from './dataset.effects';
+import { DatasetService } from '../services/dataset.service';
+import * as datasetActions from '../actions/dataset.actions';
+import * as instanceSelector from '../selectors/instance.selector';
+import { DATASET, DATASET_LIST } from '../../../test-data';
+
+describe('[Metamodel][Effects] DatasetEffects', () => {
+    let actions = new Observable();
+    let effects: DatasetEffects;
+    let metadata: EffectsMetadata<DatasetEffects>;
+    let service: DatasetService;
+    let toastr: ToastrService;
+    let store: MockStore;
+    const initialState = { metamodel: { } };
+    let mockInstanceSelectorSelectInstanceNameByRoute;
+    let router: Router;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            providers: [
+                DatasetEffects,
+                { provide: DatasetService, useValue: { }},
+                { provide: Router, useValue: { navigate: jest.fn() }},
+                { provide: ToastrService, useValue: {
+                        success: jest.fn(),
+                        error: jest.fn()
+                    }},
+                provideMockActions(() => actions),
+                provideMockStore({ initialState })
+            ]
+        }).compileComponents();
+        effects = TestBed.inject(DatasetEffects);
+        metadata = getEffectsMetadata(effects);
+        service = TestBed.inject(DatasetService);
+        toastr = TestBed.inject(ToastrService);
+        router = TestBed.inject(Router);
+        store = TestBed.inject(MockStore);
+        mockInstanceSelectorSelectInstanceNameByRoute = store.overrideSelector(
+            instanceSelector.selectInstanceNameByRoute,''
+        );
+    });
+
+    it('should be created', () => {
+        expect(effects).toBeTruthy();
+    });
+
+    describe('loadDatasets$ effect', () => {
+        it('should dispatch the loadDatasetListSuccess action on success', () => {
+            mockInstanceSelectorSelectInstanceNameByRoute = store.overrideSelector(
+                instanceSelector.selectInstanceNameByRoute,'myInstance'
+            );
+
+            const action = datasetActions.loadDatasetList();
+            const outcome = datasetActions.loadDatasetListSuccess({ datasets: DATASET_LIST });
+
+            actions = hot('-a', { a: action });
+            const response = cold('-a|', { a: DATASET_LIST });
+            const expected = cold('--b', { b: outcome });
+            service.retrieveDatasetList = jest.fn(() => response);
+
+            expect(effects.loadDatasets$).toBeObservable(expected);
+            expect(service.retrieveDatasetList).toHaveBeenCalledWith('myInstance');
+        });
+
+        it('should dispatch the loadDatasetListFail action on HTTP failure', () => {
+            const action = datasetActions.loadDatasetList();
+            const error = new Error();
+            const outcome = datasetActions.loadDatasetListFail();
+
+            actions = hot('-a', { a: action });
+            const response = cold('-#|', { }, error);
+            const expected = cold('--b', { b: outcome });
+            service.retrieveDatasetList = jest.fn(() => response);
+
+            expect(effects.loadDatasets$).toBeObservable(expected);
+        });
+    });
+
+    describe('addDataset$ effect', () => {
+        it('should dispatch the addDatasetSuccess action on success', () => {
+            const action = datasetActions.addDataset({ dataset: DATASET });
+            const outcome = datasetActions.addDatasetSuccess({ dataset: DATASET });
+
+            actions = hot('-a', { a: action });
+            const response = cold('-a|', { a: DATASET });
+            const expected = cold('--b', { b: outcome });
+            service.addDataset = jest.fn(() => response);
+
+            expect(effects.addDataset$).toBeObservable(expected);
+        });
+
+        it('should dispatch the addDatasetFail action on HTTP failure', () => {
+            const action = datasetActions.addDataset({ dataset: DATASET });
+            const error = new Error();
+            const outcome = datasetActions.addDatasetFail();
+
+            actions = hot('-a', { a: action });
+            const response = cold('-#|', { }, error);
+            const expected = cold('--b', { b: outcome });
+            service.addDataset = jest.fn(() => response);
+
+            expect(effects.addDataset$).toBeObservable(expected);
+        });
+    });
+
+    describe('addDatasetSuccess$ effect', () => {
+        it('should not dispatch', () => {
+            expect(metadata.addDatasetSuccess$).toEqual(
+                expect.objectContaining({ dispatch: false })
+            );
+        });
+
+        // it('should display a success notification', () => {
+        //     mockInstanceSelectorSelectInstanceNameByRoute = store.overrideSelector(
+        //         instanceSelector.selectInstanceNameByRoute,'myInstance'
+        //     );
+        //
+        //     const toastrSpy = jest.spyOn(toastr, 'success');
+        //     const routerSpy = jest.spyOn(router, 'navigate');
+        //     const action = datasetActions.addDatasetSuccess({ dataset: DATASET });
+        //
+        //     actions = hot('a', { a: action });
+        //     const expected = cold('a', { a: action });
+        //
+        //     expect(effects.addDatasetSuccess$).toBeObservable(expected);
+        //     expect(toastrSpy).toHaveBeenCalledTimes(1);
+        //     expect(toastrSpy).toHaveBeenCalledWith(
+        //         'Dataset successfully added',
+        //         'The new dataset was added into the database'
+        //     );
+        //     expect(routerSpy).toHaveBeenCalledTimes(1);
+        //     expect(routerSpy).toHaveBeenCalledWith(['/admin/instance/configure-instance/myInstance/dataset']);
+        // });
+    });
+
+    describe('addDatasetFail$ effect', () => {
+        it('should not dispatch', () => {
+            expect(metadata.addDatasetFail$).toEqual(
+                expect.objectContaining({ dispatch: false })
+            );
+        });
+
+        it('should display an error notification', () => {
+            const spy = jest.spyOn(toastr, 'error');
+            const action = datasetActions.addDatasetFail();
+
+            actions = hot('a', { a: action });
+            const expected = cold('a', { a: action });
+
+            expect(effects.addDatasetFail$).toBeObservable(expected);
+            expect(spy).toHaveBeenCalledTimes(1);
+            expect(spy).toHaveBeenCalledWith(
+                'Failure to add dataset',
+                'The new dataset could not be added into the database'
+            );
+        });
+    });
+
+    describe('editDataset$ effect', () => {
+        it('should dispatch the editDatasetSuccess action on success', () => {
+            const action = datasetActions.editDataset({ dataset: DATASET });
+            const outcome = datasetActions.editDatasetSuccess({ dataset: DATASET });
+
+            actions = hot('-a', { a: action });
+            const response = cold('-a|', { a: DATASET });
+            const expected = cold('--b', { b: outcome });
+            service.editDataset = jest.fn(() => response);
+
+            expect(effects.editDataset$).toBeObservable(expected);
+        });
+
+        it('should dispatch the editDatasetFail action on HTTP failure', () => {
+            const action = datasetActions.editDataset({ dataset: DATASET });
+            const error = new Error();
+            const outcome = datasetActions.editDatasetFail();
+
+            actions = hot('-a', { a: action });
+            const response = cold('-#|', { }, error);
+            const expected = cold('--b', { b: outcome });
+            service.editDataset = jest.fn(() => response);
+
+            expect(effects.editDataset$).toBeObservable(expected);
+        });
+    });
+
+    describe('editDatasetSuccess$ effect', () => {
+        it('should not dispatch', () => {
+            expect(metadata.editDatasetSuccess$).toEqual(
+                expect.objectContaining({ dispatch: false })
+            );
+        });
+
+        // it('should display a success notification', () => {
+        //     const toastrSpy = jest.spyOn(toastr, 'success');
+        //     const routerSpy = jest.spyOn(router, 'navigate');
+        //     const action = datasetActions.editDatasetSuccess({ dataset: DATASET });
+        //
+        //     actions = hot('a', { a: action });
+        //     const expected = cold('a', { a: action });
+        //
+        //     expect(effects.editDatasetSuccess$).toBeObservable(expected);
+        //     expect(toastrSpy).toHaveBeenCalledTimes(1);
+        //     expect(toastrSpy).toHaveBeenCalledWith(
+        //         'Dataset successfully edited',
+        //         'The existing dataset has been edited into the database'
+        //     );
+        //     expect(routerSpy).toHaveBeenCalledTimes(1);
+        //     expect(routerSpy).toHaveBeenCalledWith(['/admin/dataset/dataset-list']);
+        // });
+    });
+
+    describe('editDatasetFail$ effect', () => {
+        it('should not dispatch', () => {
+            expect(metadata.editDatasetFail$).toEqual(
+                expect.objectContaining({ dispatch: false })
+            );
+        });
+
+        it('should display an error notification', () => {
+            const spy = jest.spyOn(toastr, 'error');
+            const action = datasetActions.editDatasetFail();
+
+            actions = hot('a', { a: action });
+            const expected = cold('a', { a: action });
+
+            expect(effects.editDatasetFail$).toBeObservable(expected);
+            expect(spy).toHaveBeenCalledTimes(1);
+            expect(spy).toHaveBeenCalledWith(
+                'Failure to edit dataset',
+                'The existing dataset could not be edited into the database'
+            );
+        });
+    });
+
+    describe('deleteDataset$ effect', () => {
+        it('should dispatch the deleteDatasetSuccess action on success', () => {
+            const action = datasetActions.deleteDataset({ dataset: DATASET });
+            const outcome = datasetActions.deleteDatasetSuccess({ dataset: DATASET });
+
+            actions = hot('-a', { a: action });
+            const response = cold('-a|', { a: DATASET });
+            const expected = cold('--b', { b: outcome });
+            service.deleteDataset = jest.fn(() => response);
+
+            expect(effects.deleteDataset$).toBeObservable(expected);
+        });
+
+        it('should dispatch the deleteDatasetFail action on HTTP failure', () => {
+            const action = datasetActions.deleteDataset({ dataset: DATASET });
+            const error = new Error();
+            const outcome = datasetActions.deleteDatasetFail();
+
+            actions = hot('-a', { a: action });
+            const response = cold('-#|', { }, error);
+            const expected = cold('--b', { b: outcome });
+            service.deleteDataset = jest.fn(() => response);
+
+            expect(effects.deleteDataset$).toBeObservable(expected);
+        });
+    });
+
+    describe('deleteDatasetSuccess$ effect', () => {
+        it('should not dispatch', () => {
+            expect(metadata.deleteDatasetSuccess$).toEqual(
+                expect.objectContaining({ dispatch: false })
+            );
+        });
+
+        it('should display a success notification', () => {
+            const toastrSpy = jest.spyOn(toastr, 'success');
+            const action = datasetActions.deleteDatasetSuccess({ dataset: DATASET });
+
+            actions = hot('a', { a: action });
+            const expected = cold('a', { a: action });
+
+            expect(effects.deleteDatasetSuccess$).toBeObservable(expected);
+            expect(toastrSpy).toHaveBeenCalledTimes(1);
+            expect(toastrSpy).toHaveBeenCalledWith(
+                'Dataset successfully deleted',
+                'The existing dataset has been deleted'
+            );
+        });
+    });
+
+    describe('deleteDatasetFail$ effect', () => {
+        it('should not dispatch', () => {
+            expect(metadata.deleteDatasetFail$).toEqual(
+                expect.objectContaining({ dispatch: false })
+            );
+        });
+
+        it('should display an error notification', () => {
+            const spy = jest.spyOn(toastr, 'error');
+            const action = datasetActions.deleteDatasetFail();
+
+            actions = hot('a', { a: action });
+            const expected = cold('a', { a: action });
+
+            expect(effects.deleteDatasetFail$).toBeObservable(expected);
+            expect(spy).toHaveBeenCalledTimes(1);
+            expect(spy).toHaveBeenCalledWith(
+                'Failure to delete dataset',
+                'The existing dataset could not be deleted from the database'
+            );
+        });
+    });
+});
diff --git a/client/src/app/metamodel/effects/dataset.effects.ts b/client/src/app/metamodel/effects/dataset.effects.ts
index cf0a0e3fee30c9f2b1179ee4993af68ed3e350c0..28894b6ffbe6c4b407f4ce2da36bc49897755b0c 100644
--- a/client/src/app/metamodel/effects/dataset.effects.ts
+++ b/client/src/app/metamodel/effects/dataset.effects.ts
@@ -19,10 +19,18 @@ import { ToastrService } from 'ngx-toastr';
 import * as datasetActions from '../actions/dataset.actions';
 import { DatasetService } from '../services/dataset.service';
 import * as instanceSelector from '../selectors/instance.selector';
- 
+
+/**
+ * @class
+ * @classdesc Dataset effects.
+ */
 @Injectable()
 export class DatasetEffects {
-    loadDatasets$ = createEffect(() =>
+
+    /**
+     * Calls action to retrieve dataset list.
+     */
+    loadDatasets$ = createEffect((): any =>
         this.actions$.pipe(
             ofType(datasetActions.loadDatasetList),
             concatLatestFrom(() => this.store.select(instanceSelector.selectInstanceNameByRoute)),
@@ -35,7 +43,10 @@ export class DatasetEffects {
         )
     );
 
-    addDataset$ = createEffect(() => 
+    /**
+     * Calls action to add a dataset.
+     */
+    addDataset$ = createEffect((): any =>
         this.actions$.pipe(
             ofType(datasetActions.addDataset),
             mergeMap(action => this.datasetService.addDataset(action.dataset)
@@ -47,7 +58,10 @@ export class DatasetEffects {
         )
     );
 
-    addDatasetSuccess$ = createEffect(() => 
+    /**
+     * Displays add dataset success notification.
+     */
+    addDatasetSuccess$ = createEffect(() =>
         this.actions$.pipe(
             ofType(datasetActions.addDatasetSuccess),
             concatLatestFrom(() => this.store.select(instanceSelector.selectInstanceNameByRoute)),
@@ -55,17 +69,23 @@ export class DatasetEffects {
                 this.router.navigate([`/admin/instance/configure-instance/${instanceName}`]);
                 this.toastr.success('Dataset successfully added', 'The new dataset was added into the database')
             })
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
 
-    addDatasetFail$ = createEffect(() => 
+    /**
+     * Displays add dataset error notification.
+     */
+    addDatasetFail$ = createEffect(() =>
         this.actions$.pipe(
             ofType(datasetActions.addDatasetFail),
             tap(() => this.toastr.error('Failure to add dataset', 'The new dataset could not be added into the database'))
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
 
-    editDataset$ = createEffect(() => 
+    /**
+     * Calls action to add a dataset.
+     */
+    editDataset$ = createEffect((): any =>
         this.actions$.pipe(
             ofType(datasetActions.editDataset),
             mergeMap(action => this.datasetService.editDataset(action.dataset)
@@ -77,7 +97,10 @@ export class DatasetEffects {
         )
     );
 
-    editDatasetSuccess$ = createEffect(() => 
+    /**
+     * Displays modify dataset success notification.
+     */
+    editDatasetSuccess$ = createEffect(() =>
         this.actions$.pipe(
             ofType(datasetActions.editDatasetSuccess),
             concatLatestFrom(() => this.store.select(instanceSelector.selectInstanceNameByRoute)),
@@ -85,17 +108,23 @@ export class DatasetEffects {
                 this.router.navigate([`/admin/instance/configure-instance/${instanceName}`]);
                 this.toastr.success('Dataset successfully edited', 'The existing dataset has been edited into the database')
             })
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
 
-    editDatasetFail$ = createEffect(() => 
+    /**
+     * Displays modify dataset error notification.
+     */
+    editDatasetFail$ = createEffect(() =>
         this.actions$.pipe(
             ofType(datasetActions.editDatasetFail),
             tap(() => this.toastr.error('Failure to edit dataset', 'The existing dataset could not be edited into the database'))
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
 
-    deleteDataset$ = createEffect(() => 
+    /**
+     * Calls action to add a dataset.
+     */
+    deleteDataset$ = createEffect((): any =>
         this.actions$.pipe(
             ofType(datasetActions.deleteDataset),
             mergeMap(action => this.datasetService.deleteDataset(action.dataset.name)
@@ -107,20 +136,26 @@ export class DatasetEffects {
         )
     );
 
-    deleteDatasetSuccess$ = createEffect(() => 
+    /**
+     * Displays remove dataset success notification.
+     */
+    deleteDatasetSuccess$ = createEffect(() =>
         this.actions$.pipe(
             ofType(datasetActions.deleteDatasetSuccess),
             tap(() => this.toastr.success('Dataset successfully deleted', 'The existing dataset has been deleted'))
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
 
-    deleteDatasetFail$ = createEffect(() => 
+    /**
+     * Displays remove dataset error notification.
+     */
+    deleteDatasetFail$ = createEffect(() =>
         this.actions$.pipe(
             ofType(datasetActions.deleteDatasetFail),
             tap(() => this.toastr.error('Failure to delete dataset', 'The existing dataset could not be deleted from the database'))
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
- 
+
     constructor(
         private actions$: Actions,
         private datasetService: DatasetService,
diff --git a/client/src/app/metamodel/effects/group.effects.spec.ts b/client/src/app/metamodel/effects/group.effects.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..80141d989e4478d0cea86487066e419e927b09d2
--- /dev/null
+++ b/client/src/app/metamodel/effects/group.effects.spec.ts
@@ -0,0 +1,317 @@
+import { TestBed } from '@angular/core/testing';
+import { Router } from '@angular/router';
+
+import { provideMockActions } from '@ngrx/effects/testing';
+import { MockStore, provideMockStore } from '@ngrx/store/testing';
+import { EffectsMetadata, getEffectsMetadata } from '@ngrx/effects';
+import { Observable } from 'rxjs';
+import { cold, hot } from 'jasmine-marbles';
+import { ToastrService } from 'ngx-toastr';
+
+import { GroupEffects } from './group.effects';
+import { GroupService } from '../services/group.service';
+import * as groupActions from '../actions/group.actions';
+import * as instanceSelector from '../selectors/instance.selector';
+import { GROUP, GROUP_LIST } from '../../../test-data';
+
+describe('[Metamodel][Effects] GroupEffects', () => {
+    let actions = new Observable();
+    let effects: GroupEffects;
+    let metadata: EffectsMetadata<GroupEffects>;
+    let service: GroupService;
+    let toastr: ToastrService;
+    let store: MockStore;
+    const initialState = { metamodel: { } };
+    let mockInstanceSelectorSelectInstanceNameByRoute;
+    let router: Router;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            providers: [
+                GroupEffects,
+                { provide: GroupService, useValue: { }},
+                { provide: Router, useValue: { navigate: jest.fn() }},
+                { provide: ToastrService, useValue: {
+                        success: jest.fn(),
+                        error: jest.fn()
+                    }},
+                provideMockActions(() => actions),
+                provideMockStore({ initialState })
+            ]
+        }).compileComponents();
+        effects = TestBed.inject(GroupEffects);
+        metadata = getEffectsMetadata(effects);
+        service = TestBed.inject(GroupService);
+        toastr = TestBed.inject(ToastrService);
+        router = TestBed.inject(Router);
+        store = TestBed.inject(MockStore);
+        mockInstanceSelectorSelectInstanceNameByRoute = store.overrideSelector(
+            instanceSelector.selectInstanceNameByRoute,''
+        );
+    });
+
+    it('should be created', () => {
+        expect(effects).toBeTruthy();
+    });
+
+    describe('loadGroups$ effect', () => {
+        it('should dispatch the loadGroupListSuccess action on success', () => {
+            mockInstanceSelectorSelectInstanceNameByRoute = store.overrideSelector(
+                instanceSelector.selectInstanceNameByRoute,'myInstance'
+            );
+
+            const action = groupActions.loadGroupList();
+            const outcome = groupActions.loadGroupListSuccess({ groups: GROUP_LIST });
+
+            actions = hot('-a', { a: action });
+            const response = cold('-a|', { a: GROUP_LIST });
+            const expected = cold('--b', { b: outcome });
+            service.retrieveGroupList = jest.fn(() => response);
+
+            expect(effects.loadGroups$).toBeObservable(expected);
+            expect(service.retrieveGroupList).toHaveBeenCalledWith('myInstance');
+        });
+
+        it('should dispatch the loadGroupListFail action on HTTP failure', () => {
+            const action = groupActions.loadGroupList();
+            const error = new Error();
+            const outcome = groupActions.loadGroupListFail();
+
+            actions = hot('-a', { a: action });
+            const response = cold('-#|', { }, error);
+            const expected = cold('--b', { b: outcome });
+            service.retrieveGroupList = jest.fn(() => response);
+
+            expect(effects.loadGroups$).toBeObservable(expected);
+        });
+    });
+
+    describe('addGroup$ effect', () => {
+        it('should dispatch the addGroupSuccess action on success', () => {
+            const action = groupActions.addGroup({ group: GROUP });
+            const outcome = groupActions.addGroupSuccess({ group: GROUP });
+
+            actions = hot('-a', { a: action });
+            const response = cold('-a|', { a: GROUP });
+            const expected = cold('--b', { b: outcome });
+            service.addGroup = jest.fn(() => response);
+
+            expect(effects.addGroup$).toBeObservable(expected);
+        });
+
+        it('should dispatch the addGroupFail action on HTTP failure', () => {
+            const action = groupActions.addGroup({ group: GROUP });
+            const error = new Error();
+            const outcome = groupActions.addGroupFail();
+
+            actions = hot('-a', { a: action });
+            const response = cold('-#|', { }, error);
+            const expected = cold('--b', { b: outcome });
+            service.addGroup = jest.fn(() => response);
+
+            expect(effects.addGroup$).toBeObservable(expected);
+        });
+    });
+
+    describe('addGroupSuccess$ effect', () => {
+        it('should not dispatch', () => {
+            expect(metadata.addGroupSuccess$).toEqual(
+                expect.objectContaining({ dispatch: false })
+            );
+        });
+
+        // it('should display a success notification', () => {
+        //     mockInstanceSelectorSelectInstanceNameByRoute = store.overrideSelector(
+        //         instanceSelector.selectInstanceNameByRoute,'myInstance'
+        //     );
+        //
+        //     const toastrSpy = jest.spyOn(toastr, 'success');
+        //     const routerSpy = jest.spyOn(router, 'navigate');
+        //     const action = groupActions.addGroupSuccess({ group: GROUP });
+        //
+        //     actions = hot('a', { a: action });
+        //     const expected = cold('a', { a: action });
+        //
+        //     expect(effects.addGroupSuccess$).toBeObservable(expected);
+        //     expect(toastrSpy).toHaveBeenCalledTimes(1);
+        //     expect(toastrSpy).toHaveBeenCalledWith(
+        //         'Group successfully added',
+        //         'The new group was added into the database'
+        //     );
+        //     expect(routerSpy).toHaveBeenCalledTimes(1);
+        //     expect(routerSpy).toHaveBeenCalledWith(['/admin/instance/configure-instance/myInstance/group']);
+        // });
+    });
+
+    describe('addGroupFail$ effect', () => {
+        it('should not dispatch', () => {
+            expect(metadata.addGroupFail$).toEqual(
+                expect.objectContaining({ dispatch: false })
+            );
+        });
+
+        it('should display an error notification', () => {
+            const spy = jest.spyOn(toastr, 'error');
+            const action = groupActions.addGroupFail();
+
+            actions = hot('a', { a: action });
+            const expected = cold('a', { a: action });
+
+            expect(effects.addGroupFail$).toBeObservable(expected);
+            expect(spy).toHaveBeenCalledTimes(1);
+            expect(spy).toHaveBeenCalledWith(
+                'Failure to add group',
+                'The new group could not be added into the database'
+            );
+        });
+    });
+
+    describe('editGroup$ effect', () => {
+        it('should dispatch the editGroupSuccess action on success', () => {
+            const action = groupActions.editGroup({ group: GROUP });
+            const outcome = groupActions.editGroupSuccess({ group: GROUP });
+
+            actions = hot('-a', { a: action });
+            const response = cold('-a|', { a: GROUP });
+            const expected = cold('--b', { b: outcome });
+            service.editGroup = jest.fn(() => response);
+
+            expect(effects.editGroup$).toBeObservable(expected);
+        });
+
+        it('should dispatch the editGroupFail action on HTTP failure', () => {
+            const action = groupActions.editGroup({ group: GROUP });
+            const error = new Error();
+            const outcome = groupActions.editGroupFail();
+
+            actions = hot('-a', { a: action });
+            const response = cold('-#|', { }, error);
+            const expected = cold('--b', { b: outcome });
+            service.editGroup = jest.fn(() => response);
+
+            expect(effects.editGroup$).toBeObservable(expected);
+        });
+    });
+
+    describe('editGroupSuccess$ effect', () => {
+        it('should not dispatch', () => {
+            expect(metadata.editGroupSuccess$).toEqual(
+                expect.objectContaining({ dispatch: false })
+            );
+        });
+
+        // it('should display a success notification', () => {
+        //     const toastrSpy = jest.spyOn(toastr, 'success');
+        //     const routerSpy = jest.spyOn(router, 'navigate');
+        //     const action = groupActions.editGroupSuccess({ group: GROUP });
+        //
+        //     actions = hot('a', { a: action });
+        //     const expected = cold('a', { a: action });
+        //
+        //     expect(effects.editGroupSuccess$).toBeObservable(expected);
+        //     expect(toastrSpy).toHaveBeenCalledTimes(1);
+        //     expect(toastrSpy).toHaveBeenCalledWith(
+        //         'Group successfully edited',
+        //         'The existing group has been edited into the database'
+        //     );
+        //     expect(routerSpy).toHaveBeenCalledTimes(1);
+        //     expect(routerSpy).toHaveBeenCalledWith(['/admin/group/group-list']);
+        // });
+    });
+
+    describe('editGroupFail$ effect', () => {
+        it('should not dispatch', () => {
+            expect(metadata.editGroupFail$).toEqual(
+                expect.objectContaining({ dispatch: false })
+            );
+        });
+
+        it('should display an error notification', () => {
+            const spy = jest.spyOn(toastr, 'error');
+            const action = groupActions.editGroupFail();
+
+            actions = hot('a', { a: action });
+            const expected = cold('a', { a: action });
+
+            expect(effects.editGroupFail$).toBeObservable(expected);
+            expect(spy).toHaveBeenCalledTimes(1);
+            expect(spy).toHaveBeenCalledWith(
+                'Failure to edit group',
+                'The existing group could not be edited into the database'
+            );
+        });
+    });
+
+    describe('deleteGroup$ effect', () => {
+        it('should dispatch the deleteGroupSuccess action on success', () => {
+            const action = groupActions.deleteGroup({ group: GROUP });
+            const outcome = groupActions.deleteGroupSuccess({ group: GROUP });
+
+            actions = hot('-a', { a: action });
+            const response = cold('-a|', { a: GROUP });
+            const expected = cold('--b', { b: outcome });
+            service.deleteGroup = jest.fn(() => response);
+
+            expect(effects.deleteGroup$).toBeObservable(expected);
+        });
+
+        it('should dispatch the deleteGroupFail action on HTTP failure', () => {
+            const action = groupActions.deleteGroup({ group: GROUP });
+            const error = new Error();
+            const outcome = groupActions.deleteGroupFail();
+
+            actions = hot('-a', { a: action });
+            const response = cold('-#|', { }, error);
+            const expected = cold('--b', { b: outcome });
+            service.deleteGroup = jest.fn(() => response);
+
+            expect(effects.deleteGroup$).toBeObservable(expected);
+        });
+    });
+
+    describe('deleteGroupSuccess$ effect', () => {
+        it('should not dispatch', () => {
+            expect(metadata.deleteGroupSuccess$).toEqual(
+                expect.objectContaining({ dispatch: false })
+            );
+        });
+
+        it('should display a success notification', () => {
+            const toastrSpy = jest.spyOn(toastr, 'success');
+            const action = groupActions.deleteGroupSuccess({ group: GROUP });
+
+            actions = hot('a', { a: action });
+            const expected = cold('a', { a: action });
+
+            expect(effects.deleteGroupSuccess$).toBeObservable(expected);
+            expect(toastrSpy).toHaveBeenCalledTimes(1);
+            expect(toastrSpy).toHaveBeenCalledWith(
+                'Group successfully deleted',
+                'The existing group has been deleted'
+            );
+        });
+    });
+
+    describe('deleteGroupFail$ effect', () => {
+        it('should not dispatch', () => {
+            expect(metadata.deleteGroupFail$).toEqual(
+                expect.objectContaining({ dispatch: false })
+            );
+        });
+
+        it('should display an error notification', () => {
+            const spy = jest.spyOn(toastr, 'error');
+            const action = groupActions.deleteGroupFail();
+
+            actions = hot('a', { a: action });
+            const expected = cold('a', { a: action });
+
+            expect(effects.deleteGroupFail$).toBeObservable(expected);
+            expect(spy).toHaveBeenCalledTimes(1);
+            expect(spy).toHaveBeenCalledWith(
+                'Failure to delete group',
+                'The existing group could not be deleted from the database'
+            );
+        });
+    });
+});
diff --git a/client/src/app/metamodel/effects/group.effects.ts b/client/src/app/metamodel/effects/group.effects.ts
index 6f3567afd9e0a71550dfba4713df71b5cf69a80d..f9001e0764849b1d33e13ed8e756ef1d96dddafc 100644
--- a/client/src/app/metamodel/effects/group.effects.ts
+++ b/client/src/app/metamodel/effects/group.effects.ts
@@ -19,10 +19,18 @@ import { ToastrService } from 'ngx-toastr';
 import * as groupActions from '../actions/group.actions';
 import { GroupService } from '../services/group.service';
 import * as instanceSelector from '../selectors/instance.selector';
- 
+
+/**
+ * @class
+ * @classdesc Survey effects.
+ */
 @Injectable()
 export class GroupEffects {
-    loadGroups$ = createEffect(() =>
+
+    /**
+     * Calls action to retrieve group list.
+     */
+    loadGroups$ = createEffect((): any =>
         this.actions$.pipe(
             ofType(groupActions.loadGroupList),
             concatLatestFrom(() => this.store.select(instanceSelector.selectInstanceNameByRoute)),
@@ -35,7 +43,10 @@ export class GroupEffects {
         )
     );
 
-    addGroup$ = createEffect(() => 
+    /**
+     * Calls action to add a group.
+     */
+    addGroup$ = createEffect((): any =>
         this.actions$.pipe(
             ofType(groupActions.addGroup),
             concatLatestFrom(() => this.store.select(instanceSelector.selectInstanceNameByRoute)),
@@ -48,25 +59,34 @@ export class GroupEffects {
         )
     );
 
-    addGroupSuccess$ = createEffect(() => 
+    /**
+     * Displays add group success notification.
+     */
+    addGroupSuccess$ = createEffect(() =>
         this.actions$.pipe(
             ofType(groupActions.addGroupSuccess),
             concatLatestFrom(() => this.store.select(instanceSelector.selectInstanceNameByRoute)),
-            tap(([, instanceName]) => {
+            tap(instanceName => {
                 this.router.navigateByUrl(`/admin/instance/configure-instance/${instanceName}/group`);
                 this.toastr.success('Group successfully added', 'The new group was added into the database')
             })
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
 
-    addGroupFail$ = createEffect(() => 
+    /**
+     * Displays add group error notification.
+     */
+    addGroupFail$ = createEffect(() =>
         this.actions$.pipe(
             ofType(groupActions.addGroupFail),
             tap(() => this.toastr.error('Failure to add group', 'The new group could not be added into the database'))
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
 
-    editGroup$ = createEffect(() => 
+    /**
+     * Calls action to modify a group.
+     */
+    editGroup$ = createEffect((): any =>
         this.actions$.pipe(
             ofType(groupActions.editGroup),
             mergeMap(action => this.groupService.editGroup(action.group)
@@ -78,7 +98,10 @@ export class GroupEffects {
         )
     );
 
-    editGroupSuccess$ = createEffect(() => 
+    /**
+     * Displays edit group success notification.
+     */
+    editGroupSuccess$ = createEffect(() =>
         this.actions$.pipe(
             ofType(groupActions.editGroupSuccess),
             concatLatestFrom(() => this.store.select(instanceSelector.selectInstanceNameByRoute)),
@@ -86,17 +109,23 @@ export class GroupEffects {
                 this.router.navigateByUrl(`/admin/instance/configure-instance/${instanceName}/group`);
                 this.toastr.success('Group successfully edited', 'The existing group has been edited into the database')
             })
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
 
-    editGroupFail$ = createEffect(() => 
+    /**
+     * Displays edit group error notification.
+     */
+    editGroupFail$ = createEffect(() =>
         this.actions$.pipe(
             ofType(groupActions.editGroupFail),
             tap(() => this.toastr.error('Failure to edit group', 'The existing group could not be edited into the database'))
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
 
-    deleteGroup$ = createEffect(() => 
+    /**
+     * Calls action to remove a group.
+     */
+    deleteGroup$ = createEffect((): any =>
         this.actions$.pipe(
             ofType(groupActions.deleteGroup),
             mergeMap(action => this.groupService.deleteGroup(action.group.id)
@@ -108,20 +137,26 @@ export class GroupEffects {
         )
     );
 
-    deleteGroupSuccess$ = createEffect(() => 
+    /**
+     * Displays delete group success notification.
+     */
+    deleteGroupSuccess$ = createEffect(() =>
         this.actions$.pipe(
             ofType(groupActions.deleteGroupSuccess),
             tap(() => this.toastr.success('Group successfully deleted', 'The existing group has been deleted'))
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
 
-    deleteGroupFail$ = createEffect(() => 
+    /**
+     * Displays delete group error notification.
+     */
+    deleteGroupFail$ = createEffect(() =>
         this.actions$.pipe(
             ofType(groupActions.deleteGroupFail),
             tap(() => this.toastr.error('Failure to delete group', 'The existing group could not be deleted from the database'))
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
- 
+
     constructor(
         private actions$: Actions,
         private groupService: GroupService,
diff --git a/client/src/app/metamodel/effects/output-category.effects.spec.ts b/client/src/app/metamodel/effects/output-category.effects.spec.ts
index ee3f625d6994a42da5b0e03fd743dc1ecfc997af..770166a623856441a5c7b0f17b073cdbe55c91c3 100644
--- a/client/src/app/metamodel/effects/output-category.effects.spec.ts
+++ b/client/src/app/metamodel/effects/output-category.effects.spec.ts
@@ -2,15 +2,15 @@ import { TestBed } from '@angular/core/testing';
 import { Router } from '@angular/router';
 
 import { provideMockActions } from '@ngrx/effects/testing';
+import { MockStore, provideMockStore } from '@ngrx/store/testing';
 import { EffectsMetadata, getEffectsMetadata } from '@ngrx/effects';
 import { Observable } from 'rxjs';
 import { cold, hot } from 'jasmine-marbles';
-import { ToastrService } from 'ngx-toastr';
 
+import { ToastrService } from 'ngx-toastr';
 import { OutputCategoryEffects } from './output-category.effects';
 import { OutputCategoryService } from '../services/output-category.service';
 import * as outputCategoryActions from '../actions/output-category.actions';
-import { MockStore, provideMockStore } from '@ngrx/store/testing';
 import * as datasetSelector from '../selectors/dataset.selector';
 import { CATEGORY, CATEGORY_LIST } from '../../../test-data';
 
diff --git a/client/src/app/metamodel/effects/output-family.effects.spec.ts b/client/src/app/metamodel/effects/output-family.effects.spec.ts
index de18e0327eeea31914944fa0b122b2fee0b59936..267056d81f2d00f9ef42926d741237c1fd140f9a 100644
--- a/client/src/app/metamodel/effects/output-family.effects.spec.ts
+++ b/client/src/app/metamodel/effects/output-family.effects.spec.ts
@@ -2,6 +2,7 @@ import { TestBed } from '@angular/core/testing';
 import { Router } from '@angular/router';
 
 import { provideMockActions } from '@ngrx/effects/testing';
+import { MockStore, provideMockStore } from '@ngrx/store/testing';
 import { EffectsMetadata, getEffectsMetadata } from '@ngrx/effects';
 import { Observable } from 'rxjs';
 import { cold, hot } from 'jasmine-marbles';
@@ -11,7 +12,6 @@ import { OutputFamilyEffects } from './output-family.effects';
 import { OutputFamilyService } from '../services/output-family.service';
 import * as outputFamilyActions from '../actions/output-family.actions';
 import { OUTPUT_FAMILY, OUTPUT_FAMILY_LIST } from '../../../test-data';
-import { MockStore, provideMockStore } from '@ngrx/store/testing';
 import * as datasetSelector from '../selectors/dataset.selector';
 
 describe('[Metamodel][Effects] OutputFamilyEffects', () => {
@@ -86,7 +86,7 @@ describe('[Metamodel][Effects] OutputFamilyEffects', () => {
         });
     });
 
-    describe('addOutputFamilies$ effect', () => {
+    describe('addOutputFamily$ effect', () => {
         it('should dispatch the addOutputFamilySuccess action on success', () => {
             mockDatasetSelectorSelectDatasetNameByRoute = store.overrideSelector(
                 datasetSelector.selectDatasetNameByRoute, 'myDataset'
@@ -100,7 +100,7 @@ describe('[Metamodel][Effects] OutputFamilyEffects', () => {
             const expected = cold('--b', { b: outcome });
             service.addOutputFamily = jest.fn(() => response);
 
-            expect(effects.addOutputFamilies$).toBeObservable(expected);
+            expect(effects.addOutputFamily$).toBeObservable(expected);
             expect(service.addOutputFamily).toHaveBeenCalledWith('myDataset', OUTPUT_FAMILY);
         });
 
@@ -114,7 +114,7 @@ describe('[Metamodel][Effects] OutputFamilyEffects', () => {
             const expected = cold('--b', { b: outcome });
             service.addOutputFamily = jest.fn(() => response);
 
-            expect(effects.addOutputFamilies$).toBeObservable(expected);
+            expect(effects.addOutputFamily$).toBeObservable(expected);
         });
     });
 
diff --git a/client/src/app/metamodel/effects/output-family.effects.ts b/client/src/app/metamodel/effects/output-family.effects.ts
index c714657b7cb7d093becc2d7a83f6c875aa6c4dfc..dfe82c0babd7a66cc87862c7678ec14bf5e4ea03 100644
--- a/client/src/app/metamodel/effects/output-family.effects.ts
+++ b/client/src/app/metamodel/effects/output-family.effects.ts
@@ -45,7 +45,7 @@ export class OutputFamilyEffects {
     /**
      * Calls action to add an output family to the given dataset.
      */
-    addOutputFamilies$ = createEffect((): any =>
+    addOutputFamily$ = createEffect((): any =>
         this.actions$.pipe(
             ofType(outputFamilyActions.addOutputFamily),
             concatLatestFrom(() => this.store.select(datasetSelector.selectDatasetNameByRoute)),
@@ -136,7 +136,7 @@ export class OutputFamilyEffects {
         this.actions$.pipe(
             ofType(outputFamilyActions.deleteOutputFamilySuccess),
             tap(() => this.toastr.success('Output family successfully deleted', 'The existing output family has been deleted'))
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
 
     /**
@@ -146,7 +146,7 @@ export class OutputFamilyEffects {
         this.actions$.pipe(
             ofType(outputFamilyActions.deleteOutputFamilyFail),
             tap(() => this.toastr.error('Failure to delete output family', 'The existing output family could not be deleted from the database'))
-        ), { dispatch: false}
+        ), { dispatch: false }
     );
 
     constructor(