diff --git a/client/src/app/metamodel/models/attribute.model.ts b/client/src/app/metamodel/models/attribute.model.ts
index d5397bb427a5f482e707b2868aa484c3917e7f25..f58acd2c159e59532c9bf8e085b840b170a9b145 100644
--- a/client/src/app/metamodel/models/attribute.model.ts
+++ b/client/src/app/metamodel/models/attribute.model.ts
@@ -8,8 +8,13 @@
  */
 
 import { Option } from './option.model';
-import { RendererConfig } from './renderers/renderer-config.model';
+import { RendererConfig } from './renderers';
 
+/**
+ * Interface for attribute.
+ *
+ * @interface Attribute
+ */
 export interface Attribute {
     id: number;
     name: string;
diff --git a/client/src/app/metamodel/models/column.model.ts b/client/src/app/metamodel/models/column.model.ts
index c06bebf009ba8cab65cc21ed544e5be68ba23cfd..83e1ff2799679a2461e6165a74487344f3b6310b 100644
--- a/client/src/app/metamodel/models/column.model.ts
+++ b/client/src/app/metamodel/models/column.model.ts
@@ -7,6 +7,11 @@
  * file that was distributed with this source code.
  */
 
+/**
+ * Interface for column.
+ *
+ * @interface Column
+ */
 export interface Column {
     name: string;
     type: string;
diff --git a/client/src/app/metamodel/models/criteria-family.model.ts b/client/src/app/metamodel/models/criteria-family.model.ts
index aeb7f90aa539d50d73eadad7016bbf1986c4fba1..4870fc29908f90f0011f2391ecd9c528cc4136dd 100644
--- a/client/src/app/metamodel/models/criteria-family.model.ts
+++ b/client/src/app/metamodel/models/criteria-family.model.ts
@@ -7,6 +7,11 @@
  * file that was distributed with this source code.
  */
 
+/**
+ * Interface for criteria family.
+ *
+ * @interface CriteriaFamily
+ */
 export interface CriteriaFamily {
     id: number;
     label: string;
diff --git a/client/src/app/metamodel/models/database.model.ts b/client/src/app/metamodel/models/database.model.ts
index e2889a40f945641d8928cbb54000b30ff44cf055..96ce8db984564381c9362c3bc6f7ef09c26cdbf3 100644
--- a/client/src/app/metamodel/models/database.model.ts
+++ b/client/src/app/metamodel/models/database.model.ts
@@ -7,6 +7,11 @@
  * file that was distributed with this source code.
  */
 
+/**
+ * Interface for database.
+ *
+ * @interface Database
+ */
 export interface Database {
     id: number;
     label: string;
diff --git a/client/src/app/metamodel/models/dataset-family.model.ts b/client/src/app/metamodel/models/dataset-family.model.ts
index 391f90392ee3e08741ef0b34ff73ad65cdb81569..98ff77f2a92fda884f097227880d648b3b11c5f3 100644
--- a/client/src/app/metamodel/models/dataset-family.model.ts
+++ b/client/src/app/metamodel/models/dataset-family.model.ts
@@ -7,6 +7,11 @@
  * file that was distributed with this source code.
  */
 
+/**
+ * Interface for dataset family.
+ *
+ * @interface DatasetFamily
+ */
 export interface DatasetFamily {
     id: number;
     label: string;
diff --git a/client/src/app/metamodel/models/dataset.model.ts b/client/src/app/metamodel/models/dataset.model.ts
index 22e73074318ab24c91fdb32836dd9c3834c8a1ea..7c7baa5d11a922ea9bb4353133a9e0c0a883ca92 100644
--- a/client/src/app/metamodel/models/dataset.model.ts
+++ b/client/src/app/metamodel/models/dataset.model.ts
@@ -7,6 +7,11 @@
  * file that was distributed with this source code.
  */
 
+/**
+ * Interface for dataset.
+ *
+ * @interface Dataset
+ */
 export interface Dataset {
     name: string;
     table_ref: string;
diff --git a/client/src/app/metamodel/models/file-info.model.ts b/client/src/app/metamodel/models/file-info.model.ts
index 675c092cfd0cb0b163701fcd37234034f705cce8..f966093e908d5f5a1ce1c72732f3829c9b9d7757 100644
--- a/client/src/app/metamodel/models/file-info.model.ts
+++ b/client/src/app/metamodel/models/file-info.model.ts
@@ -7,6 +7,12 @@
  * file that was distributed with this source code.
  */
 
+
+/**
+ * Interface for file info.
+ *
+ * @interface FileInfo
+ */
 export interface FileInfo {
     name: string;
     size: number;
diff --git a/client/src/app/metamodel/models/group.model.ts b/client/src/app/metamodel/models/group.model.ts
index 788f669b99d768c8edfdc416eb3e2966011d5526..64ed71fea6cdc94abb8f633ff238b16f0b053819 100644
--- a/client/src/app/metamodel/models/group.model.ts
+++ b/client/src/app/metamodel/models/group.model.ts
@@ -7,6 +7,11 @@
  * file that was distributed with this source code.
  */
 
+/**
+ * Interface for group.
+ *
+ * @interface Group
+ */
 export interface Group {
     id: number;
     role: string;
diff --git a/client/src/app/metamodel/models/instance.model.ts b/client/src/app/metamodel/models/instance.model.ts
index c50e7bc234b97659b9b950b118669774f02ee582..bbb5436413cfed03eb5fe121d83183fab8d11246 100644
--- a/client/src/app/metamodel/models/instance.model.ts
+++ b/client/src/app/metamodel/models/instance.model.ts
@@ -7,6 +7,11 @@
  * file that was distributed with this source code.
  */
 
+/**
+ * Interface for instance.
+ *
+ * @interface Instance
+ */
 export interface Instance {
     name: string;
     label: string;
diff --git a/client/src/app/metamodel/models/option.model.ts b/client/src/app/metamodel/models/option.model.ts
index 3b934e2551fe4e1bcd30278ed5da1201dcf6da26..91ab5ee69236517db59a12fea55da73f3e0ac202 100644
--- a/client/src/app/metamodel/models/option.model.ts
+++ b/client/src/app/metamodel/models/option.model.ts
@@ -7,6 +7,11 @@
  * file that was distributed with this source code.
  */
 
+/**
+ * Interface for option.
+ *
+ * @interface Option
+ */
 export interface Option {
     label: string;
     value: string;
diff --git a/client/src/app/metamodel/models/output-category.model.ts b/client/src/app/metamodel/models/output-category.model.ts
index 408d7c8d54b113cb2b19058b7162132109714ab1..637b562ff24d3d1696f4a695d0ef1bb5a519a8f9 100644
--- a/client/src/app/metamodel/models/output-category.model.ts
+++ b/client/src/app/metamodel/models/output-category.model.ts
@@ -7,6 +7,11 @@
  * file that was distributed with this source code.
  */
 
+/**
+ * Interface for output category.
+ *
+ * @interface OutputCategory
+ */
 export interface OutputCategory {
     id: number;
     label: string;
diff --git a/client/src/app/metamodel/models/output-family.model.ts b/client/src/app/metamodel/models/output-family.model.ts
index d1d1e076bba1a1bdba4a83c4f48705b8eed3b334..f0970ab3b9155dcbd9c1bb0afecfbec650393633 100644
--- a/client/src/app/metamodel/models/output-family.model.ts
+++ b/client/src/app/metamodel/models/output-family.model.ts
@@ -7,6 +7,11 @@
  * file that was distributed with this source code.
  */
 
+/**
+ * Interface for output family.
+ *
+ * @interface OutputFamily
+ */
 export interface OutputFamily {
     id: number;
     label: string;
diff --git a/client/src/app/metamodel/models/renderers/detail-renderer-config.model.ts b/client/src/app/metamodel/models/renderers/detail-renderer-config.model.ts
index 4012f3c47917e6d1624da3be0ab9e98e52c0fc8a..921abadd662842ed0555c99fe5c9ea00ae1818a0 100644
--- a/client/src/app/metamodel/models/renderers/detail-renderer-config.model.ts
+++ b/client/src/app/metamodel/models/renderers/detail-renderer-config.model.ts
@@ -1,5 +1,20 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
 import { RendererConfig } from './renderer-config.model';
 
+/**
+ * Interface for detail renderer config.
+ *
+ * @interface DetailRendererConfig
+ * @extends RendererConfig
+ */
 export interface DetailRendererConfig extends RendererConfig {
     display: string;
     icon_button: string;
diff --git a/client/src/app/metamodel/models/renderers/download-renderer-config.model.ts b/client/src/app/metamodel/models/renderers/download-renderer-config.model.ts
index 93747e6e08d8c1375560448e493f51120005f5a0..c9291889176a2a6997a020295576198094c441a9 100644
--- a/client/src/app/metamodel/models/renderers/download-renderer-config.model.ts
+++ b/client/src/app/metamodel/models/renderers/download-renderer-config.model.ts
@@ -1,5 +1,20 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
 import { RendererConfig } from './renderer-config.model';
 
+/**
+ * Interface for download renderer config.
+ *
+ * @interface DownloadRendererConfig
+ * @extends RendererConfig
+ */
 export interface DownloadRendererConfig extends RendererConfig {
     display: string;
     text: string;
diff --git a/client/src/app/metamodel/models/renderers/image-renderer-config.model.ts b/client/src/app/metamodel/models/renderers/image-renderer-config.model.ts
index a93270e3bcec7f71509cec94a56714ef7058d670..2e6e89efc8495344dd08f04f268d171525d51ad6 100644
--- a/client/src/app/metamodel/models/renderers/image-renderer-config.model.ts
+++ b/client/src/app/metamodel/models/renderers/image-renderer-config.model.ts
@@ -1,5 +1,20 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
 import { RendererConfig } from './renderer-config.model';
 
+/**
+ * Interface for image renderer config.
+ *
+ * @interface ImageRendererConfig
+ * @extends RendererConfig
+ */
 export interface ImageRendererConfig extends RendererConfig {
     type: string;
     display: string;
diff --git a/client/src/app/metamodel/models/renderers/link-renderer-config.model.ts b/client/src/app/metamodel/models/renderers/link-renderer-config.model.ts
index 9c2c296561ae411cc7288e5c7e57d28b46e3bb49..2cb4fc07c1eb2217a32d11f9e74d8ea33f999e18 100644
--- a/client/src/app/metamodel/models/renderers/link-renderer-config.model.ts
+++ b/client/src/app/metamodel/models/renderers/link-renderer-config.model.ts
@@ -1,5 +1,20 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
 import { RendererConfig } from './renderer-config.model';
 
+/**
+ * Interface for link renderer config.
+ *
+ * @interface LinkRendererConfig
+ * @extends RendererConfig
+ */
 export interface LinkRendererConfig extends RendererConfig {
     href: string;
     display: string;
diff --git a/client/src/app/metamodel/models/renderers/renderer-config.model.ts b/client/src/app/metamodel/models/renderers/renderer-config.model.ts
index 00fafcd4a0df22cf3b9efdde9803ed1e5d190c25..cd8d137570dd14e95be1ab28cf25f5707e3d3416 100644
--- a/client/src/app/metamodel/models/renderers/renderer-config.model.ts
+++ b/client/src/app/metamodel/models/renderers/renderer-config.model.ts
@@ -7,6 +7,11 @@
  * file that was distributed with this source code.
  */
 
+/**
+ * Interface for renderer config.
+ *
+ * @interface RendererConfig
+ */
 export interface RendererConfig {
     id: 'renderer-config';
 }
diff --git a/client/src/app/metamodel/models/select-option.model.ts b/client/src/app/metamodel/models/select-option.model.ts
index 014a43f253ec46c4f71433f272e77dd7eca42395..bb3473f08f3b095e7b8985fe355acab0587b5799 100644
--- a/client/src/app/metamodel/models/select-option.model.ts
+++ b/client/src/app/metamodel/models/select-option.model.ts
@@ -7,6 +7,11 @@
  * file that was distributed with this source code.
  */
 
+/**
+ * Interface for select option.
+ *
+ * @interface SelectOption
+ */
 export interface SelectOption {
     id: number;
     label: string;
diff --git a/client/src/app/metamodel/models/select.model.ts b/client/src/app/metamodel/models/select.model.ts
index c969f18c16d0d5447d0ab3857f88233eee1e3bfe..4bdb3d403ae6b2c5238f4240f11bccba687da673 100644
--- a/client/src/app/metamodel/models/select.model.ts
+++ b/client/src/app/metamodel/models/select.model.ts
@@ -7,6 +7,11 @@
  * file that was distributed with this source code.
  */
 
+/**
+ * Interface for select.
+ *
+ * @interface Select
+ */
 export interface Select {
     name: string;
     label: string;
diff --git a/client/src/app/metamodel/models/survey.model.ts b/client/src/app/metamodel/models/survey.model.ts
index bba021fddcc2f97f94b5b25104fb639c27c60fef..c23ab90afca9832f448b6f69ddc457218803d680 100644
--- a/client/src/app/metamodel/models/survey.model.ts
+++ b/client/src/app/metamodel/models/survey.model.ts
@@ -7,6 +7,11 @@
  * file that was distributed with this source code.
  */
 
+/**
+ * Interface for survey.
+ *
+ * @interface Survey
+ */
 export interface Survey {
     name: string;
     label: string;
diff --git a/client/src/app/metamodel/reducers/attribute-distinct.reducer.spec.ts b/client/src/app/metamodel/reducers/attribute-distinct.reducer.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e94ea987ae68546de0e171b54972a78a845874d5
--- /dev/null
+++ b/client/src/app/metamodel/reducers/attribute-distinct.reducer.spec.ts
@@ -0,0 +1,63 @@
+import { Action } from '@ngrx/store';
+
+import * as fromAttributeDistinct from './attribute-distinct.reducer';
+import * as attributeDistinctActions from '../actions/attribute-distinct.actions';
+import { ATTRIBUTE, SURVEY, SURVEY_LIST } from '../../../test-data';
+
+describe('[Metamodel][Reducers] AttributeDistinct reducer', () => {
+    it('unknown action should return the default state', () => {
+        const { initialState } = fromAttributeDistinct;
+        const action = { type: 'Unknown' };
+        const state = fromAttributeDistinct.attributeDistinctReducer(initialState, action);
+        expect(state).toBe(initialState);
+    });
+
+    it('loadAttributeDistinctList action should set attributeDistinctListIsLoading to true', () => {
+        const { initialState } = fromAttributeDistinct;
+        const action = attributeDistinctActions.loadAttributeDistinctList({ attribute: ATTRIBUTE });
+        const state = fromAttributeDistinct.attributeDistinctReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual({ });
+        expect(state.attributeDistinctListIsLoading).toEqual(true);
+        expect(state.attributeDistinctListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('loadAttributeDistinctListSuccess action should add attributeDistinct list, set attributeDistinctListIsLoading to false and set attributeDistinctListIsLoaded to true', () => {
+        const { initialState } = fromAttributeDistinct;
+        const action = attributeDistinctActions.loadAttributeDistinctListSuccess({ values: ['val-one', 'val-two'] });
+        const state = fromAttributeDistinct.attributeDistinctReducer(initialState, action);
+        expect(state.ids.length).toEqual(2);
+        expect(state.ids).toContain('val-one');
+        expect(state.ids).toContain('val-two');
+        expect(Object.keys(state.entities).length).toEqual(2);
+        expect(state.attributeDistinctListIsLoading).toEqual(false);
+        expect(state.attributeDistinctListIsLoaded).toEqual(true);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('loadAttributeDistinctListFail action should set attributeDistinctListIsLoading to false', () => {
+        const { initialState } = fromAttributeDistinct;
+        const action = attributeDistinctActions.loadAttributeDistinctListFail();
+        const state = fromAttributeDistinct.attributeDistinctReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual({ });
+        expect(state.attributeDistinctListIsLoading).toEqual(false);
+        expect(state.attributeDistinctListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('should get attributeDistinctListIsLoading', () => {
+        const action = {} as Action;
+        const state =  fromAttributeDistinct.attributeDistinctReducer(undefined, action);
+
+        expect(fromAttributeDistinct.selectAttributeDistinctListIsLoading(state)).toEqual(false);
+    });
+
+    it('should get attributeDistinctListIsLoaded', () => {
+        const action = {} as Action;
+        const state = fromAttributeDistinct.attributeDistinctReducer(undefined, action);
+
+        expect(fromAttributeDistinct.selectAttributeDistinctListIsLoaded(state)).toEqual(false);
+    });
+});
diff --git a/client/src/app/metamodel/reducers/attribute-distinct.reducer.ts b/client/src/app/metamodel/reducers/attribute-distinct.reducer.ts
index 657d050033e7cb11b6ad3c23023731930c57f393..533d4c31ad6431a8d9906b7999decfde8a8f5755 100644
--- a/client/src/app/metamodel/reducers/attribute-distinct.reducer.ts
+++ b/client/src/app/metamodel/reducers/attribute-distinct.reducer.ts
@@ -12,6 +12,11 @@ import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity';
 
 import * as attributeDistinctActions from '../actions/attribute-distinct.actions';
 
+/**
+ * Interface for attribute distinct state.
+ *
+ * @interface State
+ */
 export interface State extends EntityState<string> {
     attributeDistinctListIsLoading: boolean;
     attributeDistinctListIsLoaded: boolean;
@@ -37,8 +42,8 @@ export const attributeDistinctReducer = createReducer(
     }),
     on(attributeDistinctActions.loadAttributeDistinctListSuccess, (state, { values }) => {
         return adapter.setAll(
-            values, 
-            { 
+            values,
+            {
                 ...state,
                 attributeDistinctListIsLoading: false,
                 attributeDistinctListIsLoaded: true
diff --git a/client/src/app/metamodel/reducers/attribute.reducer.spec.ts b/client/src/app/metamodel/reducers/attribute.reducer.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b1abaad67d767c1afd7f6a8a025a863fb5ba070f
--- /dev/null
+++ b/client/src/app/metamodel/reducers/attribute.reducer.spec.ts
@@ -0,0 +1,109 @@
+import { Action } from '@ngrx/store';
+
+import * as fromAttribute from './attribute.reducer';
+import * as attributeActions from '../actions/attribute.actions';
+import { ATTRIBUTE, ATTRIBUTE_LIST } from '../../../test-data';
+
+describe('[Metamodel][Reducers] Attribute reducer', () => {
+    it('unknown action should return the default state', () => {
+        const { initialState } = fromAttribute;
+        const action = { type: 'Unknown' };
+        const state = fromAttribute.attributeReducer(initialState, action);
+        expect(state).toBe(initialState);
+    });
+
+    it('loadAttributeList action should set attributeListIsLoading to true', () => {
+        const { initialState } = fromAttribute;
+        const action = attributeActions.loadAttributeList();
+        const state = fromAttribute.attributeReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual({ });
+        expect(state.attributeListIsLoading).toEqual(true);
+        expect(state.attributeListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('loadAttributeListSuccess action should add attribute list, set attributeListIsLoading to false and set attributeListIsLoaded to true', () => {
+        const { initialState } = fromAttribute;
+        const action = attributeActions.loadAttributeListSuccess({ attributes: ATTRIBUTE_LIST });
+        const state = fromAttribute.attributeReducer(initialState, action);
+        expect(state.ids.length).toEqual(4);
+        expect(state.ids).toContain(1);
+        expect(state.ids).toContain(2);
+        expect(state.ids).toContain(3);
+        expect(state.ids).toContain(4);
+        expect(Object.keys(state.entities).length).toEqual(4);
+        expect(state.attributeListIsLoading).toEqual(false);
+        expect(state.attributeListIsLoaded).toEqual(true);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('loadAttributeListFail action should set attributeListIsLoading to false', () => {
+        const { initialState } = fromAttribute;
+        const action = attributeActions.loadAttributeListFail();
+        const state = fromAttribute.attributeReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual({ });
+        expect(state.attributeListIsLoading).toEqual(false);
+        expect(state.attributeListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('addAttributeSuccess action should add a attribute', () => {
+        const { initialState } = fromAttribute;
+        const action = attributeActions.addAttributeSuccess({ attribute: ATTRIBUTE });
+        const state = fromAttribute.attributeReducer(initialState, action);
+        expect(state.ids.length).toEqual(1);
+        expect(state.ids).toContain(1);
+        expect(Object.keys(state.entities).length).toEqual(1);
+        expect(state.attributeListIsLoading).toEqual(false);
+        expect(state.attributeListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('editAttributeSuccess action should modify a attribute', () => {
+        const initialState = {
+            ...fromAttribute.initialState,
+            ids: [1],
+            entities: { 1: { ...ATTRIBUTE, label: 'label' }}
+        };
+        const action = attributeActions.editAttributeSuccess({ attribute: ATTRIBUTE });
+        const state = fromAttribute.attributeReducer(initialState, action);
+        expect(state.ids.length).toEqual(1);
+        expect(state.ids).toContain(1);
+        expect(Object.keys(state.entities).length).toEqual(1);
+        expect(state.entities[1]).toEqual(ATTRIBUTE);
+        expect(state.attributeListIsLoading).toEqual(false);
+        expect(state.attributeListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('deleteAttributeSuccess action should modify a attribute', () => {
+        const initialState = {
+            ...fromAttribute.initialState,
+            ids: [1],
+            entities: { 1: ATTRIBUTE }
+        };
+        const action = attributeActions.deleteAttributeSuccess({ attribute: ATTRIBUTE });
+        const state = fromAttribute.attributeReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual( { });
+        expect(state.attributeListIsLoading).toEqual(false);
+        expect(state.attributeListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('should get attributeListIsLoading', () => {
+        const action = {} as Action;
+        const state =  fromAttribute.attributeReducer(undefined, action);
+
+        expect(fromAttribute.selectAttributeListIsLoading(state)).toEqual(false);
+    });
+
+    it('should get attributeListIsLoaded', () => {
+        const action = {} as Action;
+        const state = fromAttribute.attributeReducer(undefined, action);
+
+        expect(fromAttribute.selectAttributeListIsLoaded(state)).toEqual(false);
+    });
+});
diff --git a/client/src/app/metamodel/reducers/attribute.reducer.ts b/client/src/app/metamodel/reducers/attribute.reducer.ts
index 769d7e329f6b32c2cc12e9699f11cb0ad62c8965..3def9fef90535dcb6dcf5875d2b84dd7dbe78ebc 100644
--- a/client/src/app/metamodel/reducers/attribute.reducer.ts
+++ b/client/src/app/metamodel/reducers/attribute.reducer.ts
@@ -13,6 +13,11 @@ import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity';
 import { Attribute } from '../models';
 import * as attributeActions from '../actions/attribute.actions';
 
+/**
+ * Interface for attribute state.
+ *
+ * @interface State
+ */
 export interface State extends EntityState<Attribute> {
     attributeListIsLoading: boolean;
     attributeListIsLoaded: boolean;
@@ -36,8 +41,8 @@ export const attributeReducer = createReducer(
     }),
     on(attributeActions.loadAttributeListSuccess, (state, { attributes }) => {
         return adapter.setAll(
-            attributes, 
-            { 
+            attributes,
+            {
                 ...state,
                 attributeListIsLoading: false,
                 attributeListIsLoaded: true
diff --git a/client/src/app/metamodel/reducers/column.reducer.spec.ts b/client/src/app/metamodel/reducers/column.reducer.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..69efb358fa86cc72d48707c818a3e3fde47b60fa
--- /dev/null
+++ b/client/src/app/metamodel/reducers/column.reducer.spec.ts
@@ -0,0 +1,63 @@
+import { Action } from '@ngrx/store';
+
+import * as fromColumn from './column.reducer';
+import * as columnActions from '../actions/column.actions';
+import { COLUMN_LIST } from '../../../test-data';
+
+describe('[Metamodel][Reducers] Column reducer', () => {
+    it('unknown action should return the default state', () => {
+        const { initialState } = fromColumn;
+        const action = { type: 'Unknown' };
+        const state = fromColumn.columnReducer(initialState, action);
+        expect(state).toBe(initialState);
+    });
+
+    it('loadColumnList action should set columnListIsLoading to true', () => {
+        const { initialState } = fromColumn;
+        const action = columnActions.loadColumnList();
+        const state = fromColumn.columnReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual({ });
+        expect(state.columnListIsLoading).toEqual(true);
+        expect(state.columnListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('loadColumnListSuccess action should add column list, set columnListIsLoading to false and set columnListIsLoaded to true', () => {
+        const { initialState } = fromColumn;
+        const action = columnActions.loadColumnListSuccess({ columns: COLUMN_LIST });
+        const state = fromColumn.columnReducer(initialState, action);
+        expect(state.ids.length).toEqual(2);
+        expect(state.ids).toContain('myCol');
+        expect(state.ids).toContain('anotherCol');
+        expect(Object.keys(state.entities).length).toEqual(2);
+        expect(state.columnListIsLoading).toEqual(false);
+        expect(state.columnListIsLoaded).toEqual(true);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('loadColumnListFail action should set columnListIsLoading to false', () => {
+        const { initialState } = fromColumn;
+        const action = columnActions.loadColumnListFail();
+        const state = fromColumn.columnReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual({ });
+        expect(state.columnListIsLoading).toEqual(false);
+        expect(state.columnListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('should get columnListIsLoading', () => {
+        const action = {} as Action;
+        const state =  fromColumn.columnReducer(undefined, action);
+
+        expect(fromColumn.selectColumnListIsLoading(state)).toEqual(false);
+    });
+
+    it('should get columnListIsLoaded', () => {
+        const action = {} as Action;
+        const state = fromColumn.columnReducer(undefined, action);
+
+        expect(fromColumn.selectColumnListIsLoaded(state)).toEqual(false);
+    });
+});
diff --git a/client/src/app/metamodel/reducers/column.reducer.ts b/client/src/app/metamodel/reducers/column.reducer.ts
index ad36e21591ca9513ec60f6a1664ebdf47cb84f50..faee0a628bff04249e65c8e3edf36a8fbe20e010 100644
--- a/client/src/app/metamodel/reducers/column.reducer.ts
+++ b/client/src/app/metamodel/reducers/column.reducer.ts
@@ -13,6 +13,11 @@ import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity';
 import { Column } from '../models';
 import * as columnActions from '../actions/column.actions';
 
+/**
+ * Interface for column state.
+ *
+ * @interface State
+ */
 export interface State extends EntityState<Column> {
     columnListIsLoading: boolean;
     columnListIsLoaded: boolean;
@@ -38,8 +43,8 @@ export const columnReducer = createReducer(
     }),
     on(columnActions.loadColumnListSuccess, (state, { columns }) => {
         return adapter.setAll(
-            columns, 
-            { 
+            columns,
+            {
                 ...state,
                 columnListIsLoading: false,
                 columnListIsLoaded: true
diff --git a/client/src/app/metamodel/reducers/criteria-family.reducer.spec.ts b/client/src/app/metamodel/reducers/criteria-family.reducer.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..249bd1c78ba8250d081513fd2b93b6c26de65772
--- /dev/null
+++ b/client/src/app/metamodel/reducers/criteria-family.reducer.spec.ts
@@ -0,0 +1,107 @@
+import { Action } from '@ngrx/store';
+
+import * as fromCriteriaFamily from './criteria-family.reducer';
+import * as criteriaFamilyActions from '../actions/criteria-family.actions';
+import { CRITERIA_FAMILY, CRITERIA_FAMILY_LIST } from '../../../test-data';
+
+describe('[Metamodel][Reducers] CriteriaFamily reducer', () => {
+    it('unknown action should return the default state', () => {
+        const { initialState } = fromCriteriaFamily;
+        const action = { type: 'Unknown' };
+        const state = fromCriteriaFamily.criteriaFamilyReducer(initialState, action);
+        expect(state).toBe(initialState);
+    });
+
+    it('loadCriteriaFamilyList action should set criteriaFamilyListIsLoading to true', () => {
+        const { initialState } = fromCriteriaFamily;
+        const action = criteriaFamilyActions.loadCriteriaFamilyList();
+        const state = fromCriteriaFamily.criteriaFamilyReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual({ });
+        expect(state.criteriaFamilyListIsLoading).toEqual(true);
+        expect(state.criteriaFamilyListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('loadCriteriaFamilyListSuccess action should add criteriaFamily list, set criteriaFamilyListIsLoading to false and set criteriaFamilyListIsLoaded to true', () => {
+        const { initialState } = fromCriteriaFamily;
+        const action = criteriaFamilyActions.loadCriteriaFamilyListSuccess({ criteriaFamilies: CRITERIA_FAMILY_LIST });
+        const state = fromCriteriaFamily.criteriaFamilyReducer(initialState, action);
+        expect(state.ids.length).toEqual(2);
+        expect(state.ids).toContain(1);
+        expect(state.ids).toContain(2);
+        expect(Object.keys(state.entities).length).toEqual(2);
+        expect(state.criteriaFamilyListIsLoading).toEqual(false);
+        expect(state.criteriaFamilyListIsLoaded).toEqual(true);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('loadCriteriaFamilyListFail action should set criteriaFamilyListIsLoading to false', () => {
+        const { initialState } = fromCriteriaFamily;
+        const action = criteriaFamilyActions.loadCriteriaFamilyListFail();
+        const state = fromCriteriaFamily.criteriaFamilyReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual({ });
+        expect(state.criteriaFamilyListIsLoading).toEqual(false);
+        expect(state.criteriaFamilyListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('addCriteriaFamilySuccess action should add a criteriaFamily', () => {
+        const { initialState } = fromCriteriaFamily;
+        const action = criteriaFamilyActions.addCriteriaFamilySuccess({ criteriaFamily: CRITERIA_FAMILY });
+        const state = fromCriteriaFamily.criteriaFamilyReducer(initialState, action);
+        expect(state.ids.length).toEqual(1);
+        expect(state.ids).toContain(1);
+        expect(Object.keys(state.entities).length).toEqual(1);
+        expect(state.criteriaFamilyListIsLoading).toEqual(false);
+        expect(state.criteriaFamilyListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('editCriteriaFamilySuccess action should modify a criteriaFamily', () => {
+        const initialState = {
+            ...fromCriteriaFamily.initialState,
+            ids: [1],
+            entities: { 1: { ...CRITERIA_FAMILY, label: 'label' }}
+        };
+        const action = criteriaFamilyActions.editCriteriaFamilySuccess({ criteriaFamily: CRITERIA_FAMILY });
+        const state = fromCriteriaFamily.criteriaFamilyReducer(initialState, action);
+        expect(state.ids.length).toEqual(1);
+        expect(state.ids).toContain(1);
+        expect(Object.keys(state.entities).length).toEqual(1);
+        expect(state.entities[1]).toEqual(CRITERIA_FAMILY);
+        expect(state.criteriaFamilyListIsLoading).toEqual(false);
+        expect(state.criteriaFamilyListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('deleteCriteriaFamilySuccess action should modify a criteriaFamily', () => {
+        const initialState = {
+            ...fromCriteriaFamily.initialState,
+            ids: [1],
+            entities: { 1: CRITERIA_FAMILY }
+        };
+        const action = criteriaFamilyActions.deleteCriteriaFamilySuccess({ criteriaFamily: CRITERIA_FAMILY });
+        const state = fromCriteriaFamily.criteriaFamilyReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual( { });
+        expect(state.criteriaFamilyListIsLoading).toEqual(false);
+        expect(state.criteriaFamilyListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('should get criteriaFamilyListIsLoading', () => {
+        const action = {} as Action;
+        const state =  fromCriteriaFamily.criteriaFamilyReducer(undefined, action);
+
+        expect(fromCriteriaFamily.selectCriteriaFamilyListIsLoading(state)).toEqual(false);
+    });
+
+    it('should get criteriaFamilyListIsLoaded', () => {
+        const action = {} as Action;
+        const state = fromCriteriaFamily.criteriaFamilyReducer(undefined, action);
+
+        expect(fromCriteriaFamily.selectCriteriaFamilyListIsLoaded(state)).toEqual(false);
+    });
+});
diff --git a/client/src/app/metamodel/reducers/criteria-family.reducer.ts b/client/src/app/metamodel/reducers/criteria-family.reducer.ts
index 76ccaae48cbaa1e8d6b28da6f878b495756734d6..9e072db237fd32c014340643282e4194b8f7c9fd 100644
--- a/client/src/app/metamodel/reducers/criteria-family.reducer.ts
+++ b/client/src/app/metamodel/reducers/criteria-family.reducer.ts
@@ -13,6 +13,11 @@ import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity';
 import { CriteriaFamily } from '../models';
 import * as criteriaFamilyActions from '../actions/criteria-family.actions';
 
+/**
+ * Interface for criteria family state.
+ *
+ * @interface State
+ */
 export interface State extends EntityState<CriteriaFamily> {
     criteriaFamilyListIsLoading: boolean;
     criteriaFamilyListIsLoaded: boolean;
@@ -38,8 +43,8 @@ export const criteriaFamilyReducer = createReducer(
     }),
     on(criteriaFamilyActions.loadCriteriaFamilyListSuccess, (state, { criteriaFamilies }) => {
         return adapter.setAll(
-            criteriaFamilies, 
-            { 
+            criteriaFamilies,
+            {
                 ...state,
                 criteriaFamilyListIsLoading: false,
                 criteriaFamilyListIsLoaded: true
diff --git a/client/src/app/metamodel/reducers/database.reducer.spec.ts b/client/src/app/metamodel/reducers/database.reducer.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..dd92d42f2ec01f3d5c4a5e498cb6cd9ecf70181d
--- /dev/null
+++ b/client/src/app/metamodel/reducers/database.reducer.spec.ts
@@ -0,0 +1,107 @@
+import { Action } from '@ngrx/store';
+
+import * as fromDatabase from './database.reducer';
+import * as databaseActions from '../actions/database.actions';
+import { DATABASE, DATABASE_LIST } from '../../../test-data';
+
+describe('[Metamodel][Reducers] Database reducer', () => {
+    it('unknown action should return the default state', () => {
+        const { initialState } = fromDatabase;
+        const action = { type: 'Unknown' };
+        const state = fromDatabase.databaseReducer(initialState, action);
+        expect(state).toBe(initialState);
+    });
+
+    it('loadDatabaseList action should set databaseListIsLoading to true', () => {
+        const { initialState } = fromDatabase;
+        const action = databaseActions.loadDatabaseList();
+        const state = fromDatabase.databaseReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual({ });
+        expect(state.databaseListIsLoading).toEqual(true);
+        expect(state.databaseListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('loadDatabaseListSuccess action should add database list, set databaseListIsLoading to false and set databaseListIsLoaded to true', () => {
+        const { initialState } = fromDatabase;
+        const action = databaseActions.loadDatabaseListSuccess({ databases: DATABASE_LIST });
+        const state = fromDatabase.databaseReducer(initialState, action);
+        expect(state.ids.length).toEqual(2);
+        expect(state.ids).toContain(1);
+        expect(state.ids).toContain(2);
+        expect(Object.keys(state.entities).length).toEqual(2);
+        expect(state.databaseListIsLoading).toEqual(false);
+        expect(state.databaseListIsLoaded).toEqual(true);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('loadDatabaseListFail action should set databaseListIsLoading to false', () => {
+        const { initialState } = fromDatabase;
+        const action = databaseActions.loadDatabaseListFail();
+        const state = fromDatabase.databaseReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual({ });
+        expect(state.databaseListIsLoading).toEqual(false);
+        expect(state.databaseListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('addDatabaseSuccess action should add a database', () => {
+        const { initialState } = fromDatabase;
+        const action = databaseActions.addDatabaseSuccess({ database: DATABASE });
+        const state = fromDatabase.databaseReducer(initialState, action);
+        expect(state.ids.length).toEqual(1);
+        expect(state.ids).toContain(1);
+        expect(Object.keys(state.entities).length).toEqual(1);
+        expect(state.databaseListIsLoading).toEqual(false);
+        expect(state.databaseListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('editDatabaseSuccess action should modify a database', () => {
+        const initialState = {
+            ...fromDatabase.initialState,
+            ids: [1],
+            entities: { 1: { ...DATABASE, label: 'label' }}
+        };
+        const action = databaseActions.editDatabaseSuccess({ database: DATABASE });
+        const state = fromDatabase.databaseReducer(initialState, action);
+        expect(state.ids.length).toEqual(1);
+        expect(state.ids).toContain(1);
+        expect(Object.keys(state.entities).length).toEqual(1);
+        expect(state.entities[1]).toEqual(DATABASE);
+        expect(state.databaseListIsLoading).toEqual(false);
+        expect(state.databaseListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('deleteDatabaseSuccess action should modify a database', () => {
+        const initialState = {
+            ...fromDatabase.initialState,
+            ids: [1],
+            entities: { 1: DATABASE }
+        };
+        const action = databaseActions.deleteDatabaseSuccess({ database: DATABASE });
+        const state = fromDatabase.databaseReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual( { });
+        expect(state.databaseListIsLoading).toEqual(false);
+        expect(state.databaseListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('should get databaseListIsLoading', () => {
+        const action = {} as Action;
+        const state =  fromDatabase.databaseReducer(undefined, action);
+
+        expect(fromDatabase.selectDatabaseListIsLoading(state)).toEqual(false);
+    });
+
+    it('should get databaseListIsLoaded', () => {
+        const action = {} as Action;
+        const state = fromDatabase.databaseReducer(undefined, action);
+
+        expect(fromDatabase.selectDatabaseListIsLoaded(state)).toEqual(false);
+    });
+});
diff --git a/client/src/app/metamodel/reducers/database.reducer.ts b/client/src/app/metamodel/reducers/database.reducer.ts
index 045397b12d64d1e7d5c768783fe7e033064e60e6..d361230babec00ec9b86a676e39156de9f018a70 100644
--- a/client/src/app/metamodel/reducers/database.reducer.ts
+++ b/client/src/app/metamodel/reducers/database.reducer.ts
@@ -13,6 +13,11 @@ import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity';
 import { Database } from '../models';
 import * as databaseActions from '../actions/database.actions';
 
+/**
+ * Interface for database state.
+ *
+ * @interface State
+ */
 export interface State extends EntityState<Database> {
     databaseListIsLoading: boolean;
     databaseListIsLoaded: boolean;
@@ -35,8 +40,8 @@ export const databaseReducer = createReducer(
     }),
     on(databaseActions.loadDatabaseListSuccess, (state, { databases }) => {
         return adapter.setAll(
-            databases, 
-            { 
+            databases,
+            {
                 ...state,
                 databaseListIsLoading: false,
                 databaseListIsLoaded: true
diff --git a/client/src/app/metamodel/reducers/dataset-family.reducer.spec.ts b/client/src/app/metamodel/reducers/dataset-family.reducer.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d0175fd1b444cd9f18996a1ae53ac0867be3fa94
--- /dev/null
+++ b/client/src/app/metamodel/reducers/dataset-family.reducer.spec.ts
@@ -0,0 +1,107 @@
+import { Action } from '@ngrx/store';
+
+import * as fromDatasetFamily from './dataset-family.reducer';
+import * as datasetFamilyActions from '../actions/dataset-family.actions';
+import { DATASET_FAMILY, DATASET_FAMILY_LIST } from '../../../test-data';
+
+describe('[Metamodel][Reducers] DatasetFamily reducer', () => {
+    it('unknown action should return the default state', () => {
+        const { initialState } = fromDatasetFamily;
+        const action = { type: 'Unknown' };
+        const state = fromDatasetFamily.datasetFamilyReducer(initialState, action);
+        expect(state).toBe(initialState);
+    });
+
+    it('loadDatasetFamilyList action should set datasetFamilyListIsLoading to true', () => {
+        const { initialState } = fromDatasetFamily;
+        const action = datasetFamilyActions.loadDatasetFamilyList();
+        const state = fromDatasetFamily.datasetFamilyReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual({ });
+        expect(state.datasetFamilyListIsLoading).toEqual(true);
+        expect(state.datasetFamilyListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('loadDatasetFamilyListSuccess action should add datasetFamily list, set datasetFamilyListIsLoading to false and set datasetFamilyListIsLoaded to true', () => {
+        const { initialState } = fromDatasetFamily;
+        const action = datasetFamilyActions.loadDatasetFamilyListSuccess({ datasetFamilies: DATASET_FAMILY_LIST });
+        const state = fromDatasetFamily.datasetFamilyReducer(initialState, action);
+        expect(state.ids.length).toEqual(2);
+        expect(state.ids).toContain(1);
+        expect(state.ids).toContain(2);
+        expect(Object.keys(state.entities).length).toEqual(2);
+        expect(state.datasetFamilyListIsLoading).toEqual(false);
+        expect(state.datasetFamilyListIsLoaded).toEqual(true);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('loadDatasetFamilyListFail action should set datasetFamilyListIsLoading to false', () => {
+        const { initialState } = fromDatasetFamily;
+        const action = datasetFamilyActions.loadDatasetFamilyListFail();
+        const state = fromDatasetFamily.datasetFamilyReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual({ });
+        expect(state.datasetFamilyListIsLoading).toEqual(false);
+        expect(state.datasetFamilyListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('addDatasetFamilySuccess action should add a datasetFamily', () => {
+        const { initialState } = fromDatasetFamily;
+        const action = datasetFamilyActions.addDatasetFamilySuccess({ datasetFamily: DATASET_FAMILY });
+        const state = fromDatasetFamily.datasetFamilyReducer(initialState, action);
+        expect(state.ids.length).toEqual(1);
+        expect(state.ids).toContain(1);
+        expect(Object.keys(state.entities).length).toEqual(1);
+        expect(state.datasetFamilyListIsLoading).toEqual(false);
+        expect(state.datasetFamilyListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('editDatasetFamilySuccess action should modify a datasetFamily', () => {
+        const initialState = {
+            ...fromDatasetFamily.initialState,
+            ids: [1],
+            entities: { 1: { ...DATASET_FAMILY, label: 'label' }}
+        };
+        const action = datasetFamilyActions.editDatasetFamilySuccess({ datasetFamily: DATASET_FAMILY });
+        const state = fromDatasetFamily.datasetFamilyReducer(initialState, action);
+        expect(state.ids.length).toEqual(1);
+        expect(state.ids).toContain(1);
+        expect(Object.keys(state.entities).length).toEqual(1);
+        expect(state.entities[1]).toEqual(DATASET_FAMILY);
+        expect(state.datasetFamilyListIsLoading).toEqual(false);
+        expect(state.datasetFamilyListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('deleteDatasetFamilySuccess action should modify a datasetFamily', () => {
+        const initialState = {
+            ...fromDatasetFamily.initialState,
+            ids: [1],
+            entities: { 1: DATASET_FAMILY }
+        };
+        const action = datasetFamilyActions.deleteDatasetFamilySuccess({ datasetFamily: DATASET_FAMILY });
+        const state = fromDatasetFamily.datasetFamilyReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual( { });
+        expect(state.datasetFamilyListIsLoading).toEqual(false);
+        expect(state.datasetFamilyListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('should get datasetFamilyListIsLoading', () => {
+        const action = {} as Action;
+        const state =  fromDatasetFamily.datasetFamilyReducer(undefined, action);
+
+        expect(fromDatasetFamily.selectDatasetFamilyListIsLoading(state)).toEqual(false);
+    });
+
+    it('should get datasetFamilyListIsLoaded', () => {
+        const action = {} as Action;
+        const state = fromDatasetFamily.datasetFamilyReducer(undefined, action);
+
+        expect(fromDatasetFamily.selectDatasetFamilyListIsLoaded(state)).toEqual(false);
+    });
+});
diff --git a/client/src/app/metamodel/reducers/dataset-family.reducer.ts b/client/src/app/metamodel/reducers/dataset-family.reducer.ts
index 923f88374e7b4211d4dd156554d7fa239bce8aa8..df8f9452ab6e0de8e384a7ab8724dde030b402f5 100644
--- a/client/src/app/metamodel/reducers/dataset-family.reducer.ts
+++ b/client/src/app/metamodel/reducers/dataset-family.reducer.ts
@@ -13,6 +13,11 @@ import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity';
 import { DatasetFamily } from '../models';
 import * as datasetFamilyActions from '../actions/dataset-family.actions';
 
+/**
+ * Interface for dataset family state.
+ *
+ * @interface State
+ */
 export interface State extends EntityState<DatasetFamily> {
     datasetFamilyListIsLoading: boolean;
     datasetFamilyListIsLoaded: boolean;
@@ -38,8 +43,8 @@ export const datasetFamilyReducer = createReducer(
     }),
     on(datasetFamilyActions.loadDatasetFamilyListSuccess, (state, { datasetFamilies }) => {
         return adapter.setAll(
-            datasetFamilies, 
-            { 
+            datasetFamilies,
+            {
                 ...state,
                 datasetFamilyListIsLoading: false,
                 datasetFamilyListIsLoaded: true
diff --git a/client/src/app/metamodel/reducers/dataset.reducer.spec.ts b/client/src/app/metamodel/reducers/dataset.reducer.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9284176096f040ebaac4ecb99f735029de90c820
--- /dev/null
+++ b/client/src/app/metamodel/reducers/dataset.reducer.spec.ts
@@ -0,0 +1,107 @@
+import { Action } from '@ngrx/store';
+
+import * as fromDataset from './dataset.reducer';
+import * as datasetActions from '../actions/dataset.actions';
+import { DATASET, DATASET_LIST } from '../../../test-data';
+
+describe('[Metamodel][Reducers] Dataset reducer', () => {
+    it('unknown action should return the default state', () => {
+        const { initialState } = fromDataset;
+        const action = { type: 'Unknown' };
+        const state = fromDataset.datasetReducer(initialState, action);
+        expect(state).toBe(initialState);
+    });
+
+    it('loadDatasetList action should set datasetListIsLoading to true', () => {
+        const { initialState } = fromDataset;
+        const action = datasetActions.loadDatasetList();
+        const state = fromDataset.datasetReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual({ });
+        expect(state.datasetListIsLoading).toEqual(true);
+        expect(state.datasetListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('loadDatasetListSuccess action should add dataset list, set datasetListIsLoading to false and set datasetListIsLoaded to true', () => {
+        const { initialState } = fromDataset;
+        const action = datasetActions.loadDatasetListSuccess({ datasets: DATASET_LIST });
+        const state = fromDataset.datasetReducer(initialState, action);
+        expect(state.ids.length).toEqual(2);
+        expect(state.ids).toContain('myDataset');
+        expect(state.ids).toContain('anotherDataset');
+        expect(Object.keys(state.entities).length).toEqual(2);
+        expect(state.datasetListIsLoading).toEqual(false);
+        expect(state.datasetListIsLoaded).toEqual(true);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('loadDatasetListFail action should set datasetListIsLoading to false', () => {
+        const { initialState } = fromDataset;
+        const action = datasetActions.loadDatasetListFail();
+        const state = fromDataset.datasetReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual({ });
+        expect(state.datasetListIsLoading).toEqual(false);
+        expect(state.datasetListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('addDatasetSuccess action should add a dataset', () => {
+        const { initialState } = fromDataset;
+        const action = datasetActions.addDatasetSuccess({ dataset: DATASET });
+        const state = fromDataset.datasetReducer(initialState, action);
+        expect(state.ids.length).toEqual(1);
+        expect(state.ids).toContain('myDataset');
+        expect(Object.keys(state.entities).length).toEqual(1);
+        expect(state.datasetListIsLoading).toEqual(false);
+        expect(state.datasetListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('editDatasetSuccess action should modify a dataset', () => {
+        const initialState = {
+            ...fromDataset.initialState,
+            ids: ['myDataset'],
+            entities: { 'myDataset': { ...DATASET, label: 'label' }}
+        };
+        const action = datasetActions.editDatasetSuccess({ dataset: DATASET });
+        const state = fromDataset.datasetReducer(initialState, action);
+        expect(state.ids.length).toEqual(1);
+        expect(state.ids).toContain('myDataset');
+        expect(Object.keys(state.entities).length).toEqual(1);
+        expect(state.entities['myDataset']).toEqual(DATASET);
+        expect(state.datasetListIsLoading).toEqual(false);
+        expect(state.datasetListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('deleteDatasetSuccess action should modify a dataset', () => {
+        const initialState = {
+            ...fromDataset.initialState,
+            ids: ['myDataset'],
+            entities: { 'myDataset': DATASET }
+        };
+        const action = datasetActions.deleteDatasetSuccess({ dataset: DATASET });
+        const state = fromDataset.datasetReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual( { });
+        expect(state.datasetListIsLoading).toEqual(false);
+        expect(state.datasetListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('should get datasetListIsLoading', () => {
+        const action = {} as Action;
+        const state =  fromDataset.datasetReducer(undefined, action);
+
+        expect(fromDataset.selectDatasetListIsLoading(state)).toEqual(false);
+    });
+
+    it('should get datasetListIsLoaded', () => {
+        const action = {} as Action;
+        const state = fromDataset.datasetReducer(undefined, action);
+
+        expect(fromDataset.selectDatasetListIsLoaded(state)).toEqual(false);
+    });
+});
diff --git a/client/src/app/metamodel/reducers/dataset.reducer.ts b/client/src/app/metamodel/reducers/dataset.reducer.ts
index becb9691e69c08353c027083fad1b096dcc8f522..013feea1abd912d6a2a9aac6c9fe3c4dbe78c450 100644
--- a/client/src/app/metamodel/reducers/dataset.reducer.ts
+++ b/client/src/app/metamodel/reducers/dataset.reducer.ts
@@ -13,6 +13,11 @@ import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity';
 import { Dataset } from '../models';
 import * as datasetActions from '../actions/dataset.actions';
 
+/**
+ * Interface for dataset state.
+ *
+ * @interface State
+ */
 export interface State extends EntityState<Dataset> {
     datasetListIsLoading: boolean;
     datasetListIsLoaded: boolean;
@@ -38,8 +43,8 @@ export const datasetReducer = createReducer(
     }),
     on(datasetActions.loadDatasetListSuccess, (state, { datasets }) => {
         return adapter.setAll(
-            datasets, 
-            { 
+            datasets,
+            {
                 ...state,
                 datasetListIsLoading: false,
                 datasetListIsLoaded: true
diff --git a/client/src/app/metamodel/reducers/group.reducer.spec.ts b/client/src/app/metamodel/reducers/group.reducer.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..354425566c71e03b08fbf0c9b65491842526ef4a
--- /dev/null
+++ b/client/src/app/metamodel/reducers/group.reducer.spec.ts
@@ -0,0 +1,107 @@
+import { Action } from '@ngrx/store';
+
+import * as fromGroup from './group.reducer';
+import * as groupActions from '../actions/group.actions';
+import { GROUP, GROUP_LIST } from '../../../test-data';
+
+describe('[Metamodel][Reducers] Group reducer', () => {
+    it('unknown action should return the default state', () => {
+        const { initialState } = fromGroup;
+        const action = { type: 'Unknown' };
+        const state = fromGroup.groupReducer(initialState, action);
+        expect(state).toBe(initialState);
+    });
+
+    it('loadGroupList action should set groupListIsLoading to true', () => {
+        const { initialState } = fromGroup;
+        const action = groupActions.loadGroupList();
+        const state = fromGroup.groupReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual({ });
+        expect(state.groupListIsLoading).toEqual(true);
+        expect(state.groupListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('loadGroupListSuccess action should add group list, set groupListIsLoading to false and set groupListIsLoaded to true', () => {
+        const { initialState } = fromGroup;
+        const action = groupActions.loadGroupListSuccess({ groups: GROUP_LIST });
+        const state = fromGroup.groupReducer(initialState, action);
+        expect(state.ids.length).toEqual(2);
+        expect(state.ids).toContain(1);
+        expect(state.ids).toContain(2);
+        expect(Object.keys(state.entities).length).toEqual(2);
+        expect(state.groupListIsLoading).toEqual(false);
+        expect(state.groupListIsLoaded).toEqual(true);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('loadGroupListFail action should set groupListIsLoading to false', () => {
+        const { initialState } = fromGroup;
+        const action = groupActions.loadGroupListFail();
+        const state = fromGroup.groupReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual({ });
+        expect(state.groupListIsLoading).toEqual(false);
+        expect(state.groupListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('addGroupSuccess action should add a group', () => {
+        const { initialState } = fromGroup;
+        const action = groupActions.addGroupSuccess({ group: GROUP });
+        const state = fromGroup.groupReducer(initialState, action);
+        expect(state.ids.length).toEqual(1);
+        expect(state.ids).toContain(1);
+        expect(Object.keys(state.entities).length).toEqual(1);
+        expect(state.groupListIsLoading).toEqual(false);
+        expect(state.groupListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('editGroupSuccess action should modify a group', () => {
+        const initialState = {
+            ...fromGroup.initialState,
+            ids: [1],
+            entities: { 1: { ...GROUP, role: 'role' }}
+        };
+        const action = groupActions.editGroupSuccess({ group: GROUP });
+        const state = fromGroup.groupReducer(initialState, action);
+        expect(state.ids.length).toEqual(1);
+        expect(state.ids).toContain(1);
+        expect(Object.keys(state.entities).length).toEqual(1);
+        expect(state.entities[1]).toEqual(GROUP);
+        expect(state.groupListIsLoading).toEqual(false);
+        expect(state.groupListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('deleteGroupSuccess action should modify a group', () => {
+        const initialState = {
+            ...fromGroup.initialState,
+            ids: [1],
+            entities: { 1: GROUP }
+        };
+        const action = groupActions.deleteGroupSuccess({ group: GROUP });
+        const state = fromGroup.groupReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual( { });
+        expect(state.groupListIsLoading).toEqual(false);
+        expect(state.groupListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('should get groupListIsLoading', () => {
+        const action = {} as Action;
+        const state =  fromGroup.groupReducer(undefined, action);
+
+        expect(fromGroup.selectGroupListIsLoading(state)).toEqual(false);
+    });
+
+    it('should get groupListIsLoaded', () => {
+        const action = {} as Action;
+        const state = fromGroup.groupReducer(undefined, action);
+
+        expect(fromGroup.selectGroupListIsLoaded(state)).toEqual(false);
+    });
+});
diff --git a/client/src/app/metamodel/reducers/group.reducer.ts b/client/src/app/metamodel/reducers/group.reducer.ts
index ad3c3f4343c53db72b4880b56662315308c6af97..3037765737375444edf3397c598de886dec72b4c 100644
--- a/client/src/app/metamodel/reducers/group.reducer.ts
+++ b/client/src/app/metamodel/reducers/group.reducer.ts
@@ -13,6 +13,11 @@ import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity';
 import { Group } from '../models';
 import * as groupActions from '../actions/group.actions';
 
+/**
+ * Interface for group state.
+ *
+ * @interface State
+ */
 export interface State extends EntityState<Group> {
     groupListIsLoading: boolean;
     groupListIsLoaded: boolean;
@@ -35,8 +40,8 @@ export const groupReducer = createReducer(
     }),
     on(groupActions.loadGroupListSuccess, (state, { groups }) => {
         return adapter.setAll(
-            groups, 
-            { 
+            groups,
+            {
                 ...state,
                 groupListIsLoading: false,
                 groupListIsLoaded: true
diff --git a/client/src/app/metamodel/reducers/instance.reducer.spec.ts b/client/src/app/metamodel/reducers/instance.reducer.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4e13bdc69f4257b10f48bd884136dd75991e6bb9
--- /dev/null
+++ b/client/src/app/metamodel/reducers/instance.reducer.spec.ts
@@ -0,0 +1,107 @@
+import { Action } from '@ngrx/store';
+
+import * as fromInstance from './instance.reducer';
+import * as instanceActions from '../actions/instance.actions';
+import { INSTANCE, INSTANCE_LIST } from '../../../test-data';
+
+describe('[Metamodel][Reducers] Instance reducer', () => {
+    it('unknown action should return the default state', () => {
+        const { initialState } = fromInstance;
+        const action = { type: 'Unknown' };
+        const state = fromInstance.instanceReducer(initialState, action);
+        expect(state).toBe(initialState);
+    });
+
+    it('loadInstanceList action should set instanceListIsLoading to true', () => {
+        const { initialState } = fromInstance;
+        const action = instanceActions.loadInstanceList();
+        const state = fromInstance.instanceReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual({ });
+        expect(state.instanceListIsLoading).toEqual(true);
+        expect(state.instanceListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('loadInstanceListSuccess action should add instance list, set instanceListIsLoading to false and set instanceListIsLoaded to true', () => {
+        const { initialState } = fromInstance;
+        const action = instanceActions.loadInstanceListSuccess({ instances: INSTANCE_LIST });
+        const state = fromInstance.instanceReducer(initialState, action);
+        expect(state.ids.length).toEqual(2);
+        expect(state.ids).toContain('myInstance');
+        expect(state.ids).toContain('myOtherInstance');
+        expect(Object.keys(state.entities).length).toEqual(2);
+        expect(state.instanceListIsLoading).toEqual(false);
+        expect(state.instanceListIsLoaded).toEqual(true);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('loadInstanceListFail action should set instanceListIsLoading to false', () => {
+        const { initialState } = fromInstance;
+        const action = instanceActions.loadInstanceListFail();
+        const state = fromInstance.instanceReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual({ });
+        expect(state.instanceListIsLoading).toEqual(false);
+        expect(state.instanceListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('addInstanceSuccess action should add a instance', () => {
+        const { initialState } = fromInstance;
+        const action = instanceActions.addInstanceSuccess({ instance: INSTANCE });
+        const state = fromInstance.instanceReducer(initialState, action);
+        expect(state.ids.length).toEqual(1);
+        expect(state.ids).toContain('myInstance');
+        expect(Object.keys(state.entities).length).toEqual(1);
+        expect(state.instanceListIsLoading).toEqual(false);
+        expect(state.instanceListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('editInstanceSuccess action should modify a instance', () => {
+        const initialState = {
+            ...fromInstance.initialState,
+            ids: ['myInstance'],
+            entities: { 'myInstance': { ...INSTANCE, label: 'label' }}
+        };
+        const action = instanceActions.editInstanceSuccess({ instance: INSTANCE });
+        const state = fromInstance.instanceReducer(initialState, action);
+        expect(state.ids.length).toEqual(1);
+        expect(state.ids).toContain('myInstance');
+        expect(Object.keys(state.entities).length).toEqual(1);
+        expect(state.entities['myInstance']).toEqual(INSTANCE);
+        expect(state.instanceListIsLoading).toEqual(false);
+        expect(state.instanceListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('deleteInstanceSuccess action should modify a instance', () => {
+        const initialState = {
+            ...fromInstance.initialState,
+            ids: ['myInstance'],
+            entities: { 'myInstance': INSTANCE }
+        };
+        const action = instanceActions.deleteInstanceSuccess({ instance: INSTANCE });
+        const state = fromInstance.instanceReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual( { });
+        expect(state.instanceListIsLoading).toEqual(false);
+        expect(state.instanceListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('should get instanceListIsLoading', () => {
+        const action = {} as Action;
+        const state =  fromInstance.instanceReducer(undefined, action);
+
+        expect(fromInstance.selectInstanceListIsLoading(state)).toEqual(false);
+    });
+
+    it('should get instanceListIsLoaded', () => {
+        const action = {} as Action;
+        const state = fromInstance.instanceReducer(undefined, action);
+
+        expect(fromInstance.selectInstanceListIsLoaded(state)).toEqual(false);
+    });
+});
diff --git a/client/src/app/metamodel/reducers/instance.reducer.ts b/client/src/app/metamodel/reducers/instance.reducer.ts
index 33a282126917158df332a246bae615276f47dc17..e9f454ef2dae9be6d92023c64e4a30ef7ac6baf0 100644
--- a/client/src/app/metamodel/reducers/instance.reducer.ts
+++ b/client/src/app/metamodel/reducers/instance.reducer.ts
@@ -13,6 +13,11 @@ import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity';
 import { Instance } from '../models';
 import * as instanceActions from '../actions/instance.actions';
 
+/**
+ * Interface for instance state.
+ *
+ * @interface State
+ */
 export interface State extends EntityState<Instance> {
     instanceListIsLoading: boolean;
     instanceListIsLoaded: boolean;
@@ -38,8 +43,8 @@ export const instanceReducer = createReducer(
     }),
     on(instanceActions.loadInstanceListSuccess, (state, { instances }) => {
         return adapter.setAll(
-            instances, 
-            { 
+            instances,
+            {
                 ...state,
                 instanceListIsLoading: false,
                 instanceListIsLoaded: true
diff --git a/client/src/app/metamodel/reducers/output-category.reducer.spec.ts b/client/src/app/metamodel/reducers/output-category.reducer.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5af1ebc777ffbcf3b7278efd7793b2370e7d8262
--- /dev/null
+++ b/client/src/app/metamodel/reducers/output-category.reducer.spec.ts
@@ -0,0 +1,108 @@
+import { Action } from '@ngrx/store';
+
+import * as fromOutputCategory from './output-category.reducer';
+import * as outputCategoryActions from '../actions/output-category.actions';
+import { CATEGORY, CATEGORY_LIST } from '../../../test-data';
+
+describe('[Metamodel][Reducers] OutputCategory reducer', () => {
+    it('unknown action should return the default state', () => {
+        const { initialState } = fromOutputCategory;
+        const action = { type: 'Unknown' };
+        const state = fromOutputCategory.outputCategoryReducer(initialState, action);
+        expect(state).toBe(initialState);
+    });
+
+    it('loadOutputCategoryList action should set outputCategoryListIsLoading to true', () => {
+        const { initialState } = fromOutputCategory;
+        const action = outputCategoryActions.loadOutputCategoryList();
+        const state = fromOutputCategory.outputCategoryReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual({ });
+        expect(state.outputCategoryListIsLoading).toEqual(true);
+        expect(state.outputCategoryListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('loadOutputCategoryListSuccess action should add outputCategory list, set outputCategoryListIsLoading to false and set outputCategoryListIsLoaded to true', () => {
+        const { initialState } = fromOutputCategory;
+        const action = outputCategoryActions.loadOutputCategoryListSuccess({ outputCategories: CATEGORY_LIST });
+        const state = fromOutputCategory.outputCategoryReducer(initialState, action);
+        expect(state.ids.length).toEqual(3);
+        expect(state.ids).toContain(1);
+        expect(state.ids).toContain(2);
+        expect(state.ids).toContain(3);
+        expect(Object.keys(state.entities).length).toEqual(3);
+        expect(state.outputCategoryListIsLoading).toEqual(false);
+        expect(state.outputCategoryListIsLoaded).toEqual(true);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('loadOutputCategoryListFail action should set outputCategoryListIsLoading to false', () => {
+        const { initialState } = fromOutputCategory;
+        const action = outputCategoryActions.loadOutputCategoryListFail();
+        const state = fromOutputCategory.outputCategoryReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual({ });
+        expect(state.outputCategoryListIsLoading).toEqual(false);
+        expect(state.outputCategoryListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('addOutputCategorySuccess action should add a outputCategory', () => {
+        const { initialState } = fromOutputCategory;
+        const action = outputCategoryActions.addOutputCategorySuccess({ outputCategory: CATEGORY });
+        const state = fromOutputCategory.outputCategoryReducer(initialState, action);
+        expect(state.ids.length).toEqual(1);
+        expect(state.ids).toContain(1);
+        expect(Object.keys(state.entities).length).toEqual(1);
+        expect(state.outputCategoryListIsLoading).toEqual(false);
+        expect(state.outputCategoryListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('editOutputCategorySuccess action should modify a outputCategory', () => {
+        const initialState = {
+            ...fromOutputCategory.initialState,
+            ids: [1],
+            entities: { 1: { ...CATEGORY, label: 'label' }}
+        };
+        const action = outputCategoryActions.editOutputCategorySuccess({ outputCategory: CATEGORY });
+        const state = fromOutputCategory.outputCategoryReducer(initialState, action);
+        expect(state.ids.length).toEqual(1);
+        expect(state.ids).toContain(1);
+        expect(Object.keys(state.entities).length).toEqual(1);
+        expect(state.entities[1]).toEqual(CATEGORY);
+        expect(state.outputCategoryListIsLoading).toEqual(false);
+        expect(state.outputCategoryListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('deleteOutputCategorySuccess action should modify a outputCategory', () => {
+        const initialState = {
+            ...fromOutputCategory.initialState,
+            ids: [1],
+            entities: { 1: CATEGORY }
+        };
+        const action = outputCategoryActions.deleteOutputCategorySuccess({ outputCategory: CATEGORY });
+        const state = fromOutputCategory.outputCategoryReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual( { });
+        expect(state.outputCategoryListIsLoading).toEqual(false);
+        expect(state.outputCategoryListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('should get outputCategoryListIsLoading', () => {
+        const action = {} as Action;
+        const state =  fromOutputCategory.outputCategoryReducer(undefined, action);
+
+        expect(fromOutputCategory.selectOutputCategoryListIsLoading(state)).toEqual(false);
+    });
+
+    it('should get outputCategoryListIsLoaded', () => {
+        const action = {} as Action;
+        const state = fromOutputCategory.outputCategoryReducer(undefined, action);
+
+        expect(fromOutputCategory.selectOutputCategoryListIsLoaded(state)).toEqual(false);
+    });
+});
diff --git a/client/src/app/metamodel/reducers/output-category.reducer.ts b/client/src/app/metamodel/reducers/output-category.reducer.ts
index ddbed47415434fee7336a5e45078c8557d1b956e..437058cbeca194d5dcbf83789d8913ba0417ecfe 100644
--- a/client/src/app/metamodel/reducers/output-category.reducer.ts
+++ b/client/src/app/metamodel/reducers/output-category.reducer.ts
@@ -13,6 +13,11 @@ import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity';
 import { OutputCategory } from '../models';
 import * as outputCategoryActions from '../actions/output-category.actions';
 
+/**
+ * Interface for output category state.
+ *
+ * @interface State
+ */
 export interface State extends EntityState<OutputCategory> {
     outputCategoryListIsLoading: boolean;
     outputCategoryListIsLoaded: boolean;
@@ -38,8 +43,8 @@ export const outputCategoryReducer = createReducer(
     }),
     on(outputCategoryActions.loadOutputCategoryListSuccess, (state, { outputCategories }) => {
         return adapter.setAll(
-            outputCategories, 
-            { 
+            outputCategories,
+            {
                 ...state,
                 outputCategoryListIsLoading: false,
                 outputCategoryListIsLoaded: true
diff --git a/client/src/app/metamodel/reducers/output-family.reducer.spec.ts b/client/src/app/metamodel/reducers/output-family.reducer.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7e2397d9aa30d2a6b848b4104ba339e906ca0c39
--- /dev/null
+++ b/client/src/app/metamodel/reducers/output-family.reducer.spec.ts
@@ -0,0 +1,107 @@
+import { Action } from '@ngrx/store';
+
+import * as fromOutputFamily from './output-family.reducer';
+import * as outputFamilyActions from '../actions/output-family.actions';
+import { OUTPUT_FAMILY, OUTPUT_FAMILY_LIST } from '../../../test-data';
+
+describe('[Metamodel][Reducers] OutputFamily reducer', () => {
+    it('unknown action should return the default state', () => {
+        const { initialState } = fromOutputFamily;
+        const action = { type: 'Unknown' };
+        const state = fromOutputFamily.outputFamilyReducer(initialState, action);
+        expect(state).toBe(initialState);
+    });
+
+    it('loadOutputFamilyList action should set outputFamilyListIsLoading to true', () => {
+        const { initialState } = fromOutputFamily;
+        const action = outputFamilyActions.loadOutputFamilyList();
+        const state = fromOutputFamily.outputFamilyReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual({ });
+        expect(state.outputFamilyListIsLoading).toEqual(true);
+        expect(state.outputFamilyListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('loadOutputFamilyListSuccess action should add outputFamily list, set outputFamilyListIsLoading to false and set outputFamilyListIsLoaded to true', () => {
+        const { initialState } = fromOutputFamily;
+        const action = outputFamilyActions.loadOutputFamilyListSuccess({ outputFamilies: OUTPUT_FAMILY_LIST });
+        const state = fromOutputFamily.outputFamilyReducer(initialState, action);
+        expect(state.ids.length).toEqual(2);
+        expect(state.ids).toContain(1);
+        expect(state.ids).toContain(2);
+        expect(Object.keys(state.entities).length).toEqual(2);
+        expect(state.outputFamilyListIsLoading).toEqual(false);
+        expect(state.outputFamilyListIsLoaded).toEqual(true);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('loadOutputFamilyListFail action should set outputFamilyListIsLoading to false', () => {
+        const { initialState } = fromOutputFamily;
+        const action = outputFamilyActions.loadOutputFamilyListFail();
+        const state = fromOutputFamily.outputFamilyReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual({ });
+        expect(state.outputFamilyListIsLoading).toEqual(false);
+        expect(state.outputFamilyListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('addOutputFamilySuccess action should add a outputFamily', () => {
+        const { initialState } = fromOutputFamily;
+        const action = outputFamilyActions.addOutputFamilySuccess({ outputFamily: OUTPUT_FAMILY });
+        const state = fromOutputFamily.outputFamilyReducer(initialState, action);
+        expect(state.ids.length).toEqual(1);
+        expect(state.ids).toContain(1);
+        expect(Object.keys(state.entities).length).toEqual(1);
+        expect(state.outputFamilyListIsLoading).toEqual(false);
+        expect(state.outputFamilyListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('editOutputFamilySuccess action should modify a outputFamily', () => {
+        const initialState = {
+            ...fromOutputFamily.initialState,
+            ids: [1],
+            entities: { 1: { ...OUTPUT_FAMILY, label: 'label' }}
+        };
+        const action = outputFamilyActions.editOutputFamilySuccess({ outputFamily: OUTPUT_FAMILY });
+        const state = fromOutputFamily.outputFamilyReducer(initialState, action);
+        expect(state.ids.length).toEqual(1);
+        expect(state.ids).toContain(1);
+        expect(Object.keys(state.entities).length).toEqual(1);
+        expect(state.entities[1]).toEqual(OUTPUT_FAMILY);
+        expect(state.outputFamilyListIsLoading).toEqual(false);
+        expect(state.outputFamilyListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('deleteOutputFamilySuccess action should modify a outputFamily', () => {
+        const initialState = {
+            ...fromOutputFamily.initialState,
+            ids: [1],
+            entities: { 1: OUTPUT_FAMILY }
+        };
+        const action = outputFamilyActions.deleteOutputFamilySuccess({ outputFamily: OUTPUT_FAMILY });
+        const state = fromOutputFamily.outputFamilyReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual( { });
+        expect(state.outputFamilyListIsLoading).toEqual(false);
+        expect(state.outputFamilyListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('should get outputFamilyListIsLoading', () => {
+        const action = {} as Action;
+        const state =  fromOutputFamily.outputFamilyReducer(undefined, action);
+
+        expect(fromOutputFamily.selectOutputFamilyListIsLoading(state)).toEqual(false);
+    });
+
+    it('should get outputFamilyListIsLoaded', () => {
+        const action = {} as Action;
+        const state = fromOutputFamily.outputFamilyReducer(undefined, action);
+
+        expect(fromOutputFamily.selectOutputFamilyListIsLoaded(state)).toEqual(false);
+    });
+});
diff --git a/client/src/app/metamodel/reducers/output-family.reducer.ts b/client/src/app/metamodel/reducers/output-family.reducer.ts
index cb7c5f6b38320c69a2542149313eaae47467d41a..93fffd5cad3a09c6a52bced1a3885c59ab7f8245 100644
--- a/client/src/app/metamodel/reducers/output-family.reducer.ts
+++ b/client/src/app/metamodel/reducers/output-family.reducer.ts
@@ -13,6 +13,11 @@ import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity';
 import { OutputFamily } from '../models';
 import * as outputFamilyActions from '../actions/output-family.actions';
 
+/**
+ * Interface for output family state.
+ *
+ * @interface State
+ */
 export interface State extends EntityState<OutputFamily> {
     outputFamilyListIsLoading: boolean;
     outputFamilyListIsLoaded: boolean;
@@ -38,8 +43,8 @@ export const outputFamilyReducer = createReducer(
     }),
     on(outputFamilyActions.loadOutputFamilyListSuccess, (state, { outputFamilies }) => {
         return adapter.setAll(
-            outputFamilies, 
-            { 
+            outputFamilies,
+            {
                 ...state,
                 outputFamilyListIsLoading: false,
                 outputFamilyListIsLoaded: true
diff --git a/client/src/app/metamodel/reducers/root-directory.reducer.spec.ts b/client/src/app/metamodel/reducers/root-directory.reducer.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..942dcd439222fccc6ad85e3725e9cebe70b442c4
--- /dev/null
+++ b/client/src/app/metamodel/reducers/root-directory.reducer.spec.ts
@@ -0,0 +1,63 @@
+import { Action } from '@ngrx/store';
+
+import * as fromRootDirectory from './root-directory.reducer';
+import * as rootDirectoryActions from '../actions/root-directory.actions';
+import { FILES } from '../../../test-data';
+
+describe('[Metamodel][Reducers] RootDirectory reducer', () => {
+    it('unknown action should return the default state', () => {
+        const { initialState } = fromRootDirectory;
+        const action = { type: 'Unknown' };
+        const state = fromRootDirectory.rootDirectoryReducer(initialState, action);
+        expect(state).toBe(initialState);
+    });
+
+    it('loadRootDirectory action should set rootDirectoryIsLoading to true', () => {
+        const { initialState } = fromRootDirectory;
+        const action = rootDirectoryActions.loadRootDirectory({ path: 'path' });
+        const state = fromRootDirectory.rootDirectoryReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual({ });
+        expect(state.rootDirectoryIsLoading).toEqual(true);
+        expect(state.rootDirectoryIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('loadRootDirectorySuccess action should add files, set rootDirectoryIsLoading to false and set rootDirectoryIsLoaded to true', () => {
+        const { initialState } = fromRootDirectory;
+        const action = rootDirectoryActions.loadRootDirectorySuccess({ files: FILES });
+        const state = fromRootDirectory.rootDirectoryReducer(initialState, action);
+        expect(state.ids.length).toEqual(2);
+        expect(state.ids).toContain('file-one');
+        expect(state.ids).toContain('file-two');
+        expect(Object.keys(state.entities).length).toEqual(2);
+        expect(state.rootDirectoryIsLoading).toEqual(false);
+        expect(state.rootDirectoryIsLoaded).toEqual(true);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('loadRootDirectoryFail action should set rootDirectoryIsLoading to false', () => {
+        const { initialState } = fromRootDirectory;
+        const action = rootDirectoryActions.loadRootDirectoryFail();
+        const state = fromRootDirectory.rootDirectoryReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual({ });
+        expect(state.rootDirectoryIsLoading).toEqual(false);
+        expect(state.rootDirectoryIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('should get rootDirectoryIsLoading', () => {
+        const action = {} as Action;
+        const state =  fromRootDirectory.rootDirectoryReducer(undefined, action);
+
+        expect(fromRootDirectory.selectRootDirectoryIsLoading(state)).toEqual(false);
+    });
+
+    it('should get rootDirectoryIsLoaded', () => {
+        const action = {} as Action;
+        const state = fromRootDirectory.rootDirectoryReducer(undefined, action);
+
+        expect(fromRootDirectory.selectRootDirectoryIsLoaded(state)).toEqual(false);
+    });
+});
diff --git a/client/src/app/metamodel/reducers/root-directory.reducer.ts b/client/src/app/metamodel/reducers/root-directory.reducer.ts
index d8d7082f7943a134b33a7c0f64a4cd2ba01b9f3e..efab0b9d840fc4bb35267e4a32b820987b221bea 100644
--- a/client/src/app/metamodel/reducers/root-directory.reducer.ts
+++ b/client/src/app/metamodel/reducers/root-directory.reducer.ts
@@ -13,6 +13,11 @@ import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity';
 import * as rootDirectoryActions from '../actions/root-directory.actions';
 import { FileInfo } from '../models';
 
+/**
+ * Interface for root directory state.
+ *
+ * @interface State
+ */
 export interface State extends EntityState<FileInfo> {
     rootDirectoryIsLoading: boolean;
     rootDirectoryIsLoaded: boolean;
@@ -39,8 +44,8 @@ export const rootDirectoryReducer = createReducer(
     }),
     on(rootDirectoryActions.loadRootDirectorySuccess, (state, { files }) => {
         return adapter.setAll(
-            files, 
-            { 
+            files,
+            {
                 ...state,
                 rootDirectoryIsLoading: false,
                 rootDirectoryIsLoaded: true
diff --git a/client/src/app/metamodel/reducers/select-option.reducer.spec.ts b/client/src/app/metamodel/reducers/select-option.reducer.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..000a74966ba13f3292949a801719dc165431b6b8
--- /dev/null
+++ b/client/src/app/metamodel/reducers/select-option.reducer.spec.ts
@@ -0,0 +1,107 @@
+import { Action } from '@ngrx/store';
+
+import * as fromSelectOption from './select-option.reducer';
+import * as selectOptionActions from '../actions/select-option.actions';
+import { SELECT_OPTION, SELECT_OPTION_LIST } from '../../../test-data';
+
+describe('[Metamodel][Reducers] SelectOption reducer', () => {
+    it('unknown action should return the default state', () => {
+        const { initialState } = fromSelectOption;
+        const action = { type: 'Unknown' };
+        const state = fromSelectOption.selectOptionReducer(initialState, action);
+        expect(state).toBe(initialState);
+    });
+
+    it('loadSelectOptionList action should set selectOptionListIsLoading to true', () => {
+        const { initialState } = fromSelectOption;
+        const action = selectOptionActions.loadSelectOptionList();
+        const state = fromSelectOption.selectOptionReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual({ });
+        expect(state.selectOptionListIsLoading).toEqual(true);
+        expect(state.selectOptionListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('loadSelectOptionListSuccess action should add selectOption list, set selectOptionListIsLoading to false and set selectOptionListIsLoaded to true', () => {
+        const { initialState } = fromSelectOption;
+        const action = selectOptionActions.loadSelectOptionListSuccess({ selectOptions: SELECT_OPTION_LIST });
+        const state = fromSelectOption.selectOptionReducer(initialState, action);
+        expect(state.ids.length).toEqual(2);
+        expect(state.ids).toContain(1);
+        expect(state.ids).toContain(2);
+        expect(Object.keys(state.entities).length).toEqual(2);
+        expect(state.selectOptionListIsLoading).toEqual(false);
+        expect(state.selectOptionListIsLoaded).toEqual(true);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('loadSelectOptionListFail action should set selectOptionListIsLoading to false', () => {
+        const { initialState } = fromSelectOption;
+        const action = selectOptionActions.loadSelectOptionListFail();
+        const state = fromSelectOption.selectOptionReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual({ });
+        expect(state.selectOptionListIsLoading).toEqual(false);
+        expect(state.selectOptionListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('addSelectOptionSuccess action should add a selectOption', () => {
+        const { initialState } = fromSelectOption;
+        const action = selectOptionActions.addSelectOptionSuccess({ selectOption: SELECT_OPTION });
+        const state = fromSelectOption.selectOptionReducer(initialState, action);
+        expect(state.ids.length).toEqual(1);
+        expect(state.ids).toContain(1);
+        expect(Object.keys(state.entities).length).toEqual(1);
+        expect(state.selectOptionListIsLoading).toEqual(false);
+        expect(state.selectOptionListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('editSelectOptionSuccess action should modify a selectOption', () => {
+        const initialState = {
+            ...fromSelectOption.initialState,
+            ids: [1],
+            entities: { 1: { ...SELECT_OPTION, label: 'label' }}
+        };
+        const action = selectOptionActions.editSelectOptionSuccess({ selectOption: SELECT_OPTION });
+        const state = fromSelectOption.selectOptionReducer(initialState, action);
+        expect(state.ids.length).toEqual(1);
+        expect(state.ids).toContain(1);
+        expect(Object.keys(state.entities).length).toEqual(1);
+        expect(state.entities[1]).toEqual(SELECT_OPTION);
+        expect(state.selectOptionListIsLoading).toEqual(false);
+        expect(state.selectOptionListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('deleteSelectOptionSuccess action should modify a selectOption', () => {
+        const initialState = {
+            ...fromSelectOption.initialState,
+            ids: [1],
+            entities: { 1: SELECT_OPTION }
+        };
+        const action = selectOptionActions.deleteSelectOptionSuccess({ selectOption: SELECT_OPTION });
+        const state = fromSelectOption.selectOptionReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual( { });
+        expect(state.selectOptionListIsLoading).toEqual(false);
+        expect(state.selectOptionListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('should get selectOptionListIsLoading', () => {
+        const action = {} as Action;
+        const state =  fromSelectOption.selectOptionReducer(undefined, action);
+
+        expect(fromSelectOption.selectSelectOptionListIsLoading(state)).toEqual(false);
+    });
+
+    it('should get selectOptionListIsLoaded', () => {
+        const action = {} as Action;
+        const state = fromSelectOption.selectOptionReducer(undefined, action);
+
+        expect(fromSelectOption.selectSelectOptionListIsLoaded(state)).toEqual(false);
+    });
+});
diff --git a/client/src/app/metamodel/reducers/select-option.reducer.ts b/client/src/app/metamodel/reducers/select-option.reducer.ts
index f63ffbd5c6f5c2cdc84386301784731bd29fb681..f6468561d435d3f003482acd019e685171be1f65 100644
--- a/client/src/app/metamodel/reducers/select-option.reducer.ts
+++ b/client/src/app/metamodel/reducers/select-option.reducer.ts
@@ -13,6 +13,11 @@ import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity';
 import { SelectOption } from '../models';
 import * as selectOptionActions from '../actions/select-option.actions';
 
+/**
+ * Interface for select option state.
+ *
+ * @interface State
+ */
 export interface State extends EntityState<SelectOption> {
     selectOptionListIsLoading: boolean;
     selectOptionListIsLoaded: boolean;
@@ -38,8 +43,8 @@ export const selectOptionReducer = createReducer(
     }),
     on(selectOptionActions.loadSelectOptionListSuccess, (state, { selectOptions }) => {
         return adapter.setAll(
-            selectOptions, 
-            { 
+            selectOptions,
+            {
                 ...state,
                 selectOptionListIsLoading: false,
                 selectOptionListIsLoaded: true
diff --git a/client/src/app/metamodel/reducers/select.reducer.spec.ts b/client/src/app/metamodel/reducers/select.reducer.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2e21a6f55ffd4e830d4a118dd2ec666340400457
--- /dev/null
+++ b/client/src/app/metamodel/reducers/select.reducer.spec.ts
@@ -0,0 +1,107 @@
+import { Action } from '@ngrx/store';
+
+import * as fromSelect from './select.reducer';
+import * as selectActions from '../actions/select.actions';
+import { SELECT, SELECT_LIST } from '../../../test-data';
+
+describe('[Metamodel][Reducers] Select reducer', () => {
+    it('unknown action should return the default state', () => {
+        const { initialState } = fromSelect;
+        const action = { type: 'Unknown' };
+        const state = fromSelect.selectReducer(initialState, action);
+        expect(state).toBe(initialState);
+    });
+
+    it('loadSelectList action should set selectListIsLoading to true', () => {
+        const { initialState } = fromSelect;
+        const action = selectActions.loadSelectList();
+        const state = fromSelect.selectReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual({ });
+        expect(state.selectListIsLoading).toEqual(true);
+        expect(state.selectListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('loadSelectListSuccess action should add select list, set selectListIsLoading to false and set selectListIsLoaded to true', () => {
+        const { initialState } = fromSelect;
+        const action = selectActions.loadSelectListSuccess({ selects: SELECT_LIST });
+        const state = fromSelect.selectReducer(initialState, action);
+        expect(state.ids.length).toEqual(2);
+        expect(state.ids).toContain('select-one');
+        expect(state.ids).toContain('select-two');
+        expect(Object.keys(state.entities).length).toEqual(2);
+        expect(state.selectListIsLoading).toEqual(false);
+        expect(state.selectListIsLoaded).toEqual(true);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('loadSelectListFail action should set selectListIsLoading to false', () => {
+        const { initialState } = fromSelect;
+        const action = selectActions.loadSelectListFail();
+        const state = fromSelect.selectReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual({ });
+        expect(state.selectListIsLoading).toEqual(false);
+        expect(state.selectListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('addSelectSuccess action should add a select', () => {
+        const { initialState } = fromSelect;
+        const action = selectActions.addSelectSuccess({ select: SELECT });
+        const state = fromSelect.selectReducer(initialState, action);
+        expect(state.ids.length).toEqual(1);
+        expect(state.ids).toContain('mySelect');
+        expect(Object.keys(state.entities).length).toEqual(1);
+        expect(state.selectListIsLoading).toEqual(false);
+        expect(state.selectListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('editSelectSuccess action should modify a select', () => {
+        const initialState = {
+            ...fromSelect.initialState,
+            ids: ['mySelect'],
+            entities: { 'mySelect': { ...SELECT, label: 'label' }}
+        };
+        const action = selectActions.editSelectSuccess({ select: SELECT });
+        const state = fromSelect.selectReducer(initialState, action);
+        expect(state.ids.length).toEqual(1);
+        expect(state.ids).toContain('mySelect');
+        expect(Object.keys(state.entities).length).toEqual(1);
+        expect(state.entities['mySelect']).toEqual(SELECT);
+        expect(state.selectListIsLoading).toEqual(false);
+        expect(state.selectListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('deleteSelectSuccess action should modify a select', () => {
+        const initialState = {
+            ...fromSelect.initialState,
+            ids: ['mySelect'],
+            entities: { 'mySelect': SELECT }
+        };
+        const action = selectActions.deleteSelectSuccess({ select: SELECT });
+        const state = fromSelect.selectReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual( { });
+        expect(state.selectListIsLoading).toEqual(false);
+        expect(state.selectListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('should get selectListIsLoading', () => {
+        const action = {} as Action;
+        const state =  fromSelect.selectReducer(undefined, action);
+
+        expect(fromSelect.selectSelectListIsLoading(state)).toEqual(false);
+    });
+
+    it('should get selectListIsLoaded', () => {
+        const action = {} as Action;
+        const state = fromSelect.selectReducer(undefined, action);
+
+        expect(fromSelect.selectSelectListIsLoaded(state)).toEqual(false);
+    });
+});
diff --git a/client/src/app/metamodel/reducers/select.reducer.ts b/client/src/app/metamodel/reducers/select.reducer.ts
index f12df3a564e146151601885be5cc0e117d8641c6..942f69e83a343c42f3d9bd1538f88921e447db47 100644
--- a/client/src/app/metamodel/reducers/select.reducer.ts
+++ b/client/src/app/metamodel/reducers/select.reducer.ts
@@ -13,6 +13,11 @@ import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity';
 import { Select } from '../models';
 import * as selectActions from '../actions/select.actions';
 
+/**
+ * Interface for select state.
+ *
+ * @interface State
+ */
 export interface State extends EntityState<Select> {
     selectListIsLoading: boolean;
     selectListIsLoaded: boolean;
@@ -38,8 +43,8 @@ export const selectReducer = createReducer(
     }),
     on(selectActions.loadSelectListSuccess, (state, { selects }) => {
         return adapter.setAll(
-            selects, 
-            { 
+            selects,
+            {
                 ...state,
                 selectListIsLoading: false,
                 selectListIsLoaded: true
diff --git a/client/src/app/metamodel/reducers/survey.reducer.spec.ts b/client/src/app/metamodel/reducers/survey.reducer.spec.ts
index 95c4c4610af8a428e9601f07ee61fdb10b010bd9..2e54b0f7716c60d2736bdfaf3d68e4043832fd9a 100644
--- a/client/src/app/metamodel/reducers/survey.reducer.spec.ts
+++ b/client/src/app/metamodel/reducers/survey.reducer.spec.ts
@@ -9,101 +9,99 @@ describe('[Metamodel][Reducers] Survey reducer', () => {
         const { initialState } = fromSurvey;
         const action = { type: 'Unknown' };
         const state = fromSurvey.surveyReducer(initialState, action);
-
         expect(state).toBe(initialState);
     });
 
-    it('addConeSearch action should add conesearch', () => {
+    it('loadSurveyList action should set surveyListIsLoading to true', () => {
+        const { initialState } = fromSurvey;
+        const action = surveyActions.loadSurveyList();
+        const state = fromSurvey.surveyReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual({ });
+        expect(state.surveyListIsLoading).toEqual(true);
+        expect(state.surveyListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('loadSurveyListSuccess action should add survey list, set surveyListIsLoading to false and set surveyListIsLoaded to true', () => {
         const { initialState } = fromSurvey;
         const action = surveyActions.loadSurveyListSuccess({ surveys: SURVEY_LIST });
         const state = fromSurvey.surveyReducer(initialState, action);
-        // expect(state.coneSearch).toEqual(coneSearch);
-        // expect(state.resolver).toBeNull();
-        // expect(state.resolverIsLoading).toBeFalsy();
-        // expect(state.resolverIsLoaded).toBeFalsy();
+        expect(state.ids.length).toEqual(2);
+        expect(state.ids).toContain('survey-one');
+        expect(state.ids).toContain('survey-two');
+        expect(Object.keys(state.entities).length).toEqual(2);
+        expect(state.surveyListIsLoading).toEqual(false);
+        expect(state.surveyListIsLoaded).toEqual(true);
         expect(state).not.toBe(initialState);
     });
 
-    // it('deleteConeSearch action should delete conesearch', () => {
-    //     const initialState = {
-    //         ...fromConeSearch.initialState,
-    //         coneSearch: { ra: 1, dec: 2, radius: 3 }
-    //     };
-    //     const action = coneSearchActions.deleteConeSearch();
-    //     const state = fromConeSearch.coneSearchReducer(initialState, action);
-    //
-    //     expect(state.coneSearch).toBeNull();
-    //     expect(state.resolver).toBeNull();
-    //     expect(state.resolverIsLoading).toBeFalsy();
-    //     expect(state.resolverIsLoaded).toBeFalsy();
-    //     expect(state).not.toBe(initialState);
-    // });
-    //
-    // it('retrieveCoordinates action should set resolverIsLoading to true and resolverIsLoaded to false', () => {
-    //     const { initialState } = fromConeSearch;
-    //     const action = coneSearchActions.retrieveCoordinates({ name: 'myObject' });
-    //     const state = fromConeSearch.coneSearchReducer(initialState, action);
-    //
-    //     expect(state.coneSearch).toBeNull();
-    //     expect(state.resolver).toBeNull();
-    //     expect(state.resolverIsLoading).toBeTruthy();
-    //     expect(state.resolverIsLoaded).toBeFalsy();
-    //     expect(state).not.toBe(initialState);
-    // });
-    //
-    // it('retrieveCoordinatesSuccess action should set resolverIsLoading to false and resolverIsLoaded to true', () => {
-    //     const { initialState } = fromConeSearch;
-    //     const resolver: Resolver = { name: 'myObject', ra: 1, dec: 2 };
-    //     const action = coneSearchActions.retrieveCoordinatesSuccess({ resolver });
-    //     const state = fromConeSearch.coneSearchReducer(initialState, action);
-    //
-    //     expect(state.coneSearch).toBeNull();
-    //     expect(state.resolver).toBe(resolver);
-    //     expect(state.resolverIsLoading).toBeFalsy();
-    //     expect(state.resolverIsLoaded).toBeTruthy();
-    //     expect(state).not.toBe(initialState);
-    // });
-    //
-    // it('retrieveCoordinatesFail action should set resolverIsLoading to false', () => {
-    //     const initialState = {
-    //         ...fromConeSearch.initialState,
-    //         resolverIsLoading: true
-    //     };
-    //     const action = coneSearchActions.retrieveCoordinatesFail();
-    //     const state = fromConeSearch.coneSearchReducer(initialState, action);
-    //
-    //     expect(state.coneSearch).toBeNull();
-    //     expect(state.resolver).toBeNull();
-    //     expect(state.resolverIsLoading).toBeFalsy();
-    //     expect(state.resolverIsLoaded).toBeFalsy();
-    //     expect(state).not.toBe(initialState);
-    // });
-    //
-    // it('should get coneSearch', () => {
-    //     const action = {} as Action;
-    //     const state =  fromConeSearch.coneSearchReducer(undefined, action);
-    //
-    //     expect(fromConeSearch.selectConeSearch(state)).toBeNull();
-    // });
-    //
-    // it('should get resolver', () => {
-    //     const action = {} as Action;
-    //     const state = fromConeSearch.coneSearchReducer(undefined, action);
-    //
-    //     expect(fromConeSearch.selectResolver(state)).toBeNull();
-    // });
-    //
-    // it('should get resolverIsLoading', () => {
-    //     const action = {} as Action;
-    //     const state =  fromConeSearch.coneSearchReducer(undefined, action);
-    //
-    //     expect(fromConeSearch.selectResolverIsLoading(state)).toBeFalsy();
-    // });
-    //
-    // it('should get resolverIsLoaded', () => {
-    //     const action = {} as Action;
-    //     const state = fromConeSearch.coneSearchReducer(undefined, action);
-    //
-    //     expect(fromConeSearch.selectResolverIsLoaded(state)).toBeFalsy();
-    // });
+    it('loadSurveyListFail action should set surveyListIsLoading to false', () => {
+        const { initialState } = fromSurvey;
+        const action = surveyActions.loadSurveyListFail();
+        const state = fromSurvey.surveyReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual({ });
+        expect(state.surveyListIsLoading).toEqual(false);
+        expect(state.surveyListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('addSurveySuccess action should add a survey', () => {
+        const { initialState } = fromSurvey;
+        const action = surveyActions.addSurveySuccess({ survey: SURVEY });
+        const state = fromSurvey.surveyReducer(initialState, action);
+        expect(state.ids.length).toEqual(1);
+        expect(state.ids).toContain('mySurvey');
+        expect(Object.keys(state.entities).length).toEqual(1);
+        expect(state.surveyListIsLoading).toEqual(false);
+        expect(state.surveyListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('editSurveySuccess action should modify a survey', () => {
+        const initialState = {
+            ...fromSurvey.initialState,
+            ids: ['mySurvey'],
+            entities: { 'mySurvey': { ...SURVEY, label: 'label' }}
+        };
+        const action = surveyActions.editSurveySuccess({ survey: SURVEY });
+        const state = fromSurvey.surveyReducer(initialState, action);
+        expect(state.ids.length).toEqual(1);
+        expect(state.ids).toContain('mySurvey');
+        expect(Object.keys(state.entities).length).toEqual(1);
+        expect(state.entities['mySurvey']).toEqual(SURVEY);
+        expect(state.surveyListIsLoading).toEqual(false);
+        expect(state.surveyListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('deleteSurveySuccess action should modify a survey', () => {
+        const initialState = {
+            ...fromSurvey.initialState,
+            ids: ['mySurvey'],
+            entities: { 'mySurvey': SURVEY }
+        };
+        const action = surveyActions.deleteSurveySuccess({ survey: SURVEY });
+        const state = fromSurvey.surveyReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual( { });
+        expect(state.surveyListIsLoading).toEqual(false);
+        expect(state.surveyListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('should get surveyListIsLoading', () => {
+        const action = {} as Action;
+        const state =  fromSurvey.surveyReducer(undefined, action);
+
+        expect(fromSurvey.selectSurveyListIsLoading(state)).toEqual(false);
+    });
+
+    it('should get surveyListIsLoaded', () => {
+        const action = {} as Action;
+        const state = fromSurvey.surveyReducer(undefined, action);
+
+        expect(fromSurvey.selectSurveyListIsLoaded(state)).toEqual(false);
+    });
 });
diff --git a/client/src/app/metamodel/reducers/survey.reducer.ts b/client/src/app/metamodel/reducers/survey.reducer.ts
index 610cd25423491752c6f23b5f8b5866a659bdc578..7514b7b3948785c2e5edb04553f0e817a0e2cedb 100644
--- a/client/src/app/metamodel/reducers/survey.reducer.ts
+++ b/client/src/app/metamodel/reducers/survey.reducer.ts
@@ -13,6 +13,11 @@ import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity';
 import { Survey } from '../models';
 import * as surveyActions from '../actions/survey.actions';
 
+/**
+ * Interface for survey state.
+ *
+ * @interface State
+ */
 export interface State extends EntityState<Survey> {
     surveyListIsLoading: boolean;
     surveyListIsLoaded: boolean;
@@ -38,8 +43,8 @@ export const surveyReducer = createReducer(
     }),
     on(surveyActions.loadSurveyListSuccess, (state, { surveys }) => {
         return adapter.setAll(
-            surveys, 
-            { 
+            surveys,
+            {
                 ...state,
                 surveyListIsLoading: false,
                 surveyListIsLoaded: true
diff --git a/client/src/app/metamodel/reducers/table.reducer.spec.ts b/client/src/app/metamodel/reducers/table.reducer.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9aff817fa8e807d7cff40cda6d4e6e9947958b86
--- /dev/null
+++ b/client/src/app/metamodel/reducers/table.reducer.spec.ts
@@ -0,0 +1,62 @@
+import { Action } from '@ngrx/store';
+
+import * as fromTable from './table.reducer';
+import * as tableActions from '../actions/table.actions';
+
+describe('[Metamodel][Reducers] Table reducer', () => {
+    it('unknown action should return the default state', () => {
+        const { initialState } = fromTable;
+        const action = { type: 'Unknown' };
+        const state = fromTable.tableReducer(initialState, action);
+        expect(state).toBe(initialState);
+    });
+
+    it('loadTableList action should set tableListIsLoading to true', () => {
+        const { initialState } = fromTable;
+        const action = tableActions.loadTableList({ idDatabase: 1 });
+        const state = fromTable.tableReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual({ });
+        expect(state.tableListIsLoading).toEqual(true);
+        expect(state.tableListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('loadTableListSuccess action should add table list, set tableListIsLoading to false and set tableListIsLoaded to true', () => {
+        const { initialState } = fromTable;
+        const action = tableActions.loadTableListSuccess({ tables: ['table-one', 'table-two'] });
+        const state = fromTable.tableReducer(initialState, action);
+        expect(state.ids.length).toEqual(2);
+        expect(state.ids).toContain('table-one');
+        expect(state.ids).toContain('table-two');
+        expect(Object.keys(state.entities).length).toEqual(2);
+        expect(state.tableListIsLoading).toEqual(false);
+        expect(state.tableListIsLoaded).toEqual(true);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('loadTableListFail action should set tableListIsLoading to false', () => {
+        const { initialState } = fromTable;
+        const action = tableActions.loadTableListFail();
+        const state = fromTable.tableReducer(initialState, action);
+        expect(state.ids.length).toEqual(0);
+        expect(state.entities).toEqual({ });
+        expect(state.tableListIsLoading).toEqual(false);
+        expect(state.tableListIsLoaded).toEqual(false);
+        expect(state).not.toBe(initialState);
+    });
+
+    it('should get tableListIsLoading', () => {
+        const action = {} as Action;
+        const state =  fromTable.tableReducer(undefined, action);
+
+        expect(fromTable.selectTableListIsLoading(state)).toEqual(false);
+    });
+
+    it('should get tableListIsLoaded', () => {
+        const action = {} as Action;
+        const state = fromTable.tableReducer(undefined, action);
+
+        expect(fromTable.selectTableListIsLoaded(state)).toEqual(false);
+    });
+});
diff --git a/client/src/app/metamodel/reducers/table.reducer.ts b/client/src/app/metamodel/reducers/table.reducer.ts
index 24acb6e6c7aedfdd20c187a1e9ef784adec331cb..5b5f369bbc4cfff2e739f8a5363ffc4d2f41fc51 100644
--- a/client/src/app/metamodel/reducers/table.reducer.ts
+++ b/client/src/app/metamodel/reducers/table.reducer.ts
@@ -12,6 +12,11 @@ import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity';
 
 import * as tableActions from '../actions/table.actions';
 
+/**
+ * Interface for table state.
+ *
+ * @interface State
+ */
 export interface State extends EntityState<string> {
     tableListIsLoading: boolean;
     tableListIsLoaded: boolean;
@@ -38,8 +43,8 @@ export const tableReducer = createReducer(
     }),
     on(tableActions.loadTableListSuccess, (state, { tables }) => {
         return adapter.setAll(
-            tables, 
-            { 
+            tables,
+            {
                 ...state,
                 tableListIsLoading: false,
                 tableListIsLoaded: true
diff --git a/client/src/test-data.ts b/client/src/test-data.ts
index f2701681f0ba1a36f433f9ced25c9d60b92062e9..fbde4ef15bbaa951120e5135cb4f1561f9263573 100644
--- a/client/src/test-data.ts
+++ b/client/src/test-data.ts
@@ -1,13 +1,36 @@
 import {
     Attribute, Column, CriteriaFamily, Database,
     Dataset,
-    DatasetFamily, Group,
+    DatasetFamily, FileInfo, Group,
     Instance,
     OutputCategory,
     OutputFamily, Select, SelectOption,
     Survey
 } from './app/metamodel/models';
 
+export const DATABASE_LIST: Database[] = [
+    {
+        id: 1,
+        label: 'database one',
+        dbname: 'database-one',
+        dbtype: 'type',
+        dbhost: 'host',
+        dbport: 1234,
+        dblogin: 'login',
+        dbpassword: 'pwd'
+    },
+    {
+        id: 2,
+        label: 'database two',
+        dbname: 'database-two',
+        dbtype: 'type',
+        dbhost: 'host',
+        dbport: 1234,
+        dblogin: 'login',
+        dbpassword: 'pwd'
+    }
+];
+
 export const DATABASE: Database = {
     id: 1,
     label: 'my database',
@@ -153,6 +176,21 @@ export const INSTANCE: Instance = {
     nb_datasets: 2
 };
 
+export const GROUP_LIST: Group[] = [
+    {
+        id: 1,
+        role: 'admin',
+        instance_name: 'myInstance',
+        datasets: ['myDataset', 'otherDataset']
+    },
+    {
+        id: 2,
+        role: 'guest',
+        instance_name: 'myInstance',
+        datasets: ['myDataset', 'otherDataset']
+    }
+];
+
 export const GROUP: Group = {
     id: 1,
     role: 'admin',
@@ -442,6 +480,11 @@ export const ATTRIBUTE: Attribute = {
     id_output_category: 2
 };
 
+export const COLUMN_LIST: Column[] = [
+    { name: 'myCol', type: 'type' },
+    { name: 'anotherCol', type: 'type' }
+];
+
 export const COLUMN: Column = { name: 'myCol', type: 'type' };
 
 export const CATEGORY_LIST: OutputCategory[] = [
@@ -479,6 +522,21 @@ export const OUTPUT_FAMILY_LIST: OutputFamily[] = [
 
 export const OUTPUT_FAMILY: OutputFamily = { id: 1, label: 'Output family One', display: 1, opened: false };
 
+export const CRITERIA_FAMILY_LIST: CriteriaFamily[] = [
+    {
+        id: 1,
+        label: 'myCriteriaFamily',
+        display: 1,
+        opened: true
+    },
+    {
+        id: 2,
+        label: 'anotherCriteriaFamily',
+        display: 1,
+        opened: true
+    }
+];
+
 export const CRITERIA_FAMILY: CriteriaFamily = {
     id: 1,
     label: 'myCriteriaFamily',
@@ -486,6 +544,11 @@ export const CRITERIA_FAMILY: CriteriaFamily = {
     opened: true
 };
 
+export const SELECT_LIST: Select[] = [
+    { name: 'select-one', label: 'Select one' },
+    { name: 'select-two', label: 'Select two' }
+];
+
 export const SELECT: Select = { name: 'mySelect', label: 'My select' };
 
 export const SELECT_OPTION_LIST: SelectOption[] = [
@@ -505,3 +568,8 @@ export const OBJECT_DETAIL: any = {
     label_four: 'spec1d',
     label_five: 5
 };
+
+export const FILES: FileInfo[] = [
+    { name: 'file-one', size: 1, type: 'type', mimetype: 'mimetype' },
+    { name: 'file-two', size: 2, type: 'type', mimetype: 'mimetype' },
+];