我有一个我应用于输入的PhoneMask指令,它将删除非数字字符并根据我设置的掩码格式化数字(例如1234567890
的输入将被格式化为{{ 1}})。面具本身有效,但我想为它编写一个单元测试,我在确定如何做到这一点时遇到了问题。
PhoneMask指令:
(123) 456-7890
PhoneMask测试/规范:
import {Directive, ElementRef, EventEmitter, Output} from '@angular/core';
import {NgControl} from '@angular/forms';
@Directive({
selector: '[PhoneMask]',
host: {
'(ngModelChange)': 'onInputChange($event)'
}
})
export class PhoneMaskDirective {
@Output() rawChange: EventEmitter<string> = new EventEmitter<string>();
constructor(public model: NgControl, private el: ElementRef) {
}
onInputChange(inputValue) {
const selectionStart = this.el.nativeElement.selectionStart;
const [rawNumber, cursor] = this.getRawNumberAndCursor(inputValue, selectionStart);
const [formattedNumber, formattedCursor] = this.getFormattedNumberAndCursor(rawNumber, cursor);
// Set input to formatted value
this.model.valueAccessor.writeValue(formattedNumber);
// Set cursor in the right spot
this.el.nativeElement.selectionStart = this.el.nativeElement.selectionEnd = formattedCursor;
this.rawChange.emit(rawNumber);
}
getRawNumberAndCursor(text: string, cursorPos: number): [string, number] {
let rawNumber = '';
let rawPos = cursorPos;
for (let i = 0, len = text.length; i < len; i++) {
if (/\d/.test(text[i])) {
rawNumber += text[i];
} else if (i < cursorPos) {
rawPos--;
}
}
return [rawNumber, rawPos];
}
getFormattedNumberAndCursor(numberVal: string, cursorPos: number): [string, number] {
let formattedNumber = '';
if (numberVal.length == 0) {
formattedNumber = '';
} else if (numberVal.length <= 3) {
formattedNumber = numberVal.replace(/^(\d{0,3})/, '($1)');
} else if (numberVal.length <= 6) {
formattedNumber = numberVal.replace(/^(\d{0,3})(\d{0,3})/, '($1) $2');
} else if (numberVal.length <= 10) {
formattedNumber = numberVal.replace(/^(\d{0,3})(\d{0,3})(.*)/, '($1) $2-$3');
} else {
formattedNumber = numberVal.replace(/^(\d{0,3})(\d{0,3})(\d{0,4})(.*)/, '($1) $2-$3 $4');
}
for (let i = 0; i < cursorPos; i++) {
if (/\D/.test(formattedNumber[i])) {
cursorPos++;
}
}
return [formattedNumber, cursorPos];
}
}
在测试中,我希望import {PhoneMaskDirective} from './phone-mask.directive';
import {Component} from '@angular/core';
import {TestBed} from '@angular/core/testing';
import {By} from '@angular/platform-browser';
import {FormsModule} from '@angular/forms';
@Component({
template: `
<input PhoneMask [(ngModel)]="phone"/>
`
})
class TestPhoneMaskDirectiveComponent {
}
describe('PhoneMaskDirective', () => {
let fixture;
let theInput;
beforeEach(async () => {
fixture = TestBed.configureTestingModule({
imports: [FormsModule],
declarations: [PhoneMaskDirective, TestPhoneMaskDirectiveComponent],
})
.createComponent(TestPhoneMaskDirectiveComponent);
fixture.detectChanges();
theInput = fixture.debugElement.query(By.directive(PhoneMaskDirective));
});
it('should find one instance of the directive', () => {
expect(theInput).toBeTruthy();
});
it('should handle input of non-numeric characters', async () => {
fixture.detectChanges();
let element = theInput.nativeElement;
element.value = 'bob123';
element.dispatchEvent(new Event('input', {bubbles: true, cancelable: true}));
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(fixture.componentInstance.phone).toEqual('(123)');
});
});
});
的输入结果为bob123
。但是,当我运行测试时,我得到(123)
的失败结果。
我尝试了Expected 'bob123' to equal '(123)'.
,async
以及fakeAsync
和detectChanges()
调用的各种组合,甚至用{{1来包装最终期望值}}。输入的valueAccessor更新后,如何访问模型的值?