Post navigation

Unit testing is something every developer agrees should be done, but often doesn’t do. Setting it up isn’t hard after reading and evaluating what feels like a 7 course meal of modules that need to come together hand in hand to allow you to write some tests. It is fairly easy after you’ve learned more than you ever wanted to know about unit testing. Not easy at all, so I’m going to distill a stack down here for you. This is just one of many possible combinations, but when you’re just trying to get started the best solution is the one you pick and stick too first.

What is in the stack?

Much of the problem with getting started is the friction of deciding which modules you want, which work well together, and did you make the right choice of technology. Don’t stress about it, any finished stack will work well. This stack is comprised of several technologies, the app framework is replaceable. For this post I will connect a JavaScript app using RequireJS to the test runner Mocha through the PhantomJS headless browser and asserted with Chai. I’m also using Backbone and MarionetteJS to illustrate frameworks in testings too.

Setup

Serving the App for Testing

In order to run testing the application will need to be hosted and accessible locally through a web browser. If you’ve already got a solution for hosting your files locally you can skip this step. For the purposes of this tutorial and testing we’ll install http-server using the command npm install http-server -g. You can spin up a server on port 8080 now by just typing http-server app from the test folder. The “app” parameter in this case is the folder where the server root will be. Point your browser to http://localhost:8080 and you should see a file listing for the folder you specified.

Collecting Dependencies

We’ll be using npm and Bower to bring in dependencies for this project. After getting npm installed you’ll want to install bower and the grunt-cli globally by running this command npm install bower grunt-cli -g. You can pull down the entire working testing application from a GitHub repository I created called requirejs-unit-testing-mocha. I had started to put each file and contents in the body of this post but it got out of hand very quickly. The gist of it is that once you clone this repo you’ll need to run npm install and bower install from the root directory of the project.

Verify the Setup

Once you’ve cloned the repo, run npm install and bower install you should be able to start the http-server pointing to the app folder. Once the server is running run grunt mocha and you should see three green tests as passed. Next we’ll go over how everything has been connected.

Wiring it up

Executing the Tests

The grunt task setup in gruntfile.js is much less complex than it may seem. The meat of the task is in the command on line 11 which is running the npm module mocha-phantomjs which loads up our tests in the PhantomJS headless browser.

Loading the Test Suite in the Browser

Loading up the all the tests is just as you’d imagine running your site would be. All the dependancies are included in the index file under our tests folder. Here we add in Mocha, Chai, all the Sinon files, and the RequireJS startup file. Important notes here are the global declaration of expect and should on line 37 for later usage as well as setting the RequireJS baseUrl on line 51 which allows the included files to work as expected.

Including the Tests

The main file loaded by the test page is mochaRunner.js which includes all the tests we have for the project. The core function is what starts up the tests, either through mocha-phantomjs or just mocha if you load it in a regular browser. At this point everything needs to be ready, so the dependency list here starting on line 3 is where you include every test file you make. A tip here is to also include any other dependancies first before you list the test files out.

Writing Tests

Test file naming

I’ve written up one test spec file in basicTest.spec.js. Each test file follows a .spec.js extension convention. This extension isn’t required but tests files tend to be made in the same name as the JavaScript file they are testing so this extra spec tail makes them easy to differentiate. You should note right now that I haven’t followed this convention in this example test spec, which now should help you remember the right way! This file should be named sample.spec.js. Putting the entire test suite in a subfolder this way also allows for easy exclusion during releases and deployments.

Test setup

Each set of tests starts with a describe block taking a description parameter that helps to organize the output and group tests that have similar buildup and teardown experiences. The before and after functions happen before and after all the tests in the describe block are completed. Similarly the beforeEach and afterEach functions happen before and after each of the individual it assertions happen.

Assertions

Each it block is a single assertion to test one piece of functionality, a single unit, hence the name unit tests. Each it block expects to end with a Chai assertion. In my examples I use should.contain and should.equals. You can use any style of assertions, but it helps to stick to a single style in a project.

Stubbed assertion

Once you’ve included a dependacy you might need to make it respond how you want, or listen for something to have been called. This is where stubbing comes in and SinonJS starts helping out. Line 42 starts a unit test where I’ve created a stub of my show function and returned an arbitrary object instead. Note that after you stub something you should restore it as well!

Asynchronous Assertions

Not all tests can be asserted immediately but need to be asserted on a following event in the JavaScript call stack. To facilitate this you pass in a function variable to your it function named done. You can then call done() explicitly in a callback or promise return to let the mocha runner know you’ve finished the test assertions.

Where to go from here

This post covers a lot, much more than I planned. If you didn’t already have knowledge of all the tools used it might have been more daunting, but it is worth sticking to it. This is something you only have to setup a few times. Once it works you can just write tests and enjoy the benefit of them as your project and team grows. This isn’t all there is to testing but it should get you going or fill a missing gap of knowledge in getting started on testing your project.

I looked into Marked at first, and found the extension support difficult to the point where I ended up forking it to rewrite some functions to allow for the creation of new rules at the cost of a couple hundred milliseconds. I was planning on making it a marked wrapper in the end, but after some team discussion we decided to try another parser out. Remarkable had only recently been released at the time but development was moving quickly, it passed the CommonMark test suite, and seemed to fit a more modern style of JavaScript writing. It also was faster than Marked, though I haven’t fully understood how, even after reading the code for quite a while. It also obviously supported extensions, addition and manipulation of rules that would be far easier to handle and maintain than an entire fork. There were no clear examples on how to create new plugins or extensions for Remarkable though. So having worked on creating some and having a measure of success it is time to share the knowledge.

