Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

typeIn helper triggers all key-related events, even if preventDefault is called #912

Open
pgengler opened this issue Aug 20, 2020 · 2 comments
Labels

Comments

@pgengler
Copy link

The typeIn helper always triggers all of the key-related events (keydown, keypress, input, and keyup) regardless of whether event.preventDefault() was called. This makes the helper work differently than actual browser input in a few cases:

  • When a keydown handler calls preventDefault, only the keydown and keyup events are triggered
  • When a keypress handler calls preventDefault, an input event is not triggered

Calling preventDefault in a keyup or input handler has no effect on which events are triggered.

(Tested with Chrome 84.0.4147.105 and Firefox 79.0.)

@rwjblue
Copy link
Member

rwjblue commented Oct 14, 2020

This definitely seems good to fix, though I think it will be somewhat difficult to do.

@rwjblue rwjblue added the bug label Oct 14, 2020
@BillyRayPreachersSon
Copy link

BillyRayPreachersSon commented Feb 25, 2021

@pgengler - I had some success rolling my own from a combination of the internal __triggerKeyEvent__ / fireEvent / buildKeyboardEvent functions.

My needs were quite specific in that I didn't need to enter any alphabetic characters, so didn't need to worry about detecting or setting the shiftKey property on the event data. There's also not a great deal of error checking, max length checking, etc., and I had no need to support older browsers, so didn't try all the KeyboardEvent / KeyboardEvents / KeyEvent combinations.

Try this for size with numeric data... your mileage may vary 🙂 .

import { find, settled } from '@ember/test-helpers';

function buildNumberKeyEvent(eventType, key) {
  const keyCode = key.charCodeAt(0);
  const keyEventProps = { keyCode, which: keyCode, key, ctrlKey: false, altKey: false, shiftKey: false, metaKey: false, bubbles: true, cancelable: true };
  const keyEvent = new KeyboardEvent(eventType, keyEventProps);
  Object.defineProperty(keyEvent, 'keyCode', {
    get() {
      return parseInt(keyCode, 10); // buildKeyboardEvent is missing the ,10... and the radix doesn't default to 10
    },
  });

  Object.defineProperty(keyEvent, 'which', {
    get() {
      return parseInt(keyCode, 10); // buildKeyboardEvent is missing the ,10... and the radix doesn't default to 10
    },
  });

  return keyEvent;
}

async function preventableNumericTypeIn(selector, string) {
  const element = find(selector);
  if (!element) {
    throw new Error(`Cannot find selector ${selector}`);
  }

  for (const key of [...string]) {
    const keyDownEvent = buildNumberKeyEvent('keydown', key);
    element.dispatchEvent(keyDownEvent);
    await settled();
    if (keyDownEvent.defaultPrevented) {
      return;
    }

    const keyPressEvent = buildNumberKeyEvent('keypress', key);
    element.dispatchEvent(keyPressEvent);
    await settled();
    if (keyPressEvent.defaultPrevented) {
      return;
    }

    element.value += key;
    const inputEvent = document.createEvent('Events');
    inputEvent.initEvent('input', true, true);
    element.dispatchEvent(inputEvent);
    await settled();

    const keyUpEvent = buildNumberKeyEvent('keyup', key);
    element.dispatchEvent(keyUpEvent);
    await settled();
    if (keyUpEvent.defaultPrevented) {
      return;
    }

    const changeEvent = document.createEvent('Events');
    changeEvent.initEvent('change', true, true);
    element.dispatchEvent(inputEvent);
    await settled();
  }
}

await preventableNumericTypeIn('input', '1.2345');

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants