diff --git a/client/src/app/instance/search/components/criteria/search-type/datetime.component.spec.ts b/client/src/app/instance/search/components/criteria/search-type/datetime.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b1b119a84306a9c7651933a0a2bfbdcfde79b7d7
--- /dev/null
+++ b/client/src/app/instance/search/components/criteria/search-type/datetime.component.spec.ts
@@ -0,0 +1,124 @@
+import { Component, Input, ViewChild } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+
+import { TooltipModule } from 'ngx-bootstrap/tooltip';
+
+import { DatetimeComponent } from './datetime.component';
+import { FieldCriterion } from '../../../../store/models/criterion';
+import { BsDatepickerModule } from 'ngx-bootstrap/datepicker';
+import { NgSelectModule } from '@ng-select/ng-select';
+import { combineAll } from 'rxjs/operators';
+
+describe('[Instance][Search][Component][Criteria][SearchType] DatetimeComponent', () => {
+    @Component({
+        selector: `app-host`,
+        template: `
+            <app-datetime 
+                    [id]="id"
+                    [operator]="operator"
+                    [label]="label"
+                    [criterion]="criterion"
+                    [advancedForm]="advancedForm">
+            </app-datetime>`
+    })
+    class TestHostComponent {
+        @ViewChild(DatetimeComponent, { static: false })
+        public testedComponent: DatetimeComponent;
+        public id: number = undefined;
+        public operator: string = undefined;
+        public label: string = undefined;
+        public criterion: FieldCriterion = undefined;
+        public advancedForm: boolean = false;
+    }
+
+    @Component({ selector: 'app-operator', template: '' })
+    class OperatorStubComponent {
+        @Input() operator: string;
+        @Input() searchType: string;
+        @Input() advancedForm: boolean;
+        @Input() disabled: boolean;
+    }
+
+    @Component({ selector: 'app-help-like', template: '' })
+    class HelpLikeStubComponent { }
+
+    let testHostComponent: TestHostComponent;
+    let testHostFixture: ComponentFixture<TestHostComponent>;
+    let testedComponent: DatetimeComponent;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                DatetimeComponent,
+                TestHostComponent,
+                OperatorStubComponent,
+                // HelpLikeStubComponent
+            ],
+            imports: [
+                FormsModule,
+                ReactiveFormsModule,
+                NgSelectModule,
+                // TooltipModule.forRoot(),
+                BsDatepickerModule.forRoot()
+            ]
+        });
+        testHostFixture = TestBed.createComponent(TestHostComponent);
+        testHostComponent = testHostFixture.componentInstance;
+        testHostFixture.detectChanges();
+        testedComponent = testHostComponent.testedComponent;
+    });
+
+    it('should create the component', () => {
+        expect(testedComponent).toBeTruthy();
+    });
+
+    it('should call ngOnChanges and apply changes', () => {
+        const spy = jest.spyOn(testedComponent, 'ngOnChanges');
+        const date: Date = new Date('2019-02-17');
+        testHostComponent.criterion = { id: 1, type: 'field', operator: 'eq', value: '2019-02-17 15:47' } as FieldCriterion;
+        testHostFixture.detectChanges();
+        expect(testedComponent.form.controls.date.value).toEqual(date);
+        expect(testedComponent.form.controls.hh.value).toEqual('15');
+        expect(testedComponent.form.controls.mm.value).toEqual('47');
+        expect(testedComponent.form.disabled).toBeTruthy();
+        testHostComponent.criterion = undefined;
+        testHostFixture.detectChanges();
+        expect(testedComponent.form.controls.date.value).toBeNull();
+        expect(testedComponent.form.controls.hh.value).toBeNull();
+        expect(testedComponent.form.controls.mm.value).toBeNull();
+        expect(testedComponent.form.enabled).toBeTruthy();
+        expect(spy).toHaveBeenCalledTimes(2);
+    });
+
+    it('#changeOperator() should change the operator', () => {
+        expect(testedComponent.operator).toBeUndefined();
+        testedComponent.changeOperator('toto');
+        expect(testedComponent.operator).toBe('toto');
+    });
+
+    it('raises the add criterion event when clicked', () => {
+        testedComponent.id = 1;
+        const operator = 'eq';
+        testedComponent.operator = operator;
+        const date: Date = new Date('2019-02-17');
+        testedComponent.form.controls.date.setValue(date);
+        testedComponent.form.controls.hh.setValue('15');
+        testedComponent.form.controls.mm.setValue('47');
+        const expectedCriterion = { id: testedComponent.id, type: 'field', operator, value: '2019-02-17 15:47' } as FieldCriterion;
+        testedComponent.addCriterion.subscribe((event: FieldCriterion) => expect(event).toEqual(expectedCriterion));
+        testedComponent.emitAdd();
+    });
+
+    it('#initTime(t) should return an array of string with 2 digits from 0 to t', () => {
+        const n = 10;
+        expect(testedComponent.initTime(n).length).toEqual(n);
+        expect(testedComponent.initTime(n)[5]).toEqual('05');
+    });
+
+    it('#getDateString() should return a date as string', () => {
+        const dateString = '2019-02-17';
+        const date = new Date(dateString);
+        expect(testedComponent.getDateString(date)).toEqual(dateString);
+    });
+});
diff --git a/client/src/app/instance/search/components/criteria/search-type/datetime.component.ts b/client/src/app/instance/search/components/criteria/search-type/datetime.component.ts
index 0ad31ef7e8cfbe70196d092f565fd28bcd258235..3f60b69ff85b040e295db91a9993d0dd2fe48034 100644
--- a/client/src/app/instance/search/components/criteria/search-type/datetime.component.ts
+++ b/client/src/app/instance/search/components/criteria/search-type/datetime.component.ts
@@ -12,15 +12,17 @@ import { FormGroup, FormControl, Validators } from '@angular/forms';
 
 import { Criterion, FieldCriterion } from 'src/app/instance/store/models';
 
+/**
+ * @class
+ * @classdesc Datetime search type component.
+ *
+ * @implements OnChanges
+ */
 @Component({
     selector: 'app-datetime',
     templateUrl: 'datetime.component.html',
     changeDetection: ChangeDetectionStrategy.OnPush
 })
-/**
- * @class
- * @classdesc Datetime search type component.
- */
 export class DatetimeComponent implements OnChanges {
     @Input() id: number;
     @Input() operator: string;
@@ -39,9 +41,9 @@ export class DatetimeComponent implements OnChanges {
         mm: new FormControl('', [Validators.required]) 
     });
 
-    disabledOperator: boolean;
+    public disabledOperator: boolean;
 
-    ngOnChanges(changes: SimpleChanges) {
+    ngOnChanges(changes: SimpleChanges): void {
         if (changes.criterion && changes.criterion.currentValue) {
             const criterion = changes.criterion.currentValue as FieldCriterion;
             const [date, time] = criterion.value.split(' ');
diff --git a/client/src/app/instance/search/components/criteria/search-type/field.component.spec.ts b/client/src/app/instance/search/components/criteria/search-type/field.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..04076f228dbd6c3a30500425910a63755e36da4b
--- /dev/null
+++ b/client/src/app/instance/search/components/criteria/search-type/field.component.spec.ts
@@ -0,0 +1,129 @@
+import { Component, Input, ViewChild } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+
+import { TooltipModule } from 'ngx-bootstrap/tooltip';
+
+import { FieldComponent } from './field.component';
+import { FieldCriterion } from '../../../../store/models/criterion';
+
+describe('[Instance][Search][Component][Criteria][SearchType] FieldComponent', () => {
+    @Component({
+        selector: `app-host`,
+        template: `
+            <app-field 
+                    [id]="id"
+                    [operator]="operator"
+                    [label]="label"
+                    [placeholder]="placeholder"
+                    [attributeType]="attributeType"
+                    [criterion]="criterion"
+                    [advancedForm]="advancedForm">
+            </app-field>`
+    })
+    class TestHostComponent {
+        @ViewChild(FieldComponent, { static: false })
+        public testedComponent: FieldComponent;
+        public id: number = undefined;
+        public operator: string = undefined;
+        public label: string = undefined;
+        public placeholder: string = undefined;
+        public attributeType: string = undefined;
+        public criterion: FieldCriterion = undefined;
+        public advancedForm: boolean = false;
+    }
+
+    @Component({ selector: 'app-operator', template: '' })
+    class OperatorStubComponent {
+        @Input() operator: string;
+        @Input() searchType: string;
+        @Input() advancedForm: boolean;
+        @Input() disabled: boolean;
+    }
+
+    @Component({ selector: 'app-help-like', template: '' })
+    class HelpLikeStubComponent { }
+
+    let testHostComponent: TestHostComponent;
+    let testHostFixture: ComponentFixture<TestHostComponent>;
+    let testedComponent: FieldComponent;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                FieldComponent,
+                TestHostComponent,
+                OperatorStubComponent,
+                HelpLikeStubComponent
+            ],
+            imports: [
+                FormsModule,
+                ReactiveFormsModule,
+                TooltipModule.forRoot()
+            ]
+        });
+        testHostFixture = TestBed.createComponent(TestHostComponent);
+        testHostComponent = testHostFixture.componentInstance;
+        testHostFixture.detectChanges();
+        testedComponent = testHostComponent.testedComponent;
+    });
+
+    it('should create the component', () => {
+        expect(testedComponent).toBeTruthy();
+    });
+
+    it('should call ngOnChanges and apply changes', () => {
+        const spy = jest.spyOn(testedComponent, 'ngOnChanges');
+        testHostComponent.criterion = { id: 1, type: 'field', operator: 'eq', value: 'myValue' } as FieldCriterion;
+        testHostFixture.detectChanges();
+        expect(testedComponent.form.controls.value.value).toEqual('myValue');
+        expect(testedComponent.form.disabled).toBeTruthy();
+        testHostComponent.criterion = undefined;
+        testHostFixture.detectChanges();
+        expect(testedComponent.form.controls.value.value).toBeNull();
+        expect(testedComponent.form.enabled).toBeTruthy();
+        expect(spy).toHaveBeenCalledTimes(2);
+    });
+
+    it('#changeOperator() should change the operator', () => {
+        expect(testedComponent.operator).toBeUndefined();
+        testedComponent.changeOperator('toto');
+        expect(testedComponent.operator).toBe('toto');
+    });
+
+    it('raises the add criterion event when clicked', () => {
+        testedComponent.id = 1;
+        const operator = 'eq';
+        testedComponent.operator = operator;
+        testedComponent.form.controls.value.setValue('myValue');
+        const expectedCriterion = { id: testedComponent.id, type: 'field', operator, value: 'myValue' } as FieldCriterion;
+        testedComponent.addCriterion.subscribe((event: FieldCriterion) => expect(event).toEqual(expectedCriterion));
+        testedComponent.emitAdd();
+    });
+
+    it('#getType() should return `number` if criterion is a number type', () => {
+        testedComponent.attributeType = 'smallint';
+        expect(testedComponent.getType()).toEqual('number');
+        testedComponent.attributeType = 'integer';
+        expect(testedComponent.getType()).toEqual('number');
+        testedComponent.attributeType = 'decimal';
+        expect(testedComponent.getType()).toEqual('number');
+        testedComponent.attributeType = 'float';
+        expect(testedComponent.getType()).toEqual('number');
+    });
+
+    it('#getType() should return `text` if criterion is not a number type', () => {
+        testedComponent.attributeType = 'char';
+        expect(testedComponent.getType()).toEqual('text');
+    });
+
+    it('#getPlaceholder() should fill the placeholder if defined', () => {
+        const placeholder = 'placeholder';
+        testedComponent.placeholder = placeholder;
+        expect(testedComponent.getPlaceholder()).toEqual(placeholder);
+    });
+
+    it('#getPlaceholder() should not fill the placeholder if not defined', () => {
+        expect(testedComponent.getPlaceholder()).toEqual('');
+    });
+});
diff --git a/client/src/app/instance/search/components/criteria/search-type/field.component.ts b/client/src/app/instance/search/components/criteria/search-type/field.component.ts
index fb942cd2b69387e2485ab88dd4d109ed6731c8c1..2cf4ed8cc112e3af8a53a02dbb18e86c4df55da4 100644
--- a/client/src/app/instance/search/components/criteria/search-type/field.component.ts
+++ b/client/src/app/instance/search/components/criteria/search-type/field.component.ts
@@ -7,21 +7,31 @@
  * file that was distributed with this source code.
  */
 
