Monday, September 1, 2014

Postinstall NPM Scripts with Output in the Working Directory

After last night's efforts on eee-polymer-tests, I can wipe my current Polymer (JS) testing install (NPM packages, tests, setup, and Karma config), install, generate new test setup, and run passing tests:

That is going to be a huge help as I work through the remainder of Patterns in Polymer, adding tests to any book code that do not already have them. But there are still a couple of outstanding issues that I would like to knock off first. One of them is more an annoyance, but it will have to be dealt with: the small sample test tends to be so small that the Karma tests don't fully initialize Polymer before running, causing errors. Another problem is that I have not really accounted for the pre-existence of any of the generated files. The last problem is that I never seem to remember to run the generator manually.

I think I will work the problems in reverse order, since the last two are somewhat related by virtue of being NPM code. I can solve the last problem by making the script part of the install, which is done with one of the package lifecycle hooks in NPM. In this case, I make my eee-polymer-tests/generator.js script a post-install script:

But there is no STDIN as part of a lifecycle script. I need a way to block for input. For that, I make use of the experimental Readline. Readline needs access to both input and output in order to read input and prompt for it:

Once I have my answer, I assign it to a global element variable for use in the templates being generated. After my generator does its thing, I tell the user that everything is ready and close the readline object.

And that works great. My generator is run after install and all of the code is generated correctly. Except...

It installs the generated code in the node_modules/eee-polymer-tests subdirectory instead of in the directory from which I called npm install. The whole point of this testing setup is to generate sane defaults and structure for my Polymer elements. So I need Jasmine tests and Karma configuration directly inside my Polymer elements—not inside the node_modules directory.

I am unsure if there is a proper way to get this working, but I solve it by checking the process.cwd() and then changing directories if this is being run from node_modules/eee-polymer-tests:

if (/node_modules\/eee-polymer-tests/.test(process.cwd())) {
// Need to run the generator from the element package, not from the
// installed node module
process.chdir('../..');
}

And that does the trick. Now I can go from a clean Polymer install to passing tests with a single command:

I still need to decide how to deal with pre-existing files of the same name as those being generated. I thought I had a good idea how to do that, but got mired in details tonight. Hopefully approaching it fresh will resolve things tomorrow. Then I need to see if I can resolve the spurious first run test failure in the generated code. That will no doubt be annoying and tedious since it does not happen all the time. If I am very lucky, I will have a brain wave that makes me understand why that happens and how to fix it. But I leave both tasks for another night.