Binding a DOM element to an observable using Knockout.js

I’ve been doing a bit of experimenting with Knockout.js recently. Having written quite a bit of .NET code over the years, I am very used to thinking in (and I prefer thinking in) the MVVM pattern when it comes to UIs, and so Knockout.js is nice.

And, as always, when writing code and living in the real world you sometimes need to do things that do not quite fit the pattern. In this case, I needed to draw on a canvas from my view model whenever some observables on it changed. The pragmatic thing to do when you need to draw on a canvas is to just grab the canvas by ID or whatever, but since this canvas lived in a template, identifying it through selectors quickly got messy (and hard).

Binding to it seemed like a much better idea, so I created the simple element Knockout.js binding. This is a one-way-to-source binding (.NET guys will be familiar with this terminology), meaning that the binding only writes to the view model from the view. In addition, the binding only does this once (when it is initialized), as the element will stay for the lifespan of the page.

So, in all its glory, here is my Knockout.js element binding:

ko.bindingHandlers.element = {
    init: function(element, valueAccessor) {
      var value = valueAccessor();
      value(element);
    }
};

Use it as you would any other binding:

<canvas width="100" height="60" data-bind="element: yourObservable"></canvas>

Simple as that. Now go use it!

Introducing JSUT – Cross-platform JavaScript Unit Testing

I write quite a bit of JavaScript these days, and one observation I have made with regards to Line-of-Business apps is that platforms like Node.js makes me lean more towards sharing business logic between the server and client side (meaning Node.js and the browsers, in practice). This creates an immediate need to unit test “universally” (across all platforms and environments), and I couldn’t find a single tool that quite did it for me.

JSUT (JavaScript Unit Testing) is an attempt at making such a tool for fun and profit (non-monetary).

JSUT stems from me growing tired of the hurdles of unit testing my JavaScript code. There are tons of alternative unit testing tools and libraries readily available, but my experience was that they all exhibited one or more of the following shortcomings:

  • Imposing a “framework” or “philosophy” or “style” on my tests
  • Bringing me additional dependencies to worry about
  • Working only in the browser or inside Node.js

In addition, I feel that many of the available tools and libraries are either undermaintained or overly featureful, and buggy and/or painful to use as a result of one or both of those. I can’t and won’t claim that this will be different in the case of JSUT, so it’s not really an argument, but more a motivation for me.

Goals

I sat down and wrote a few goals for JSUT:

  • Universal, cross-platform
  • Minimalistic, simple, non-constraining
  • Accessible

I then took to writing code and brushing up my rather rusty shell scripting skills, and a few hours later I wound up with what I present to you now.

JSUT – JavaScript Unit Testing – An introduction

Writing a test in JSUT is about as simple as it can get. You write a function:

function myTest(test) {
  // JSUTs only requirement:
  // Call test.done() when the test is done
  test.done(); 
}

Now, let’s say you save this function to a file called test.js. You can then move to your preferred shell and write the following:

jsut -b chrome test.js

This will run your test in Chrome. To run your test in Node.js, do:

jsut -n test.js

You can combine the -b and -n flags any way you like, of course.

Getting JSUT

Getting JSUT is very simple. Assuming you have npm, just do:

npm install jsut

Which will install jsut locally. If you want a global installation, issue:

npm install jsut -g

Of course, with the goals for JSUT, you can also just download and copy deploy JSUT. Visit http://github.com/havard/jsut for source code and further instructions.

Requirements

As mentioned in the above sample, the only requirement JSUT imposes on you is to call test.done() when your test is done. Obviously, this seems redundant for the simple case of a synchronously executing function, but since most JavaScript functions these days are asynchronous at some level, there has to be a way to tell JSUT that a test is done. I am actively considering easing this requirement for simple cases, but this has not been a priority so far.

For Node.js, you are required to add the functions you want to test to the exports of each test file. Building on the example above, you can maintain cross-platform compatibility by doing the following:

if (typeof(exports) !== 'undefined') {
  exports.myTest = myTest;
}

This will add exports only if the exports variable is defined. Now, if you wanted to run your test in Node.js, you simply do:

jsut -n test.js

This will run your test in Node.js. You are free to combine the -n and -b flags any way you like, so that you can target all required platforms with a single command.

Assertions

JSUT automatically injects a CommonJS compatible assert module in your browser tests, so you can write stuff like assert.ok(true); anywhere in your test.

Planned features

JSUT currently only runs browser tests on OS X. I plan to support Linux and Windows as soon as possible. Follow me and JSUT on GitHub!

How to combine Git, Windows, and non-ASCII letters

The default Git installation in Windows works really bad if you’re using cmd.exe and have non-ASCII letters in your commit information and/or code.

Thankfully, Git is highly configurable, and the fix is rather easy:

  1. Set i18n.commitencoding to the codepage you’re on in cmd.exe (I’m on windows-1252)
  2. Set i18n.logoutputencoding to the same codepage.
  3. Set the LESSCHARSET environment variable to a proper name for the code page you’re on (I’m on latin1), either by:
    • Adding a user environment variable in Control Panel > System and Security > System > Advanced System Settings > Advanced > Environment Variables..., or…
    • Setting it your cmd.exe session (e.g. set LESSCHARSET=latin1)

Boilerplate version for your copy-paste convenience (replace encodings as necessary):

git config --global i18n.commitencodig windows-1252
git config --global i18n.logoutputencoding windows-1252
set LESSCHARSET=latin1

The first setting tells Git how your commit messages, including your author information, are encoded. The second tells Git what encoding it should use when writing output from a command like git log. The third and final setting tells less, the pager that Git runs git log output through, what encoding to use.

Diffie-Hellman support in Node.js

Yay! My patch implementing support for Diffie-Hellman key exchange in Node.js has finally been merged into the Node.js master branch. This will simplify the OpenID for Node.js codebase a lot. It will also make the OpenID association phase run a lot faster, since the current code does Diffie-Hellman in Javascript while the Node.js crypto version does it all in native code using OpenSSL.

A brief API overview:

  • crypto.createDiffieHellman(prime_length)
    • Creates a Diffie-Hellman key exchange object and generates a prime of the given bit length. The generator used is 2.
  • crypto.createDiffieHellman(prime, encoding='binary')
    • Creates a Diffie-Hellman key exchange object using the supplied prime. The generator used is 2. Encoding can be 'binary', 'hex', or 'base64'.
  • diffieHellman.generateKeys(encoding='binary')
    • Generates private and public Diffie-Hellman key values, and returns the public key in the specified encoding. This key should be transferred to the other party. Encoding can be 'binary', 'hex', or 'base64'.
  • diffieHellman.computeSecret(other_public_key, input_encoding='binary', output_encoding=input_encoding)
    • Computes the shared secret using other_public_key as the other party’s public key and returns the computed shared secret. Supplied key is interpreted using specified input_encoding, and secret is encoded using specified output_encoding. Encodings can be 'binary', 'hex', or 'base64'. If no output encoding is given, the input encoding is used as output encoding.
  • diffieHellman.getPrime(encoding='binary')
    • Returns the Diffie-Hellman prime in the specified encoding, which can be 'binary', 'hex', or 'base64'.
  • diffieHellman.getGenerator(encoding='binary')
    • Returns the Diffie-Hellman prime in the specified encoding, which can be 'binary', 'hex', or 'base64'.
  • diffieHellman.getPublicKey(encoding='binary')
    • Returns the Diffie-Hellman public key in the specified encoding, which can be 'binary', 'hex', or 'base64'.
  • diffieHellman.getPrivateKey(encoding='binary')
    • Returns the Diffie-Hellman private key in the specified encoding, which can be 'binary', 'hex', or 'base64'.
  • diffieHellman.setPublicKey(public_key, encoding='binary')
    • Sets the Diffie-Hellman public key. Key encoding can be 'binary', 'hex', or 'base64'.
  • diffieHellman.setPrivateKey(public_key, encoding='binary')
    • Sets the Diffie-Hellman private key. Key encoding can be 'binary', 'hex', or 'base64'.

NOTE: The API is still subject to change.

I would appreciate getting a note if you actually do something useful with it. :) Play around with it and let me know what you think!

Mocking HtmlHelper in ASP.NET MVC 2 and 3 using Moq

Still having trouble mocking HtmlHelper? This is an update to my previous post on mocking HtmlHelper way back when ASP.NET MVC RC1 was released. Eric notified me through a comment on the post and a question on StackOverflow that the code for ASP.NET MVC RC1 did not work with ASP.NET MVC 2. The code in this post should work with ASP.NET MVC 2 and ASP.NET MVC 3 Preview 1.


public static HtmlHelper CreateHtmlHelper(ViewDataDictionary vd)
{
    Mock<ViewContext> mockViewContext = new Mock<ViewContext>(
        new ControllerContext(
            new Mock<HttpContextBase>().Object,
            new RouteData(),
            new Mock<ControllerBase>().Object),
        new Mock<IView>().Object,
        vd,
        new TempDataDictionary(),
        new Mock<TextWriter>().Object);
    var mockViewDataContainer = new Mock<IViewDataContainer>();
    mockViewDataContainer.Setup(v => v.ViewData)
        .Returns(vd);
    return new HtmlHelper(mockViewContext.Object,
                            mockViewDataContainer.Object);
}