A DSL for Testing in JavaScript

October 12, 2016

Given an array:

var xs = [2, 4, 8, 16];

Write from scratch a library to check the values of elements within it:

forArray(xs).elemAt(3).shouldBe(equalTo(16));
// throws no exceptions

// forArray(xs).elemAt(2).shouldBe(equalTo(16));
// throws "expected 16 at index 2, but found 8"

// forArray(xs).elemAt(4).shouldBe(equalTo(16));
// throws "expected 16 at index 4, but the largest valid index is 3"

console.log('Finished without exceptions!')

Bonus

Add support for checking other characteristics of the elements:

forArray(xs).elemAt(3).shouldBe(atLeast(16));
// throws no exceptions

// forArray(xs).elemAt(2).shouldBe(greaterThan(8));
// throws "expected a value greater than 8 at index 2, but found 8"
forArray(xs).elemAt(3).shouldBe(even());
// throws no exceptions

// forArray(xs).elemAt(3).shouldBe(odd());
// throws "expected an odd number at index 3, but found 16"

console.log('Finished bonus without exceptions!')

Solution

Here is one possible solution.
function forArray(xs) {
  return {
    elemAt: function(index) {
      return {
        shouldBe: function(comparator) {
          comparator(xs, index);
        },
      };
    },
  };
}

function equalTo(expected) {
  return function(xs, index) {
    if (index >= xs.length) {
      throw 'expected ' + expected + ' at index ' + index +
            ', but the largest valid index is ' + (xs.length - 1);
    } else if (expected !== xs[index]) {
      throw 'expected ' + expected + ' at index ' + index +
            ', but found ' + xs[index] + '';
    }
  };
}

Bonus

function checkLength(xs, index) {
  if (index >= xs.length) {
    throw 'expected a value at index ' + index +
            ', but the largest valid index is ' + (xs.length - 1);
  }
}

function atLeast(value) {
  return function(xs, index) {
    checkLength(xs, index);
    if (value > xs[index]) {
      throw 'expected a value of at least ' + value + ' at index ' + index +
            ', but found ' + xs[index] + '';
    }
  };
}

function greaterThan(value) {
  return function(xs, index) {
    checkLength(xs, index);
    if (value <= xs[index]) {
      throw 'expected a value greater than ' + value + ' at index ' + index +
            ', but found ' + xs[index] + '';
    }
  };
}

function even() {
  return function(xs, index) {
    checkLength(xs, index);
    if (xs[index] % 2 !== 0) {
      throw 'expected an even number at index ' + index +
            ', but found ' + xs[index] + '';
    }
  };
}

function odd() {
  return function(xs, index) {
    checkLength(xs, index);
    if (xs[index] % 2 !== 1) {
      throw 'expected an odd number at index ' + index +
            ', but found ' + xs[index] + '';
    }
  };
}

Demo

This file is literate JavaScript, and can be run using Codedown:

$ curl https://earldouglas.com/exercises/javascript-testing.md |
  codedown javascript |
  node
Finished without exceptions!
Finished bonus without exceptions!