Reputation: 2761
I have a directive AllowOnlyNumbers
which applied to input type textbox.
<input
[AllowOnlyNumbers]=true
[maxLength]= 'yearlyFieldMaxLength'
type="tel"
name="totalAnnualIncome"
formControlName="totalAnnualIncome"
[(ngModel)]="yearlyIncomeAmt"
(focus)="onFocusEnableToolTip('TotalAnnualIncome')"
(focusout)="onFocusOutDisableToolTip('TotalAnnualIncome')"
minlength="2"
autocomplete="off"/>
A very simple directive restricts users to put only numbers in the textbox.
import { Directive, HostListener, Input } from '@angular/core';
@Directive({
selector: '[AllowOnlyNumbers]'
})
/**
* @method AllowOnlyNumbers
* @desc This directive restricts the keyboard entry to numbers only.
* Users can enter numbers and can use backspace, tab,enter, escape, end, home, left, right and del keys.
* Usage: <input type = "text" [AllowOnlyNumbers] = true />
*/
export class AllowOnlyNumbers {
constructor() { }
@Input() AllowOnlyNumbers: boolean;
/**
* @methodspace AllowOnlyNumbers
* @method onKeyDown
* @desc It restricts the keyboard entry to numbers only.
* @argument event
* @returns returns only digit
*
*/
@HostListener('keydown', ['$event']) onKeyDown(event) {
const e = event as KeyboardEvent;
if (this.AllowOnlyNumbers) {
// Allow: 8=Backspace, 9= Tab, 13=CR, 27=ESC, 35=END, 36=HOME, 37=Left, 39=Right, 46=DEL
if ([8, 9, 13, 27, 35, 36, 37, 39, 46].indexOf(e.keyCode) !== -1) {
return;
}
// Ensure that it is a number and stop the keypress
if ((e.shiftKey || (e.keyCode < 48 || e.keyCode > 57)) && (e.keyCode < 96 || e.keyCode > 105)) {
e.preventDefault();
}
}
}
}
Now, when writing the Unit test case using jasmine, I am not able to set the @Input() AllowOnlyNumbers
property as true. This is always undefined.
Below is my UT file. (Note: Keydown event is getting fired)
import {ComponentFixture, TestBed} from '@angular/core/testing';
import { AllowOnlyNumbers } from './allow-only-numbers.directive';
import { Component, DebugElement, NO_ERRORS_SCHEMA } from '@angular/core';
import { By } from '@angular/platform-browser';
@Component({
template: `<input [AllowOnlyNumbers]= true type="text" name="totalAnnualIncome" />`
})
// tslint:disable-next-line:no-unnecessary-class
class TestAllowOnlyNumbersComponent {
// allowNumbers = true;
}
fdescribe('Directive: AllowOnlyNumbers', () => {
let component: TestAllowOnlyNumbersComponent;
let fixture: ComponentFixture<TestAllowOnlyNumbersComponent>;
let inputEl: DebugElement;
let linkDes;
let routerLinks;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [TestAllowOnlyNumbersComponent, AllowOnlyNumbers],
schemas: [ NO_ERRORS_SCHEMA ]
});
fixture = TestBed.createComponent(TestAllowOnlyNumbersComponent);
component = fixture.componentInstance;
inputEl = fixture.debugElement.query(By.css('input[name="totalAnnualIncome"]'));
});
it('keydown input', () => {
inputEl.triggerEventHandler('keydown', {});
fixture.detectChanges();
expect(true).toBe(true);
});
});
I am using this link as reference. I am not able to set the @Input() AllowOnlyNumbers
property as true. This is always undefined.
Upvotes: 3
Views: 5312
Reputation: 232
Answer to your issue:
It should be [AllowOnlyNumbers]="true"
not [AllowOnlyNumbers]= true
in TestAllowOnlyNumbersComponent
.
What you're actually doing is [AllowOnlyNumbers]=
which does not assign any value to the input of directive.
Also you should move fixture.detectChanges()
before the triggerEventHandler
to trigger initial value binding or even better would be to add it at the end of the beforeEach
beforeEach(() => {
...
fixture.detectChanges();
});
it('keydown input', () => {
inputEl.triggerEventHandler('keydown', {});
expect(true).toBe(true);
});
Also additional comment about your directive:
I think you should replace keyCode
with key
in your directive, as it looks like keyCode
is deprecated https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.
I think change should be easy, in your directive you just read that key string and a code based on that value const code = e.key.charCodeAt()
Then I'd create following test, to test one of the keys in this case 'F' key:
it('keydown input', () => {
const event = new KeyboardEvent('keydown', { key: 'F' });
inputEl.nativeElement.dispatchEvent(event);
expect(event.defaultPrevented).toBe(true);
});
I guess that might work when making that change in the directive.
Upvotes: 7