Send to Kindle

Friday, April 18, 2014

Submitting Forms with Polymer Elements (Still) Doesn't Work


While working through the remaining errata for Patterns in Polymer, I came across one that states that you can put a vanilla form inside of a Polymer element and expect that it should form-submit to an HTTP server like any other form. I honestly do not know that I have ever thought to do that, let alone try it. Now is as good a time as any.

I did research submitting a Polymer element as part of a normal form. That is, the Polymer element is some kind of super date picker and it is embedded in a vanilla HTML form. The expectation was that <input> fields within the Polymer element would be submitted along with any other form data on the page. As I found, this was not the case—the Polymer data was not submitted. In the end, I came up with a MutationObserver workaround, which served as the basis for a chapter in the book.

So first things first, with the latest versions of the JavaScript version of the library and with Polymer.dart, does submitting forms that contain Polymer elements with <input> elements now work?

I am still working with the sample form that looks like:



The first and last text <input> fields are defined in the HTML of the main page while the middle <input> is defined inside the very simple <hello-you> element:



But, if I enter data in all text <input> fields and submit the form, only the form elements that are part of the main document's HTML are submitted:
plain_old_param:plain
distributed_param:projected
And, loading this up in the JavaScript version, I find the same thing.

So you cannot submit a normal HTML form with a Polymer element that contains its own <input> tags. The MutationObserver approach is still needed. A bit of a bummer, but I confess that I relieved that I do not have to rewrite the chapter!

That said, this was not what the errata report specifically addressed. Said reviewer indicated that, if the Polymer element contained both the <form> and the <input>, then submitting it should work just fine.

And, indeed, that does work. I copy the HTML from the page into the <template> of my Polymer element:
<polymer-element name="hello-you">
  <template>
    <form action="test" method="post">
      <h1>Plain-old Form</h1>
      <input type=text name="plain_old_param" placeholder="Plain-old form field">
      <input type=submit value=Play>
    </form>
  </template>
  <script type="application/dart;component=1" src="hello_you.dart"></script>
</polymer-element>
When I fill out that plain_old_param text <input> and submit the <form> contained entirely inside the Polymer element, I find that it is submitted:
plain_old_param:asdf
And, when I try the same approach in the JavaScript version, I find the same results.

So in the end, not much needs to change in that chapter. In my opinion, Polymer elements that serve as <input> fields are a more likely use-case than a Polymer element that contains an entire <form>, so the chapter seems a very worthwhile one to include in the book. Still, I go back to rework the wording a little to (hopefully) make the use-case clearer.


Day #38

Thursday, April 17, 2014

Bare Minimum Polymer.dart Testing


I finally have my Polymer.dart tests passing again. But that is insufficient for Patterns in Polymer. I have to ensure that I am not programming by coincidence, which is a poor programming practice and disastrous book writing practice.

James Hurford was kind enough to give me a head start on this. He noted that he was able to get my Polymer.dart tests passing even without a few things that I had previously thought required—things like async() calls to flush the Polymer platform and onPolymer futures to ensure that platform was in place.

James hypothesized that the non-necessity of these actions might be due to the dev-channel Dart that he is running whereas I am still on stable 1.3. I have 1.4 at the ready, but begin with 1.3 to put that to the test.

I am explicitly invoking the Polymer.onReady future as part of my test, so I will just comment that out from my setUp() block:
@initMethod
main() {
  setUp((){
    // schedule(()=> Polymer.onReady);
    // More setup here...
  });
  // Tests here...
}
The schedule() here is not built into Dart's very excellent unittest library. Rather it comes from the also excellent scheduled_test package which extends unittest with some asynchronous goodness.

With that commented out, I also remove the async() calls. This was pulled into my Dart code because it was, at one point, necessary in both JavaScript and Dart versions of Polymer elements. I am not using this directly in the tests, but rather as a method on the Page Object that I am using to interact with the Polymer element:
class XPizzaComponent {
  String get currentPizzaStateDisplay => // ...
  Future addWholeTopping(String topping) {
    /* ... */
    return flush();
  }
  Future flush() {
    var _completer = new Completer();
    el.async((_)=> _completer.complete());
    return _completer.future;
  }
}
The async() method on Polymer elements is supremely handy when testing. It tells the Polymer element to immediately process all outstanding asynchronous operations like updating bound variables. It also tells the Polymer platform to “flush,” which updates all UI elements.

