diff --git a/projects/components/src/search-box/search-box.component.test.ts b/projects/components/src/search-box/search-box.component.test.ts new file mode 100644 index 000000000..1e315de13 --- /dev/null +++ b/projects/components/src/search-box/search-box.component.test.ts @@ -0,0 +1,63 @@ +import { fakeAsync } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { runFakeRxjs } from '@hypertrace/test-utils'; +import { createHostFactory, Spectator } from '@ngneat/spectator/jest'; +import { SearchBoxComponent } from './search-box.component'; + +describe('Search box Component', () => { + let spectator: Spectator; + + const createHost = createHostFactory({ + component: SearchBoxComponent, + shallow: true + }); + + test('should work with default values', fakeAsync(() => { + spectator = createHost( + ``, + { + hostProps: { + placeholder: 'Test Placeholder' + } + } + ); + + const inputDebugElement = spectator.debugElement.query(By.css('input')); + expect((inputDebugElement.nativeElement as HTMLInputElement)?.placeholder).toEqual('Test Placeholder'); + spectator.component.value = 'Test'; + + runFakeRxjs(({ expectObservable }) => { + expectObservable(spectator.component.valueChange).toBe('x', { + x: 'Test' + }); + + spectator.triggerEventHandler(inputDebugElement, 'input', spectator.component.value); + spectator.tick(); + }); + })); + + test('should work with arbitrary debounce time', fakeAsync(() => { + spectator = createHost( + ``, + { + hostProps: { + placeholder: 'Test Placeholder', + debounceTime: 200 + } + } + ); + + const inputDebugElement = spectator.debugElement.query(By.css('input')); + expect((inputDebugElement.nativeElement as HTMLInputElement)?.placeholder).toEqual('Test Placeholder'); + spectator.component.value = 'Test2'; + + runFakeRxjs(({ expectObservable }) => { + expectObservable(spectator.component.valueChange).toBe('200ms x', { + x: 'Test2' + }); + + spectator.triggerEventHandler(inputDebugElement, 'input', spectator.component.value); + spectator.tick(); + }); + })); +}); diff --git a/projects/components/src/search-box/search-box.component.ts b/projects/components/src/search-box/search-box.component.ts index 6efb532a5..939ffad98 100644 --- a/projects/components/src/search-box/search-box.component.ts +++ b/projects/components/src/search-box/search-box.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, Output } from '@angular/core'; +import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core'; import { IconType } from '@hypertrace/assets-library'; import { SubscriptionLifecycle, TypedSimpleChanges } from '@hypertrace/common'; import { Subject } from 'rxjs'; @@ -33,7 +33,7 @@ import { IconSize } from '../icon/icon-size'; ` }) -export class SearchBoxComponent implements OnChanges { +export class SearchBoxComponent implements OnInit, OnChanges { @Input() public placeholder: string = 'Search'; @@ -41,7 +41,7 @@ export class SearchBoxComponent implements OnChanges { public value: string = ''; @Input() - public debounceTime: number = 0; + public debounceTime?: number; @Output() public readonly valueChange: EventEmitter = new EventEmitter(); @@ -55,14 +55,13 @@ export class SearchBoxComponent implements OnChanges { public isFocused: boolean = false; private readonly debouncedValueSubject: Subject = new Subject(); + public ngOnInit(): void { + this.setDebouncedSubscription(); + } + public ngOnChanges(changes: TypedSimpleChanges): void { if (changes.debounceTime) { - this.subscriptionLifecycle.unsubscribe(); - this.subscriptionLifecycle.add( - this.debouncedValueSubject - .pipe(debounceTime(this.debounceTime)) - .subscribe(value => this.valueChange.emit(value)) - ); + this.setDebouncedSubscription(); } } @@ -82,4 +81,13 @@ export class SearchBoxComponent implements OnChanges { this.value = ''; this.onValueChange(); } + + private setDebouncedSubscription(): void { + this.subscriptionLifecycle.unsubscribe(); + this.subscriptionLifecycle.add( + this.debouncedValueSubject + .pipe(debounceTime(this.debounceTime ?? 0)) + .subscribe(value => this.valueChange.emit(value)) + ); + } }