-import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, SimpleChanges } from '@angular/core';
+import {
+    Component,
+    Input,
+    Output,
+    EventEmitter,
+    ChangeDetectionStrategy,
+    SimpleChanges,
+    OnChanges
+} from '@angular/core';
 import { FormGroup, FormControl, Validators } from '@angular/forms';
 
 import { FieldCriterion, Criterion } from 'src/app/instance/store/models';
 
+/**
+ * @class
+ * @classdesc Field search type component.
+ *
+ * @implements OnChanges
+ */
 @Component({
     selector: 'app-field',
     templateUrl: 'field.component.html',
     changeDetection: ChangeDetectionStrategy.OnPush,
 })
-/**
- * @class
- * @classdesc Field search type component.
- */
-export class FieldComponent {
+export class FieldComponent implements OnChanges {
     @Input() id: number;
     @Input() operator: string;
     @Input() label: string;
@@ -36,9 +46,9 @@ export class FieldComponent {
         value: new FormControl('', [Validators.required])
     });
     
-    disabledOperator: boolean;
+    public disabledOperator: boolean;
 
-    ngOnChanges(changes: SimpleChanges) {
+    ngOnChanges(changes: SimpleChanges): void {
         if (changes.criterion && changes.criterion.currentValue) {
             this.form.patchValue(this.criterion);
             this.form.disable();
diff --git a/client/src/app/instance/search/components/criteria/search-type/help-like.component.spec.ts b/client/src/app/instance/search/components/criteria/search-type/help-like.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..bb1eb2c0c12dc402d9ca65f7c6bc8223bd936f73
--- /dev/null
+++ b/client/src/app/instance/search/components/criteria/search-type/help-like.component.spec.ts
@@ -0,0 +1,20 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { HelpLikeComponent } from './help-like.component';
+
+describe('[Instance][Search][Component][Criteria][SearchType] HelpLikeComponent', () => {
+    let component: HelpLikeComponent;
+    let fixture: ComponentFixture<HelpLikeComponent>;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [HelpLikeComponent]
+        });
+        fixture = TestBed.createComponent(HelpLikeComponent);
+        component = fixture.componentInstance;
+    });
+
+    it('should create the component', () => {
+        expect(component).toBeTruthy();
+    });
+});
diff --git a/client/src/app/instance/search/components/criteria/search-type/help-like.component.ts b/client/src/app/instance/search/components/criteria/search-type/help-like.component.ts
index 3600c6055e3399883bdddbdf05f3947f1b986491..57598de55d2dac348413b3c91b9957d49b3b782b 100644
--- a/client/src/app/instance/search/components/criteria/search-type/help-like.component.ts
+++ b/client/src/app/instance/search/components/criteria/search-type/help-like.component.ts
@@ -9,12 +9,12 @@
 
 import { Component } from '@angular/core';
 
-@Component({
-    selector: 'app-help-like',
-    templateUrl: 'help-like.component.html'
-})
 /**
  * @class
  * @classdesc Help like operator component.
  */
+@Component({
+    selector: 'app-help-like',
+    templateUrl: 'help-like.component.html'
+})
 export class HelpLikeComponent { }
diff --git a/client/src/app/instance/search/components/criteria/search-type/json.component.spec.ts b/client/src/app/instance/search/components/criteria/search-type/json.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6941d1178975af0f51ce2abd9358ab0d873204ed
--- /dev/null
+++ b/client/src/app/instance/search/components/criteria/search-type/json.component.spec.ts
@@ -0,0 +1,77 @@
+import { Component, ViewChild } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+
+import { JsonComponent } from './json.component';
+import { JsonCriterion } from '../../../../store/models/criterion';
+
+describe('[Instance][Search][Component][Criteria][SearchType] JsonComponent', () => {
+    @Component({
+        selector: `app-host`,
+        template: `
+            <app-json-criteria 
+                    [id]="id"
+                    [label]="label"
+                    [criterion]="criterion">
+            </app-json-criteria>`
+    })
+    class TestHostComponent {
+        @ViewChild(JsonComponent, { static: false })
+        public testedComponent: JsonComponent;
+        public id: number = undefined;
+        public label: string = undefined;
+        public criterion: JsonCriterion = undefined;
+    }
+
+    let testHostComponent: TestHostComponent;
+    let testHostFixture: ComponentFixture<TestHostComponent>;
+    let testedComponent: JsonComponent;
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                JsonComponent,
+                TestHostComponent
+            ],
+            imports: [
+                FormsModule,
+                ReactiveFormsModule
+            ]
+        });
+        testHostFixture = TestBed.createComponent(TestHostComponent);
+        testHostComponent = testHostFixture.componentInstance;
+        testHostFixture.detectChanges();
+        testedComponent = testHostComponent.testedComponent;
+    });
+
+    it('should create the component', () => {
+        expect(testedComponent).toBeTruthy();
+    });
+
+    it('should call ngOnChanges and apply changes', () => {
+        const spy = jest.spyOn(testedComponent, 'ngOnChanges');
+        testHostComponent.criterion = { id: testedComponent.id, type: 'json', path: 'myPath', operator: 'myOperator', value: 'myValue' } as JsonCriterion;
+        testHostFixture.detectChanges();
+        expect(testedComponent.form.controls.path.value).toEqual('myPath');
+        expect(testedComponent.form.controls.operator.value).toEqual('myOperator');
+        expect(testedComponent.form.controls.value.value).toEqual('myValue');
+        expect(testedComponent.form.disabled).toBeTruthy();
+        testHostComponent.criterion = undefined;
+        testHostFixture.detectChanges();
+        expect(testedComponent.form.controls.path.value).toBeNull();
+        expect(testedComponent.form.controls.operator.value).toBeNull();
+        expect(testedComponent.form.controls.value.value).toBeNull();
+        expect(testedComponent.form.enabled).toBeTruthy();
+        expect(spy).toHaveBeenCalledTimes(2);
+    });
+
+    it('raises the add criterion event when clicked', () => {
+        testedComponent.id = 1;
+        testedComponent.form.controls.path.setValue('myPath');
+        testedComponent.form.controls.operator.setValue('myOperator');
+        testedComponent.form.controls.value.setValue('myValue');
+        const expectedCriterion = { id: testedComponent.id, type: 'json', path: 'myPath', operator: 'myOperator', value: 'myValue' } as JsonCriterion;
+        testedComponent.addCriterion.subscribe((event: JsonCriterion) => expect(event).toEqual(expectedCriterion));
+        testedComponent.emitAdd();
+    });
+});
diff --git a/client/src/app/instance/search/components/criteria/search-type/json.component.ts b/client/src/app/instance/search/components/criteria/search-type/json.component.ts
index 32ddefd758ba96bfa9c9d31bb3834bfff1c0e490..cb9e4b16ff0ad9d2b5186532012e90a57e00e406 100644
--- a/client/src/app/instance/search/components/criteria/search-type/json.component.ts
+++ b/client/src/app/instance/search/components/criteria/search-type/json.component.ts
@@ -12,15 +12,17 @@ import { FormGroup, FormControl, Validators } from '@angular/forms';
 
 import { JsonCriterion, Criterion } from 'src/app/instance/store/models';
 
+/**
+ * @class
+ * @classdesc JSON search type component.
+ *
+ * @implements OnChanges
+ */
 @Component({
     selector: 'app-json-criteria',
     templateUrl: 'json.component.html',
     changeDetection: ChangeDetectionStrategy.OnPush
 })
-/**
- * @class
- * @classdesc JSON search type component.
- */
 export class JsonComponent implements OnChanges {
     @Input() id: number;
     @Input() label: string;
@@ -34,7 +36,7 @@ export class JsonComponent implements OnChanges {
         value: new FormControl('', [Validators.required])
     });
 
-    ngOnChanges(changes: SimpleChanges) {
+    ngOnChanges(changes: SimpleChanges): void {
         if (changes.criterion && changes.criterion.currentValue) {
             this.form.patchValue(changes.criterion.currentValue);
             this.form.disable();
@@ -52,7 +54,7 @@ export class JsonComponent implements OnChanges {
      * @fires EventEmitter<JsonCriterion>
      */
     emitAdd(): void {
-        const js = {id: this.id, type: 'json', ...this.form.value};
+        const js = { id: this.id, type: 'json', ...this.form.value };
         this.addCriterion.emit(js);
     }
 }