A Simple Extension: Open Links in a New Window

The simplest ways of modifying the Markdown parser is to change the rendered output. Open up the rules file from the Remarkable source and search for the current rule renderer you want to modify. In this case we are looking for link_open. That is what we want to extend to add our own code, note the output string is the first part of a complete anchor tag. These rules are exposed through a property named renderer on a new Remarkable object.

Through a bit of JavaScript closure we have saved off the original link_open function as the variable original which we then use to get the normal Remarkable anchor tag output. Then we append our target property to open all links in new windows. This function replaces the one on our current instance of the Remarkable object. For my purposes I have extended a single Remarkable object and reuse it throughout my application.

Another Simple Extension: Adding Images to Lighbox

This is another rule rendering extension example where we want to include any Markdown images into a lightbox. The lightbox library I use looks for anchor tags with a data-lightbox attribute wrapping an img element. Again we look into the rules file from Remarkable and find the rules.image is the renderer we want to extend to add this functionality.

We’ve had to do a bit more work here since the anchor tags href is a link to the image used by the lightbox library. This exposes a little of the Remarkable inner workings. We get an array of tokens, and our current index that we can use to get information gathered in earlier steps. Specifically we want to get the image src. We leverage the existing Remarkable utility functions exposed in the utils property to get a safe href string. Then we get the original image function output, and return it wrapped in our new anchor tag.

A True Remarkable Plugin

Remarkable has a use function to include new plugins. The architecture isn’t well documented however, and this requires a great deal more work. By no means am I suggesting my example is the best practice, but it does work. Use expects a function that takes the current Remarkable instance, and an optional options parameter. This function assigns adds itself to the rules list and to the parsing functionality. So far we’ve only looked at rendering. The parser goes character by character to match a complex rule set. For example to you can add emphasis to text by using asterisks or underscores. The emphasis parser looks for a sequence of either, but not exceeding 3 characters, then continues down the string it has been given looking for a matching closing sequence of characters. This type of code isn’t often seen outside of parsers so may look alien.

Lets make a smiley emoticon plugin as an example. We’ll define the syntax as a colon followed by an exclamation mark followed by a colon :!:. That markdown will be rendered as a smiley GIF. Our parser function will check each character in the sequence to make certain we finish a completed smiley before adding it to the token list to be rendered.

Making our renderer is much more straight forward. The render will be called when the token comes back up in the rendering process. The render function we create will pass back the string to be rendered. The check you see at the end for options.xhtmlOut is to comply with the Remarkable option for outputting XHTML.

This is just scratching the surface of writing plugins for Remarkable, and writing a parser in general. The smiley example above is an inline rule, there are also block and core rules. Hopefully these examples get you started and you can come up with new and creative ways to extend Remarkable and Markdown syntax to suit your own needs.

Cross-platform mobile web development is heating up and the the performance level is continuing to increase as new an more powerful devices are released. One of the allures to this style of mobile development is the single code base you can use across multiple platforms. With wrappers like Cordova and modern web frameworks you can get up and running super quick, but you incur a technical debt in debug time that you won’t know you need until it breaks in an unexpected way. It will break if you work on a sufficiently complex application.

When you start in cross-platform you’re probably thinking about hitting the most devices possible with the least amount of development time. Google reports, as of this posting, that Ice Cream Sandwich and KitKat account for 17.7% of Android installs (http://developer.android.com/about/dashboards). Those devices have it easy because they are coming with Chrome for Android installed. Chrome for Android features the future of debugging mobile web applications with the new remote debugger you can read about https://developers.google.com/chrome-developer-tools/docs/remote-debugging. That is wonderful for the future, but the other 82.3% of devices don’t get this new browser, and that means you don’t get those fancy new debugging features.

The first option for debugging on Android is a hosted JavaScript file that is served by a tool called Weinre. The quick way to give Weinre a try is to use the version hosted by PhoneGap at http://debug.phonegap.com. Just load up the script on that page in your app, but you’ll have to use Safari, Chrome didn’t work for me though it did for my colleague. Again poor planning for the extra Android debug efforts lead to confusion and short patience. From here you can see current CSS, DOM and execute JavaScript, but you can’t set any breakpoints. It is very slow, think slower to use than the Android ARM emulator is, and will cause frustration for developers.

Another option that you can use is jsHybugger which is an instrumentation library. This is the solution for proper JavaScript debugging, but the instrumentation does change your code when enabled and deployed to your device. I was personally met with race conditions when the JavaScript files were loaded in a large application and felt uneasy about relying on it for accurate debugging. We suffered from the same poor planning I am advising you don’t do in your project. By the time we needed to debug the app our patience was short, and we didn’t give it enough time or planning.

In the end, to debug your cross-platform mobile web application I would use a combination of both jsHybugger and Weinre. When you start your project and are thinking about all the speed of development improvements just don’t forget about debugging your program. You’ll want to allow for more time debugging your application on Android than you would on iOS. Eventually this won’t be as much of an issue, and it isn’t an issue at all of you only support Chrome for Android, but for now you’ll need to work with more than one debugging solution to deploy a successful cross-platform mobile web app.