Friday, October 11, 2013

Trying to Figure Out What I Can Test with KeyEvent

Still stinging from last night's defeat, I try to pick up the broken pieces of my soul tonight.

I mean, how cool would it have been to get custom keyboard events working in Dart on the 900th day of the current chain? Having dutifully file the requisite bug, I move on tonight to see what I can salvage from last night's effort.

I start by pulling down the latest Dart DSK (Dart VM version: (Fri Oct 11 14:06:31 2013) on "linux_x64") from the continuous build archive. The first two listeners in the following still generate errors:
import 'dart:html';
  var subscription = KeyboardEventStream.onKeyDown(document.body).listen(
      (e) => print('KeyboardEventStream listener'));
  var subscription2 = KeyEvent.keyDownEvent.forTarget(document.body).listen(
      (e) => print('KeyEvent listener'));
  var subscription3 = document.body.onKeyDown.listen(
      (e) => print('regular listener'));
Only subscription3 from the document.body.onDown stream give me results when I hit a key:
regular listener 
The other two spew multiple Dartium errors:
Exception: InvalidStateError: Internal Dartium Exception 
As far as I can tell, the first two streams (from KeyboardEventStream and KeyEvent) are both useless in user-facing code. Even if I run the unit tests for the new KeyEvent in Dartium, hitting any key after running the test generates oodles of Internal Dartium Exceptions. But maybe the onKeyDown can be of some use?

Well, no. The onKeyDown property is a _ElementEventStreamImpl. Sadly that is not a subclass of the new CustomStream and therefore does not support the add() method for dispatching events:
Exception: Class '_ElementEventStreamImpl' has no instance method 'add'.

NoSuchMethodError : method not found: 'add'
Receiver: Instance of '_ElementEventStreamImpl@0x3918afae'
Arguments: [Instance of 'KeyEvent']
Bummer. I suppose this is the purpose of the KeyboardEventStream and KeyEvent wrappers. But still… bummer.

Well, it seems that I remain at a dead-end in ICE Code Editor—at least until my bug is addressed. I can write testable code that crashes the browser or non-testable code because the working property does not support dispatching events. In my mind, testing trumps runnable code. At some point the testable code will work—and maybe it already does when compiled to JavaScript.

Even this proves difficult. Consider if I stick with the KeyEvent class and listen for keydown events:
  var subscription2 = KeyEvent.keyDownEvent.forTarget(document.body).listen(
      (e) => print('KeyEvent listener'));

  // Trigger / listen for event on document.body
  var streamDown = KeyEvent.keyDownEvent.forTarget(document.body);
  var subscription4 = streamDown.listen(
      (e) => print('streamDown listener ${e.keyCode}'));
  streamDown.add(new KeyEvent('keydown', keyCode: 4, charCode: 0));

  // Trigger / listen for event on the H1
  var h1Down = KeyEvent.keyDownEvent.forTarget(query('h1'));
  var subscription5 = h1Down.listen(
      (e) => print('h1Down listener ${e.keyCode}'));
  h1Down.add(new KeyEvent('keydown', keyCode: 5, charCode: 0));
Both subscription2 and subscription4 listen for keydown events on document.body. When I add a new keydown KeyEvent to the stream from the second group, I expect to see both event listeners fire. But it turns out that I am adding the KeyEvent to the second stream and only the second stream. I am not generating an event that will be seen by all listeners on document.body—only an event that will be seen by that second stream. Worse, when I add an event to the keydown stream of an <h1>, it is again only to the <h1> tag's stream and it does not bubble up.

I expect the above code to trigger both the document.body listeners twice—both should see the custom keyboard event on document.body and both should see the <h1> event bubble. But I only see the direct events:
streamDown listener 4 undefined:1
h1Down listener 5 
This is of very limited use for me. For instance, if I want to test that a keydown in the ICE project filter shows all the projects that start with “a” I need access to the KeyEvent stream that actually listens to the corresponding text field. For that to work, I would need to expose the filter stream (and every other stream) in the ICE code as a public property. There is no way I am doing that just to support testing.


As depressing as all of that is, hope is not completely lost. I do believe that the keyboard shortcut code ought to be somewhat testable. Given what I learned today, I doubt that I will be able to add a custom KeyEvent for Ctrl+O to a stream in ICE to test that the open dialog appears. Still, I think the keyboard shortcut library itself ought to be testable. And perhaps I can expose some high-level testing methods from that same package to support limited keyboard testing in ICE. Something for tomorrow. Hope.

Day #901


  1. Thank you that Ctrl-alt-foo is finally working again. Just yesterday I found a very odd bug, and I am not sure if you can reproduce it..
    On Ctrl-S and Meta-S I do a save operation of the currently open file.
    When I hit Ctrl-S it does exactly what it should and the POST HttpRequest works, but when I use Meta-S the save-dialog of dartium opens and the HttpRequest fails (which I think is probably the oddest part about it). Interestingly Meta-S did work before..
    If I insert a break point, the open dialog still appears, but after continuing the HttpRequest also works with Meta-S. It appears that there is some kind of race condition when Meta is pressed.

    1. There are some keyboard shortcuts that the browser just won't let though: Is it possible Meta-S is one of them on your platform?

    2. I tested it with your keyboard event tester, this is the output:
      As I said, it did work in Dartium before ctrl-alt-foo broke and I reported the bug. Nonetheless, in google mail Meta-S does not open a dialog, so it appears to be possible.

  2. Chris, any update on this? I just updated to Dart 1.0 and my reactive keyboard library is completely kaput. Sigh.

    1. Sadly, it's still completely broken. I've resorted to this kind of awful hackery:

      The two bugs that need to be addressed are:


      There hasn't been any recent activity on them, but hopefully that'll change now that the 1.0 dust is settling.

    2. Thanks for the update. I just updated my library to support Dart v1.0:

      I haven't pushed it to pub yet due to the lack of proper docs and tests.

    3. > I haven't pushed it to pub yet due to the lack of proper docs and tests.

      That never stopped me before! :D