Anders Tornblad

All about the code

Label archive for lbrtw

Phenomenal & Enigmatic, part 3

When I made Phenomenal & Enigmatic, I didn't want to reuse any of the graphics art from the original demo. I had decided to take the music and some sense of the overall demo design, but didn't want to infringe on the original graphics artist's creativity, so for the Enigmatic logo, I turned to rendering the logo using code.

Enigmatic logoOne popular technique of creating good-looking logos back in the Amiga days was to first draw the logo flat, then duplicating it in a new layer a few pixels off, making that new layer translucent. Then one would paint in side surfaces and edge lines with varying levels of opacity. After adding some final touches, like surface textures or lens flares, the end result would be a glossy, glassy look, much like the original Enigma logo by Uno of Scoopex.

Enigmatic logoThe logo scene uses the same technique, painting the front, back and sides of the word ENIGMATIC as filled polygons with slightly different colors and opacity levels. During the scene, I animate some of the transformation vectors for effect. Of course, the original artwork by Uno is much better in exactly every way, but it was a fun exercise.

Pseudocode

function transformLogoCoord(chapterId, time, x, y) {     // Left out: Perform a simple coordinate transformation     return { x : transformedX, y : transformedY }; }   function logoMoveTo(chapterId, time, x, y, xOffset, yOffset) {     var coords = transformLogoCoords(chapterId, time, x, y);     context.moveTo(coords.x, coords.y); }   function logoLineTo(chapterId, time, x, y, xOffset, yOffset) {     var coords = transformLogoCoords(chapterId, time, x, y);     context.lineTo(coords.x, coords.y); }   function renderLogo(chapterId, time) { var xOffset, yOffset;     // Left out: Calculate xOffset and yOffset from the chapterId and time values         // Draw bottom surfaces     context.beginPath();     for (var block, i = 0; block = logoPolygons[i++];) {         logoMoveTo(chapterId, time, block[0].x, block[0].y, 0, 0);         for (var coord, j = 1; j = block[j++];) {             logoLineTo(chapterId, time, coord.x, coord.y, 0, 0); }         logoLineTo(chapterId, time, block[0].x, block[0].y, 0, 0);     }     context.closePath();     context.fill();         // Left out: draw side surfaces         // Left out: draw top surfaces }

Phenomenal & Enigmatic, part 1
Phenomenal & Enigmatic, part 2
Phenomenal & Enigmatic, part 3 (this part)
Phenomenal & Enigmatic, part 4

The entire demo, including non-minified JavaScript, is available on GitHub: /lbrtw/enigmatic

Phenomenal & Enigmatic, part 2

Stars and text intro

Stars and text Enigma screendumpThe opening scene of Enigma by Phenomena starts out looking like an average side-scrolling star parallax, which was very normal in 1991. Nice way to lower people's expectations. :) But after just a couple of seconds, the stars begin twisting and turning in space around all three axes.

Back in 1991 I knew how to rotate a plane around the origo, by simply applying the angle sum identities of Sine and Cosine. I also realized that rotating any 3D coordinate in space could by done by simply the case of rotating around more than one axis, one axis a time.

Stars and text screendumpIn the Phenomenal & Enigmatic demo, I only rotate the stars around two axes. First I rotate the (x,z) components around the Y axis to get (x',z'), and then the (y,z') components around the X axis to get (y',z''). I also translate each star along the X axis before the rotation takes place. To finally get the 2D screen coordinates of the 3D space coordinate, I take the (x',y') coordinate and multiply by (2/(2+z'')) for a pseudo-distance feel. The z'' value controls both the color alpha component, and the size of the rectangle being drawn.

The even better way of doing this is through vector addition and multiplication, but I'm sticking to the math that I know. :) After all this math is in place, the trick is to change the offset and rotation variables in a nice way.

Rendering text is just a couple of calls to the context.fillText method and animating the value of context.globalAlpha.

Pseudo code

// Prefetch sin and cosine of angles var cosY = Math.cos(yAngle); var sinY = Math.sin(yAngle); var cosX = Math.cos(xAngle); var sinX = Math.sin(xAngle);   for (var star, i = 0; star = stars[i++]; ) {     // Fetch x, y, z and translate x     var x = star.x + xOffset;     var y = star.y;     var z = star.z;         // Limit x to [-1 .. 1]     while (x > 1) x -= 2;     while (x < -1) x += 2;         // Rotate (x, z) around Y axis     var x2 = x * cosY + z * sinY; // x'     var z2 = z * cosY - x * sinY; // z'         // Rotate (y, z') around X axis     var y2 = y * cosX + z2 * sinX; // y'     var z3 = z2 * cosX - y * sinX; // z''         // Transform to screen coordinates     var screenX = x2 * 2 / (2 + z3) * halfScreenWidth + halfScreenWidth;     var screenY = y2 * 2 / (2 + z3) * halfScreenWidth + halfScreenHeight;         // Draw the star     context.fillRect(screenX, screenY, 2 - z3, 2 - z3); }

Phenomenal & Enigmatic, part 1
Phenomenal & Enigmatic, part 2 (this part)
Phenomenal & Enigmatic, part 3
Phenomenal & Enigmatic, part 4

The entire demo, including non-minified JavaScript, is available on GitHub: /lbrtw/enigmatic

Phenomenal & Enigmatic, part 1

Twenty-two years ago, the Amiga demo scene was extremely active. The boundaries of the little 16-bit miracle machine were stretched a little bit more for each new release, and a special breed of programmers was created. We loved efficient algorithms, we enjoyed squeezing out as much as possible from every CPU clock cycle, and we really liked showing off to each other.

Back then, I was a decent 68000 assembler programmer, but nowhere near being among the greatest. I knew my way around the Copper and the Blitter, I knew how trigonometry and vector mathematics worked for creating 3D worlds, and I understood that the "shadebobs" effect on the Amiga was nothing more than repeated half-adders with carry, using the "Fat Agnus" chip's dedicated memory block manipulation instruction set.

My favorite demo from 1991 was Enigma by Phenomena, programmed by Olof "Azatoth" Lindroth, with music by the amazing Jimmy "Firefox" Fredriksson and Robert "Tip" Österbergh. The combination of music and direction with some really good programming set a new standard for demos on the Amiga.

First attempt

About four years ago, I started replicating the Enigma demo in C# and Silverlight 2, just as a side-project. I got as far as the opening scene and the "TV Cube" effect, which I must say I really nailed! But then I grew tired of the effort, and put the whole project aside. It just wasn't rewarding enough, but I did re-awaken some of my old "hacking the bare metal" programming skills.

Come 2013

For the last couple of weeks, I've been working from scratch, exploring what is possible using just a HTML5 AUDIO element, a CANVAS element, and a truck-load of JavaScript. Instead of trying to recreate the exact Enigma experience, I "borrowed" the amazing music, and did something of my own, inspired by Enigma.

I'll write a bit about each scene in the following weeks, but for now you're welcome to check out the fruit of my effort at demo.atornblad.se/enigmatic

Links

Phenomenal & Enigmatic, part 1 (this part)
Phenomenal & Enigmatic, part 2
Phenomenal & Enigmatic, part 3
Phenomenal & Enigmatic, part 4

JavaScript unit test framework, part 4

This is the last part of the first subject – my JavaScript unit test framework. The last thing I'm adding are just some extra bells and whistles:

  • Pluggable output system, using custom events

New requirements

  1. Events should be triggered on the window object at key points in time
    • When run() is called, the lbrtwUtEngineStarting event should be triggered
    • Before running one unit test, the lbrtwUtTestStarting event should be triggered
    • After running one unit test, the lbrtwUtTestEnded event should be triggered
    • After running the last unit test, the lbrtwUtEngineEnded event should be triggered
    • The lbrtwUtEngineStarting event object should contain the testCount property
    • The lbrtwUtTestStarting event object should contain the testName and testIndex properties
    • The lbrtwUtTestEnded event object should contain the testName, testIndex, testSuccess, testErrorMessage, testCount, successCount and failureCount properties
    • The lbrtwEngineEnded event object should contain the testCount, successCount, failureCount, testNames and failures properties

Tenth requirement

When testing for events being thrown to the window, it is important to clean up after oneself by removing all event listeners. These are the tests:

engine.add("Calling run() should trigger the lbrtwUtEngineStarting event once", function(testContext, the) { // Arrange var eng = new ut.Engine(); var triggered = 0; var onStarting = function(event) { window.removeEventListener("lbrtwUtEngineStarting", onStarting, false); triggered++; }; window.addEventListener("lbrtwUtEngineStarting", onStarting, false);   // Act testContext.actAndWait(100, function() { eng.run(); }).   // Assert thenAssert(function() { the(triggered).shouldBeExactly(1); }) });   engine.add("The lbrtwUtEngineStarting event object should contain testCount", function(testContext, the) { // Arrange var eng = new ut.Engine(); eng.add("a", function() {}); eng.add("b", function() {}); var testCount; var onStarting = function(event) { window.removeEventListener("lbrtwUtEngineStarting", onStarting, false); testCount = event.testCount; }; window.addEventListener("lbrtwUtEngineStarting", onStarting, false);   // Act testContext.actAndWait(100, function() { eng.run(); }).   // Assert thenAssert(function() { the(testCount).shouldBeExactly(2); }) });   engine.add("lbrtwUtTestStarting event should be triggered once per unit test", function(testContext, the) { // Arrange var eng = new ut.Engine(); var triggered = {}; var triggeredByIndex = []; eng.add("a", function() {}); eng.add("b", function() {}); var onTestStarting = function(event) { triggered[event.testName] = (triggered[event.testName] || 0) + 1; triggeredByIndex[event.testIndex] = (triggeredByIndex[event.testIndex] || 0) + 1; }; window.addEventListener("lbrtwUtTestStarting", onTestStarting, false);   // Act testContext.actAndWait(100, function() { eng.run().then(function() { window.removeEventListener("lbrtwUtTestStarting", onTestStarting, false); }); }).   // Assert thenAssert(function() { the("a").propertyOf(triggered).shouldBeExactly(1); the("b").propertyOf(triggered).shouldBeExactly(1); the(0).propertyOf(triggeredByIndex).shouldBeExactly(1); the(1).propertyOf(triggeredByIndex).shouldBeExactly(1); }) });   engine.add("lbrtwUtTestEnded event should be triggered once per unit test", function(testContext, the) { // Arrange var eng = new ut.Engine(); var results = {}; eng.add("a", function() {}); eng.add("b", function() { throw "Crash!"; }); var onTestEnded = function(event) { results[event.testName] = { success : event.testSuccess, errorMessage : event.testErrorMessage, successCount : event.successCount, failureCount : event.failureCount, testCount : event.testCount }; }; window.addEventListener("lbrtwUtTestEnded", onTestEnded, false);   // Act testContext.actAndWait(100, function() { eng.run().then(function() { window.removeEventListener("lbrtwUtTestEnded", onTestEnded, false); }); }).   // Assert thenAssert(function() { the("a").propertyOf(results).shouldBeTruthy(); the("success").propertyOf(results.a).shouldBeTrue(); the("errorMessage").propertyOf(results.a).shouldBeNull(); the("successCount").propertyOf(results.a).shouldBeExactly(1); the("failureCount").propertyOf(results.a).shouldBeExactly(0); the("testCount").propertyOf(results.a).shouldBeExactly(2);   the("b").propertyOf(results).shouldBeTruthy(); the("success").propertyOf(results.b).shouldBeFalse(); the("errorMessage").propertyOf(results.b).shouldBeExactly("Crash!"); the("successCount").propertyOf(results.b).shouldBeExactly(1); the("failureCount").propertyOf(results.b).shouldBeExactly(1); the("testCount").propertyOf(results.b).shouldBeExactly(2); }) });   engine.add("The lbrtwUtEngineEnded event object should contain testCount, failureCount, successCount, testNames and failures", function(testContext, the) { // Arrange var eng = new ut.Engine(); eng.add("a", function() {}); eng.add("b", function() {}); eng.add("c", function() { throw "Crash!"; }); var testCount; var failureCount; var successCount; var testNames; var failures;   var onEnded = function(event) { window.removeEventListener("lbrtwUtEngineEnded", onEnded, false); testCount = event.testCount; failureCount = event.failureCount; successCount = event.successCount; testNames = event.testNames; failures = event.failures; }; window.addEventListener("lbrtwUtEngineEnded", onEnded, false);   // Act testContext.actAndWait(100, function() { eng.run(); }).   // Assert thenAssert(function() { the(testCount).shouldBeExactly(3); the(failureCount).shouldBeExactly(1); the(successCount).shouldBeExactly(2); the("length").propertyOf(testNames).shouldBeExactly(3); the("length").propertyOf(failures).shouldBeExactly(1); }) });

The implementation is actually pretty easy. I write a helper function for dispatching my custom events, and then I use it at various points during the test process. Here is the helper function. Download the code below to see the complete implementation.

var triggerEvent = function(name, properties) { var event = document.createEvent("HTMLEvents"); event.initEvent(name, true, false);   for (var key in properties) { event[key] = properties[key]; }   window.dispatchEvent(event); };   // call like this: // triggerEvent("lbrtwUtTestStarting", { // testName : name, // testIndex : index // });

Making the output pretty

By listening to the four events dispatched by the framework it is possible to create any output you like. When you download the code below, you will find an example of what you can do.

Sending results to your server

By listening to the lbrtwUtEngineEnded event, I can now send the complete test results to any server using XMLHttpRequest directly or using any of the jQuery.ajax shortcuts.

$.on("lbrtwUtEngineEnded", function(event) { var oev = event.originalEvent;   $.post("http://myserver/unit-test-results", { userAgent : navigator.userAgent, testCount : oev.testCount, successCount : oev.successCount, failureCount : oev.failureCount });   // Of course, you can also use the failures and testNames properties });   myEngine.run();

The finished code can be found on github at /lbrtw/ut

JavaScript unit test framework, part 1
JavaScript unit test framework, part 2
JavaScript unit test framework, part 3
JavaScript unit test framework, part 4 (this part)

JavaScript unit test framework, part 3

Any mature unit test framework contains lots of helper methods for validating requirements. Instead of manually validating values and references using if and then throwing errors when requirements aren't satisfied, one should use helper methods.

I would like to be able to do this:

eng.add("Test stuff", function(testContext, the) { // Arrange var obj = new SomeClass();   // Act var result = obj.doStuff(1, 2, 3);   // Assert the(result).shouldNotBeNull(); the(result).shouldBeInstanceOf(ResultClass); the("foo").propertyOf(result).shouldBeLessThan(1000); the("bar").propertyOf(result).shouldBeExactly(1); the("abc").propertyOf(result).shouldBeTrue(); // and so on... });   eng.add("Test that a method throws an error", function(testContext, the) { // Arrange var obj = new SomeClass();   // Act and assert the("doStuff").methodOf(obj).withArguments(1, 2, 3).shouldThrowAnError(); });

When some should* method discovers a failing test, it should throw an exception to signal the failure to the test engine. I'm thinking that the shouldThrowAnError track would be the best to develop first, because it would make all future tests easier to write.

If the object or function being tested is named through the methodOf() or propertyOf() methods, and the requirement is not fulfilled, the error message should contain the name of the object or function being tested.

New requirements

  1. The second argument to a test function should be the ut.The function
  2. The ut.The function should simplify unit testing
    • calling the(func).shouldThrowAnError() should call func()
    • calling the(func).withArguments(...).shouldThrowAnError() should call func(...)
    • calling the(func).shouldThrowAnError() should throw an error if and only if func() does not throw an error
    • calling the(methodname).methodOf(object).shouldThrowAnError() should call object[methodname]()
    • calling the(x).shouldBeNull() should throw an error if x is not null
    • calling the(x).shouldNotBeNull() should throw an error if x is null
    • calling the(x).shouldBeExactly(y) should throw an error if x is not exactly y
    • calling the(x).shouldNotBeExactly(y) should throw an error if x is exactly y
    • calling the(x).shouldBeTrue() should throw an error if x is not true
    • calling the(x).shouldBeFalse() should throw an error if x is not false
    • calling the(x).shouldBeTruthy() should throw an error if x is not truthy
    • calling the(x).shouldBeFalsy() should throw an error if x is not falsy
    • calling the(x).shouldBeGreaterThan(y) should throw an error if x is not greater than y
    • calling the(x).shouldBeLessThan(y) should throw an error if x is not less than y
    • calling the(x).shouldBeGreaterThanOrEqualTo(y) should throw an error if x is not greater than or equal to y
    • calling the(x).shouldBeLessThanOrEqualTo(y) should throw an error if x is not less than or equal to y
    • calling the(x).shouldBeInstanceOf(y) should throw an error if x is not an instance of the y class
    • calling the("x").methodOf(y) should make an error message contain the text The x method
    • calling the("x").propertyOf(y) should make an error message contain the text The x property

Eighth requirement

engine.add("second argument to test functions should be the ut.The function", function() { // Arrange var eng = new ut.Engine(); var theThe; eng.add("Get the The", function(first, second) { theThe = second; });   // Act eng.run();   // Assert if (!theThe) { throw "Second argument null or missing"; } if (theThe !== ut.The) { throw "Second argument isn't ut.The"; } }); var utThe = function() { };   var runOneTestOrAssertFunc = function(engine, func, context) { try { func.call(null, context, utThe); if (!engine.actAndWaitFunc) { ++engine.successCount; } } catch(e) { engine.failures.push({ name : engine.currentTestName, message : e.toString() }); ++engine.failureCount; } };   window.ut = { "Engine" : utEngine, "TestContext" : utTestContext, "The" : utThe };

Ninth requirement

Requirement 9 – first batch

The first batch focuses on the shouldThrowAnError function. It should simply call the function passed to the the function, then examine the results. If there is an error, everything is fine, otherwise an error should be thrown because the expected error did not occur. This batch also deals with extracting a named method from an object using the methodOf function, and passing arguments to a function using the withArguments function.

engine.add("calling the(func).shouldThrowAnError() should call func()", function() { // Arrange var called = false; var func = function() { called = true; };   // Act try { ut.The(func).shouldThrowAnError(); } catch(e) { }   // Assert if (!called) { throw "func() wasn't called!"; } });   engine.add("calling the(func).withArguments(...).shouldThrowAnError() should call func(...)", function() { // Arrange var theA, theB, theC; var func = function(a, b, c) { theA = a; theB = b; theC = c; };   // Act try { ut.The(func).withArguments(1, 2, 3).shouldThrowAnError(); } catch(e) { }   // Assert if (theA !== 1) { throw "First argument was not passed"; } if (theB !== 2) { throw "Second argument was not passed"; } if (theC !== 3) { throw "Third argument was not passed"; } });   engine.add("the('foo').methodOf(bar) should be the same as the(bar.foo)", function() { // Arrange var called = false; var bar = { foo : function() { called = true; } };   // Act try { ut.The("foo").methodOf(bar).shouldThrowAnError(); } catch(e) { }   // Assert if (!called) { throw "bar.foo() was not called"; } });   engine.add("the('foo').methodOf(bar) should be the same as the(bar.foo), part 2", function() { // Arrange var theA, theB; var bar = { foo : function(a, b) { theA = a; theB = b; } };   // Act try { ut.The("foo").methodOf(bar).withArguments(1, 2).shouldThrowAnError(); } catch(e) { }   // Assert if (theA !== 1 || theB !== 2) { throw "bar.foo(1, 2) was not called"; } });   engine.add("shouldThrowAnError() should not throw an error if some error was thrown", function() { // Arrange var errorThrown = false; var func = function() { throw "Expected failure"; };   // Act try { ut.The(func).shouldThrowAnError(); } catch (e) { errorThrown = true; }   // Assert if (errorThrown) { throw "An error was thrown!"; } });   engine.add("shouldThrowAnError() should throw an error if no error was thrown", function() { // Arrange var errorThrown = false; var func = function() { };   // Act try { ut.The(func).shouldThrowAnError(); } catch (e) { errorThrown = true; }   // Assert if (!errorThrown) { throw "No error was thrown!"; } }); var asserter = function(arg) { this.target = arg; };   asserter.prototype = { methodOf : function(obj) { this.target = (function(obj, name) { return obj[name]; })(obj, this.target);   return this; },   withArguments : function() { var args = [].slice.call(arguments);   this.target = (function(method, args) { return function() { method.apply(null, args); }; })(this.target, args);   return this; },   shouldThrowAnError : function() { var threw = false; try { this.target.call(); } catch (e) { threw = true; } if (!threw) { throw "Did not throw an error"; } } };   var utThe = function(arg) { return new asserter(arg); };

Requirement 9 – second batch

The last few tests for this time validate all the comparison functions, like shouldBeNull() and shouldBeGreaterThan(). These should throw descriptive error messages, so I test the actual message texts.

Instead of writing every single unit test separately for the validation methods (which would have me writing 30+ unit tests by hand), I write a helper function to create three unit tests per validation method: One for validating that no error is thrown when no error should be thrown, and two for validating the correct error messages.

engine.add("the('foo').methodOf(bar) should be the same as the(bar.foo), but change the error message", function() { // Arrange var errorThrown = false; var bar = { foo : function() { } };   // Act try { ut.The("foo").methodOf(bar).shouldThrowAnError(); } catch (e) { errorThrown = e.toString(); }   // Assert if (!errorThrown) { throw "No error was thrown!"; } var expected = "The foo method did not throw an error"; if (errorThrown != expected) { throw "The wrong error was thrown! Expected: '" + expected + "', actual: '" + errorThrown + "'"; } });   var addAssertTestsForMethod = function(engine, methodName, goodValue, badValue, arg, expectedError) { if (typeof goodValue != "undefined") { var passingTestName = methodName + "() should not throw an error";   var passingTestFunc = (function(methodName, goodValue, arg) { return function() { // Act ut.The(goodValue)[methodName](arg); }; })(methodName, goodValue, arg);   engine.add(passingTestName, passingTestFunc); } if (typeof badValue != "undefined") { var failingTestName = methodName + "() should throw an error"; var namedFailingTestName = methodName + "() should throw an error with correct name";   var failingTestFunc = (function(methodName, badValue, arg, expectedError) { return function() { // Arrange var errorThrown = false;   // Act try { ut.The(badValue)[methodName](arg); } catch (e) { errorThrown = e; }   // Assert if (!errorThrown) { throw "Did not throw an error"; } if (errorThrown != expectedError) { throw "Did not throw the correct error. Expected: '" + expectedError + "', actual: '" + errorThrown + "'"; } }; })(methodName, badValue, arg, expectedError.replace(/%/, "The value"));   var namedFailingTestFunc = (function(methodName, badValue, arg, expectedError) { return function() { // Arrange var errorThrown = false; var obj = { prop : badValue };   // Act try { ut.The("prop").propertyOf(obj)[methodName](arg); } catch (e) { errorThrown = e; }   // Assert if (!errorThrown) { throw "Did not throw an error"; } if (errorThrown != expectedError) { throw "Did not throw the correct error. Expected: '" + expectedError + "', actual: '" + errorThrown + "'"; } }; })(methodName, badValue, arg, expectedError.replace(/%/, "The prop property"));   engine.add(failingTestName, failingTestFunc); engine.add(namedFailingTestName, namedFailingTestFunc); } };   var testClass = function() { this.foo = "bar"; };   addAssertTestsForMethod(engine, "shouldBeNull", null, 123, undefined, "% is not null"); addAssertTestsForMethod(engine, "shouldNotBeNull", 123, null, undefined, "% is null"); addAssertTestsForMethod(engine, "shouldBeExactly", 1, true, 1, "Expected: exactly 1, %: true"); addAssertTestsForMethod(engine, "shouldNotBeExactly", true, 1, 1, "% is exactly 1"); addAssertTestsForMethod(engine, "shouldBeLessThan", 1, 2, 2, "Expected: less than 2, %: 2"); addAssertTestsForMethod(engine, "shouldBeGreaterThan", 3, 2, 2, "Expected: greater than 2, %: 2"); addAssertTestsForMethod(engine, "shouldBeLessThanOrEqualTo", 2, 3, 2, "Expected: less than or equal to 2, %: 3"); addAssertTestsForMethod(engine, "shouldBeGreaterThanOrEqualTo", 2, 1, 2, "Expected: greater than or equal to 2, %: 1"); addAssertTestsForMethod(engine, "shouldBeTrue", true, 1, undefined, "% is not true"); addAssertTestsForMethod(engine, "shouldBeTruthy", 1, false, undefined, "% is not truthy"); addAssertTestsForMethod(engine, "shouldBeFalse", false, 0, undefined, "% is not false"); addAssertTestsForMethod(engine, "shouldBeFalsy", 0, true, undefined, "% is not falsy"); addAssertTestsForMethod(engine, "shouldBeInstanceOf", new testClass(), testClass, testClass, "% is not of correct type"); var asserter = function(arg) { this.target = arg; this.valueName = "The value"; this.methodName = "The function"; };   asserter.prototype = { methodOf : function(obj) { this.methodName = "The " + this.target + " method";   this.target = (function(obj, name) { return obj[name]; })(obj, this.target);   return this; },   withArguments : function() { var args = [].slice.call(arguments);   this.target = (function(method, args) { return function() { method.apply(null, args); }; })(this.target, args);   return this; },   shouldThrowAnError : function() { var threw = false; try { this.target.call(); } catch (e) { threw = true; } if (!threw) { throw this.methodName + " did not throw an error"; } },   propertyOf : function(obj) { this.valueName = "The " + this.target + " property"; this.target = obj[this.target];   return this; },   shouldBeNull : function() { if (this.target !== null) { throw this.valueName + " is not null"; } },   shouldNotBeNull : function() { if (this.target === null) { throw this.valueName + " is null"; } },   shouldBeExactly : function(arg) { if (this.target !== arg) { throw "Expected: exactly " + arg + ", " + this.valueName + ": " + this.target; } },   shouldNotBeExactly : function(arg) { if (this.target === arg) { throw this.valueName + " is exactly " + arg; } },   shouldBeLessThan : function(arg) { if (!(this.target arg)) { throw "Expected: greater than " + arg + ", " + this.valueName + ": " + this.target; } },   shouldBeLessThanOrEqualTo : function(arg) { if (!(this.target = arg)) { throw "Expected: greater than or equal to " + arg + ", " + this.valueName + ": " + this.target; } },   shouldBeTrue : function() { if (this.target !== true) { throw this.valueName + " is not true"; } },   shouldBeTruthy : function() { if (!this.target) { throw this.valueName + " is not truthy"; } },   shouldBeFalse : function() { if (this.target !== false) { throw this.valueName + " is not false"; } },   shouldBeFalsy : function() { if (this.target) { throw this.valueName + " is not falsy"; } },   shouldBeInstanceOf : function(theClass) { if (!(this.target instanceof theClass)) { throw this.valueName + " is not of correct type"; } } };

There we go. This is actually all I'm going to do for the actual testing of things. The next and final post will deal with better output of test results, including sending test result data to your server of choice. I will also add some pluggability to the unit test framework.

The finished code can be found on github at /lbrtw/ut

JavaScript unit test framework, part 1
JavaScript unit test framework, part 2
JavaScript unit test framework, part 3 (this part)
JavaScript unit test framework, part 4

JavaScript unit test framework, part 2

While adding new features to a project, you're supposed to add only one or a few unit tests at a time, see them fail, and then implement as little code as possible to make it/them pass. The current version of the unit test framework only shows the number of passing/failing tests, so you cannot be sure about which test is actually failing – especially after making some code changes. Also, there is no way of seeing the actual error message thrown when running a failing unit test. I really need to improve on this, so I introduce the failures property, which will contain names and error messages of all failing tests.

There is also the case of testing asynchronous code, such as timers, event handlers, AJAX requests, CSS transitions and so on. The way the run method is currently implemented, there is no way of properly waiting for it to complete if some unit test contains event handlers or timers.

New requirements

  1. The engine should keep track of failing tests and their error messages
    • after eng.run() is done, the eng.failures should contain a list of objects containing the name and error message of each failing test
  2. Each test function should be called with a ut.TestContext object as its first argument
    • testContext.actAndWait(timeout, actFunc) should run the actFunc function, and wait timeout milliseconds before continuing
    • if the actFunc function crashes, the test is marked as a failed test
    • the actFunc function should receive a ut.TestContext object as its first argument
    • calling testContext.actDone() from within an asynchronous test function stops the waiting immediately
    • the testContext.actAndWait method should return the test context object itself, for call chaining purposes
    • calling testContext.thenAssert(assertFunc) should make the assertFunc function get called after the actFunc function is either timed out, or marked as done using the actDone() method
    • the assertFunc function should receive a ut.TestContext object as its first argument
  3. The framework should provide a function hook to be called after all unit tests have been run
    • the run() method of ut.Engine should return the engine itself
    • the then(func) method should register a function to be run after all unit tests are done running, passing the engine as the first parameter to the func function
    • If none of the registered unit tests contain any asynchronous code, calling run() should run all tests before returning, and the caller of run() shouldn't need to use the then() method

Fifth requirement

engine.add("The engine should keep track of which tests fail/succeed", function() { var eng = new ut.Engine(); var failFunc = function() { throw "I did crash!"; }; eng.add("Failing", failFunc);    // Act eng.run();    // Assert if (eng.failures.length !== 1) { throw "failures.length should be 1, but is " + eng.failures.length; } if (eng.failures[0].name != "Failing") { throw "failures[0].name should be 'Failing', but is " + eng.failures[0].name; } if (eng.failures[0].message != "I did crash!") { throw "failures[0].message should be 'I did crash!', but is " + eng.failures[0].message; } });

The implementation is pretty simple, and after this refactoring, I can use the failures property to list failing tests and their error messages.

run : function() { this.failures = []; for (var name in this.tests) { var testfunc = this.tests[name]; try { testfunc.call(); ++this.successCount; } catch(e) { this.failures.push({ name : name, message : e.toString() }); ++this.failureCount; } } } engine.run();    console.log(engine.failureCount + " failures and " + engine.successCount + " successes, out of " + engine.testCount + " tests");    for (var i = 0; i < engine.failures.length; ++i) { var fail = engine.failures[i]; console.log(fail.name + ": " + fail.message); }

Sixth and seventh requirement

Requirements for an API or a framework are often expressed better in code. This is how I want to be able to use the features described in requirements 6/7:

var eng = new ut.Engine();    eng.add("Asynch test", function(testContext) { // Arrange var someObj = new SomeClass(); var result = null;    // Act testContext.actAndWait(1000, function(tc) { someObj.someAsyncMethod({ success : function(r) { result = r; tc.actDone(); } }); }). // < -- notice the dot here... call chaining!    // Assert thenAssert(function(tc) { if (result == null) { throw "Timeout!"; } if (result.foo !== "bar") { throw "Expected 'bar', but found " + result.foo; } }); });    eng.run().then(function(engine) { // Display test results });

Requirements 6/7 – first batch

The first batch of eight unit tests addresses every piece of the sixth requirement except for the actDone() function.

engine.add("Test functions should be called with a ut.TestContext as its first argument", function() { // Arrange var innerTc; var eng = new ut.Engine(); eng.add("set inner test context", function(tc) { innerTc = tc; });   // Act eng.run();   // Assert if (!(innerTc instanceof ut.TestContext)) { throw "innerTc is not a ut.TestContext object"; } });   engine.add("testContext.actAndWait should return the testContext itself", function() { // Arrange var innerTc; var returnedTc; var eng = new ut.Engine(); eng.add("set inner test context", function(tc) { innerTc = tc; returnedTc = tc.actAndWait(1, function() {}); });   // Act eng.run();   // Assert if (innerTc !== returnedTc) { throw "actAndWait did not return the testContext itself"; } });   engine.add("actAndWait(timeout, actFunc) should run the actFunc, and wait (at least) timeout milliseconds", function(testContext) { // Arrange var timeout = 100; var calledAt = 0, endedAt = 0; var eng = new ut.Engine(); var actFunc = function() { calledAt = new Date().getTime(); } var testFunc = function(tc) { tc.actAndWait(timeout, actFunc); }; eng.add("actAndWait should wait correct amount of ms", testFunc);   // Act testContext.actAndWait(timeout + 100, function() { eng.run().then(function() { endedAt = new Date().getTime(); }); }).   // Assert thenAssert(function() { if (calledAt == 0) { throw "Did not call the actFunc function"; } if (endedAt == 0) { throw "Did not finish running the tests properly"; } // Minor timing issue: one or two milliseconds off is not a big deal if (endedAt < calledAt + timeout) { throw "Did not wait enough ms (waited " + (endedAt - calledAt) + " ms"; } }); });   engine.add("thenAssert(func) should called the assert function after (at least) the registered number of milliseconds", function(testContext) { // Arrange var timeout = 100; var calledAt = 0, assertedAt = 0; var eng = new ut.Engine(); var actFunc = function() { calledAt = new Date().getTime(); }; var assertFunc = function() { assertedAt = new Date().getTime(); }; var testFunc = function(tc) { tc.actAndWait(timeout, actFunc).thenAssert(assertFunc); } eng.add("thenAssert should wait correct amount of ms", testFunc);   // Act testContext.actAndWait(timeout + 100, function() { eng.run(); }).   // Assert thenAssert(function() { if (calledAt == 0) { throw "Did not call the actFunc function"; } if (assertedAt == 0) { throw "Did not call the assertFunc function"; } if (assertedAt < calledAt + timeout) { throw "Did not wait enough ms (waited " + (assertedAt - calledAt) + " ms"; } }); });   engine.add("if the actFunc for actAndWait crashes, the test should be failed", function(testContext) { // Arrange var eng = new ut.Engine(); eng.add("This should crash", function(tc) { tc.actAndWait(100, function() { throw "Crashing!"; }); });   // Run testContext.actAndWait(200, function() { eng.run(); }).   // Assert thenAssert(function() { if (eng.failures.length !== 1) { throw "Did not register exactly one failure"; } }); });   engine.add("then(func) should run func immediately if there are no asynchronous unit tests", function() { // Arrange var thenCalled = false; var eng = new ut.Engine(); eng.add("no-op test", function() { });   // Run eng.run().then(function() { thenCalled = true; });   // Assert if (!thenCalled) { throw "the thenFunc was not called"; } });   engine.add("then(func) should NOT run func immediately if there are some asynchronous unit test", function() { // Arrange var thenCalled = false; var eng = new ut.Engine(); eng.add("async test", function(tc) { tc.actAndWait(100, function() { }); });   // Run eng.run().then(function() { thenCalled = true; });   // Assert if (thenCalled) { throw "the thenFunc was called, but shouldn't!"; } });   engine.add("then(func) should run func after all asynchronous tests are done", function(testContext) { // Arrange var thenCalled = false; var eng = new ut.Engine(); eng.add("async test", function(tc) { tc.actAndWait(100, function() { }); });   // Run testContext.actAndWait(200, function() { eng.run().then(function() { thenCalled = true; }); }).   // Assert thenAssert(function() { if (!thenCalled) { throw "the thenFunc wasn't called"; } }); });   // new way of printing successes/failures engine.run().then(function() { console.log(engine.failureCount + " failures and " + engine.successCount + " successes, out of " + engine.testCount + " tests");   for (var i = 0; i < engine.failures.length; ++i) { var fail = engine.failures[i]; console.log(fail.name + ": " + fail.message); } });

This takes a pretty big piece of refactoring. I'm essentially transforming a sequential traversal of the tests property into a "wait-and-continue" loop using window.setTimeout to save engine state, halt the unit test engine, let a test run its course, then continue with the assert function or the next test.

First, the new ut.TestContext class:

var utTestContext = function(engine) { this.engine = engine; };   utTestContext.prototype = { actAndWait : function(timeout, actFunc) { this.engine.actAndWaitFunc = actFunc; this.engine.actAndWaitContext = this; this.engine.actAndWaitTimeout = timeout; return this; },   thenAssert : function(assertFunc) { this.engine.thenAssertFunc = assertFunc; this.engine.thenAssertContext = this; } };   window.ut = { "Engine" : utEngine, "TestContext" : utTestContext };

Then the new ut.Engine implementation:

var utEngine = function() { this.tests = {}; this.testCount = this.successCount = this.failureCount = 0; };   // private function, not exposed var runOneTestOrAssertFunc = function(engine, func, context) { try { func.call(null, context); if (!engine.actAndWaitFunc) { ++engine.successCount; } } catch(e) { engine.failures.push({ name : engine.currentTestName, message : e.toString() }); ++engine.failureCount; } };   utEngine.prototype = { add : function(name, testfunc) { this.tests[name] = testfunc; ++this.testCount; },   run : function() { if (this.initialized !== true) { this.initialized = true;   this.failures = [];   this.testNameIndex = 0; this.testNames = []; for (var name in this.tests) this.testNames.push(name); }   this.running = true;   if (this.actAndWaitFunc) { runOneTestOrAssertFunc(this, this.actAndWaitFunc, this.actAndWaitContext);   delete this.actAndWaitFunc; var self = this;   // pause the engine for a number of milliseconds this.actAndWaitTimeoutId = window.setTimeout(function() { self.run(); }, this.actAndWaitTimeout);   return this; }   if (this.thenAssertFunc) { runOneTestOrAssertFunc(this, this.thenAssertFunc, this.thenAssertContext);   delete this.thenAssertFunc; delete this.thenAssertContext; }   while (this.testNameIndex < this.testNames.length) { var name = this.testNames[this.testNameIndex++]; var testFunc = this.tests[name]; var context = new ut.TestContext(this); this.currentTestName = name;   runOneTestOrAssertFunc(this, testFunc, context);   if (this.actAndWaitFunc) { var self = this; window.setTimeout(function() { self.run(); }, 0); return this; } }   this.running = false;   if (this.thenFunc) { this.thenFunc.call(null, this); }   return this; },   then : function(thenFunc) { if (this.running) { this.thenFunc = thenFunc; } else { thenFunc.call(null, this); } } };

The unit test framework is starting to be really useful now, but is still only just over a hundred lines of production code, and about 350 lines of test code.

Requirements 6/7 – second batch

If you have lots of asynchronous unit tests where you need a large timeout value, but the tests still might finish quickly, it doesn't really feel good to always wait for the maximum expected timeout before moving on to the next test. You should be able to move on instantly if a test finishes early. That's why I add the actDone() method to tell the engine to move on to assertion and/or the next test instantly.

engine.add("actDone() should move immediately to the thenAssert assert function", function(testContext) { // Arrange var calledAt = 0, assertAt = 0; var eng = new ut.Engine(); eng.add("10ms func with 10000ms timeout", function(tc) { tc.actAndWait(10000, function() { calledAt = new Date().getTime(); window.setTimeout(function() { tc.actDone(); }, 10); }).thenAssert(function() { assertAt = new Date().getTime(); }); });   // Act testContext.actAndWait(500, function() { eng.run(); }).   // Assert thenAssert(function() { if (assertAt === 0) { throw "Assert wasn't called!"; } if (assertAt > (calledAt + 100)) { throw "Assert took way too long to get called!"; } }); }); The solution is to add this to the ut.TestContext prototype: actDone : function() { var engine = this.engine; if (engine.actAndWaitTimeoutId) { window.clearTimeout(engine.actAndWaitTimeoutId); delete engine.actAndWaitTimeoutId;   window.setTimeout(function() { engine.run(); }, 0); } }

There it is. Sixteen unit tests have rendered 137 lines of production code, which actually makes a pretty decent unit test framework. What is missing is a group of convenient helper functions and hooks for asserting and pretty output. If you want to use this in a automated testing environment it is already pretty much good to go. In the then() function, you could add a jQuery.ajax call to automatically post the test results to some server. Then just add a post-build script to your CI environment of choice to run your unit tests in a number of different browsers.

Next part will focus on assert helper functions and output hooks. Then I will look into mocking and some inversion of control magic.

The finished code can be found on github at /lbrtw/ut.

JavaScript unit test framework, part 1
JavaScript unit test framework, part 2 (this part)
JavaScript unit test framework, part 3
JavaScript unit test framework, part 4

JavaScript unit test framework, part 1

I have been involved in lots of agile and non-agile development projects, so I have experienced enough benefits of agile test-driven development to see a pattern. Smaller codebase, higher quality code, less bugs, more fun, lower startup threshold for adding new developers to the team, more efficient refactoring, maintainability, etc.

One key tool in achieving all of that is a unit test framework, which is why my first LBRTW project is to develop such a framework in JavaScript. Also, I will use the very unit test framework I'm writing to unit-test the framework itself.

The intended users of this framework are developers, so I can use pretty technical language in the specs, but I will still focus on keeping requirements short and concise. The first group of requirements look like this:

  1. eng = new ut.Engine() should create a new unit testing engine
    • upon creating a new engine, the eng.testCount should be zero
  2. eng.add(name, testfunc) should add a new unit test to the engine
    • eng.tests[name] should point to the testfunc function
    • the eng.testCount property should be increased
  3. eng.run() should run the test function of each added unit test once
    • if running the test function throws an exception, that indicates a failed unit test
    • all unit tests should always run, even if some unit test function crashes (or even all of them)
  4. The engine should keep track of the number of failed/succeeded tests
    • after eng.run() is done, the eng.successCount and eng.failureCount should contain the number of succeeded/failed unit tests respectively, and the sum of them should be the same as eng.testCount

First requirement

After establishing this, writing and running the first test is easy:

var engine = new ut.Engine();    engine.add("new ut.Engine should create a new unit testing engine", function() { // Act var eng = new ut.Engine();    // Assert if (eng.testCount !== 0) { throw "Did not set testCount to zero"; } });    engine.run();

Of course, when I try to run this, I will get a reference error saying ut is not defined. Also, I won't be able to actually run any tests before both add and run are somewhat implemented, so here is iteration zero of ut.Engine:

var utEngine = function() { this.tests = []; };    utEngine.prototype = { add : function(name, testfunc) { this.tests.push(testfunc); },    run : function() { for (var i = 0; i < this.tests.length; ++i) { var testfunc = this.tests[i]; testfunc.call(); } } };    window.ut = { "Engine" : utEngine };

Now it's possible to add and run unit tests, so it actually produces the first failing unit test output, albeit only visible in the developer console: Did not set testCount to zero. One small code change, and no errors are thrown:

var utEngine = function() { this.tests = []; this.testCount = 0; };

Second requirement

The next requirement deals with adding test functions to the tests collection and increasing the testCount property. This is what those tests look like:

engine.add("add() should set tests[name] to func", function() { // Arrange var eng = new ut.Engine(); var bar = function() {};    // Act eng.add("foo", bar);    // Assert if (eng.tests["foo"] !== bar) { throw "tests.foo does not point to bar"; } });    engine.add("add() should increase testCount", function() { // Arrange var eng = new ut.Engine(); var func = function() {};    // Act eng.add("foo", func);    // Assert if (eng.testCount !== 1) { throw "Did not increase testCount"; } });

The first test is made to pass by refactoring the tests array into an anonymous object, changing the add method to add by name instead of by index, and the run method to traverse the object using for ... in. The second test passes after a small refactoring of the add method:

var utEngine = function() { this.tests = {}; this.testCount = 0; };    utEngine.prototype = { add : function(name, testfunc) { this.tests[name] = testfunc; ++this.testCount; },    run : function() { for (var name in this.tests) { var testfunc = this.tests[name]; testfunc.call(); } } };

Third requirement

If this one isn't satisfied, any failing test will stop all concurrent tests from running, which will only allow us to deal with one failing test at a time.

engine.add("run() should run each added test once", function() { // Arrange var eng = new ut.Engine(); var called = [0, 0]; var func1 = function() { called[0]++; }; var func2 = function() { called[1]++; }; eng.add("func1", func1); eng.add("func2", func2);    // Act eng.run();    // Assert if (called[0] !== 1) { throw "Did not call func1"; } if (called[1] !== 1) { throw "Did not call func2"; } });    engine.add("run() should run all tests even when crash", function() { // Arrange var eng = new ut.Engine(); var called = 0; var func = function() { ++called; throw "Crash!"; } eng.add("Going once", func); eng.add("Going twice", func);    // Act eng.run();    // Assert if (called !== 2) { throw "Did not call both added tests"; } });

The first test of this requirement already passes, but the second one does crash. It doesn't even run all the way to the assertion part. It's the test function itself that produces the developer console output – not the unit test framework. To make the test pass, I simply wrap calling test functions in try ... catch.

run : function() { for (var name in this.tests) { var testfunc = this.tests[name]; try { testfunc.call(); } catch(e) { } } }

Fourth requirement

When writing the unit test for this requirement, I also adopt the new way of checking for failing unit tests. Instead of just letting the developer console print out the exception message, I print out the values of failureCount, successCount and testCount after run() has been called.

engine.add("The engine should count successes and failures", function() { // Arrange var eng = new ut.Engine(); var failFunc = function() { throw "Crash!"; }; var successFunc = function() { }; eng.add("One fail", failFunc); eng.add("Two fails", failFunc); eng.add("Three fails", failFunc); eng.add("One success", successFunc);    // Act eng.run();    // Assert if (eng.successCount !== 1) { throw "successCount should be 1, but is " + eng.successCount; } if (eng.failureCount !== 3) { throw "failureCount should be 3, but is " + eng.failureCount; } });    engine.run();    console.log(engine.failureCount + " failures and " + engine.successCount + " successes, out of " + engine.testCount + " tests"); When running all unit tests now, the output simply says undefined failures and undefined successes, out of 6 tests, simply because the engine does not yet count failures or successes. A small refactoring of the constructor and the run method later: var utEngine = function() { this.tests = {}; this.testCount = this.successCount = this.failureCount = 0; };    // inside prototype definition: run : function() { for (var name in this.tests) { var testfunc = this.tests[name]; try { testfunc.call(); ++this.successCount; } catch(e) { ++this.failureCount; } } }

There it is – the first iteration of my JavaScript unit test framework. Feel free to use it. There is still lots of important stuff to do, like a way of knowing which tests are failing and not just how many of them.

The finished code can be found on github at /lbrtw/ut.

JavaScript unit test framework, part 1 (this part)
JavaScript unit test framework, part 2
JavaScript unit test framework, part 3
JavaScript unit test framework, part 4