如何在Angular中对输入框的keyDown指令进行单元测试?
如何在Angular单元测试中模拟用户输入字符(解决KeyboardEvent无法设置输入框值的问题)
我尝试了多种现有解决方案的变体,但都没用,KeyboardEvent始终无法为输入框设置值。请问该如何模拟用户输入字符?
单元测试代码
@Component({ selector: 'app-test-container', template: ` <div> <label for="integerValue">Integer Value</label> <input id="integerValue" type="text" class="form-control" formControlName="IntegerValue" appOnlyInteger> </div> ` }) class MyComponent {} fdescribe('IntegerOnlyDirective', () => { let fixture: ComponentFixture<MyComponent>; beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [MyComponent, IntegerOnlyDirective], }).compileComponents(); fixture = TestBed.createComponent(MyComponent); fixture.detectChanges(); }); it('should accept integer as is', async () => { fixture.detectChanges(); await fixture.whenStable(); const inputElement: HTMLInputElement = fixture.debugElement.nativeElement.querySelector('input[type=text]'); inputElement.dispatchEvent(new KeyboardEvent('keydown', { key: '1' })); fixture.detectChanges(); expect(inputElement.value).toBe('1'); // FAILS -> value is '' }); });
指令代码
@Directive({ selector: '[appOnlyInteger]' }) export class IntegerOnlyDirective { constructor(private el: ElementRef) { } @HostListener('input', ['$event']) onKeyDown(event) { const initialValue = this.el.nativeElement.value as string; // 只保留正整数,忽略所有非数字字符 // g表示全局匹配,捕获所有符合条件的内容 this.el.nativeElement.value = initialValue.replace(/\D*/g, ''); } }
问题分析
- 键盘事件不自动修改输入框值:手动触发
keydown事件只是模拟了按键动作,但浏览器不会像真实用户输入那样自动更新输入框的value属性。 - 指令监听事件不匹配:你的指令监听的是
input事件,而非keydown事件,所以触发keydown不会触发指令的过滤逻辑。
解决方案
要模拟真实用户输入,需要先手动设置输入框的value,再触发input事件,这样才能触发指令的处理逻辑。修改单元测试的it块代码如下:
it('should accept integer as is', async () => { fixture.detectChanges(); await fixture.whenStable(); const inputElement: HTMLInputElement = fixture.debugElement.nativeElement.querySelector('input[type=text]'); // 1. 设置输入框初始值 inputElement.value = '1'; // 2. 触发input事件,触发指令的处理逻辑 inputElement.dispatchEvent(new Event('input')); fixture.detectChanges(); expect(inputElement.value).toBe('1'); // 验证通过 });
如果想更贴合Angular测试的写法,也可以使用DebugElement的triggerEventHandler方法:
it('should accept integer as is', async () => { fixture.detectChanges(); await fixture.whenStable(); const inputDebugEl = fixture.debugElement.query(By.css('input[type=text]')); const inputElement: HTMLInputElement = inputDebugEl.nativeElement; inputElement.value = '1'; inputDebugEl.triggerEventHandler('input', { target: inputElement }); fixture.detectChanges(); expect(inputElement.value).toBe('1'); });
这样操作后,输入框的value会被更新,同时触发指令监听的input事件,指令会执行整数过滤逻辑,最终就能验证输入值是否符合预期。
内容的提问来源于stack exchange,提问作者ymoreau
相关产品推荐
相关产品推荐