This came in extremely handy when the test interacted with the Polymer element (e.g. adding a whole topping to the <x-pizza> element) and needed to ensure that all updates had taken place before checking expectations. To put James' hypothesis to the test, I change the flush() method to return nothing instead of a Future:
class XPizzaComponent {
  String get currentPizzaStateDisplay => // ...
  Future addWholeTopping(String topping) {
    // ...
    return flush();
  }
   void flush() {}
}
And, just as James had found my tests all still pass:
➜  dart git:(master) ✗ ./test/run.sh
#READY
CONSOLE MESSAGE: unittest-suite-wait-for-done
CONSOLE MESSAGE: PASS: [defaults] it has no toppings
CONSOLE MESSAGE: PASS: [adding toppings] updates the pizza state accordingly
CONSOLE MESSAGE: 
CONSOLE MESSAGE: All 2 tests passed.
CONSOLE MESSAGE: unittest-suite-success
CONSOLE WARNING: line 213: PASS
So what gives? This works just fine in both Dart 1.3 and 1.4 without worrying about asynchronous operations. How did that happen?

Well, it turns out that there is a little nod to the asynchronous nature of Polymer that is still implicit. The scheduled test library is running each of those schedules in separate event loops. And, when each schedule finishes, it allows the main Dart event loop to continue processing whatever else it needs to—like Polymer bound variables and platform flushes. I can verify this by removing all schedules from my setUp():
  setUp((){
    // schedule(()=> Polymer.onReady);

    // schedule((){
      _el = createElement('<x-pizza></x-pizza>');
      document.body.append(_el);

      xPizza = new XPizzaComponent(_el);
      // return xPizza.flush();
    // });

    currentSchedule.onComplete.schedule(() => _el.remove());
  });
With that, all tests fail:
➜  dart git:(master) ✗ ./test/run.sh
#EOF
#READY
CONSOLE MESSAGE: unittest-suite-wait-for-done
CONSOLE MESSAGE: FAIL: [defaults] it has no toppings
  Caught ScheduleError:
  | Expected: '{"firstHalfToppings":[],"secondHalfToppings":[],"wholeToppings":[]}'
  |   Actual: ''
  |    Which: is different. Both strings start the same, but the given value is missing the following trailing characters: {"firstHal ...

CONSOLE MESSAGE: FAIL: [adding toppings] updates the pizza state accordingly
  Caught ScheduleError:
  | Expected: '{"firstHalfToppings":[],"secondHalfToppings":[],"wholeToppings":["green peppers"]}'
  |   Actual: '{"firstHalfToppings":[],"secondHalfToppings":[],"wholeToppings":[""]}'
  |    Which: is different.
  | Expected: ... ppings":["green pepp ...
  |   Actual: ... ppings":[""]}
  |                         ^
  |  Differ at offset 66
CONSOLE MESSAGE:
CONSOLE MESSAGE: 0 PASSED, 2 FAILED, 0 ERRORS
CONSOLE MESSAGE: Uncaught Error: Exception: Some tests failed.
I can make that pass by adding either the original async()/flush() or the schedule for Polymer.onReady, but I do not need both. Even so, I think that I will likely wind up recommending both in Patterns in Polymer. It better mirrors the approach in the JavaScript Polymer. Also, I think they make conceptual sense.


Day #37

Wednesday, April 16, 2014

Never Forget the Polymer.dart Transformer (No Really, NEVER Forget It)


I thought to try to finish off the Strategy Pattern chapter in Patterns in Polymer tonight. Only when I loaded some “play” code in Dartium, I saw the following error in the console:
Exception: The "smoke" library has not been configured. Make sure you import and configure one of the implementations (package:smoke/mirrors.dart or package:smoke/static.dart).
#0      throwNotConfiguredError (package:smoke/src/implementation.dart:34:3)
#1      typeInspector (package:smoke/src/implementation.dart:26:5)
#2      query (package:smoke/smoke.dart:85:20)
#3      _getPublishedProperties (package:polymer/src/declaration.dart:409:31)
#4      PolymerDeclaration.publishAttributes (package:polymer/src/declaration.dart:175:39)
#5      PolymerDeclaration.buildType (package:polymer/src/declaration.dart:95:22)
#6      PolymerDeclaration.register (package:polymer/src/declaration.dart:72:14)
#7      _hookJsPolymer.registerDart.<anonymous closure> (package:polymer/src/loader.dart:100:75)
#8      _rootRun (dart:async/zone.dart:719)
#9      _ZoneDelegate.run (dart:async/zone.dart:453)
#10     _CustomizedZone.run (dart:async/zone.dart:663)
#11     _hookJsPolymer.registerDart (package:polymer/src/loader.dart:99:22)
Are. You. FREAKING. Kidding me?!

I specifically started tonight with writing so that I could get away from that stupid error. It is the same error that has plagued my testing efforts for the past two nights and now I am seeing it application code. Noooooo!

This was some relatively old Polymer.dart code that I am upgrading to the 0.10 version of the library. So I have already gone through it to tack on component=1 to the mime types so that the Dart VM will know to run all Polymer code in the same isolate:
<polymer-element name="store-changes-load">
  <template><!-- ... --></template>
  <script src="store_changes_load.dart"
          type="application/dart;component=1"></script>
</polymer-element>
I have already fixed the dependencies of my play application to use the appropriate bleeding-edge versions of the libraries in my pubspec.yaml file:
name: change_history
dependencies:
  polymer: ">0.10.0-pre"
  polymer_elements: ">0.2.0-pre"
dev_dependencies:
  unittest: any
So why, oh why am I still getting “smoke” package exceptions? Well, the title of this post pretty much gives it away: since this is old code, I have not specified a Polymer pub transformer in my Dart Pub configuration. If I add it to pubspec.yaml:
name: change_history
dependencies:
  polymer: ">0.10.0-pre"
  polymer_elements: ">0.2.0-pre"
dev_dependencies:
  unittest: any
transformers:
- polymer:
    entry_points: web/index.html
Then all of my Polymer code magically starts working.

And yup, if I go back to the pubspec.yaml from last night, add my test page to the list of files that are transformed by the Polymer transformer:
name: model_example
dependencies:
  polymer: ">=0.10.0-pre"
dev_dependencies:
  scheduled_test: any
transformers:
- polymer:
    entry_points:
    - web/index.html
    - test/index.html
Then my test magically passes.

Ah, life on the bleeding edge. Sometimes it does cut deep. But lesson learned: always include all pages using Polymer elements in the list of Polymer transformers—even test pages. I will never, NEVER forget that.


Day #36

Tuesday, April 15, 2014

Still Can't Test Polymer.dart


I cannot believe that I can no longer test Polymer.dart elements.

This was the very first chapter that I wrote in Patterns in Polymer and now it is completely broken. Not only that, I no longer have any way to automatically determine if the code for the other chapters in the book work. Not cool.

Fortunately, this is a pre-release version of Polymer.dart (0.10), so I can hope for one of two things: (1) the library authors address this to make it easier or (2) I can figure out how to make this work as-is. There is little that I can do for (1) aside from contact that authors, though I would prefer to understand things better first—I hate to bother folks if I can figure it out on my own with a little effort. I do try a pub update, but the most recent version of Polymer.dart (that matches ">=0.10.0-pre.7") is still the same 0.10.0-pre.9 that did not work for me last night.

So it looks like I need to investigate some more. Tonight, I follow the examples laid out in the Polymer.dart test directory. There are many tests in the package, though they include templates directly in the test page and the backing classes directly in the test code. This approach is of limited value when testing custom elements, but still it is a start.

So instead of importing the <x-pizza> element that I would like to test:
<head>
  <!-- Load Polymer -->
  <link rel="import" href="packages/polymer/polymer.html">

  <!-- Load component(s) -->
  <link rel="import" href="packages/model_example/elements/x-pizza.html">

  <script src="packages/unittest/test_controller.js"></script>
</head>
<body>
  <!-- The actual tests -->
  <script type="application/dart;component=1" src="test.dart"></script>
</body>
I instead pull the <polymer-element> from that source HTML directly into the <body> of my test page:
<head>
  <link rel="import" href="packages/polymer/polymer.html">
  <script src="packages/unittest/test_controller.js"></script>
</head>
<body>
  <polymer-element name="x-pizza">
    <template>
      <!-- Template code here... -->
    </template>
  </polymer-element>
  <polymer-element name="x-pizza-toppings">
    <template>
      <!-- Template code here... -->
    </template>
  </polymer-element>

  <!-- The actual tests -->
  <script type="application/dart;component=1" src="test.dart"></script>
</body>
There are actually two elements that comprise the element being tested, so I include both.

Then, in the test.dart file, I follow the Polymer.dart convention of defining the backing class directly in the test:
library x_pizza_test;

import 'dart:html';
import 'package:scheduled_test/scheduled_test.dart';
import 'package:polymer/polymer.dart';

@CustomTag('x-pizza')
class XPizza extends PolymerElement {
  // ...
}

@CustomTag('x-pizza-toppings')
class XPizzaToppings extends PolymerElement {
  // ...
}

@initMethod
main() {
  setUp((){
    schedule(()=> Polymer.onReady);
    // Other setup...
  });
  // Tests here...
}
With that, it still does not work:
Exception: Unhandled exception:
Exception: The "smoke" library has not been configured. Make sure you import and configure one of the implementations (package:smoke/mirrors.dart or package:smoke/static.dart).
#0      throwNotConfiguredError (package:smoke/src/implementation.dart:34:3)
#1      typeInspector (package:smoke/src/implementation.dart:26:5)
#2      query (package:smoke/smoke.dart:85:20)
#3      _getPublishedProperties (package:polymer/src/declaration.dart:409:31)
#4      PolymerDeclaration.publishAttributes (package:polymer/src/declaration.dart:175:39)
#5      PolymerDeclaration.buildType (package:polymer/src/declaration.dart:95:22)
#6      PolymerDeclaration.register (package:polymer/src/declaration.dart:72:14)
#7      _hookJsPolymer.registerDart.<anonymous closure> (package:polymer/src/loader.dart:100:75)
#8      _rootRun (dart:async/zone.dart:719)
#9      _ZoneDelegate.run (dart:async/zone.dart:453)
#10     _CustomizedZone.run (dart:async/zone.dart:663)
#11     _hookJsPolymer.registerDart (package:polymer/src/loader.dart:99:22)
Bother.

I need to keep working on the chapters in Patterns in Polymer that do work, so I call it a night here. Tomorrow, I will try working with simpler Polymer elements—like those in the Polymer.dart test suite (I may even try those tests directly). If that still does not work, the Polymer.dart tests mention a test_suite.dart file that I have not yet found. Perhaps the answers I seek can be found in that file.


Day #35

Monday, April 14, 2014

Can No Longer Test Polymer.dart Code


My tests are broken. Again. Time to fix my tests.

Actually, I have tests that have not passed for months at this point. Tonight, I am just going to fix the test that broke in the last 4 days (since I upgraded to Polymer.dart). Hmmm... this might not bode well for a solid test suite for Patterns in Polymer. I'll save that for another day. For now, I just want to get one Polymer element under test...

The first thing that I need to change is the no-longer-used initPolymer() from my test setup:
library x_pizza_test;

import 'package:scheduled_test/scheduled_test.dart';
import 'package:polymer/polymer.dart';


main() {
  initPolymer();

  // DOM element to hold test element
  PolymerElement _el;
  // Page object for better testing
  XPizzaComponent xPizza;

  // Tests here...
}
After deleting that line, I need another way to start the Polymer platform in my tests. In application code, this is now done with a <link> import, so I add that to the test page that holds my browser tests:
<head>
  <!-- Load Polymer -->
  <link rel="import" href="packages/polymer/polymer.html">

  <!-- Load component(s) -->
  <link rel="import" href="packages/model_example/elements/x-pizza.html">
  <script type="application/dart" src="test.dart"></script>
  <script src="packages/unittest/test_controller.js"></script>
</head>
With that, I get a nice failing test:
FAIL: [defaults] it has no toppings
  Caught ScheduleError:
  | Class 'HtmlElement' has no instance method 'async'.
  | 
  | NoSuchMethodError: method not found: 'async'
  | Receiver: Instance of 'HtmlElement'
  | Arguments: [Closure: (dynamic) => dynamic]
I think this is an indication that Polymer has not finished initializing when the test runs. The async() method on Polymer elements is something of a cure-all when it comes to dealing with the asynchronous nature of Polymer elements. It updates all observed variables in the associated Polymer and tells the polyfilled platform to flush—to process all queued UI updates. Since this is failing—and failing on an HtmlElement element instead of a PolymerElement—it seems likely that I need to wait for Polymer… to be ready.

I have to confess that I am unsure how to check for Polymer to be ready in Dart. In JavaScript, it is done by listening for a polymer-ready event, so I create a scheduled_test (unittest suped up for async) schedule to listen for polymer-ready:
main() {
  PolymerElement _el;
  XPizzaComponent xPizza;

  setUp((){
    schedule((){
      var _completer = new Completer();
      document.body.on['polymer-ready'].listen((_){
        _completer.complete();
      });
      return _completer.future;
    });
    // More setup...
  });
  // Tests here...
}
That seems to work. At least it changes the error message, which I count for progress.

The error message is now the Dart VM complaining about two main() entry points:
Dartium currently only allows a single Dart script tag per application, and in the future it will run them in separtate isolates.  To prepare for this all the following script tags need to be updated to use the mime-type "application/dart;component=1" instead of "application/dart":
​
Error: 

http://localhost:8081/:-1:
Only one Dart script tag allowed per document
Taking the advice the error message, I make my test part of the web component isolate with the mime type of application/dart;component=1:
<head>
  <!-- Load Polymer -->
  <link rel="import" href="packages/polymer/polymer.html">

  <!-- Load component(s) -->
  <link rel="import" href="packages/model_example/elements/x-pizza.html">
  <script src="packages/unittest/test_controller.js"></script>
</head>
<body>
  <!-- The actual tests -->
  <script type="application/dart;component=1" src="test.dart"></script>
</body>
That still does not work. The error message is now a baffling:
Exception: Unhandled exception:
Exception: The "smoke" library has not been configured. Make sure you import and configure one of the implementations (package:smoke/mirrors.dart or package:smoke/static.dart).
#0      throwNotConfiguredError (package:smoke/src/implementation.dart:34:3)
#1      typeInspector (package:smoke/src/implementation.dart:26:5)
#2      query (package:smoke/smoke.dart:85:20)
#3      _getPublishedProperties (package:polymer/src/declaration.dart:409:31)
#4      PolymerDeclaration.publishAttributes (package:polymer/src/declaration.dart:175:39)
#5      PolymerDeclaration.buildType (package:polymer/src/declaration.dart:95:22)
#6      PolymerDeclaration.register (package:polymer/src/declaration.dart:72:14)
#7      _hookJsPolymer.registerDart. (package:polymer/src/loader.dart:100:75)
#8      _rootRun (dart:async/zone.dart:719)
#9      _ZoneDelegate.run (dart:async/zone.dart:453)
#10     _CustomizedZone.run (dart:async/zone.dart:663)
#11     _hookJsPolymer.registerDart (package:polymer/src/loader.dart:99:22)
Ya know, if every time the library changes it takes me a hour of fiddling to get a single test passing, then I really have no hope of testing the Dart version of the book. But test I must, so...

I will have to pick back up with this tomorrow.



Day #34


Sunday, April 13, 2014

No Debugging Polymer


It pains me to admit this, but most of my debugging in Polymer is done in the venerable print STDERR style. If something is not quite working, I add print / console.log statement at the last known point in the code that I know is behaving and work from there.

I have gotten a lot of mileage from this style of debugging over the years, but recently have grown fond of the Chrome (and Dart) debugger. That said, there is much event debugging in Polymer that would be simplified if I could just watch all events play out as they happen.

Which is exactly what the logging flags in Polymer would seem to do. There are also debug flags, but I am not clear what they do. I'll check that out after the logging flags.

First up, I replace the regular Polymer libraries with the development versions. In my application's bower.json, I normally depend on the regular Polymer library:
{
  "name": "mdv_example",
  // ...
  "dependencies": {
    "polymer": "Polymer/polymer"
  }
}
So instead I manually install the development versions of Polymer and its associated platform with Bower:
$ bower install polymer=Polymer/polymer-dev platform=Polymer/platform-dev
bower polymer#*                 cached git://github.com/Polymer/polymer-dev.git#0.2.2
bower polymer#*               validate 0.2.2 against git://github.com/Polymer/polymer-dev.git#*
bower platform#*                cached git://github.com/Polymer/platform-dev.git#0.2.2
bower platform#*              validate 0.2.2 against git://github.com/Polymer/platform-dev.git#*
Then I fire up my application with some logging flags. It seems like this can be done within the application, in the URL, or on the script tag that loads the platform. I opt for the latter:
<script src="bower_components/platform/platform.js" debug log="watch,bind,ready"></script>
And, when I load my page…

I see nothing. There is no change in behavior or in the console log.

Looking at the installed bower_components I find that the original Polymer and platform packages remain unchanged. The -dev versions are installed alongside, but they have not replaced the original packages as I had expected. So I force the issue by removing the original and replacing them with the -dev versions:
$ cd bower_components
$ rm -rf platform
$ mv platform-dev platform
$ rm -rf polymer
$ mv polymer-dev polymer
And, with that, it still does not work. I see no debugging at all:



And I cannot figure this out. Am I missing something obvious or did this break? Hopefully some intrepid soul can point me in the right direction. Otherwise, print STDERR may continue to be my go-to solution.


Day #33

Saturday, April 12, 2014

Binding JSON to Polymer Attributes


So how do you pass list data into a Polymer element?

I was pretty darn certain that starting with a smaller <x-pizza-toppings> element in the model driven view chapter of Patterns in Polymer would be brilliant. And then I tried using it.

Adding it the page works just fine:



But this was originally meant to be a composable, internal-only element for use in a whole pizza builder element, <x-pizza>. To ensure that all topping elements (first half, second half, whole pizza) used the same list of ingredients, I created the list in <x-pizza>:
@CustomTag('x-pizza')
class XPizza extends PolymerElement {
  final List ingredients = [
    'pepperoni',
    'sausage',
    'green peppers'
  ];
  // ...
}
And then bound that variable to all instances of <x-pizza-toppings> in the corresponding template:
<link rel="import" href="x-pizza-toppings.html">
<polymer-element name="x-pizza">
  <template>
    <!-- ... -->
    <x-pizza-toppings id="firstHalfToppings"
                      name="First Half Toppings"
                      ingredients="{{ingredients}}"></x-pizza-toppings>
    <!-- ... -->
  </template>
  <script type="application/dart;component=1" src="x_pizza.dart"></script>
</polymer-element>
But how do you do that from the outside when you don't have a List, Array or Object? How can I bind a list of strings (the ingredients) to the ingredients attribute of <x-pizza-toppings>?

I may have found the answer by accident three nights ago. While fiddling with Polymer.dart JavaScript interoperablity, I found that the only way to make certain things work was to bind attributes as JSON instead of native programming types. Perhaps that will work here?
      <x-pizza-toppings
         ingredients="['pepperoni', 'sausage', 'green peppers']">
      </x-pizza-toppings>
And indeed that does work:



Cool! But does it work in the JavaScript version of Polymer as well? Yup:



It makes sense that Polymer would behave this way, but it is good to have confirmation. I cannot find any documentation for this behavior, but binding JSON seems a reasonable thing to do. And, since it behaves like this in both Dart and JavaScript, it seems safe to use this feature.

So, phew! I can finish off the MDV chapter rewrite without any further worries. Well, until I try the next easy thing...


Day #32