Tuesday, September 23, 2014

Verifying a Polymer.dart Fix with a Text Input Event Test?!


I thought I had the internationalization project code for Patterns in Polymer 100% solid. It turns out that I missed one thing: the bound variable in a pluralization is not updating properly.

After last night, I have <hello-you> element localization into English, Spanish, and French working just fine. I can start the element localized or change it on the fly. All except the number of red balloons the user currently happens to own:



As I found last night, this is not completely broken. Only the bound variable in the pluralization fails to update. If I switch the locale to Spanish, the message then displays correctly:



So what have I done?

The answer turns out to be “not much.” In fact, the answer is that I did nothing—the underlying Polymer library (and by extension the Polymer.dart library) changed when I was not looking. And, since I lack a test for this particular bit of functionality, it went completely unnoticed.

The actual problem is simple enough. The <x-translate> element is not listening for changes to the labels (including the count):
@CustomTag('x-translate')
class XTranslate extends PolymerElement {
  XTranslate.created(): super.created();
  // ...
  enteredView() {
    super.enteredView();
    labels.changes.listen((_)=> update());
  }
  // ...
}
It looks very much like it should be listening, but this listener is never established because enteredView() is never called. The enteredView() method used to be a callback method, but has since been replaced with attached(), making the fix trivial:
@CustomTag('x-translate')
class XTranslate extends PolymerElement {
  XTranslate.created(): super.created();
  // ...
  attached() {
    super.attached();
    labels.changes.listen((_)=> update());
  }
  // ...
}
With that, I have everything working again:



It works now, but I am only setting myself up for future failure. If the library changed once, it is likely to change again (the library is still in alpha release, after all). The only way to prevent this from breaking again without my knowledge is to write a test. But how?

Ideally I would want a test like the following (scheduled_test schedules are there to ensure serial execution):
    test('localizes the number of balloons', (){
      schedule((){
        _el.$['count'].value = '99';
      });
      schedule((){
        expect(_el.shadowRoot.text, contains("J'ai 99 ballons rouges."));
      });
    });
But that does work. Polymer does recognize the updated value as a reason to change its attributes. And I know that sending input events does not work.

Bleh. I may as well try some of those. Who knows? Maybe the Dart / Polymer folks fixed this....

Holy Cow! They fixed it!

If I send a Text Input event to the element:
    test('localizes the number of balloons', (){
      schedule((){
        var evt = new TextEvent('textInput', data: '99');
        _el.$['count'].
          dispatchEvent(evt);
      });
      schedule((){
        expect(_el.shadowRoot.text, contains("J'ai 99 ballons rouges."));
      });
    });
Then my test now passes:
PASS: <hello-you/> (i18n) defaults to English
PASS: <hello-you/> (i18n) can localize to French
PASS: <hello-you/> (i18n) can localize to Spanish
PASS: <hello-you locale="fr"/> (French) starts in French
PASS: <hello-you locale="fr"/> (French) localizes the number of balloons
PASS: <hello-you locale="es"/> (Spanish) starts in Spanish
I am so darn excited about this. I wonder if this means that all text input event generation works now? That would be amazing (it has long been my go-to answer to name something I don't like about Dart). But, for now, I am thrilled to have this particular element well tested for the future.


Day #192

No comments:

Post a Comment