Saturday, June 8, 2013

Dynamically Creating Keyboard Events in Dart: Not Possible?

‹prev | My Chain | next›

I remain somewhat annoyed that Dart does not support dynamically building keyboard events. Today I discovered TextEvent. Maybe that will work as a solution.

My hacky solution in the ICE Code Editor test suite was to insert the key code into the keyIdentifier attribute of a KeyboardEvent:
hitEnter()=> type(13);
hitEscape()=> type(27);

type(int charCode) {
  document.activeElement.dispatchEvent(
    new KeyboardEvent(
      'keyup',
      keyIdentifier: new String.fromCharCode(charCode)
    )
  );
}
This is hacky because the key code does not make it into the actual keyCode attribute of the event. Instead, I have to accommodate this with a helper method in the application code:
_isEnterKey(e) =>
  e.keyCode == 13 || e.$dom_keyIdentifier.codeUnits.first == 13;
There is a fine line between a test telling you that there is a flaw in your design and changing good code just to suit testability. Here, I am well past changing good code and into code whose sole purpose is to deal with a deficiency in the programming language.

So what happens if I change the event being dispatched from a KeyboardEvent, which does not expose a means to set keyCode, into a TextEvent, which supports a data parameter in the constructor?
type(int charCode) {
  document.activeElement.dispatchEvent(
    new TextEvent(
      'keyup',
      data: new String.fromCharCode(charCode)
    )
  );
}
Unfortunately, I get a bunch of exceptions:
Exception: Class 'TextEvent' has no instance getter 'keyCode'.

NoSuchMethodError : method not found: 'keyCode'
Receiver: Instance of 'TextEvent'
Arguments: [] dart:core-patch/object_patch.dart:19
Object.noSuchMethod dart:core-patch/object_patch.dart:19
_isEnterKey package:ice_code_editor/full.dart:212
RenameDialog.open.<anonymous closure>
I can get rid of the exceptions by checking the data attribute instead of the keyCode attribute:
_isEnterKey(e) => e.data == new String.fromCharCode(13);
That even gets a few more tests to pass. Unfortunately, it does not allow the escape key tests to pass:
FAIL: New Project Dialog the escape key closes the new project dialog
  Expected: List of elements not contains match 'Save'
       But: Element list content was [
    '\n'
      '            Update\n'
      '         ',
    'Hide Code',
    'Show Code',
    '☰',
    'Save'
  ].
That test expects that hitting the escape key hides the new project dialog, along with its Save button. Instead, the Save button is still active because, lets face it, the escape key is not a TextEvent.

Bummer. The TextEvent class is still a good find for me. It lets me enter content dynamically, an ability that I will be making good use of in some upcoming material. Still, I am again thwarted in trying to dynamically create keyboard events in my tests.


Day #776

2 comments:

  1. From looking at the documentation on MDN, keyCode is decremented. What it looks like you should actually be using is KeyName, http://api.dartlang.org/docs/releases/latest/dart_html/KeyName.html#ENTER. No idea if that'll end up populating the keyCode properly, but everything in Dart fits with whats technically available. JS might let you get away with setting a readonly value, but to me that's the real deficiency.

    This came up on IRC so figured I'd comment.

    ReplyDelete