I have created a very simple directive to use on input elements, that should only allow entry of a decimal number (numeric with single decimal point).
The directive is defined as follows:
import { HostListener, Directive, ElementRef } from '@angular/core';
// Directive attribute to stop any input, other than a decimal number.
@Directive({
selector: '[decimalinput]'
})
export class DecimalInputDirective {
constructor(private element : ElementRef) { }
// Hook into the key press event.
@HostListener('keypress', ['$event']) onkeypress( keyEvent : KeyboardEvent ) : boolean {
// Check if a full stop already exists in the input.
var alreadyHasFullStop = this.element.nativeElement.value.indexOf('.') != -1;
// Get the key that was pressed in order to check it against the regEx.
let input = String.fromCharCode(keyEvent.which);
// Test for allowed character using regEx. Allowed is number or decimal.
var isAllowed = /^(\d+)?([.]?\d{0,2})?$/.test( input );
// If this is an invlid character (i.e. alpha or symbol) OR we already have a full stop, prevent key press.
if (!isAllowed || (isAllowed && input == '.' && alreadyHasFullStop)){
keyEvent.preventDefault();
return false;
}
return true;
}
}
This directive should allow "123.123"
not "abc"
, nor "1.2.1"
. Now I want to test this directive, reading online, I've come up with this so far:
import { Component, OnInit, TemplateRef,DebugElement, ComponentFactory, ViewChild, ViewContainerRef } from '@angular/core';
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { DecimalInputDirective } from './decimalinput.directive';
import { By } from '@angular/platform-browser';
@Component({
template: `<input type="text" name="txtDecimalTest" decimalinput>`
})
class TestDecimalComponent { }
describe('Directive: DecimalInputDirective', () => {
let component: TestDecimalComponent;
let fixture: ComponentFixture<TestDecimalComponent>;
let decimalInput: DebugElement;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [TestDecimalComponent]
});
fixture = TestBed.createComponent(TestDecimalComponent);
component = fixture.componentInstance;
decimalInput = fixture.debugElement.query(By.css('input[name=txtDecimalTest]'));
});
it('Entering email and password emits loggedIn event', () => {
// This sets the value (I can even put "abc" here and it will work.
decimalInput.nativeElement.value = "12345";
// But I am trying to initialize the keypress event, so the character is tested in a real world way when the user is using.
decimalInput.nativeElement.dispatchEvent(new KeyboardEvent("keypress", { key: "a" })); // Nothing happens here! This was my attempt...
// This
expect(decimalInput.nativeElement.value).toBe("12345");
});
});
You can see from the code, the line:
decimalInput.nativeElement.dispatchEvent(new KeyboardEvent...
Is my attempt to simulate keypresses, as if the user was inputting. If I simulated a, then b, then c, then 1, then 2, then 3, I'd expect the test to make sure the value is only "123" and its ignored "abc" in the way the directive works.
Two questions - 1) is this the correct test I should be doing? 2) Whats wrong with my code - why is the simulated key press doing nothing?
Thanks for any pointers in advance! :)