You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular Jest中NumberLimitDirective指令单元测试preventDefault未生效问题

Fixing Jest Unit Test for Angular NumberLimitDirective where preventDefault Isn't Working

Let's break down why your unit test isn't behaving as expected and fix it step by step.

The Root Cause

Your test is failing because two key issues with how you're handling the keyboard event:

  1. The KeyboardEvent you're creating isn't cancelable — by default, native KeyboardEvent instances have cancelable: false, so calling event.preventDefault() on them does nothing.
  2. You're checking defaultPrevented synchronously before the event handler finishes — Angular's HostListener processes events asynchronously in some cases, so you need to wait for the event handling to complete before checking if the event was canceled.

Step-by-Step Fixes

1. Create a Cancelable Keyboard Event

When you instantiate your keypress event, explicitly set cancelable: true so preventDefault() can actually block the event:

async function testInput(inputElement: any, text: number | string) {
  const keypressEvent = new KeyboardEvent('keypress', {
    key: `${text}`,
    cancelable: true // Critical: allows preventDefault() to work
  });
  await sendKeyDown(inputElement, keypressEvent); // Wait for event processing
  if (!keypressEvent.defaultPrevented) {
    await sendInput(inputElement, text);
  }
}

2. Wait for Asynchronous Event Handling

Notice we added await before sendKeyDown — your sendKeyDown function returns fixture.whenStable(), so we need to wait for that promise to resolve before checking if the event was canceled. This ensures Angular has finished running the directive's onKeyPress handler.

3. Fix the Undefined current Variable in the Directive

Looking at your directive code, there's a missing variable definition that would break it in production (even if you said it works now, this is likely a paste error):

@HostListener('keypress', ['$event']) 
public onKeyPress(event) {
  const current = this.el.nativeElement.value; // Add this line!
  const next: string = current.concat(event.key);
  const regexp = RegExp(this.setRegexp(), 'g');
  if (next && !String(next).match(regexp)) {
    event.preventDefault();
  }
}

Without defining current, the directive would throw a ReferenceError — fixing this ensures both production and test environments behave consistently.

4. Adjust Your Test Expectation (If Needed)

Your test expects the final value to be 01, but let's check the default regex logic:

  • Default integerLimit: 10, fractionalLimit: 0 creates the regex ^[0-9]{0,10}$
  • This allows digits only, so inputting 0 (initial value) → 1 (allowed) → , (blocked) → 0 (allowed) would result in 010, not 01.
    If you intended to block leading zeros or single 0 inputs, you'd need to adjust the regex in setRegexp(), but that's a separate issue from the test failure.

Updated Test Code Snippet

Here's how your modified testInput and test case would look:

async function testInput(inputElement: any, text: number | string) {
  const keypressEvent = new KeyboardEvent('keypress', {
    key: `${text}`,
    cancelable: true
  });
  await sendKeyDown(inputElement, keypressEvent);
  if (!keypressEvent.defaultPrevented) {
    await sendInput(inputElement, text);
  }
}

test('Check valid input for default input.', async () => {
  fixture.detectChanges();
  const testLocator = fixture.debugElement.query(By.css('#default'));
  expect(testLocator).not.toBe(null);
  
  await testInput(testLocator, 1);
  await testInput(testLocator, ',');
  await testInput(testLocator, 0);
  
  expect(testLocator.nativeElement.value).toBe('010'); // Updated expectation to match regex logic
});

Final Notes

  • Always ensure test events are cancelable when testing preventDefault() logic
  • Use await with fixture.whenStable() to wait for Angular's change detection and event processing to finish
  • Double-check for missing variable definitions in your directive code to avoid inconsistencies between environments

内容的提问来源于stack exchange,提问作者Max

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:03:15