diff --git a/Makefile b/Makefile
index 993b6e2b78b97b8deea0c5bdc64e393bdf9612f5..d4fb97bc85d38a9d3bc20038fc43ad40fe35e291 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
-UID := 1000
-GID := 1000
+UID := 9898
+GID := 4000
 
 
 list:
diff --git a/client/src/app/admin/instance/dataset/components/add-attribute.component.spec.ts b/client/src/app/admin/instance/dataset/components/add-attribute.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..cae0ad59d44730cab7db5edd8b34ccd3df7e520e
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/add-attribute.component.spec.ts
@@ -0,0 +1,74 @@
+/**
+ * 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 { TemplateRef } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
+
+import { Column } from 'src/app/admin/store/models';
+import { Attribute } from 'src/app/metamodel/models';
+import { AddAttributeComponent } from './add-attribute.component';
+
+describe('[admin][instance][dataset][components] AddAttributeComponent', () => {
+    let component: AddAttributeComponent;
+    let fixture: ComponentFixture<AddAttributeComponent>;
+    const modalServiceStub = {
+        show: jest.fn(),
+    };
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                AddAttributeComponent,
+            ],
+            providers: [
+                BsModalRef,
+                { provide: BsModalService, useValue: modalServiceStub }
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(AddAttributeComponent);
+        component = fixture.componentInstance;
+        let attribute: Attribute;
+        component.attributeList = [{ ...attribute, name: 'test1' }, { ...attribute, name: 'test2test' }]
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+
+    it('should call modalRef.show(template)', () => {
+        let template: TemplateRef<any> = null;
+        let spyOnLoadColumnList = jest.spyOn(component.loadColumnList, 'emit');
+        let spy = jest.spyOn(modalServiceStub, 'show');
+        component.openModal(template);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(template);
+        expect(spyOnLoadColumnList).toHaveBeenCalledTimes(1);
+    });
+
+    it('alreadyExists(columnName: string) should return true', () => {
+        expect(component.alreadyExists('test1')).toEqual(true);
+        expect(component.alreadyExists('test')).toEqual(false);
+    });
+
+    it('alreadyExists(columnName: string) should call emit on add', () => {
+        let spy = jest.spyOn(component.add, 'emit');
+        let column: Column = { name: 'test', type: 'test' };
+        component.addNewAttribute(column);
+        expect(spy).toHaveBeenCalledTimes(1);
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/attribute/criteria/generate-option-list.component.spec.ts b/client/src/app/admin/instance/dataset/components/attribute/criteria/generate-option-list.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..77393a3e7dc55dd1beb059de8e22e3f05c1ae01b
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/attribute/criteria/generate-option-list.component.spec.ts
@@ -0,0 +1,73 @@
+/**
+ * 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 { TemplateRef } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
+
+import { GenerateOptionListComponent } from './generate-option-list.component';
+
+describe('[admin][instance][dataset][components][attribute][criteria] GenerateOptionListComponent', () => {
+    let component: GenerateOptionListComponent;
+    let fixture: ComponentFixture<GenerateOptionListComponent>;
+
+    const modalServiceStub = {
+        show: jest.fn().mockReturnThis(),
+        hide: jest.fn()
+    };
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                GenerateOptionListComponent,
+            ],
+            providers: [
+                BsModalRef,
+                { provide: BsModalService, useValue: modalServiceStub }
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(GenerateOptionListComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+
+    it('should call modalRef.show(template) and  loadAttributeDistinctList.emit', () => {
+        let template: TemplateRef<any> = null;
+        let spyOnModal = jest.spyOn(modalServiceStub, 'show');
+        let spyOnloadAttributeDistinctList = jest.spyOn(component.loadAttributeDistinctList, 'emit');
+        component.openModal(template);
+        expect(spyOnModal).toHaveBeenCalledTimes(1);
+        expect(spyOnModal).toHaveBeenCalledWith(template);
+        expect(spyOnloadAttributeDistinctList).toHaveBeenCalledTimes(1);
+    });
+
+    it('should emit attributeDistinctList and call  modalRef.hide()', () => {
+        let template: TemplateRef<any> = null;
+        let spyOnModal = jest.spyOn(modalServiceStub, 'hide');
+        let spyOngenerateOptionList = jest.spyOn(component.generateOptionList, 'emit');
+        let attributeDistinctList: string[] = ['test'];
+        component.attributeDistinctList = attributeDistinctList;
+        component.openModal(template);
+        component.generate();
+        expect(spyOngenerateOptionList).toHaveBeenCalledTimes(1);
+        expect(spyOngenerateOptionList).toHaveBeenCalledWith(attributeDistinctList);
+        expect(spyOnModal).toHaveBeenCalledTimes(1);
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/attribute/criteria/index.spec.ts b/client/src/app/admin/instance/dataset/components/attribute/criteria/index.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..aa433ed0a5e9eeaab733e80bbee67b84bb319f35
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/attribute/criteria/index.spec.ts
@@ -0,0 +1,16 @@
+/**
+ * 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 { criteriaComponents } from './index';
+
+describe('[admin][instance][dataset][components][attribute][criteria] index', () => {
+    it('Test criteria index components', () => {
+        expect(criteriaComponents.length).toEqual(5);
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/attribute/criteria/option-list.component.spec.ts b/client/src/app/admin/instance/dataset/components/attribute/criteria/option-list.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..56fae7298c8053aaeac1fecb8e9582152a066436
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/attribute/criteria/option-list.component.spec.ts
@@ -0,0 +1,97 @@
+/**
+ * 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 { Component } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule, UntypedFormArray, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { OptionListComponent } from './option-list.component';
+
+@Component({
+    selector: 'app-option-form',
+})
+class OptionFormComponent {
+    form: UntypedFormGroup = new UntypedFormGroup({});
+}
+@Component({
+    selector: 'app-generate-option-list',
+})
+export class GenerateOptionListComponent {}
+
+describe('[admin][instance][dataset][components][attribute][criteria] OptionListComponent', () => {
+    let component: OptionListComponent;
+    let fixture: ComponentFixture<OptionListComponent>;
+    let newOptionFormGroup: UntypedFormGroup = new UntypedFormGroup({
+        label: new UntypedFormControl('', [Validators.required]),
+        value: new UntypedFormControl('', [Validators.required]),
+        display: new UntypedFormControl('', [Validators.required]),
+    });
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                OptionListComponent,
+                OptionFormComponent,
+                GenerateOptionListComponent
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(OptionListComponent);
+        component = fixture.componentInstance;
+        component.optionList = [{ label: '', display: 10, value: null }];
+        component.form = new UntypedFormArray([]);
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+
+    it('buildFormGroup() return an instance of UntypedFormGroup', () => {
+        let result = component.buildFormGroup();
+        expect(result).toBeInstanceOf(UntypedFormGroup);
+    });
+
+    it('addOption() should add newOptionFormGroup in form array , call buildFormGroup() and form.markAsDirty()', () => {
+        component.form = new UntypedFormArray([]);
+        component.newOptionFormGroup = newOptionFormGroup;
+        let spyOnBuildFormGroup = jest.spyOn(component, 'buildFormGroup')
+        let spyOnFormDirty = jest.spyOn(component.form, 'markAsDirty')
+        expect(component.form.controls.length).toEqual(0);
+        component.addOption();
+        expect(component.form.controls.length).toEqual(1);
+        expect(spyOnBuildFormGroup).toHaveBeenCalledTimes(1);
+        expect(spyOnFormDirty).toHaveBeenCalledTimes(1);
+    });
+    
+    it('removeOption(index: number) should remove the element on the index in the form array and call form.markAsDirty()', () => {
+        component.form = new UntypedFormArray([newOptionFormGroup]);
+        let spyOnForm = jest.spyOn(component.form, 'markAsDirty')
+        expect(component.form.controls.length).toEqual(1);
+        component.removeOption(0);
+        expect(component.form.controls.length).toEqual(0);
+        expect(spyOnForm).toHaveBeenCalledTimes(1);
+    });
+
+    it('generateOptionList(attributeDistinctList: string[]) should call form.clear()', () => {
+        component.form = new UntypedFormArray([]);
+        let spyOnFormClear = jest.spyOn(component.form, 'clear');
+        let spyOnFormDirty = jest.spyOn(component.form, 'markAsDirty');
+        let attributeDistinctList: string[] = ['test1', 'test2', 'test3'];
+        expect(component.form.controls.length).toEqual(0);
+        component.generateOptionList(attributeDistinctList);
+        expect(spyOnFormClear).toHaveBeenCalledTimes(1);
+        expect(component.form.controls.length).toEqual(attributeDistinctList.length);
+        expect(spyOnFormDirty).toHaveBeenCalledTimes(1);
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/attribute/criteria/table-criteria.component.spec.ts b/client/src/app/admin/instance/dataset/components/attribute/criteria/table-criteria.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..dc4b79c5395bb88d54121cb2f88864ed7266cf74
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/attribute/criteria/table-criteria.component.spec.ts
@@ -0,0 +1,37 @@
+/**
+ * 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 { ComponentFixture, TestBed } from '@angular/core/testing';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { TableCriteriaComponent } from './table-criteria.component';
+
+describe('[admin][instance][dataset][components][attribute][criteria] TableCriteriaComponent', () => {
+    let component: TableCriteriaComponent;
+    let fixture: ComponentFixture<TableCriteriaComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                TableCriteriaComponent,
+            ],
+            providers: [],
+            imports: [
+                BrowserAnimationsModule,
+            ],
+        });
+        fixture = TestBed.createComponent(TableCriteriaComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/attribute/criteria/tr-criteria.component.spec.ts b/client/src/app/admin/instance/dataset/components/attribute/criteria/tr-criteria.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f38ba390338a8c16bc0728f1eab42f5f483350c9
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/attribute/criteria/tr-criteria.component.spec.ts
@@ -0,0 +1,109 @@
+/**
+ * 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 { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule, UntypedFormArray, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { Attribute } from 'src/app/metamodel/models';
+import { TrCriteriaComponent } from './tr-criteria.component';
+
+describe('[admin][instance][dataset][components][attribute][criteria] TrCriteriaComponent', () => {
+    let component: TrCriteriaComponent;
+    let fixture: ComponentFixture<TrCriteriaComponent>;
+    let form;
+    let attribute: Attribute;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                TrCriteriaComponent
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(TrCriteriaComponent);
+        component = fixture.componentInstance;
+    });
+
+    beforeEach(() => {
+        form = new UntypedFormGroup({
+            name: new UntypedFormControl({ value: '', disabled: true }),
+            type: new UntypedFormControl({ value: '', disabled: true }),
+            id_criteria_family: new UntypedFormControl(''),
+            search_type: new UntypedFormControl(''),
+            operator: new UntypedFormControl(''),
+            dynamic_operator: new UntypedFormControl(),
+            min: new UntypedFormControl(''),
+            max: new UntypedFormControl(''),
+            options: new UntypedFormArray([]),
+            placeholder_min: new UntypedFormControl(''),
+            placeholder_max: new UntypedFormControl(''),
+            criteria_display: new UntypedFormControl('')
+        });
+        component.attribute = { ...attribute, name: 'test', id_criteria_family: 0, options: [] };
+        fixture.detectChanges();
+    })
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+
+    it('criteriaFamilyOnChange() should set id_criteria_family to null and call searchTypeOnChange()', () => {
+        let spy = jest.spyOn(component, 'searchTypeOnChange');
+        component.form = form;
+        expect(form.controls.id_criteria_family.value).toEqual('');
+        component.criteriaFamilyOnChange();
+        expect(form.controls.id_criteria_family.value).toEqual(null);
+        expect(spy).toHaveBeenCalledTimes(1);
+    });
+
+    it('searchTypeOnChange() should set search_type to null and call operatorOnChange()', () => {
+        let spy = jest.spyOn(component, 'operatorOnChange');
+        component.form = form;
+        expect(form.controls.search_type.value).toEqual('');
+        component.searchTypeOnChange();
+        expect(form.controls.search_type.value).toEqual(null);
+        expect(spy).toHaveBeenCalledTimes(1);
+    });
+
+    it('should set operator, min, max, palceholder_min, palceholder_max to null and call clear method on optionsFormArray', () => {
+        let spy = jest.spyOn(component.optionsFormArray, 'clear');
+        component.form = form;
+        expect(component.form.controls.operator.value).toEqual('');
+        component.operatorOnChange();
+        expect(component.form.controls.operator.value).toEqual(null);
+        expect(component.form.controls.min.value).toEqual(null);
+        expect(component.form.controls.max.value).toEqual(null);
+        expect(component.form.controls.placeholder_min.value).toEqual(null);
+        expect(component.form.controls.placeholder_max.value).toEqual(null);
+        expect(spy).toHaveBeenCalledTimes(1)
+    });
+    
+    it('getMinValuePlaceholder(searchType: string) should return Default min value (optional)', () => {
+        let searchType: string = 'between-date';
+        let result = component.getMinValuePlaceholder(searchType);
+        expect(result).toEqual('Default min value (optional)')
+    });
+
+    it('getMinValuePlaceholder(searchType: string) should return Default value (optional)', () => {
+        let searchType: string = 'test';
+        let result = component.getMinValuePlaceholder(searchType);
+        expect(result).toEqual('Default value (optional)')
+    });
+
+    it('submit() should emit component.attribute and component.form.value', () => {
+        let spy = jest.spyOn(component.save, 'emit');
+        component.submit();
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith({ ...component.attribute, ...component.form.value })
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/attribute/detail/index.spec.ts b/client/src/app/admin/instance/dataset/components/attribute/detail/index.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..97dcfc5df4e7738a5466fb7754ab62c2804dba19
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/attribute/detail/index.spec.ts
@@ -0,0 +1,17 @@
+/**
+ * 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 { detailComponents } from './index';
+
+describe('[admin][instance][dataset][components][attribute][detail] index', () => {
+    it('Test detail index components', () => {
+        expect(detailComponents.length).toEqual(3);
+    });
+});
+
diff --git a/client/src/app/admin/instance/dataset/components/attribute/detail/table-detail.component.spec.ts b/client/src/app/admin/instance/dataset/components/attribute/detail/table-detail.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e7beb8f1316d586b246f699b52c190a4412602d4
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/attribute/detail/table-detail.component.spec.ts
@@ -0,0 +1,36 @@
+/**
+ * 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 { ComponentFixture, TestBed } from '@angular/core/testing';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { TableDetailComponent } from './table-detail.component';
+
+describe('[admin][instance][dataset][components][attribute][detail] TableDetailComponent', () => {
+    let component: TableDetailComponent;
+    let fixture: ComponentFixture<TableDetailComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                TableDetailComponent,
+            ],
+            imports: [
+                BrowserAnimationsModule,
+            ],
+        });
+        fixture = TestBed.createComponent(TableDetailComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+});
+
diff --git a/client/src/app/admin/instance/dataset/components/attribute/detail/tr-detail.component.spec.ts b/client/src/app/admin/instance/dataset/components/attribute/detail/tr-detail.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e562209fb73d1c23fbd2303bb5b55ef02d755634
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/attribute/detail/tr-detail.component.spec.ts
@@ -0,0 +1,63 @@
+/**
+ * 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 { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { Attribute, OutputFamily } from 'src/app/metamodel/models';
+import { TrDetailComponent } from './tr-detail.component';
+
+describe('[admin][instance][dataset][components][attribute][detail] TrDetailComponent', () => {
+    let component: TrDetailComponent;
+    let fixture: ComponentFixture<TrDetailComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                TrDetailComponent,
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(TrDetailComponent);
+        component = fixture.componentInstance;
+        let attribute: Attribute;
+        component.attribute = { ...attribute, name: 'test', id_detail_output_category: 0, detail_display: 0 };
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+    it('detailOutputCategoryOnChange() should set form.id_detail_output_category to null', () => {
+        component.form.controls.id_detail_output_category.setValue('');
+        expect(component.form.controls.id_detail_output_category.value).toEqual('');
+        component.detailOutputCategoryOnChange();
+        expect(component.form.controls.id_detail_output_category.value).toEqual(null);
+    });
+    it('getOutputFamilyLabel(idOutputFamilly: number) should return test1', () => {
+        let outputFamilyList: OutputFamily[] = [
+            { display: 0, id: 1, label: 'test0', opened: false },
+            { display: 0, id: 2, label: 'test1', opened: false },
+            { display: 0, id: 3, label: 'test2', opened: false }
+        ]
+        component.outputFamilyList = outputFamilyList;
+        let result: string = component.getOutputFamilyLabel(2);
+        expect(result).toEqual('test1');
+    })
+    it('submit() should emit with attribute and form.value', () => {
+        let spy = jest.spyOn(component.save, 'emit');
+        component.submit();
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith({ ...component.attribute, ...component.form.value });
+    })
+});
+
diff --git a/client/src/app/admin/instance/dataset/components/attribute/general/index.spec.ts b/client/src/app/admin/instance/dataset/components/attribute/general/index.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..82cb0587851f7943eecbac656e8e125aa374c8e8
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/attribute/general/index.spec.ts
@@ -0,0 +1,17 @@
+/**
+ * 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 { generalComponents } from './index';
+
+describe('[admin][instance][dataset][components][attribute][general] index', () => {
+    it('Test general index components', () => {
+        expect(generalComponents.length).toEqual(2);
+    });
+});
+
diff --git a/client/src/app/admin/instance/dataset/components/attribute/general/table-general.component.spec.ts b/client/src/app/admin/instance/dataset/components/attribute/general/table-general.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..93d9d4a01578ecae4228190b77726d4829c3c8bd
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/attribute/general/table-general.component.spec.ts
@@ -0,0 +1,37 @@
+/**
+ * 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 { ComponentFixture, TestBed } from '@angular/core/testing';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { TableGeneralComponent } from './table-general.component';
+
+describe('[admin][instance][dataset][components][attribute][general] TableGeneralComponent', () => {
+    let component: TableGeneralComponent;
+    let fixture: ComponentFixture<TableGeneralComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                TableGeneralComponent,
+            ],
+            imports: [
+                BrowserAnimationsModule,
+            ],
+        });
+        fixture = TestBed.createComponent(TableGeneralComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+});
+
+
diff --git a/client/src/app/admin/instance/dataset/components/attribute/general/tr-general.component.spec.ts b/client/src/app/admin/instance/dataset/components/attribute/general/tr-general.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d62a63ba1daf4cc266f8cdd4872e1cccf8f6664f
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/attribute/general/tr-general.component.spec.ts
@@ -0,0 +1,57 @@
+/**
+ * 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 { Component } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { Attribute, OutputFamily } from 'src/app/metamodel/models';
+import { TrGeneralComponent } from './tr-general.component';
+@Component({
+    selector: 'app-delete-btn'
+})
+class DeleteBtnComponent {
+    type = ''
+    label = ''
+}
+describe('[admin][instance][dataset][components][attribute][general] TrDetailComponent', () => {
+    let component: TrGeneralComponent;
+    let fixture: ComponentFixture<TrGeneralComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                TrGeneralComponent,
+                DeleteBtnComponent
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(TrGeneralComponent);
+        component = fixture.componentInstance;
+        let attribute: Attribute;
+        component.attribute = { ...attribute, name: 'test', id: 0, label: 'test', form_label: 'test', description: 'test', primary_key: false };
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+
+    it('submit() should emit with attribute and form.value', () => {
+        let spy = jest.spyOn(component.save, 'emit');
+        component.submit();
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith({ ...component.attribute, ...component.form.value });
+    })
+});
+
+
diff --git a/client/src/app/admin/instance/dataset/components/attribute/index.spec.ts b/client/src/app/admin/instance/dataset/components/attribute/index.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..fe3af5d02ed4b9a2fcf4396f380d673e3eae870d
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/attribute/index.spec.ts
@@ -0,0 +1,16 @@
+/**
+ * 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 { attributeComponents } from './index';
+
+describe('[admin][instance][dataset][components][attribute] index', () => {
+    it('Test output index components', () => {
+        expect(attributeComponents.length).toEqual(7);
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/attribute/output/index.spec.ts b/client/src/app/admin/instance/dataset/components/attribute/output/index.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..bd09ef621faecb323879401828d89594f8ec1a1c
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/attribute/output/index.spec.ts
@@ -0,0 +1,17 @@
+/**
+ * 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 { outputComponents } from './index';
+
+describe('[admin][instance][dataset][components][attribute][output] index', () => {
+    it('Test output index components', () => {
+        expect(outputComponents.length).toEqual(2);
+    });
+});
+
diff --git a/client/src/app/admin/instance/dataset/components/attribute/output/table-output.component.spec.ts b/client/src/app/admin/instance/dataset/components/attribute/output/table-output.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f4f343a47953c2fd3236fd54d027bb5b89acae8d
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/attribute/output/table-output.component.spec.ts
@@ -0,0 +1,36 @@
+/**
+ * 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 { ComponentFixture, TestBed } from '@angular/core/testing';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { TableOutputComponent } from './table-output.component';
+
+describe('[admin][instance][dataset][components][attribute][output] TableOutputComponent', () => {
+    let component: TableOutputComponent;
+    let fixture: ComponentFixture<TableOutputComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                TableOutputComponent,
+            ],
+            imports: [
+                BrowserAnimationsModule,
+            ],
+        });
+        fixture = TestBed.createComponent(TableOutputComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+});
+
diff --git a/client/src/app/admin/instance/dataset/components/attribute/output/tr-output.component.spec.ts b/client/src/app/admin/instance/dataset/components/attribute/output/tr-output.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..cf15cb9550928d82865e3c553ccd9a4a5039bd7b
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/attribute/output/tr-output.component.spec.ts
@@ -0,0 +1,63 @@
+/**
+ * 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 { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { Attribute, OutputFamily } from 'src/app/metamodel/models';
+import { TrOutputComponent } from './tr-output.component';
+
+describe('[admin][instance][dataset][components][attribute][] TrOutputComponent', () => {
+    let component: TrOutputComponent;
+    let fixture: ComponentFixture<TrOutputComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                TrOutputComponent,
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(TrOutputComponent);
+        component = fixture.componentInstance;
+        let attribute: Attribute;
+        component.attribute = { ...attribute, name: 'test', output_display: 0, id_output_category: 0, selected: true };
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+    it('outputCategoryOnChange() should set form.id_output_category to null', () => {
+        component.form.controls.id_output_category.setValue('');
+        expect(component.form.controls.id_output_category.value).toEqual('');
+        component.outputCategoryOnChange();
+        expect(component.form.controls.id_output_category.value).toEqual(null);
+    });
+    it('getOutputFamilyLabel(idOutputFamilly: number) should return test2', () => {
+        let outputFamilyList: OutputFamily[] = [
+            { display: 0, id: 1, label: 'test0', opened: false },
+            { display: 0, id: 2, label: 'test1', opened: false },
+            { display: 0, id: 3, label: 'test2', opened: false }
+        ]
+        component.outputFamilyList = outputFamilyList;
+        let result: string = component.getOutputFamilyLabel(3);
+        expect(result).toEqual('test2');
+    })
+    it('submit() should emit with attribute and form.value', () => {
+        let spy = jest.spyOn(component.save, 'emit');
+        component.submit();
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith({ ...component.attribute, ...component.form.value });
+    })
+});
+
diff --git a/client/src/app/admin/instance/dataset/components/attribute/result/index.spec.ts b/client/src/app/admin/instance/dataset/components/attribute/result/index.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a5a869c86f2ab07372f8481cf0dab3590985f6b5
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/attribute/result/index.spec.ts
@@ -0,0 +1,17 @@
+/**
+ * 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 { resultComponents } from './index';
+
+describe('[admin][instance][dataset][components][attribute][result] index', () => {
+    it('Test result index components', () => {
+        expect(resultComponents.length).toEqual(3);
+    });
+});
+
diff --git a/client/src/app/admin/instance/dataset/components/attribute/result/renderers/detail-link-renderer.component.spec.ts b/client/src/app/admin/instance/dataset/components/attribute/result/renderers/detail-link-renderer.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..64db6587f688bcb61d3a24f77ca6dd8c3ff59795
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/attribute/result/renderers/detail-link-renderer.component.spec.ts
@@ -0,0 +1,44 @@
+/**
+ * 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 { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { DetailLinkRendererComponent } from './detail-link-renderer.component';
+
+describe('[admin][instance][dataset][components][attribute][result][renderers] DetailLinkRendererComponent', () => {
+    let component: DetailLinkRendererComponent;
+    let fixture: ComponentFixture<DetailLinkRendererComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                DetailLinkRendererComponent,
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(DetailLinkRendererComponent);
+        component = fixture.componentInstance;
+        let form = new UntypedFormGroup({
+            display: new UntypedFormControl(),
+            text: new UntypedFormControl()
+
+        });
+        component.form = form;
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+});
+
diff --git a/client/src/app/admin/instance/dataset/components/attribute/result/renderers/index.spec.ts b/client/src/app/admin/instance/dataset/components/attribute/result/renderers/index.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2561157e931e527c7b7b2d26bf7e5537953b80a9
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/attribute/result/renderers/index.spec.ts
@@ -0,0 +1,19 @@
+/**
+ * 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 { renderers, rendererList } from './index';
+
+ describe('[admin][instance][dataset][components][attribute][result][renderers] index', () => {
+     it('Test renderers index ', () => {
+         expect(renderers.length).toEqual(1);
+         expect(rendererList.length).toEqual(5);
+     });
+ });
+ 
+ 
\ No newline at end of file
diff --git a/client/src/app/admin/instance/dataset/components/attribute/result/renderers/renderer-form-factory.spec.ts b/client/src/app/admin/instance/dataset/components/attribute/result/renderers/renderer-form-factory.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e9a601308bdd481cfea18a335e9874ada31e385b
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/attribute/result/renderers/renderer-form-factory.spec.ts
@@ -0,0 +1,77 @@
+/**
+ * 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 { TestBed } from '@angular/core/testing';
+import { UntypedFormControl } from '@angular/forms';
+import { RendererFormFactory } from './renderer-form-factory';
+
+class TestClass extends RendererFormFactory { }
+describe('[admin][instance][dataset][components][attribute][result][renderers] RendererFormFactory', () => {
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [TestClass],
+        })
+    });
+
+    it('should test case detail-link', () => {
+        let spy = jest.spyOn(TestClass, 'create');
+        let form = { display: new UntypedFormControl('text') };
+        let result = TestClass.create('detail-link');
+        expect(spy).toHaveBeenCalled();
+        expect(JSON.stringify(result)).toEqual(JSON.stringify(form));
+    })
+
+    it('should test case link', () => {
+        let spy = jest.spyOn(TestClass, 'create');
+        let result = TestClass.create('link');
+        let form = {
+            href: new UntypedFormControl('$value'),
+            display: new UntypedFormControl('text'),
+            text: new UntypedFormControl('$value'),
+            icon: new UntypedFormControl('fas fa-link'),
+            blank: new UntypedFormControl(true)
+        };
+        expect(spy).toHaveBeenCalled();
+        expect(JSON.stringify(result)).toEqual(JSON.stringify(form));
+    })
+
+    it('should test case download', () => {
+        let spy = jest.spyOn(TestClass, 'create');
+        let result = TestClass.create('download');
+        let form = {
+            display: new UntypedFormControl('icon-button'),
+            text: new UntypedFormControl('DOWNLOAD'),
+            icon: new UntypedFormControl('fas fa-download')
+        };
+        expect(spy).toHaveBeenCalled();
+        expect(JSON.stringify(result)).toEqual(JSON.stringify(form));
+    })
+
+    it('should test case image', () => {
+        let spy = jest.spyOn(TestClass, 'create');
+        let result = TestClass.create('image');
+        let form = {
+            type: new UntypedFormControl('fits'),
+            display: new UntypedFormControl('modal'),
+            width: new UntypedFormControl(''),
+            height: new UntypedFormControl('')
+        }
+        expect(spy).toHaveBeenCalled();
+        expect(JSON.stringify(result)).toEqual(JSON.stringify(form));
+
+    })
+
+    it('should test case default', () => {
+        let spy = jest.spyOn(TestClass, 'create');
+        let result = TestClass.create('');
+        expect(spy).toHaveBeenCalled();
+        expect(result).toEqual({});
+    })
+});
+
diff --git a/client/src/app/admin/instance/dataset/components/attribute/result/table-result.component.spec.ts b/client/src/app/admin/instance/dataset/components/attribute/result/table-result.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..aa0104624cb6ec48ced9634c874577c72b5920a1
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/attribute/result/table-result.component.spec.ts
@@ -0,0 +1,37 @@
+
+/**
+ * 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 { ComponentFixture, TestBed } from '@angular/core/testing';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { TableResultComponent } from './table-result.component';
+
+describe('[admin][instance][dataset][components][attribute][result] TableResultComponent ', () => {
+    let component: TableResultComponent;
+    let fixture: ComponentFixture<TableResultComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                TableResultComponent,
+            ],
+            imports: [
+                BrowserAnimationsModule
+            ],
+        });
+        fixture = TestBed.createComponent(TableResultComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+});
+
diff --git a/client/src/app/admin/instance/dataset/components/attribute/result/tr-result.component.spec.ts b/client/src/app/admin/instance/dataset/components/attribute/result/tr-result.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0cacf9ce75f21c58ed62a67782071da615e2b628
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/attribute/result/tr-result.component.spec.ts
@@ -0,0 +1,72 @@
+/**
+ * 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 { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { Attribute } from 'src/app/metamodel/models';
+import { RendererFormFactory } from './renderers';
+import { TrResultComponent } from './tr-result.component';
+
+
+describe('[admin][instance][dataset][components][attribute][result] TrResultComponent', () => {
+    let component: TrResultComponent;
+    let fixture: ComponentFixture<TrResultComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                TrResultComponent,
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(TrResultComponent);
+        component = fixture.componentInstance;
+        let attribute: Attribute;
+        component.attribute = { ...attribute, name: 'test', renderer: '', order_by: false, archive: true };
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+    it('getRendererConfigForm() should form.controls["renderer_config"] as an instance of UntypedFormGroup', () => {
+        let result = component.getRendererConfigForm();
+        expect(result).toBeInstanceOf(UntypedFormGroup);
+
+    })
+    it(' rendererOnChange() should set form.controls.renderer to nul and call setcontrol on the form ', () => {
+        let spy = jest.spyOn(component.form, 'setControl');
+        expect(component.form.controls.renderer.value).toEqual('');
+        component.rendererOnChange();
+        expect(component.form.controls.renderer.value).toEqual(null);
+        expect(spy).toHaveBeenCalledTimes(1);
+
+
+    });
+    it('rendererOnChange() should call RenderFormFactory.create', () => {
+        component.form.controls.renderer.setValue('test');
+        let spy = jest.spyOn(RendererFormFactory, 'create');
+        component.rendererOnChange()
+        expect(spy).toHaveBeenCalledTimes(1);
+
+    });
+    it('submit() should emit with attribute and form.value', () => {
+        let spy = jest.spyOn(component.save, 'emit');
+        component.submit();
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith({ ...component.attribute, ...component.form.value });
+    })
+
+
+});
+
diff --git a/client/src/app/admin/instance/dataset/components/attribute/shared-renderers/download-renderer.component.spec.ts b/client/src/app/admin/instance/dataset/components/attribute/shared-renderers/download-renderer.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b2a1feb971a067c2426bf185f591433f1b04c18a
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/attribute/shared-renderers/download-renderer.component.spec.ts
@@ -0,0 +1,45 @@
+/**
+ * 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 { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { DownloadRendererComponent } from './download-renderer.component';
+
+describe('[admin][instance][dataset][components][attribute][result][renderers] DownloadRendererComponent', () => {
+    let component: DownloadRendererComponent;
+    let fixture: ComponentFixture<DownloadRendererComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                DownloadRendererComponent,
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(DownloadRendererComponent);
+        component = fixture.componentInstance;
+        let form = new UntypedFormGroup({
+            display: new UntypedFormControl(),
+            text: new UntypedFormControl()
+
+        });
+        component.form = form;
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+});
+
+
diff --git a/client/src/app/admin/instance/dataset/components/attribute/shared-renderers/image-renderer.component.spec.ts b/client/src/app/admin/instance/dataset/components/attribute/shared-renderers/image-renderer.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ad7db9609fcde470bbfe00887fe0d601e19fce6d
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/attribute/shared-renderers/image-renderer.component.spec.ts
@@ -0,0 +1,47 @@
+/**
+ * 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 { ComponentFixture, TestBed } from '@angular/core/testing';
+ import { ReactiveFormsModule, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
+ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { ImageRendererComponent } from './image-renderer.component';
+
+ describe('[admin][instance][dataset][components][attribute][result][renderers] ImageRendererComponent', () => {
+     let component: ImageRendererComponent;
+     let fixture: ComponentFixture<ImageRendererComponent>;
+ 
+     beforeEach(() => {
+         TestBed.configureTestingModule({
+             declarations: [
+                ImageRendererComponent,
+             ],
+             imports: [
+                 BrowserAnimationsModule,
+                 ReactiveFormsModule
+             ],
+         });
+         fixture = TestBed.createComponent(ImageRendererComponent);
+         component = fixture.componentInstance;
+         let form = new UntypedFormGroup({
+            type: new UntypedFormControl(),
+             display: new UntypedFormControl(),
+           
+ 
+         });
+         component.form = form;
+         fixture.detectChanges();
+     });
+ 
+     it('should create the component', () => {
+         expect(component).toBeTruthy();
+     });
+ });
+ 
+ 
+ 
\ No newline at end of file
diff --git a/client/src/app/admin/instance/dataset/components/attribute/shared-renderers/link-renderer.component.spec.ts b/client/src/app/admin/instance/dataset/components/attribute/shared-renderers/link-renderer.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..040c59119984e2a275fdb48351592d9ec0e69523
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/attribute/shared-renderers/link-renderer.component.spec.ts
@@ -0,0 +1,48 @@
+/**
+ * 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 { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { text } from 'd3';
+import { LinkRendererComponent } from './link-renderer.component';
+
+describe('[admin][instance][dataset][components][attribute][result][renderers] LinkRendererComponent', () => {
+    let component: LinkRendererComponent;
+    let fixture: ComponentFixture<LinkRendererComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                LinkRendererComponent,
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(LinkRendererComponent);
+        component = fixture.componentInstance;
+        let form = new UntypedFormGroup({
+            href: new UntypedFormControl(),
+            display: new UntypedFormControl(),
+            blank: new UntypedFormControl(),
+            text: new UntypedFormControl()
+
+        });
+        component.form = form;
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+});
+
+
diff --git a/client/src/app/admin/instance/dataset/components/attribute/vo/index.spec.ts b/client/src/app/admin/instance/dataset/components/attribute/vo/index.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..cabfd99a6d55a15798b0902d1cf56bea70580951
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/attribute/vo/index.spec.ts
@@ -0,0 +1,18 @@
+/**
+ * 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 { voComponents } from './index';
+
+describe('[admin][instance][dataset][components][attribute][vo] index', () => {
+    it('Test output index components', () => {
+        expect(voComponents.length).toEqual(2);
+    });
+});
+
+
diff --git a/client/src/app/admin/instance/dataset/components/attribute/vo/table-vo.component.spec.ts b/client/src/app/admin/instance/dataset/components/attribute/vo/table-vo.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8c7ca8e24593fce89a803b16606a3fe01388f652
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/attribute/vo/table-vo.component.spec.ts
@@ -0,0 +1,36 @@
+/**
+ * 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 { ComponentFixture, TestBed } from '@angular/core/testing';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { TableVoComponent } from './table-vo.component';
+
+describe('[admin][instance][dataset][components][attribute][vo] TableVoComponent', () => {
+    let component: TableVoComponent;
+    let fixture: ComponentFixture<TableVoComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                TableVoComponent,
+            ],
+            imports: [
+                BrowserAnimationsModule,
+            ],
+        });
+        fixture = TestBed.createComponent(TableVoComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+});
+
diff --git a/client/src/app/admin/instance/dataset/components/attribute/vo/tr-vo.component.spec.ts b/client/src/app/admin/instance/dataset/components/attribute/vo/tr-vo.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..bb73f57154f101ffcb6279e348c325f4fe25ea43
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/attribute/vo/tr-vo.component.spec.ts
@@ -0,0 +1,47 @@
+/**
+ * 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 { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { Attribute } from 'src/app/metamodel/models';
+import { TrVoComponent } from './tr-vo.component';
+
+describe('[admin][instance][dataset][components][attribute][vo] TrVoComponent', () => {
+    let component: TrVoComponent;
+    let fixture: ComponentFixture<TrVoComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                TrVoComponent,
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(TrVoComponent);
+        component = fixture.componentInstance;
+        let attribute: Attribute;
+        component.attribute = { ...attribute, name: 'test', vo_utype: '', vo_ucd: '', vo_unit: '', vo_description: '', vo_datatype: '', vo_size: 1 };
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+    it('submit() should emit with attribute and form.value', () => {
+        let spy = jest.spyOn(component.save, 'emit');
+        component.submit();
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith({ ...component.attribute, ...component.form.value });
+    })
+});
+
diff --git a/client/src/app/admin/instance/dataset/components/cone-search-config/cone-search-config-form.component.spec.ts b/client/src/app/admin/instance/dataset/components/cone-search-config/cone-search-config-form.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..273f2044ecd1223b72f28d9f4ff28318aa1eff93
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/cone-search-config/cone-search-config-form.component.spec.ts
@@ -0,0 +1,60 @@
+/**
+ * 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 { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { ConeSearchConfigFormComponent } from './cone-search-config-form.component';
+
+describe('[admin][instance][dataset][components][cone-search-config] ConeSearchConfigFormComponent', () => {
+    let component: ConeSearchConfigFormComponent;
+    let fixture: ComponentFixture<ConeSearchConfigFormComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                ConeSearchConfigFormComponent
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(ConeSearchConfigFormComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+
+    it('enable() should set (opened, column_ra, colomn_dec, plot_enabled) disabled property to false', () => {
+        component.form.controls.enabled.setValue(true);
+        expect(component.form.controls.opened.disabled).toEqual(true)
+        expect(component.form.controls.column_ra.disabled).toEqual(true)
+        expect(component.form.controls.plot_enabled.disabled).toEqual(true)
+        expect(component.form.controls.column_dec.disabled).toEqual(true);
+        component.checkConeSearchDisableOpened();
+        expect(component.form.controls.opened.disabled).toEqual(false)
+        expect(component.form.controls.column_ra.disabled).toEqual(false)
+        expect(component.form.controls.plot_enabled.disabled).toEqual(false)
+        expect(component.form.controls.column_dec.disabled).toEqual(false);
+    });
+
+    it('should emit form.getRawValue and call makAsPristine', () => {
+        let spyOnSubmit = jest.spyOn(component.onSubmit, 'emit');
+        let spyForm = jest.spyOn(component.form, 'markAsPristine');
+        component.submit();
+        expect(spyOnSubmit).toHaveBeenCalledTimes(1);
+        expect(spyOnSubmit).toHaveBeenCalledWith({ ...component.form.getRawValue() })
+        expect(spyForm).toHaveBeenCalledTimes(1);
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/cone-search-config/cone-search-config.component.spec.ts b/client/src/app/admin/instance/dataset/components/cone-search-config/cone-search-config.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d748ad2691da1dc329001ebf9215c5f7386d8562
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/cone-search-config/cone-search-config.component.spec.ts
@@ -0,0 +1,92 @@
+/**
+ * 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 { Component } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { UntypedFormGroup } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { ConeSearchConfig } from 'src/app/metamodel/models';
+import { ConeSearchConfigComponent } from './cone-search-config.component';
+
+@Component({
+    selector: 'app-cone-search-config-form',
+
+})
+class ConeSearchConfigFormComponent {
+    form = new UntypedFormGroup({});
+    attributeList = []
+    coneSearchConfig: ConeSearchConfig;
+}
+
+describe('[admin][instance][dataset][components][cone-search-config] ConeSearchConfigComponent', () => {
+    let component: ConeSearchConfigComponent;
+    let fixture: ComponentFixture<ConeSearchConfigComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                ConeSearchConfigComponent,
+                ConeSearchConfigFormComponent
+            ],
+            imports: [
+                BrowserAnimationsModule,
+            ],
+        });
+        fixture = TestBed.createComponent(ConeSearchConfigComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+
+    it('save(coneSearchConfig: ConeSearchConfig) should emit the current coneSearchConfig, coneSearchConfig in args', () => {
+        let spy = jest.spyOn(component.editConeSearchConfig, 'emit');
+        let coneSearchConfig: ConeSearchConfig = {
+            id: 1,
+            enabled: false,
+            opened: false,
+            column_ra: 5,
+            column_dec: 10,
+            resolver_enabled: false,
+            default_ra: null,
+            default_dec: null,
+            default_radius: null,
+            default_ra_dec_unit: 'degrees',
+            plot_enabled: false
+        };
+        component.coneSearchConfig = coneSearchConfig;
+        let param: ConeSearchConfig = { ...coneSearchConfig, id: 2 }
+        component.save(param);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith({ ...component.coneSearchConfig, ...param })
+    });
+
+    it('save(coneSearchConfig: ConeSearchConfig) should emit the coneSearchConfig passed in args', () => {
+        let spy = jest.spyOn(component.addConeSearchConfig, 'emit');
+        let coneSearchConfig: ConeSearchConfig = {
+            id: 1,
+            enabled: false,
+            opened: false,
+            column_ra: 5,
+            column_dec: 10,
+            resolver_enabled: false,
+            default_ra: null,
+            default_dec: null,
+            default_radius: null,
+            default_ra_dec_unit: 'degrees',
+            plot_enabled: false
+        };
+        component.save(coneSearchConfig);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(coneSearchConfig);
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/cone-search-config/index.spec.ts b/client/src/app/admin/instance/dataset/components/cone-search-config/index.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..fdf3de1c08fa4fe921f21a018fe22e8b84c3055b
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/cone-search-config/index.spec.ts
@@ -0,0 +1,16 @@
+/**
+ * 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 { coneSearchConfigComponents } from './index';
+
+describe('[admin][instance][dataset][components][cone-search-config] index', () => {
+    it('Test output index components', () => {
+        expect(coneSearchConfigComponents.length).toEqual(2);
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/criteria-family/add-criteria-family.component.spec.ts b/client/src/app/admin/instance/dataset/components/criteria-family/add-criteria-family.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..42408071cc2f2bd6606a125809510eeeef4a3e30
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/criteria-family/add-criteria-family.component.spec.ts
@@ -0,0 +1,57 @@
+/**
+ * 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 { TemplateRef } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
+
+import { AddCriteriaFamilyComponent } from './add-criteria-family.component';
+
+describe('[admin][instance][dataset][components][criteria-family] AddCriteriaFamilyComponent', () => {
+    let component: AddCriteriaFamilyComponent;
+    let fixture: ComponentFixture<AddCriteriaFamilyComponent>;
+
+    const modalServiceStub = {
+        show: jest.fn(),
+    };
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                AddCriteriaFamilyComponent,
+            ],
+            providers: [
+                BsModalRef,
+                { provide: BsModalService, useValue: modalServiceStub }
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(AddCriteriaFamilyComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+
+    it('should call modalRef.show(template)', () => {
+        let template: TemplateRef<any> = null;
+        let spy = jest.spyOn(modalServiceStub, 'show');
+        component.openModal(template);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(template);
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/criteria-family/criteria-family-form.component.spec.ts b/client/src/app/admin/instance/dataset/components/criteria-family/criteria-family-form.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e56bbcd23b97749b8c46eeb34dfd53bf130ec2cd
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/criteria-family/criteria-family-form.component.spec.ts
@@ -0,0 +1,54 @@
+/**
+ * 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 { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { CriteriaFamilyFormComponent } from './criteria-family-form.component';
+
+describe('[admin][instance][dataset][components][criteria-family] CriteriaFamilyFormComponent', () => {
+    let component: CriteriaFamilyFormComponent;
+    let fixture: ComponentFixture<CriteriaFamilyFormComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                CriteriaFamilyFormComponent,
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(CriteriaFamilyFormComponent);
+        component = fixture.componentInstance;
+        component.criteriaFamily = { display: 10, id: 1, label: 'test', opened: false };
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+
+    it(' submit() should emit criterFamily and form.value', () => {
+        let spy = jest.spyOn(component.onSubmit, 'emit');
+        component.submit();
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith({ ...component.criteriaFamily, ...component.form.value });
+    });
+    
+    it(' submit() should emit form.value', () => {
+        component.criteriaFamily = null;
+        let spy = jest.spyOn(component.onSubmit, 'emit');
+        component.submit();
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(component.form.value);
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/criteria-family/criteria-family-list.component.spec.ts b/client/src/app/admin/instance/dataset/components/criteria-family/criteria-family-list.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d2ab950126168aacb0bad55d81460d1d58c4ea5b
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/criteria-family/criteria-family-list.component.spec.ts
@@ -0,0 +1,44 @@
+/**
+ * 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 { Component } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { CriteriaFamilyListComponent } from './criteria-family-list.component';
+
+@Component({
+    selector: 'app-add-criteria-family',
+    templateUrl: 'add-criteria-family.component.html',
+})
+class AddCriteriaFamilyComponent { }
+
+describe('[admin][instance][dataset][components][criteria-family] CriteriaFamilyListComponent', () => {
+    let component: CriteriaFamilyListComponent;
+    let fixture: ComponentFixture<CriteriaFamilyListComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                CriteriaFamilyListComponent,
+                AddCriteriaFamilyComponent
+            ],
+            imports: [
+                BrowserAnimationsModule,
+            ],
+        });
+        fixture = TestBed.createComponent(CriteriaFamilyListComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/criteria-family/edit-criteria-family.component.spec.ts b/client/src/app/admin/instance/dataset/components/criteria-family/edit-criteria-family.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..cc1bf9a9ce4bb67f8a647cc9ff8b7c340617140a
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/criteria-family/edit-criteria-family.component.spec.ts
@@ -0,0 +1,57 @@
+/**
+ * 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 { TemplateRef } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
+
+import { EditCriteriaFamilyComponent } from './edit-criteria-family.component';
+
+describe('[admin][instance][dataset][components][criteria-family] EditCriteriaFamilyComponent', () => {
+    let component: EditCriteriaFamilyComponent;
+    let fixture: ComponentFixture<EditCriteriaFamilyComponent>;
+
+    const modalServiceStub = {
+        show: jest.fn(),
+    };
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                EditCriteriaFamilyComponent,
+            ],
+            providers: [
+                BsModalRef,
+                { provide: BsModalService, useValue: modalServiceStub }
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(EditCriteriaFamilyComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+
+    it('should call modalRef.show(template)', () => {
+        let template: TemplateRef<any> = null;
+        let spy = jest.spyOn(modalServiceStub, 'show');
+        component.openModal(template);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(template);
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/criteria-family/index.spec.ts b/client/src/app/admin/instance/dataset/components/criteria-family/index.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a1d2465eaee1c0431a2e564f6cc20a5ad5bb945c
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/criteria-family/index.spec.ts
@@ -0,0 +1,16 @@
+/**
+ * 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 { criteriaFamilyComponents } from './index';
+
+describe('[admin][instance][dataset][components][criteria-family] index', () => {
+    it('should test criteria-family index components', () => {
+        expect(criteriaFamilyComponents.length).toEqual(4);
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/dataset-family/dataset-family-card.component.spec.ts b/client/src/app/admin/instance/dataset/components/dataset-family/dataset-family-card.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..50a4bffa9cd1c4149840bbcbfc05e6b455ca83dc
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/dataset-family/dataset-family-card.component.spec.ts
@@ -0,0 +1,67 @@
+/**
+ * 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 { Component, Pipe, PipeTransform } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { Dataset } from 'src/app/metamodel/models';
+import { DatasetFamilyCardComponent } from './dataset-family-card.component';
+
+@Pipe({ name: 'datasetListByFamily' })
+class DatasetListByFamilyPipe implements PipeTransform {
+    transform(datasetList: Dataset[], idDatasetFamily: number): Dataset[] {
+        return datasetList.filter(dataset => dataset.id_dataset_family === idDatasetFamily);
+    }
+}
+
+@Component({
+    selector: 'app-edit-dataset-family',
+})
+export class EditDatasetFamilyComponent { }
+
+@Component({
+    selector: 'app-delete-btn',
+})
+export class DeleteBtnComponent { }
+
+describe('[admin][instance][dataset][components][dataset-family] DatasetFamilyCardComponent', () => {
+    let component: DatasetFamilyCardComponent;
+    let fixture: ComponentFixture<DatasetFamilyCardComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                DatasetFamilyCardComponent,
+                DatasetListByFamilyPipe,
+                EditDatasetFamilyComponent,
+                DeleteBtnComponent
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(DatasetFamilyCardComponent);
+        component = fixture.componentInstance;
+        let dataset: Dataset;
+        component.datasetList = [{ ...dataset, id_dataset_family: 1, label: 'test' }, { ...dataset, id_dataset_family: 2, label: 'test' }]
+        component.datasetFamily = { display: 10, id: 2, label: 'test', opened: false };
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+
+    it('nbDatasetsByDatasetFamily() should return 1', () => {
+
+        let result = component.nbDatasetsByDatasetFamily();
+        expect(result).toEqual(1);
+    })
+});
diff --git a/client/src/app/admin/instance/dataset/components/dataset-family/dataset-family-form.component.spec.ts b/client/src/app/admin/instance/dataset/components/dataset-family/dataset-family-form.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8cbcc47cf5addb30d3eab9cbbea10fa61bffff08
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/dataset-family/dataset-family-form.component.spec.ts
@@ -0,0 +1,53 @@
+/**
+ * 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 { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { DatasetFamilyFormComponent } from './dataset-family-form.component';
+
+describe('[admin][instance][dataset][components][dataset-family] DatasetFamilyFormComponent', () => {
+    let component: DatasetFamilyFormComponent;
+    let fixture: ComponentFixture<DatasetFamilyFormComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                DatasetFamilyFormComponent,
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(DatasetFamilyFormComponent);
+        component = fixture.componentInstance;
+        component.datasetFamily = { display: 10, id: 1, label: 'test', opened: false };
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+
+    it('submit() should emit databaseFamily and form.value', () => {
+        let spy = jest.spyOn(component.onSubmit, 'emit');
+        component.submit();
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith({ ...component.datasetFamily, ...component.form.value });
+    });
+
+    it('submit() should emitform.value only', () => {
+        let spy = jest.spyOn(component.onSubmit, 'emit');
+        component.datasetFamily = null;
+        component.submit();
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith({ ...component.form.value });
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/dataset-family/edit-dataset-family.component.spec.ts b/client/src/app/admin/instance/dataset/components/dataset-family/edit-dataset-family.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..798735c44013e3fc4cc38c14ec685599a1570aa2
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/dataset-family/edit-dataset-family.component.spec.ts
@@ -0,0 +1,57 @@
+/**
+ * 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 { TemplateRef } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
+
+import { EditDatasetFamilyComponent } from './edit-dataset-family.component';
+
+describe('[admin][instance][dataset][components][dataset-family] EditDatasetFamilyComponent', () => {
+    let component: EditDatasetFamilyComponent;
+    let fixture: ComponentFixture<EditDatasetFamilyComponent>;
+
+    const modalServiceStub = {
+        show: jest.fn(),
+    };
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                EditDatasetFamilyComponent,
+            ],
+            providers: [
+                BsModalRef,
+                { provide: BsModalService, useValue: modalServiceStub }
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(EditDatasetFamilyComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+
+    it('should call modalRef.show(template)', () => {
+        let template: TemplateRef<any> = null;
+        let spy = jest.spyOn(modalServiceStub, 'show');
+        component.openModal(template);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(template);
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/dataset-family/index.spec.ts b/client/src/app/admin/instance/dataset/components/dataset-family/index.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..cf7c46ef3a21ca86b1d1c7a0e92706621f76efe5
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/dataset-family/index.spec.ts
@@ -0,0 +1,16 @@
+/**
+ * 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 { datasetFamilyComponents } from './index';
+
+describe('[admin][instance][dataset][components][dataset-family] index', () => {
+    it('should test dataset index components', () => {
+        expect(datasetFamilyComponents.length).toEqual(3);
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/dataset/dataset-card.component.spec.ts b/client/src/app/admin/instance/dataset/components/dataset/dataset-card.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2ff2721285b0fcc9adefa2fc2b960a574de1fc1f
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/dataset/dataset-card.component.spec.ts
@@ -0,0 +1,52 @@
+/**
+ * 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 { Component } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { RouterTestingModule } from '@angular/router/testing';
+
+import { Dataset, Instance } from 'src/app/metamodel/models';
+import { DatasetCardComponent } from './dataset-card.component';
+
+@Component({
+    selector: 'app-delete-btn',
+})
+export class DeleteBtnComponent { }
+
+describe('[admin][instance][dataset][components][dataset] DatasetCardComponent', () => {
+    let component: DatasetCardComponent;
+    let fixture: ComponentFixture<DatasetCardComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                DatasetCardComponent,
+                DeleteBtnComponent
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                RouterTestingModule.withRoutes([
+                    { path: 'test', component: DeleteBtnComponent }
+                   ])
+            ],
+        });
+        fixture = TestBed.createComponent(DatasetCardComponent);
+        component = fixture.componentInstance;
+        let dataset: Dataset;
+        let instance: Instance;
+        component.dataset = { ...dataset, label: 'test' };
+        component.instance = { ...instance, name: 'test' }
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/dataset/dataset-form.component.spec.ts b/client/src/app/admin/instance/dataset/components/dataset/dataset-form.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8ea32850c4d2788a495f80b9d759569af1612a93
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/dataset/dataset-form.component.spec.ts
@@ -0,0 +1,127 @@
+/**
+ * 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 { SimpleChange } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { AccordionModule } from 'ngx-bootstrap/accordion';
+
+import { DatasetFormComponent } from './dataset-form.component';
+import { Dataset, Instance } from 'src/app/metamodel/models';
+
+describe('[admin][instance][dataset][components][dataset] DatasetFormComponent', () => {
+    let component: DatasetFormComponent;
+    let fixture: ComponentFixture<DatasetFormComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                DatasetFormComponent,
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule,
+                AccordionModule
+            ],
+        });
+        fixture = TestBed.createComponent(DatasetFormComponent);
+        component = fixture.componentInstance;
+        let dataset: Dataset;
+        let instance: Instance;
+        component.instance = { ...instance, data_path: 'test' };
+        component.dataset = { ...dataset, label: 'test' };
+        component.idDatasetFamily = 1;
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+
+    it('submit() should emit dataset and form.getRawValue()', () => {
+        let spy = jest.spyOn(component.onSubmit, 'emit');
+        component.submit();
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith({ ...component.dataset, ...component.form.getRawValue() });
+    });
+
+    it('submit() should emit form.getRawValue() only', () => {
+        let spy = jest.spyOn(component.onSubmit, 'emit');
+        component.dataset = null;
+        component.submit();
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith({ ...component.form.getRawValue() });
+    });
+
+    it('onChangeDatabase() should call disable on form table_ref raw', () => {
+        let spy = jest.spyOn(component.form.controls.table_ref, 'disable');
+        component.onChangeDatabase();
+        expect(spy).toHaveBeenCalledTimes(1);
+    });
+
+    it('onChangeDatabase() should emit idDatabase', () => {
+        let spy = jest.spyOn(component.changeDatabase, 'emit');
+        component.form.controls.id_database.setValue(1);
+        component.onChangeDatabase();
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(1);
+    });
+
+    it('onChangeDataPath(path: string) should emit the instance data_path property', () => {
+        let spy = jest.spyOn(component.loadRootDirectory, 'emit');
+        let path: string = 'test';
+        component.onChangeDataPath(path);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(`${component.instance.data_path}${path}`);
+    });
+
+    it('checkDatatableDisablOpened() should call enable on  form datatable_selectable_rows', () => {
+        let spy = jest.spyOn(component.form.controls.datatable_selectable_rows, 'enable');
+        component.checkDatatableDisablOpened();
+        expect(spy).toHaveBeenCalledTimes(1);
+    });
+
+    it('checkDatatableDisablOpened() should call desable on  form datatable_selectable_rows and set it value to false', () => {
+        let spy = jest.spyOn(component.form.controls.datatable_selectable_rows, 'disable');
+        component.form.controls.datatable_enabled.setValue(false);
+        component.checkDatatableDisablOpened();
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(component.form.controls.datatable_selectable_rows.value).toEqual(false);
+    });
+
+    it('should call ngOnChanges and enable on table_ref ', () => {
+        let spy = jest.spyOn(component, 'ngOnChanges');
+        let spyOnTable_ref = jest.spyOn(component.form.controls.table_ref, 'enable');
+        let tableListIsLoaded: boolean = true;
+        component.ngOnChanges(
+            {
+                tableListIsLoaded: new SimpleChange(undefined, tableListIsLoaded, false),
+            }
+        )
+        fixture.detectChanges();
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spyOnTable_ref).toHaveBeenCalledTimes(1);
+    });
+
+    it('should call ngOnChanges and desable on table_ref ', () => {
+        let spy = jest.spyOn(component, 'ngOnChanges');
+        let spyOnTable_ref = jest.spyOn(component.form.controls.table_ref, 'disable');
+        let tableListIsLoaded: boolean = false;
+        component.ngOnChanges(
+            {
+                tableListIsLoaded: new SimpleChange(undefined, tableListIsLoaded, false),
+            }
+        )
+        fixture.detectChanges();
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spyOnTable_ref).toHaveBeenCalledTimes(1);
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/dataset/index.spec.ts b/client/src/app/admin/instance/dataset/components/dataset/index.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c717703513e2f1a12313f584f2a57f987b13ec98
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/dataset/index.spec.ts
@@ -0,0 +1,16 @@
+/**
+ * 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 { datasetComponents } from './index';
+
+describe('[admin][instance][dataset][components][dataset] index', () => {
+    it('should test dataset index components', () => {
+        expect(datasetComponents.length).toEqual(2);
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/detail-page/detail-config-form.component.spec.ts b/client/src/app/admin/instance/dataset/components/detail-page/detail-config-form.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d0765d1267392e8180a01396d13893ff7f30a31b
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/detail-page/detail-config-form.component.spec.ts
@@ -0,0 +1,56 @@
+/**
+ * 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 { Component } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { DetailConfigFormComponent } from './detail-config-form.component';
+
+@Component({
+    selector: 'app-webpage-form-content'
+})
+class WebpageFormContentComponent {
+    form: UntypedFormGroup;
+}
+
+describe('[admin][instance][dataset][components][detail-page] DetailConfigFormComponent', () => {
+    let component: DetailConfigFormComponent;
+    let fixture: ComponentFixture<DetailConfigFormComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                DetailConfigFormComponent,
+                WebpageFormContentComponent
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(DetailConfigFormComponent);
+        component = fixture.componentInstance;
+        component.detailConfig = { content: '', id: 1, style_sheet: 'test' };
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+
+    it('submit() should emit databaseFamily and form.value', () => {
+        let spy = jest.spyOn(component.onSubmit, 'emit');
+        let spyOnForm = jest.spyOn(component.form, 'markAsPristine');
+        component.submit();
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spyOnForm).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith({ ...component.form.getRawValue() });
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/detail-page/detail-config.component.spec.ts b/client/src/app/admin/instance/dataset/components/detail-page/detail-config.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..88012451dddbd3b58a28b3ec7c10fcb4b9bf5346
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/detail-page/detail-config.component.spec.ts
@@ -0,0 +1,69 @@
+/**
+ * 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 { Component } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
+
+import { DetailConfig } from 'src/app/metamodel/models';
+import { DetailConfigComponent } from './detail-config.component';
+
+@Component({
+    selector: 'app-detail-config-form',
+    templateUrl: 'detail-config-form.component.html',
+})
+class DetailConfigFormComponent  {
+    form = new UntypedFormGroup({
+        content: new UntypedFormControl(),
+        style_sheet: new UntypedFormControl(null)
+    });
+}
+
+describe('[admin][instance][dataset][components][detail-page] DetailConfigComponent', () => {
+    let component: DetailConfigComponent;
+    let fixture: ComponentFixture<DetailConfigComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                DetailConfigComponent,
+                DetailConfigFormComponent
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(DetailConfigComponent);
+        component = fixture.componentInstance;
+        component.detailConfig = { content: '', id: 1, style_sheet: 'test' };
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+
+    it('save(detailConfig) should emit component.detailConfig and detaiConfig', () => {
+        let spy = jest.spyOn(component.editDetailConfig, 'emit');
+        let detailConfig: DetailConfig = { content: '', id: 1, style_sheet: 'test2' };
+        component.save(detailConfig);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith({ ...component.detailConfig, ...detailConfig });
+    });
+
+    it('save(detailConfig) should emit  detaiConfig only', () => {
+        let spy = jest.spyOn(component.addDetailConfig, 'emit');
+        let detailConfig: DetailConfig = { content: '', id: 1, style_sheet: 'test2' };
+        component.detailConfig = null;
+        component.save(detailConfig);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith({ ...detailConfig });
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/detail-page/index.spec.ts b/client/src/app/admin/instance/dataset/components/detail-page/index.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..088cd7dc49043c802ce36b755b6508542b6c595e
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/detail-page/index.spec.ts
@@ -0,0 +1,16 @@
+/**
+ * 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 { detailConfigComponents } from './index';
+
+describe('[admin][instance][dataset][components]detail-page] index', () => {
+    it('should test detail-page index components', () => {
+        expect(detailConfigComponents.length).toEqual(2);
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/file/add-file.component.spec.ts b/client/src/app/admin/instance/dataset/components/file/add-file.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..243194034a7c0331deddad10c7662b8f803ae2c3
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/file/add-file.component.spec.ts
@@ -0,0 +1,57 @@
+/**
+ * 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 { TemplateRef } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
+
+import { AddFileComponent } from './add-file.component';
+
+describe('[admin][instance][dataset][components][file] AddFileComponent', () => {
+    let component: AddFileComponent;
+    let fixture: ComponentFixture<AddFileComponent>;
+
+    const modalServiceStub = {
+        show: jest.fn(),
+    };
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                AddFileComponent,
+            ],
+            providers: [
+                BsModalRef,
+                { provide: BsModalService, useValue: modalServiceStub }
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(AddFileComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+
+    it('should call modalRef.show(template)', () => {
+        let template: TemplateRef<any> = null;
+        let spy = jest.spyOn(modalServiceStub, 'show');
+        component.openModal(template);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(template);
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/file/edit-file.component.spec.ts b/client/src/app/admin/instance/dataset/components/file/edit-file.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..91297c7acaf0b787a5241404090ae5480e492dfe
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/file/edit-file.component.spec.ts
@@ -0,0 +1,57 @@
+/**
+ * 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 { TemplateRef } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
+
+import { EditFileComponent } from './edit-file.component';
+
+describe('[admin][instance][dataset][components][file] EditFileComponent', () => {
+    let component: EditFileComponent;
+    let fixture: ComponentFixture<EditFileComponent>;
+
+    const modalServiceStub = {
+        show: jest.fn(),
+    };
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                EditFileComponent,
+            ],
+            providers: [
+                BsModalRef,
+                { provide: BsModalService, useValue: modalServiceStub }
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(EditFileComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+
+    it('should call modalRef.show(template)', () => {
+        let template: TemplateRef<any> = null;
+        let spy = jest.spyOn(modalServiceStub, 'show');
+        component.openModal(template);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(template);
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/file/file-form.component.spec.ts b/client/src/app/admin/instance/dataset/components/file/file-form.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6abfe14e63003091fd2bbe1b78e44e4cf7c68608
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/file/file-form.component.spec.ts
@@ -0,0 +1,76 @@
+/**
+ * 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 { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { FileInfo } from 'src/app/admin/store/models';
+import { Dataset, Instance } from 'src/app/metamodel/models';
+import { FileFormComponent } from './file-form.component';
+
+describe('[admin][instance][dataset][components][file] FileFormComponent', () => {
+    let component: FileFormComponent;
+    let fixture: ComponentFixture<FileFormComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                FileFormComponent,
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(FileFormComponent);
+        component = fixture.componentInstance;
+        component.file = { id: 1, file_path: 'test', file_size: 1000, label: 'test', type: 'test' };
+        let instance: Instance;
+        let dataset: Dataset;
+        component.instance = { ...instance, data_path: 'test3' };
+        component.dataset = { ...dataset, data_path: 'test_dataset' }
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+
+    it('onChangeFileSelect(path: string) should emit instance.data_path, dataset.data_path and path', () => {
+        let spy = jest.spyOn(component.loadRootDirectory, 'emit');
+        let path: string = 'test1';
+        component.onChangeFileSelect(path);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(component.instance.data_path + component.dataset.data_path + path);
+    });
+
+    it(' onFileSelect(fileInfo: FileInfo) should set form.file_size to 2000', () => {
+
+        expect(component.form.controls.file_size.value).toEqual(1000);
+        let fileInfo: FileInfo = {mimetype: 'test',name: 'test',size : 2000, type: 'test'};
+        component.onFileSelect(fileInfo)
+        expect(component.form.controls.file_size.value).toEqual(2000);
+    });
+
+    it('submit() should emit file and form.getRawValue()', () => {
+        let spy = jest.spyOn(component.onSubmit, 'emit');
+        component.submit();
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith({...component.file, ...component.form.getRawValue()});
+    });
+
+    it('submit() should emit only form.getRawValue()', () => {
+        let spy = jest.spyOn(component.onSubmit, 'emit');
+        component.file = null;
+        component.submit();
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith({...component.form.getRawValue()});
+    })
+});
diff --git a/client/src/app/admin/instance/dataset/components/file/file-list.component.spec.ts b/client/src/app/admin/instance/dataset/components/file/file-list.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d8dff12c8e41a28590a8a93a2d0f6d022f1d912f
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/file/file-list.component.spec.ts
@@ -0,0 +1,36 @@
+/**
+ * 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 { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { FileListComponent } from './file-list.component';
+
+describe('[admin][instance][dataset][components][file] FileListComponent', () => {
+    let component: FileListComponent;
+    let fixture: ComponentFixture<FileListComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                FileListComponent
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(FileListComponent);
+        component = fixture.componentInstance;
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/file/index.spec.ts b/client/src/app/admin/instance/dataset/components/file/index.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b4672ce5604bf647fe4c565468e104a3d3591f3c
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/file/index.spec.ts
@@ -0,0 +1,16 @@
+/**
+ * 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 { fileComponents } from './index';
+
+describe('[admin][instance][dataset][components][file] index', () => {
+    it('should test file index components', () => {
+        expect(fileComponents.length).toEqual(4);
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/image/add-image.component.spec.ts b/client/src/app/admin/instance/dataset/components/image/add-image.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7b076344caed8ba576997e48e2210f873eda8120
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/image/add-image.component.spec.ts
@@ -0,0 +1,57 @@
+/**
+ * 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 { TemplateRef } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
+
+import { AddImageComponent } from './add-image.component';
+
+describe('[admin][instance][dataset][components][image] AddImageComponent', () => {
+    let component: AddImageComponent;
+    let fixture: ComponentFixture<AddImageComponent>;
+
+    const modalServiceStub = {
+        show: jest.fn(),
+    };
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                AddImageComponent,
+            ],
+            providers: [
+                BsModalRef,
+                { provide: BsModalService, useValue: modalServiceStub }
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(AddImageComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+
+    it('should call modalRef.show(template)', () => {
+        let template: TemplateRef<any> = null;
+        let spy = jest.spyOn(modalServiceStub, 'show');
+        component.openModal(template);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(template);
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/image/edit-image.component.spec.ts b/client/src/app/admin/instance/dataset/components/image/edit-image.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1072b411b0930c6649f013f899a140616573b6eb
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/image/edit-image.component.spec.ts
@@ -0,0 +1,57 @@
+/**
+ * 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 { TemplateRef } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
+
+import { EditImageComponent } from './edit-image.component';
+
+describe('[admin][instance][dataset][components][image] EditImageComponent', () => {
+    let component: EditImageComponent;
+    let fixture: ComponentFixture<EditImageComponent>;
+
+    const modalServiceStub = {
+        show: jest.fn(),
+    };
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                EditImageComponent,
+            ],
+            providers: [
+                BsModalRef,
+                { provide: BsModalService, useValue: modalServiceStub }
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(EditImageComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+
+    it('should call modalRef.show(template)', () => {
+        let template: TemplateRef<any> = null;
+        let spy = jest.spyOn(modalServiceStub, 'show');
+        component.openModal(template);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(template);
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/image/image-form.component.spec.ts b/client/src/app/admin/instance/dataset/components/image/image-form.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4443004f1b8e3c92ef471fd9a2ba11ad8a2c98eb
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/image/image-form.component.spec.ts
@@ -0,0 +1,103 @@
+/**
+ * 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 { SimpleChange } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { FileInfo, FitsImageLimits } from 'src/app/admin/store/models';
+import { Dataset, Instance } from 'src/app/metamodel/models';
+import { ImageFormComponent } from './image-form.component';
+
+describe('[admin][instance][dataset][components][image] ImageFormComponent', () => {
+    let component: ImageFormComponent;
+    let fixture: ComponentFixture<ImageFormComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                ImageFormComponent,
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(ImageFormComponent);
+        component = fixture.componentInstance;
+        component.image = {
+            dec_max: 10,
+            dec_min: 1,
+            file_path: 'test_path',
+            file_size: 1000,
+            id: 1,
+            label: 'test',
+            pmax: 1,
+            pmin: 0,
+            ra_max: 3,
+            ra_min: 1,
+            stretch: 'test'
+        };
+        let instance: Instance;
+        let dataset: Dataset;
+        component.instance = { ...instance, data_path: 'test3' };
+        component.dataset = { ...dataset, data_path: 'test_dataset' }
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+
+    it('onChangeFileSelect(path: string) should emit instance.data_path, dataset.data_path and path', () => {
+        let spy = jest.spyOn(component.loadRootDirectory, 'emit');
+        let path: string = 'test1';
+        component.onChangeFileSelect(path);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(component.instance.data_path + component.dataset.data_path + path);
+    });
+
+    it('onFileSelect(fileInfo: FileInfo) should set form.file_size to 2000 and emit file_path value', () => {
+        let spy = jest.spyOn(component.retrieveFitsImageLimits, 'emit');
+        expect(component.form.controls.file_size.value).toEqual(1000);
+        let fileInfo: FileInfo = { mimetype: 'test', name: 'test', size: 2000, type: 'test' };
+        component.onFileSelect(fileInfo)
+        expect(component.form.controls.file_size.value).toEqual(2000);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith('test_path');
+    });
+
+    it('submit() should emit file and form.getRawValue()', () => {
+        let spy = jest.spyOn(component.onSubmit, 'emit');
+        component.submit();
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith({ ...component.image, ...component.form.getRawValue() });
+    });
+
+    it('submit() should emit only form.getRawValue()', () => {
+        let spy = jest.spyOn(component.onSubmit, 'emit');
+        component.image = null;
+        component.submit();
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith({ ...component.form.getRawValue() });
+    });
+
+    it('should call ngOnChanges', () => {
+        let spy = jest.spyOn(component, 'ngOnChanges');
+        let fitsImageLimits: FitsImageLimits = { dec_max: 10, dec_min: 5, ra_max: 2, ra_min: 1 };
+        component.ngOnChanges(
+            {
+                fitsImageLimits: new SimpleChange(undefined, fitsImageLimits, false),
+            }
+        )
+        fixture.detectChanges();
+        expect(spy).toHaveBeenCalledTimes(1);
+    })
+});
diff --git a/client/src/app/admin/instance/dataset/components/image/image-list.component.spec.ts b/client/src/app/admin/instance/dataset/components/image/image-list.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..fd865722cf9c1408c682fd89d672c55dd1230dd8
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/image/image-list.component.spec.ts
@@ -0,0 +1,43 @@
+/**
+ * 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 { Component } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { ImageListComponent } from './image-list.component';
+
+@Component({
+    selector: 'app-add-image',
+})
+export class AddImageComponent { }
+
+describe('[admin][instance][dataset][components][image] ImageListComponent', () => {
+    let component: ImageListComponent;
+    let fixture: ComponentFixture<ImageListComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                ImageListComponent,
+                AddImageComponent
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(ImageListComponent);
+        component = fixture.componentInstance;
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/image/index.spec.ts b/client/src/app/admin/instance/dataset/components/image/index.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..41f5f1dbf4841bd07d9dfd25cccddf0a7a3ea536
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/image/index.spec.ts
@@ -0,0 +1,16 @@
+/**
+ * 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 { imageComponents } from './index';
+
+describe('[admin][instance][dataset][components][image] index', () => {
+    it('should test image index components', () => {
+        expect(imageComponents.length).toEqual(4);
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/instance-buttons.component.spec.ts b/client/src/app/admin/instance/dataset/components/instance-buttons.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0bfaf3071a6f3a94774d01f3fc3b715669e6331a
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/instance-buttons.component.spec.ts
@@ -0,0 +1,59 @@
+/**
+ * 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 { TemplateRef } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
+
+import { Instance } from 'src/app/metamodel/models';
+import { InstanceButtonsComponent } from './instance-buttons.component';
+
+describe('[admin][instance][dataset][components] InstanceButtonsComponent', () => {
+    let component: InstanceButtonsComponent;
+    let fixture: ComponentFixture<InstanceButtonsComponent>;
+    const modalServiceStub = {
+        show: jest.fn(),
+    };
+    let instance: Instance;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                InstanceButtonsComponent,
+            ],
+            providers: [
+                BsModalRef,
+                { provide: BsModalService, useValue: modalServiceStub }
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(InstanceButtonsComponent);
+        component = fixture.componentInstance;
+        component.instance = { ...instance, name: 'test' };
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+
+    it('should call modalRef.show(template)', () => {
+        let template: TemplateRef<any> = null;
+        let spy = jest.spyOn(modalServiceStub, 'show');
+        component.openModal(template);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(template);
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/output-category/add-output-category.component.spec.ts b/client/src/app/admin/instance/dataset/components/output-category/add-output-category.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ecc93b0d16ef741c18bd839c1c61ca04c26fef06
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/output-category/add-output-category.component.spec.ts
@@ -0,0 +1,57 @@
+/**
+ * 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 { TemplateRef } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
+
+import { AddOutputCategoryComponent } from './add-output-category.component';
+
+describe('[admin][instance][dataset][components][output-category] AddOutputCategoryComponent', () => {
+    let component: AddOutputCategoryComponent;
+    let fixture: ComponentFixture<AddOutputCategoryComponent>;
+
+    const modalServiceStub = {
+        show: jest.fn(),
+    };
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                AddOutputCategoryComponent,
+            ],
+            providers: [
+                BsModalRef,
+                { provide: BsModalService, useValue: modalServiceStub }
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(AddOutputCategoryComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+
+    it('should call modalRef.show(template)', () => {
+        let template: TemplateRef<any> = null;
+        let spy = jest.spyOn(modalServiceStub, 'show');
+        component.openModal(template);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(template);
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/output-category/edit-output-category.component.spec.ts b/client/src/app/admin/instance/dataset/components/output-category/edit-output-category.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5e373df8c80e53cc0e9f78caa94a7cb6f790014d
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/output-category/edit-output-category.component.spec.ts
@@ -0,0 +1,57 @@
+/**
+ * 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 { TemplateRef } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
+
+import { EditOutputCategoryComponent } from './edit-output-category.component';
+
+describe('[admin][instance][dataset][components][output-category] EditOutputCategoryComponent', () => {
+    let component: EditOutputCategoryComponent;
+    let fixture: ComponentFixture<EditOutputCategoryComponent>;
+
+    const modalServiceStub = {
+        show: jest.fn(),
+    };
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                EditOutputCategoryComponent,
+            ],
+            providers: [
+                BsModalRef,
+                { provide: BsModalService, useValue: modalServiceStub }
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(EditOutputCategoryComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+
+    it('should call modalRef.show(template)', () => {
+        let template: TemplateRef<any> = null;
+        let spy = jest.spyOn(modalServiceStub, 'show');
+        component.openModal(template);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(template);
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/output-category/index.spec.ts b/client/src/app/admin/instance/dataset/components/output-category/index.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c9aa822e9134a6426f16f23046824adc3b3417b0
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/output-category/index.spec.ts
@@ -0,0 +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 { outputCategoryComponents } from './index';
+
+ describe('[admin][instance][dataset][components][output-category] index', () => {
+     it('should test output-category index components', () => {
+         expect(outputCategoryComponents.length).toEqual(4);
+     });
+ });
+ 
+ 
+ 
+ 
\ No newline at end of file
diff --git a/client/src/app/admin/instance/dataset/components/output-category/output-category-form.component.spec.ts b/client/src/app/admin/instance/dataset/components/output-category/output-category-form.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e7140342cfee8b073e9c4d2d42ce911bf2930c5d
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/output-category/output-category-form.component.spec.ts
@@ -0,0 +1,59 @@
+/**
+ * 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 { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { OutputCategoryFormComponent } from './output-category-form.component';
+
+describe('[admin][instance][dataset][components][output-category] OutputCategoryFormComponent', () => {
+    let component: OutputCategoryFormComponent;
+    let fixture: ComponentFixture<OutputCategoryFormComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                OutputCategoryFormComponent,
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(OutputCategoryFormComponent);
+        component = fixture.componentInstance;
+        component.outputCategory = {
+            display: 10,
+            id: 1,
+            id_output_family: 1,
+            label: 'test'
+        };
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+
+    it('submit() should emit outputCategory and form.value()', () => {
+        let spy = jest.spyOn(component.onSubmit, 'emit');
+        component.submit();
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith({ ...component.outputCategory, ...component.form.value });
+    });
+
+    it('submit() should emit only form.value()', () => {
+        let spy = jest.spyOn(component.onSubmit, 'emit');
+        component.outputCategory = null;
+        component.submit();
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith({ ...component.form.value });
+    })
+});
diff --git a/client/src/app/admin/instance/dataset/components/output-category/output-category-list.component.spec.ts b/client/src/app/admin/instance/dataset/components/output-category/output-category-list.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f5cb89c3a35b2e808e1f4979945c19cf1e904ee4
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/output-category/output-category-list.component.spec.ts
@@ -0,0 +1,36 @@
+/**
+ * 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 { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { OutputCategoryListComponent } from './output-category-list.component';
+
+describe('[admin][instance][dataset][components][output-category] OutputCategoryListComponent', () => {
+    let component: OutputCategoryListComponent;
+    let fixture: ComponentFixture<OutputCategoryListComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                OutputCategoryListComponent,
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(OutputCategoryListComponent);
+        component = fixture.componentInstance;
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/output-family/add-output-family.component.spec.ts b/client/src/app/admin/instance/dataset/components/output-family/add-output-family.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..62a7c4d3d11d5acb7447c08ebf96563d112bf594
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/output-family/add-output-family.component.spec.ts
@@ -0,0 +1,56 @@
+/**
+ * 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 { TemplateRef } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
+
+import { AddOutputFamilyComponent } from './add-output-family.component';
+
+describe('[admin][instance][dataset][components][output-family] AddOutputFamilyComponent', () => {
+    let component: AddOutputFamilyComponent;
+    let fixture: ComponentFixture<AddOutputFamilyComponent>;
+    const modalServiceStub = {
+        show: jest.fn(),
+    };
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                AddOutputFamilyComponent,
+            ],
+            providers: [
+                BsModalRef,
+                { provide: BsModalService, useValue: modalServiceStub }
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(AddOutputFamilyComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+
+    it('should call modalRef.show(template)', () => {
+        let template: TemplateRef<any> = null;
+        let spy = jest.spyOn(modalServiceStub, 'show');
+        component.openModal(template);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(template);
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/components/output-family/edit-output-family.component.spec.ts b/client/src/app/admin/instance/dataset/components/output-family/edit-output-family.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4119d9a2ec5f97b7d53de588cf21a714e9e2be51
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/output-family/edit-output-family.component.spec.ts
@@ -0,0 +1,58 @@
+/**
+ * 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 { TemplateRef } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
+
+import { EditOutputFamilyComponent } from './edit-output-family.component';
+
+describe('[admin][instance][dataset][components][output-family] EditOutputFamilyComponent', () => {
+    let component: EditOutputFamilyComponent;
+    let fixture: ComponentFixture<EditOutputFamilyComponent>;
+    
+    const modalServiceStub = {
+        show: jest.fn(),
+    };
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+            EditOutputFamilyComponent,
+            ],
+            providers: [
+                BsModalRef,
+                { provide: BsModalService, useValue: modalServiceStub }
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(EditOutputFamilyComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+
+    it('should call modalRef.show(template)', () => {
+        let template: TemplateRef<any> = null;
+        let spy = jest.spyOn(modalServiceStub, 'show');
+        component.openModal(template);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(template);
+    });
+});
+ 
\ No newline at end of file
diff --git a/client/src/app/admin/instance/dataset/components/output-family/index.spec.ts b/client/src/app/admin/instance/dataset/components/output-family/index.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ba5cb82eb46c5889f8505b43ac5f9f6c0ecfc2ea
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/output-family/index.spec.ts
@@ -0,0 +1,19 @@
+/**
+ * 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 { outputFamilyComponents } from './index';
+
+describe('[admin][instance][dataset][components][output-family] index', () => {
+    it('should test output-family index components', () => {
+        expect(outputFamilyComponents.length).toEqual(4);
+    });
+});
+
+
+
diff --git a/client/src/app/admin/instance/dataset/components/output-family/output-family-form.component.spec.ts b/client/src/app/admin/instance/dataset/components/output-family/output-family-form.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..427e4a62287b9deac0d44591b5b39b1dd4291487
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/output-family/output-family-form.component.spec.ts
@@ -0,0 +1,59 @@
+/**
+ * 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 { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { OutputFamilyFormComponent } from './output-family-form.component';
+
+describe('[admin][instance][dataset][components][output-family] OutputFamilyFormComponent', () => {
+    let component: OutputFamilyFormComponent;
+    let fixture: ComponentFixture<OutputFamilyFormComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                OutputFamilyFormComponent,
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(OutputFamilyFormComponent);
+        component = fixture.componentInstance;
+        component.outputFamily = {
+            display: 10,
+            id: 1,
+            label: 'test',
+            opened: false
+        };
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+
+    it('submit() should emit outputCategory and form.value()', () => {
+        let spy = jest.spyOn(component.onSubmit, 'emit');
+        component.submit();
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith({ ...component.outputFamily, ...component.form.value });
+    });
+
+    it('submit() should emit only form.value()', () => {
+        let spy = jest.spyOn(component.onSubmit, 'emit');
+        component.outputFamily = null;
+        component.submit();
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith({ ...component.form.value });
+    })
+});
diff --git a/client/src/app/admin/instance/dataset/components/output-family/output-family-list.component.spec.ts b/client/src/app/admin/instance/dataset/components/output-family/output-family-list.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..16a50b009c0b05c285972cfe4bb26ed01de3fe56
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/components/output-family/output-family-list.component.spec.ts
@@ -0,0 +1,44 @@
+/**
+ * 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 { Component } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { OutputFamilyListComponent } from './output-family-list.component';
+
+@Component({
+    selector: 'app-add-output-family',
+
+})
+class AddOutputFamilyComponent { }
+
+describe('[admin][instance][dataset][components][output-family] OutputFamilyListComponent', () => {
+    let component: OutputFamilyListComponent;
+    let fixture: ComponentFixture<OutputFamilyListComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                OutputFamilyListComponent,
+                AddOutputFamilyComponent
+            ],
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule
+            ],
+        });
+        fixture = TestBed.createComponent(OutputFamilyListComponent);
+        component = fixture.componentInstance;
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/configure-dataset-title.resolver.spec.ts b/client/src/app/admin/instance/dataset/configure-dataset-title.resolver.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9acbc58b14cb08462afaa97b29c4702fcc49119d
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/configure-dataset-title.resolver.spec.ts
@@ -0,0 +1,91 @@
+/**
+ * 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 { TestBed } from '@angular/core/testing';
+import { MockStore, provideMockStore } from '@ngrx/store/testing';
+
+import { cold, hot } from 'jasmine-marbles';
+import * as datasetSelector from 'src/app/metamodel/selectors/dataset.selector';
+import * as datasetActions from 'src/app/metamodel/actions/dataset.actions';
+import { ConfigureDatasetTitleResolver } from './configure-dataset-title.resolver';
+import { Dataset, Instance } from 'src/app/metamodel/models';
+import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector';
+import { ActivatedRouteSnapshot } from '@angular/router';
+import { Type } from '@angular/core';
+
+class MockActivatedRouteSnapshot extends ActivatedRouteSnapshot{
+    constructor() {
+        super()
+    }
+    component: any;
+
+}
+describe('[admin][instance][dataset] ConfigureDatasetTitleResolver', () => {
+    let configureDatasetTitleResolver: ConfigureDatasetTitleResolver;
+    let store: MockStore;
+    let mockDatabaseSelectorDatasetListIsLoaded;
+    let mockDatabaseSelectorDatasetByRouteName;
+    let mockInstanceSelectorInstanceByRouteName;
+    let dataset: Dataset;
+    dataset = { ...dataset, label: 'test_dataset_label' };
+    let instance: Instance;
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            imports: [],
+            providers: [
+                ConfigureDatasetTitleResolver,
+                provideMockStore({}),
+            ]
+        })
+
+        store = TestBed.inject(MockStore);
+        configureDatasetTitleResolver = TestBed.inject(ConfigureDatasetTitleResolver);
+        mockDatabaseSelectorDatasetListIsLoaded = store.overrideSelector(datasetSelector.selectDatasetListIsLoaded, false);
+        mockDatabaseSelectorDatasetByRouteName = store.overrideSelector(datasetSelector.selectDatasetByRouteName, dataset);
+
+    });
+
+    it('should be created', () => {
+        expect(configureDatasetTitleResolver).toBeTruthy();
+    });
+
+    it('should dispatch datasetActions loadDatasetList action and return datasetListIsLoaded ', () => {
+        const expected = cold('a', { a: [] });
+        let spy = jest.spyOn(store, 'dispatch');
+        let result = hot('a', { a: configureDatasetTitleResolver.resolve(null, null) });
+
+        expect(result).toBeObservable(expected);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(datasetActions.loadDatasetList());
+
+    });
+    it('should return test_instance_label - Edit dataset test_dataset_label ', () => {
+        const expected = cold('a', { a: "test_instance_label - Edit dataset test_dataset_label" });
+        instance = {...instance, label: 'test_instance_label'}
+        mockDatabaseSelectorDatasetListIsLoaded = store.overrideSelector(datasetSelector.selectDatasetListIsLoaded, true);
+        mockInstanceSelectorInstanceByRouteName =  store.overrideSelector(instanceSelector.selectInstanceByRouteName, instance);
+        let route: MockActivatedRouteSnapshot;
+        route = { ...route, component: { name: 'test'}, firstChild: null,root: null, parent: null, children: null, paramMap: null, queryParamMap: null, pathFromRoot: null}
+        let result = configureDatasetTitleResolver.resolve(route, null);
+        expect(result).toBeObservable(expected);
+
+    });
+    it('should return test_instance_label - Configure dataset test_dataset_label', () => {
+        const expected = cold('a', { a: 'test_instance_label - Configure dataset test_dataset_label' });
+        instance = {...instance, label: 'test_instance_label'}
+        mockDatabaseSelectorDatasetListIsLoaded = store.overrideSelector(datasetSelector.selectDatasetListIsLoaded, true);
+        mockInstanceSelectorInstanceByRouteName =  store.overrideSelector(instanceSelector.selectInstanceByRouteName, instance);
+        let route: MockActivatedRouteSnapshot;
+        route = { ...route, component: { name: 'ConfigureDatasetComponent'}, firstChild: null,root: null, parent: null, children: null, paramMap: null, queryParamMap: null, pathFromRoot: null}
+        let result = configureDatasetTitleResolver.resolve(route, null);
+        expect(result).toBeObservable(expected);
+
+    });
+});
+
diff --git a/client/src/app/admin/instance/dataset/containers/configure-dataset.component.spec.ts b/client/src/app/admin/instance/dataset/containers/configure-dataset.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..fdcefa99bdb2a183081358b7a28390831e7acb17
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/containers/configure-dataset.component.spec.ts
@@ -0,0 +1,304 @@
+/**
+ * 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 { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ActivatedRoute } from '@angular/router';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { firstValueFrom, of } from 'rxjs';
+import { MockStore, provideMockStore } from '@ngrx/store/testing';
+
+import { ConfigureDatasetComponent } from './configure-dataset.component';
+import * as fitsImageActions from 'src/app/admin/store/actions/fits-image.actions';
+import * as coneSearchConfigActions from 'src/app/metamodel/actions/cone-search-config.actions';
+import * as detailConfigActions from 'src/app/metamodel/actions/detail-config.actions';
+import * as columnActions from 'src/app/admin/store/actions/column.actions';
+import * as attributeDistinctActions from 'src/app/admin/store/actions/attribute-distinct.actions';
+import * as criteriaFamilyActions from 'src/app/metamodel/actions/criteria-family.actions';
+import * as outputFamilyActions from 'src/app/metamodel/actions/output-family.actions';
+import * as outputCategoryActions from 'src/app/metamodel/actions/output-category.actions';
+import * as attributeActions from 'src/app/metamodel/actions/attribute.actions';
+import * as adminFileExplorerActions from 'src/app/admin/store/actions/admin-file-explorer.actions';
+import * as imageActions from 'src/app/metamodel/actions/image.actions';
+import * as fileActions from 'src/app/metamodel/actions/file.actions';
+import { Attribute, ConeSearchConfig, CriteriaFamily, DetailConfig, File, Image, OutputCategory, OutputFamily } from 'src/app/metamodel/models';
+
+describe('[admin][instance][dataset][containers] ConfigureDatasetComponent', () => {
+    let component: ConfigureDatasetComponent;
+    let fixture: ComponentFixture<ConfigureDatasetComponent>;
+    let store: MockStore;
+    let attribute: Attribute;
+    let mockparamMap = {
+        get: jest.fn().mockImplementation((name: string) => name)
+    }
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                ConfigureDatasetComponent,
+            ],
+            providers: [
+                {
+                    provide: ActivatedRoute,
+                    useValue: {
+                        queryParamMap: of(mockparamMap),
+                    },
+                },
+                provideMockStore({}),
+            ],
+
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule,
+            ]
+        });
+        fixture = TestBed.createComponent(ConfigureDatasetComponent);
+        component = fixture.componentInstance;
+        store = TestBed.inject(MockStore);
+        fixture.detectChanges();
+    });
+
+    it('should create the component and init tabSelect', async () => {
+        expect(component).toBeTruthy();
+        expect(await firstValueFrom(component.tabSelected)).toEqual('tab_selected');
+    });
+
+    it('store should dispatch loadColumnList action', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        component.loadColumnList()
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(columnActions.loadColumnList());
+    });
+
+    it('store should dispatch loadAttributeDistinctList action', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        component.loadAttributeDistinctList(attribute);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(attributeDistinctActions.loadAttributeDistinctList({ attribute }));
+    })
+
+    it('getVoEnabled() should return true', () => {
+
+        let result = component.getVoEnabled();
+        expect(result).toEqual(true);
+    });
+
+    it('store should dispatch addCriteriaFamily action', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        let criteriaFamily: CriteriaFamily = { display: 10, id: 1, label: 'test', opened: false };
+        component.addCriteriaFamily(criteriaFamily);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(criteriaFamilyActions.addCriteriaFamily({ criteriaFamily }));
+    });
+
+    it('store should dispatch editCriteriaFamily action', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        let criteriaFamily: CriteriaFamily = { display: 10, id: 1, label: 'test', opened: false };
+        component.editCriteriaFamily(criteriaFamily);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(criteriaFamilyActions.editCriteriaFamily({ criteriaFamily }));
+    });
+
+    it('store should dispatch deleteCriteriaFamily action', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        let criteriaFamily: CriteriaFamily = { display: 10, id: 1, label: 'test', opened: false };
+        component.deleteCriteriaFamily(criteriaFamily);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(criteriaFamilyActions.deleteCriteriaFamily({ criteriaFamily }));
+    });
+
+    it('store should dispatch addOutputFamily action', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        let outputFamily: OutputFamily = { display: 10, id: 1, label: 'test', opened: false };
+        component.addOutputFamily(outputFamily);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(outputFamilyActions.addOutputFamily({ outputFamily }));
+    });
+
+    it('store should dispatch editOutputFamily action', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        let outputFamily: OutputFamily = { display: 10, id: 1, label: 'test', opened: false };
+        component.editOutputFamily(outputFamily);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(outputFamilyActions.editOutputFamily({ outputFamily }));
+    });
+
+    it('store should dispatch deleteOutputFamily action', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        let outputFamily: OutputFamily = { display: 10, id: 1, label: 'test', opened: false };
+        component.deleteOutputFamily(outputFamily);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(outputFamilyActions.deleteOutputFamily({ outputFamily }));
+    });
+
+    it('store should dispatch addOutputCategory action', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        let outputCategory: OutputCategory = { display: 10, id: 1, label: 'test', id_output_family: 1 };
+        component.addOutputCategory(outputCategory);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(outputCategoryActions.addOutputCategory({ outputCategory }));
+    });
+
+    it('store should dispatch editOutputCategory action', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        let outputCategory: OutputCategory = { display: 10, id: 1, label: 'test', id_output_family: 1 };
+        component.editOutputCategory(outputCategory);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(outputCategoryActions.editOutputCategory({ outputCategory }));
+    });
+
+    it('store should dispatch deleteOutputCategory action', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        let outputCategory: OutputCategory = { display: 10, id: 1, label: 'test', id_output_family: 1 };
+        component.deleteOutputCategory(outputCategory);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(outputCategoryActions.deleteOutputCategory({ outputCategory }));
+    });
+
+    it('store should dispatch addAttribute action', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        component.addAttribute(attribute);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(attributeActions.addAttribute({ attribute }));
+    });
+
+    it('store should dispatch editAttribute action', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        component.editAttribute(attribute);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(attributeActions.editAttribute({ attribute }));
+    });
+
+    it('store should dispatch deleteAttribute action', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        component.deleteAttribute(attribute);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(attributeActions.deleteAttribute({ attribute }));
+    });
+
+    it('store should dispatch adminFileExplorerActions.loadFiles action', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        let path: string = 'test';
+        component.loadRootDirectory(path);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(adminFileExplorerActions.loadFiles({ path }));
+    });
+
+    it('store should dispatch fitsImageActions.retrieveFitsImageLimits action', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        let filePath: string = 'test';
+        component.retrieveFitsImageLimits(filePath);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(fitsImageActions.retrieveFitsImageLimits({ filePath }));
+    });
+
+    it('store should dispatch imageActions.addImage action', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        let image: Image = { dec_max: 1, dec_min: 0, file_path: 'test', file_size: 10, id: 1, label: 'test', pmax: 10, pmin: 1, ra_max: 10, ra_min: 10, stretch: 'test' };
+        component.addImage(image);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(imageActions.addImage({ image }));
+    });
+
+    it('store should dispatch imageActions.editImage action', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        let image: Image = { dec_max: 1, dec_min: 0, file_path: 'test', file_size: 10, id: 1, label: 'test', pmax: 10, pmin: 1, ra_max: 10, ra_min: 10, stretch: 'test' };
+        component.editImage(image);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(imageActions.editImage({ image }));
+    });
+
+    it('store should dispatch imageActions.deleteImage action', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        let image: Image = { dec_max: 1, dec_min: 0, file_path: 'test', file_size: 10, id: 1, label: 'test', pmax: 10, pmin: 1, ra_max: 10, ra_min: 10, stretch: 'test' };
+        component.deleteImage(image);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(imageActions.deleteImage({ image }));
+    });
+
+    it('store should dispatch fileActions.addFile action', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        let file: File = { file_path: 'test', file_size: 10, id: 1, label: 'test', type: 'test' }
+        component.addFile(file);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(fileActions.addFile({ file }));
+    });
+
+    it('store should dispatch fileActions.editFile action', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        let file: File = { file_path: 'test', file_size: 10, id: 1, label: 'test', type: 'test' }
+        component.editFile(file);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(fileActions.editFile({ file }));
+    });
+    
+    it('store should dispatch fileActions.deleteFile action', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        let file: File = { file_path: 'test', file_size: 10, id: 1, label: 'test', type: 'test' }
+        component.deleteFile(file);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(fileActions.deleteFile({ file }));
+    });
+
+    it('store should dispatch coneSearchConfigActions.addConeSearchConfig action', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        let coneSearchConfig: ConeSearchConfig = {
+            id: 1,
+            enabled: false,
+            opened: false,
+            column_dec: 10,
+            column_ra: 10,
+            resolver_enabled: false,
+            default_ra: null,
+            default_dec: null,
+            default_radius: null,
+            default_ra_dec_unit: 'degrees',
+            plot_enabled: false
+        };
+        component.addConeSearchConfig(coneSearchConfig);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(coneSearchConfigActions.addConeSearchConfig({ coneSearchConfig }));
+    });
+
+    it('store should dispatch coneSearchConfigActions.editConeSearchConfig action', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        let coneSearchConfig: ConeSearchConfig = {
+            id: 1,
+            enabled: false,
+            opened: false,
+            column_dec: 10,
+            column_ra: 10,
+            resolver_enabled: false,
+            default_ra: null,
+            default_dec: null,
+            default_radius: null,
+            default_ra_dec_unit: 'degrees',
+            plot_enabled: false
+        };
+        component.editConeSearchConfig(coneSearchConfig);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(coneSearchConfigActions.editConeSearchConfig({ coneSearchConfig }));
+    });
+
+    it('store should dispatch detailConfigActions.addDetailConfig action', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        let detailConfig: DetailConfig = { content: 'test', id: 1, style_sheet: 'test' };
+        component.addDetailConfig(detailConfig);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(detailConfigActions.addDetailConfig({ detailConfig }));
+    });
+
+    it('store should dispatch detailConfigActions.editDetailConfig action', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        let detailConfig: DetailConfig = { content: 'test', id: 1, style_sheet: 'test' };
+        component.editDetailConfig(detailConfig);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(detailConfigActions.editDetailConfig({ detailConfig }));
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/containers/dataset-list.component.spec.ts b/client/src/app/admin/instance/dataset/containers/dataset-list.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7eca03f762b9fb99ed0a1dd4506ea58e61531516
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/containers/dataset-list.component.spec.ts
@@ -0,0 +1,105 @@
+/**
+ * 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 { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { MockStore, provideMockStore } from '@ngrx/store/testing';
+
+import { DatasetListComponent } from './dataset-list.component';
+import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector';
+import { Dataset, DatasetFamily, Instance } from 'src/app/metamodel/models';
+import * as datasetFamilyActions from 'src/app/metamodel/actions/dataset-family.actions';
+import * as datasetActions from 'src/app/metamodel/actions/dataset.actions';
+
+describe('[admin][instance][dataset][containers] DatasetListComponent', () => {
+    let component: DatasetListComponent;
+    let fixture: ComponentFixture<DatasetListComponent>;
+    let store: MockStore;
+    let mockinstanceSelectorInstanceByRouteName;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+
+                DatasetListComponent,
+            ],
+            providers: [
+                provideMockStore({}),
+            ],
+
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule,
+            ]
+        });
+
+        fixture = TestBed.createComponent(DatasetListComponent);
+        component = fixture.componentInstance;
+        store = TestBed.inject(MockStore);
+        let instance: Instance;
+        mockinstanceSelectorInstanceByRouteName = store.overrideSelector(instanceSelector.selectInstanceByRouteName, { ...instance, label: 'test' })
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+
+    it('store should dispatch datasetFamilyActions.addDatasetFamily action', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        let datasetFamily: DatasetFamily = { display: 10, id: 1, label: 'test', opened: false };
+        component.addDatasetFamily(datasetFamily);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(datasetFamilyActions.addDatasetFamily({ datasetFamily }));
+    });
+
+    it('store should dispatch datasetFamilyActions.editDatasetFamily action', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        let datasetFamily: DatasetFamily = { display: 10, id: 1, label: 'test', opened: false };
+        component.editDatasetFamily(datasetFamily);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(datasetFamilyActions.editDatasetFamily({ datasetFamily }));
+    });
+
+    it('store should dispatch datasetFamilyActions.deleteDatasetFamily action', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        let datasetFamily: DatasetFamily = { display: 10, id: 1, label: 'test', opened: false };
+        component.deleteDatasetFamily(datasetFamily);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(datasetFamilyActions.deleteDatasetFamily({ datasetFamily }));
+    });
+
+    it('store should dispatch datasetActions.deleteDataset action', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        let dataset: Dataset = {
+            display: 10,
+            label: 'test',
+            cone_search_config_id: 1,
+            data_path: 'test',
+            datatable_enabled: false,
+            datatable_selectable_rows: false,
+            description: 'test',
+            download_ascii: false,
+            download_csv: false,
+            download_json: true,
+            download_vo: true,
+            full_data_path: 'test',
+            id_database: 10,
+            id_dataset_family: 1,
+            name: 'test',
+            public: false,
+            server_link_enabled: false,
+            table_ref: 'test'
+        };
+        component.deleteDataset(dataset);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(datasetActions.deleteDataset({ dataset }));
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/containers/edit-dataset.component.spec.ts b/client/src/app/admin/instance/dataset/containers/edit-dataset.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..26a532fbe85ecb500c13f24b61b690dd425b84f9
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/containers/edit-dataset.component.spec.ts
@@ -0,0 +1,97 @@
+/**
+ * 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 { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { MockStore, provideMockStore } from '@ngrx/store/testing';;
+
+import { EditDatasetComponent } from './edit-dataset.component';
+import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector';
+import { Dataset, Instance } from 'src/app/metamodel/models';
+import * as tableActions from 'src/app/admin/store/actions/table.actions';
+import * as adminFileExplorerActions from 'src/app/admin/store/actions/admin-file-explorer.actions';
+import * as datasetActions from 'src/app/metamodel/actions/dataset.actions';
+
+describe('[admin][instance][dataset][containers] DatasetListComponent', () => {
+    let component: EditDatasetComponent;
+    let fixture: ComponentFixture<EditDatasetComponent>;
+    let store: MockStore;
+    let mockinstanceSelectorInstanceByRouteName;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                EditDatasetComponent
+            ],
+            providers: [
+                provideMockStore({}),
+            ],
+
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule,
+            ]
+        });
+
+        fixture = TestBed.createComponent(EditDatasetComponent);
+        component = fixture.componentInstance;
+        store = TestBed.inject(MockStore);
+        let instance: Instance;
+        mockinstanceSelectorInstanceByRouteName = store.overrideSelector(instanceSelector.selectInstanceByRouteName, { ...instance, name: 'test' })
+        fixture.detectChanges();
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+
+    it('store should dispatch tableActions.loadTableList', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        let idDatabase: number = 1;
+        component.loadTableList(idDatabase);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(tableActions.loadTableList({ idDatabase }));
+    });
+
+    it('store should dispatch adminFileExplorerActions.loadFiles', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        let path: string = 'test';
+        component.loadRootDirectory(path);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(adminFileExplorerActions.loadFiles({ path }));
+    });
+
+    it('store should dispatch datasetActions.editDataset', () => {
+        let spy = jest.spyOn(store, 'dispatch');
+        let dataset: Dataset = {
+            display: 10,
+            label: 'test',
+            cone_search_config_id: 1,
+            data_path: 'test',
+            datatable_enabled: false,
+            datatable_selectable_rows: false,
+            description: 'test',
+            download_ascii: false,
+            download_csv: false,
+            download_json: true,
+            download_vo: true,
+            full_data_path: 'test',
+            id_database: 10,
+            id_dataset_family: 1,
+            name: 'test',
+            public: false,
+            server_link_enabled: false,
+            table_ref: 'test'
+        };
+        component.editDataset(dataset);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(datasetActions.editDataset({ dataset }));
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/containers/new-dataset.component.spec.ts b/client/src/app/admin/instance/dataset/containers/new-dataset.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9537ac3ec4f8f9dec32ecf317a4822077c220ca8
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/containers/new-dataset.component.spec.ts
@@ -0,0 +1,113 @@
+/**
+ * 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 { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ActivatedRoute } from '@angular/router';
+import { ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { MockStore, provideMockStore } from '@ngrx/store/testing';
+import { firstValueFrom, of } from 'rxjs';
+
+import { NewDatasetComponent } from './new-dataset.component';
+import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector';
+import { Dataset, Instance } from 'src/app/metamodel/models';
+import { RouterTestingModule } from '@angular/router/testing';
+import * as tableActions from 'src/app/admin/store/actions/table.actions';
+import * as adminFileExplorerActions from 'src/app/admin/store/actions/admin-file-explorer.actions';
+import * as datasetActions from 'src/app/metamodel/actions/dataset.actions';
+
+describe('[admin][instance][dataset][containers] NewDatasetComponent', () => {
+    let component: NewDatasetComponent;
+    let fixture: ComponentFixture<NewDatasetComponent>;
+    let store: MockStore;
+    let mockInstanceSelectorSelectInstanceByRouteName;
+    let mockparamMap = {
+        get: jest.fn().mockImplementation((name: string) => 0)
+    }
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                NewDatasetComponent,
+            ],
+            providers: [
+                {
+                    provide: ActivatedRoute,
+                    useValue: {
+                        queryParamMap: of(mockparamMap)
+                    }
+                },
+                provideMockStore({})
+            ],
+
+            imports: [
+                BrowserAnimationsModule,
+                ReactiveFormsModule,
+                RouterTestingModule.withRoutes([])
+            ]
+        });
+
+        fixture = TestBed.createComponent(NewDatasetComponent);
+        component = fixture.componentInstance;
+        store = TestBed.inject(MockStore);
+        let instance: Instance;
+        mockInstanceSelectorSelectInstanceByRouteName = store.overrideSelector(instanceSelector.selectInstanceByRouteName, { ...instance, name: 'test' });
+        fixture.detectChanges();
+        TestBed.inject(ActivatedRoute);
+    });
+
+    it('should create the component', async() => {
+        expect(component).toBeTruthy()
+        expect(await firstValueFrom(component.idDatasetFamily)).toEqual(0);
+    });
+
+    it('store should dispatch tableActions.loadTableList', () => {
+        let idDatabase: number = 1;
+        let spy = jest.spyOn(store, 'dispatch');
+        component.loadTableList(idDatabase);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(tableActions.loadTableList({ idDatabase }));
+    });
+
+    it('store should dispatch adminFileExplorerActions.loadFiles', () => {
+        let path: string = 'test';
+        let spy = jest.spyOn(store, 'dispatch');
+        component.loadRootDirectory(path);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(adminFileExplorerActions.loadFiles({ path }));
+    });
+
+    it('store should dispatch datasetActions.addDataset', () => {
+        let dataset: Dataset = {
+            display: 10,
+            label: 'test',
+            cone_search_config_id: 1,
+            data_path: 'test',
+            datatable_enabled: false,
+            datatable_selectable_rows: false,
+            description: 'test',
+            download_ascii: false,
+            download_csv: false,
+            download_json: true,
+            download_vo: true,
+            full_data_path: 'test',
+            id_database: 10,
+            id_dataset_family: 1,
+            name: 'test',
+            public: false,
+            server_link_enabled: false,
+            table_ref: 'test'
+        };
+
+        let spy = jest.spyOn(store, 'dispatch');
+        component.addNewDataset(dataset);
+        expect(spy).toHaveBeenCalledTimes(1);
+        expect(spy).toHaveBeenCalledWith(datasetActions.addDataset({ dataset }));
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/dataset-title.resolver.spec.ts b/client/src/app/admin/instance/dataset/dataset-title.resolver.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b7de6e1da7d0773733e7dcfb86e0bed2921bc650
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/dataset-title.resolver.spec.ts
@@ -0,0 +1,79 @@
+/**
+ * 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 { TestBed } from '@angular/core/testing';
+import { MockStore, provideMockStore } from '@ngrx/store/testing';
+import { cold } from 'jasmine-marbles';
+import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector';
+import { ActivatedRouteSnapshot } from '@angular/router';
+import { DatasetTitleResolver } from './dataset-title.resolver';
+import { Instance } from 'src/app/metamodel/models';
+
+class MockActivatedRouteSnapshot extends ActivatedRouteSnapshot {
+    constructor() {
+        super()
+    }
+    component: any;
+}
+
+describe('[admin][instance][dataset] DatasetTitleResolver', () => {
+    let datasetTitleResolver: DatasetTitleResolver;
+    let store: MockStore;
+    let mockInstanceSelectorInstanceByRouteName;
+    let instance: Instance;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            imports: [],
+            providers: [
+                DatasetTitleResolver,
+                provideMockStore({}),
+            ]
+        })
+
+        store = TestBed.inject(MockStore);
+        datasetTitleResolver = TestBed.inject(DatasetTitleResolver);
+        mockInstanceSelectorInstanceByRouteName = store.overrideSelector(instanceSelector.selectInstanceByRouteName, instance);
+        instance = { ...instance, label: 'test_instance_label' }
+    });
+
+    it('should be created', () => {
+        expect(datasetTitleResolver).toBeTruthy();
+    });
+
+    it('should return test_instance_label - New dataset', () => {
+        const expected = cold('a', { a: "test_instance_label - New dataset" });
+        let route: MockActivatedRouteSnapshot;
+        route = { ...route, component: { name: 'test' }, firstChild: null, root: null, parent: null, children: null, paramMap: null, queryParamMap: null, pathFromRoot: null }
+        let result = datasetTitleResolver.resolve(route, null);
+        expect(result).toBeObservable(expected);
+    });
+
+    it('should return test_instance_label - Datasets list', () => {
+        const expected = cold('a', { a: 'test_instance_label - Datasets list' });
+        instance = { ...instance, label: 'test_instance_label' }
+
+        mockInstanceSelectorInstanceByRouteName = store.overrideSelector(instanceSelector.selectInstanceByRouteName, instance);
+        let route: MockActivatedRouteSnapshot;
+        route = {
+            ...route,
+            component: { name: 'DatasetListComponent' },
+            firstChild: null,
+            root: null,
+            parent: null,
+            children: null,
+            paramMap: null,
+            queryParamMap: null,
+            pathFromRoot: null
+        }
+        let result = datasetTitleResolver.resolve(route, null);
+        
+        expect(result).toBeObservable(expected);
+    });
+});
diff --git a/client/src/app/admin/instance/dataset/dataset.module.spec.ts b/client/src/app/admin/instance/dataset/dataset.module.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..292dbd38a2422e59efc03b21849645e62da2a1a4
--- /dev/null
+++ b/client/src/app/admin/instance/dataset/dataset.module.spec.ts
@@ -0,0 +1,17 @@
+/**
+ * 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 { DatasetModule } from './dataset.module';
+
+describe('[Database] DatabaseModule', () => {
+    it('Test Dataset module', () => {
+        expect(DatasetModule.name).toEqual('DatasetModule');
+    });
+});
+
diff --git a/client/src/app/admin/instance/webpage/containers/new-webpage.component.spec.ts b/client/src/app/admin/instance/webpage/containers/new-webpage.component.spec.ts
index 3fd5c4d7ed98a9dc8e96c30d6869973929089d3c..e814dc7f00b707486f9a262b72601410e6f386fe 100644
--- a/client/src/app/admin/instance/webpage/containers/new-webpage.component.spec.ts
+++ b/client/src/app/admin/instance/webpage/containers/new-webpage.component.spec.ts
@@ -12,7 +12,7 @@ import { ActivatedRoute } from '@angular/router';
 import { ReactiveFormsModule } from '@angular/forms';
 import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
 
-import { of } from 'rxjs';
+import { firstValueFrom, of } from 'rxjs';
 import { MockStore, provideMockStore } from '@ngrx/store/testing';
 
 import { Webpage } from 'src/app/metamodel/models';
@@ -38,7 +38,7 @@ describe('[admin][instance][webpage][containers] NewWebpageComponent ', () => {
                 {
                     provide: ActivatedRoute,
                     useValue: {
-                        queryParamMap: of([{ id_webpage_family: 1 }]),
+                        queryParamMap: of({ get: jest.fn().mockImplementation(() => 1) }),
                     },
                 },
                 provideMockStore({}),
@@ -51,8 +51,9 @@ describe('[admin][instance][webpage][containers] NewWebpageComponent ', () => {
         fixture.detectChanges();
     });
 
-    it('should create the component', () => {
+    it('should create the component', async () => {
         expect(component).toBeTruthy();
+        expect(await firstValueFrom(component.idWebpageFamily)).toEqual(1);
     });
 
     it('dispatch webpageActions.addWebPage with the new webpage values', () => {
@@ -62,9 +63,4 @@ describe('[admin][instance][webpage][containers] NewWebpageComponent ', () => {
         expect(spy).toHaveBeenCalledWith(webpageActions.addWebpage({ webpage }));
     });
 
-    it('idWbPageFamily should be 1', () => {
-        component.idWebpageFamily.subscribe(value => {
-            //expect(value).toEqual(1);
-        })
-    })
 });