'How to test keydown keystrokes for a directive on a textbox?
I have a directive that I created that limits the input to be from 1 - 5 and limits the value to only have one decimal point. I am trying to unit test this, but I get a failed test when I try to inject a keydown event--Expected '' to be '1'. So it is as if there were no keys entered for the test. I feel like I am missing something simple. I am new to Angular and unit-testing.
limited-value.directive.spec.ts
import { Component } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { LimitedValueDirective } from './limited-value.directive';
@Component({
selector: 'app-test-container',
template: `
<div>
<label for="limitedValue">Limited Value</label>
<input id="limitedValue" type="text" class="form-control" formControlName="LimitedValue" appLimitedValue>
</div>
`
})
class MyComponent { }
let fixture: ComponentFixture<MyComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ MyComponent, LimitedValueDirective ],
}).compileComponents();
fixture = TestBed.createComponent(MyComponent);
fixture.detectChanges();
});
describe('LimitedValueDirective', () => {
it('should be empty', () => {
let inputElement:HTMLInputElement = fixture.debugElement.nativeElement.querySelector('input[type=text]');
expect(inputElement.value).toBe('');
});
it('should be one digit', async () => {
fixture.detectChanges();
fixture.whenStable().then(() => {
let inputElement:HTMLInputElement = fixture.debugElement.nativeElement.querySelector('input[type=text]');
const event = new KeyboardEvent("keydown", {
"key": "1"
});
inputElement.dispatchEvent(event);
fixture.detectChanges();
expect(inputElement.value).toBe('1');
});
});
});
limited-value.directive.ts
import { Directive, ElementRef, HostListener, Input } from '@angular/core';
@Directive({
selector: '[appLimitedValue]'
})
export class LimitedValueDirective {
@Input() value: string;
private regex: RegExp = new RegExp(/^[1-4](\.[0-9])?$|^[1-5]\.$|^5$|^5\.0$/g);
private el: HTMLInputElement;
private specialKeys: Array<string> = [
'Backspace',
'Tab',
'End',
'Home',
'ArrowLeft',
'ArrowRight',
'Del',
'Delete',
];
constructor(private elementRef: ElementRef) {
this.el = this.elementRef.nativeElement;
}
ngOnInit() {}
@HostListener('keydown', ['$event'])
onKeyDown(event: KeyboardEvent) {
if ((this.specialKeys.indexOf(event.key) !== -1) || (event.ctrlKey && (event.key == 'v' || event.key == 'c'))) {
return;
}
let current: string = this.elementRef.nativeElement.value;
const position = this.elementRef.nativeElement.selectionStart;
const next: string = [
current.slice(0, position),
event.key == 'Decimal' ? '.' : event.key,
current.slice(position),
].join('');
if (next && !String(next).match(this.regex)) {
event.preventDefault();
}
}
}
Solution 1:[1]
Tim,
In addition to adding the new spec file to the test-files.ts file, it looks like your directive wasn't setting the value of the input. I'm not sure if this is exactly what you are after, but I made a small adjustment here: https://stackblitz.com/edit/angular-ivy-gnwbb9?file=src/app/limited-value.directive.spec.ts
The directive now sets the value of the input and I added another test for pressing 6.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Jake Smith |
