-
-
Notifications
You must be signed in to change notification settings - Fork 152
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add tests for directive and single editor.
- Loading branch information
Showing
4 changed files
with
324 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
36 changes: 36 additions & 0 deletions
36
libs/shared/common-services/src/validation.service.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { TestBed } from '@angular/core/testing'; | ||
import { ValidationService } from './validation.service'; | ||
|
||
describe('ValidationService', () => { | ||
let service: ValidationService; | ||
|
||
beforeEach(() => { | ||
TestBed.configureTestingModule({ | ||
providers: [ValidationService], | ||
}); | ||
|
||
service = TestBed.inject(ValidationService); | ||
}); | ||
|
||
it('should be created', () => { | ||
expect(service).toBeTruthy(); | ||
}); | ||
|
||
it('should have a default value of true for validationPassed$', (done: DoneFn) => { | ||
service.validationPassed$.subscribe((value) => { | ||
expect(value).toBe(true); | ||
done(); | ||
}); | ||
}); | ||
|
||
it('should emit the updated value when validationPassed$ changes', (done: DoneFn) => { | ||
// Emit a new value | ||
service.validationPassed$.next(false); | ||
|
||
// Subscribe and verify the updated value | ||
service.validationPassed$.subscribe((value) => { | ||
expect(value).toBe(false); | ||
done(); | ||
}); | ||
}); | ||
}); |
196 changes: 196 additions & 0 deletions
196
libs/shared/directives/src/validate-input.directive.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
import { Component, DebugElement } from '@angular/core'; | ||
import { TestBed, ComponentFixture } from '@angular/core/testing'; | ||
import { By } from '@angular/platform-browser'; | ||
import { ReactiveFormsModule, FormControl, FormsModule, NgControl } from '@angular/forms'; | ||
import { InputValidationDirective } from './validate-input.directive'; | ||
import { ValidationService } from '@keira/shared/common-services'; | ||
import { take } from 'rxjs'; | ||
|
||
@Component({ | ||
template: ` | ||
<form> | ||
<div> | ||
<input type="text" [formControl]="testControl" keiraInputValidation /> | ||
</div> | ||
</form> | ||
`, | ||
}) | ||
class TestComponent { | ||
testControl = new FormControl(''); | ||
} | ||
|
||
describe('InputValidationDirective', () => { | ||
let fixture: ComponentFixture<TestComponent>; | ||
let validationService: ValidationService; | ||
let debugElement: DebugElement; | ||
|
||
beforeEach(() => { | ||
TestBed.configureTestingModule({ | ||
declarations: [TestComponent], | ||
imports: [ReactiveFormsModule, FormsModule, InputValidationDirective], // Add the directive to imports | ||
providers: [ValidationService], | ||
}).compileComponents(); | ||
|
||
fixture = TestBed.createComponent(TestComponent); | ||
validationService = TestBed.inject(ValidationService); | ||
debugElement = fixture.debugElement.query(By.directive(InputValidationDirective)); | ||
fixture.detectChanges(); | ||
}); | ||
|
||
it('should create an instance', () => { | ||
const directive = debugElement.injector.get(InputValidationDirective); | ||
expect(directive).toBeTruthy(); | ||
}); | ||
|
||
it('should display error message when control is invalid and touched', () => { | ||
const control = debugElement.injector.get(NgControl).control; | ||
control?.setValidators(() => ({ required: true })); | ||
control?.markAsTouched(); | ||
control?.updateValueAndValidity(); | ||
|
||
fixture.detectChanges(); | ||
|
||
const errorDiv = debugElement.nativeElement.parentNode.querySelector('.error-message'); | ||
expect(errorDiv).toBeTruthy(); | ||
expect(errorDiv.textContent).toBe('This field is required'); | ||
}); | ||
|
||
it('should remove error message when control becomes valid', () => { | ||
const control = debugElement.injector.get(NgControl).control; | ||
control?.setValidators(() => ({ required: true })); | ||
control?.markAsTouched(); | ||
control?.updateValueAndValidity(); | ||
|
||
fixture.detectChanges(); | ||
|
||
let errorDiv = debugElement.nativeElement.parentNode.querySelector('.error-message'); | ||
expect(errorDiv).toBeTruthy(); | ||
|
||
// Make the control valid | ||
control?.clearValidators(); | ||
control?.setValue('Valid value'); // Set a valid value | ||
control?.updateValueAndValidity(); | ||
|
||
fixture.detectChanges(); | ||
|
||
errorDiv = debugElement.nativeElement.parentNode.querySelector('.error-message'); | ||
expect(errorDiv).toBeNull(); | ||
}); | ||
|
||
it('should handle empty error object gracefully', () => { | ||
const control = debugElement.injector.get(NgControl).control; | ||
control?.setValidators(() => ({})); // No errors | ||
control?.markAsTouched(); | ||
control?.updateValueAndValidity(); | ||
|
||
fixture.detectChanges(); | ||
|
||
const errorDiv = debugElement.nativeElement.parentNode.querySelector('.error-message'); | ||
expect(errorDiv).toBeNull(); | ||
}); | ||
|
||
it('should handle multiple error types gracefully', () => { | ||
const control = debugElement.injector.get(NgControl).control; | ||
control?.setValidators(() => ({ required: true, minlength: true })); // Multiple errors | ||
control?.markAsTouched(); | ||
control?.updateValueAndValidity(); | ||
|
||
fixture.detectChanges(); | ||
|
||
const errorDiv = debugElement.nativeElement.parentNode.querySelector('.error-message'); | ||
expect(errorDiv).toBeTruthy(); | ||
expect(errorDiv.textContent).toBe('This field is required'); // Test only the first error message | ||
}); | ||
|
||
it('should not throw when control is null', () => { | ||
const ngControl = debugElement.injector.get(NgControl); | ||
spyOnProperty(ngControl, 'control', 'get').and.returnValue(null); // Mock control as null | ||
|
||
expect(() => { | ||
fixture.detectChanges(); | ||
}).not.toThrow(); | ||
}); | ||
|
||
it('should not create duplicate error messages if errorDiv already exists', () => { | ||
const control = debugElement.injector.get(NgControl).control; | ||
control?.setValidators(() => ({ required: true })); | ||
control?.markAsTouched(); | ||
control?.updateValueAndValidity(); | ||
|
||
fixture.detectChanges(); | ||
|
||
const initialErrorDiv = debugElement.nativeElement.parentNode.querySelector('.error-message'); | ||
expect(initialErrorDiv).toBeTruthy(); | ||
|
||
// Trigger the updateErrorMessage logic again | ||
fixture.detectChanges(); | ||
|
||
const updatedErrorDiv = debugElement.nativeElement.parentNode.querySelector('.error-message'); | ||
expect(updatedErrorDiv).toBe(initialErrorDiv); // Same errorDiv should remain | ||
}); | ||
|
||
it('should not add error message if parentNode is null', () => { | ||
const control = debugElement.injector.get(NgControl).control; | ||
|
||
// Mock parentNode as null | ||
spyOnProperty(debugElement.nativeElement, 'parentNode', 'get').and.returnValue(null); | ||
|
||
control?.setValidators(() => ({ required: true })); | ||
control?.markAsTouched(); | ||
control?.updateValueAndValidity(); | ||
|
||
fixture.detectChanges(); | ||
|
||
const errorDiv = debugElement.nativeElement.parentNode?.querySelector('.error-message'); | ||
expect(errorDiv).toBeFalsy(); // Error message should not be added | ||
}); | ||
|
||
it('should update validationPassed$ in ValidationService', (done: DoneFn) => { | ||
const control = debugElement.injector.get(NgControl).control; | ||
|
||
control?.setValidators(() => ({ required: true })); | ||
control?.markAsTouched(); | ||
control?.updateValueAndValidity(); | ||
|
||
validationService.validationPassed$ | ||
.pipe(take(1)) // Take only the first emission | ||
.subscribe((isValid) => { | ||
expect(isValid).toBe(false); // Initially invalid | ||
done(); | ||
}); | ||
|
||
// Test invalid state | ||
control?.setValue(''); | ||
fixture.detectChanges(); | ||
|
||
// Test valid state | ||
control?.setValue('Valid value'); | ||
control?.updateValueAndValidity(); | ||
fixture.detectChanges(); | ||
}); | ||
|
||
it('should set touched when control is invalid', () => { | ||
const control = debugElement.injector.get(NgControl).control; | ||
|
||
spyOn(control!, 'markAsTouched'); | ||
control?.setValidators(() => ({ required: true })); | ||
control?.updateValueAndValidity(); | ||
|
||
fixture.detectChanges(); | ||
|
||
expect(control?.markAsTouched).toHaveBeenCalled(); | ||
}); | ||
|
||
it('should not create errorDiv if parentNode is null', () => { | ||
const control = debugElement.injector.get(NgControl).control; | ||
spyOnProperty(debugElement.nativeElement, 'parentNode', 'get').and.returnValue(null); | ||
|
||
control?.setValidators(() => ({ required: true })); | ||
control?.markAsTouched(); | ||
control?.updateValueAndValidity(); | ||
|
||
fixture.detectChanges(); | ||
|
||
expect(debugElement.nativeElement.parentNode?.querySelector('.error-message')).toBeFalsy(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters