Saturday, August 30, 2014

A Package for Common Polymer Testing

I was unable to get polymer-test-tools to work well with a custom Polymer of my own. The effort was not completely wasted as I learned a ton. The most interesting thing that I learned is that I have some definite opinions on what ought to be included in a general purpose Polymer testing tool. Enough, possibly, to write my own.

My Polymer element setup usually looks something like:
├── test
│   ├── PolymerSetup.js
│   └── ClickSinkSpec.js
├── package.json
├── karma.conf.js
├── index.html
└── elements
    └── click-sink.html
I have my element(s) in the elements subdirectory, the tests in the tests subdirectory, a package.json that includes Karma and Jasmine dependencies and a Karma configuration file. Also of note is is that I have very specific test setup that goes into test/PolymerSetup.js to enable testing with Polymer.

For a first pass at a testing tool (generator? template? not sure yet?), I initialize a git and npm repository:
➜  repos  mkdir eee-polymer-tests
➜  repos  cd !$
➜  repos  cd eee-polymer-tests
➜  eee-polymer-tests  git init
Initialized empty Git repository in /home/chris/repos/eee-polymer-tests/.git/
➜  eee-polymer-tests git:(master) npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sane defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install  --save` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
name: (eee-polymer-tests)
version: (1.0.0) 0.0.1
description: Sane Polymer test setup (including generator)
entry point: (index.js)
test command:
git repository:
keywords: polymer testing karma jasmine
author: Chris Strom
license: (ISC) MIT
To build this up, I would like to slowly replace parts in my working tests with this NPM package. Unfortunately, I do not know how to do this quickly with NPM since it does not support local filesystem dependencies. Well, that's not entirely true, NPM does support npm link, but I am unsure how to get that to install dependencies.

And, in the case of eee-polymer-tests, I need to include karma-jasmine and karma-chrome-launcher as peer dependencies. I specify those in my package.json:
  "name": "eee-polymer-tests",
  // ...
  "peerDependencies": {
    "karma-jasmine": "~0.2.0",
    "karma-chrome-launcher": ">0.0"
As peer dependencies, these will be installed in my Polymer application the same as if I had listed them as direct dependencies (or development dependencies):
  "name": "parent-events",
  "devDependencies": {
    "karma-jasmine": "~0.2.0",
    "karma-chrome-launcher": ">0.0"
The only way I can get my Polymer application to honor my local package's peer dependencies—at least the only way that I can figure out tonight—is to add my local package as a pre-install script to my Polymer element's package.json:
  "name": "parent-events",
  "scripts": {
    "preinstall": "npm install /home/chris/repos/eee-polymer-tests/"
That actually seems to work:
$ npm install
> parent-events@ preinstall /home/chris/repos/polymer-book/book/code-js/parent_events
> npm install /home/chris/repos/eee-polymer-tests/
karma-chrome-launcher@0.1.4 node_modules/karma-chrome-launcher

karma@0.12.23 node_modules/karma
└── ...

karma-jasmine@0.2.2 node_modules/karma-jasmine

eee-polymer-tests@0.0.1 node_modules/eee-polymer-tests
$ ls node_modules
eee-polymer-tests  karma  karma-chrome-launcher  karma-jasmine
Most importantly, my Karma tests still pass:
karma start --single-run
INFO [karma]: Karma v0.12.23 server started at http://localhost:9876/
INFO [launcher]: Starting browser Chrome
INFO [Chrome 37.0.2062 (Linux)]: Connected on socket wzCHNN5LnCOMY2-V4ELH with id 70589859
Chrome 37.0.2062 (Linux): Executed 2 of 2 SUCCESS (0.068 secs / 0.061 secs)
Next up, I need to borrow from a trick I learned from polymer-test-tools. I need to move my common testing setup for karma into the NPM package, but still allow developers a means to override the common stuff. Directly from polyer-test-tools, I create karma-common.conf.js in the eee-polymer-tests NPM package:
exports.mixin_common_opts = function(karma, opts) {
  var all_opts = {
    //  Common settings go here...
  for (var key in opts) {
   all_opts[key] = opts[key];
  return all_opts;
The common setting are mostly the defaults from the Karma generator. The ones specific to my preferred Polymer testing setup include the testing framework to use:
    // frameworks to use
    frameworks: ['jasmine'],
A means to facilitate fixure loading if needed:
     * Compile HTML into JS so that they can be used as templates
    preprocessors: {
      'test/*.html': 'html2js'
And the list of files to include for testing or to serve (but not directly execute):
     * Don't include Polymer HTML and JS because Polymer is very
     * particular about the order in which they are added. Serve them,
     * but defer loading to the test setup. Include test HTML
     * fixtures.
    // list of files / patterns to load in the browser
    files: [
      {pattern: 'elements/**', included: false, served: true},
      {pattern: 'bower_components/**', included: false, served: true},
Back in my Polymer element, the karma.conf.js then becomes simply:
module.exports = function(config) {
  var common = require('./node_modules/eee-polymer-tests/karma-common.conf.js');

  config.set(common.mixin_common_opts(config, {
    // Specialization could go here, but none needed!
I do not need to override any of the default settings. Furthermore, I think the common options would likely suit just about any elements that I have created so far. Famous last words, I am sure.

Anyhow, trying it out, I find:
$ karma start --single-run
ERROR [config]: Error in config file!
 { [Error: Cannot find module './node_modules/eee-polymer-tests/karma-common.conf.js'] code: 'MODULE_NOT_FOUND' }
Error: Cannot find module './node_modules/eee-polymer-tests/karma-common.conf.js'
    at Function.Module._resolveFilename (module.js:338:15)
This is a definite drawback to the pre-install NPM approach. I have to re-install each time I want to try something new. That is going to be a pain if I need to debug often. Perhaps if that is the case, I can try a hybrid approach that first installs dependencies, but then npm-links my local package. Food for thought another day.

For now, I re-install:
$ rm -rf node_modules
$ npm install
eee-polymer-tests@0.0.1 node_modules/eee-polymer-tests
With that:
karma start --single-run
INFO [karma]: Karma v0.12.23 server started at http://localhost:9876/
INFO [launcher]: Starting browser Chrome
INFO [Chrome 37.0.2062 (Linux)]: Connected on socket Q1jxhuNWJtv6SKmi2C2L with id 12087020
Chrome 37.0.2062 (Linux): Executed 2 of 2 SUCCESS (0.057 secs / 0.051 secs)

I now require only a single testing dependency and zero configuration. That may not be completely reusable by others, but it does afford a certain amount of configuration thanks to the approach from the polymer-test-tools project. Regardless, it is a good start and will help me very much in my efforts to test the remainder of the elements in Patterns in Polymer.

I have not saved myself any files required for testing. I may or may not be able to include the PolymerSetup.js directly in eee-polymer-tests. I have been including the <link> import of the element definition under test in PolymerSetup.js. It is possible that I can move the import elsewhere, but that will take some experimentation. I will always need the equivalent of ClickSinkSpec.js. Now that I think about it, both could be generated from a script in eee-polymer-tests.

I will work on that tomorrow.

Day #168

No comments:

Post a Comment