Skip to content

Instantly share code, notes, and snippets.

@tivac
Last active August 29, 2015 14:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tivac/ef1b4ec427c2e3843a67 to your computer and use it in GitHub Desktop.
Save tivac/ef1b4ec427c2e3843a67 to your computer and use it in GitHub Desktop.
Sweetie.js, an experiment in tiny test-runner creation
var sweetie = Sweetie.globalize(),
output = "",
start = Date.now(),
failures, passed;
sweetie.run(function(status, test, args) {
if(status === "finish") {
output += "\n\nTests completed in " + (Date.now() - start) + "ms";
return JS.reply({
body : output,
headers : {
"Content-Type" : "text/plain; charset=utf8"
}
});
}
switch(status) {
case "start":
output += "Starting tests\n\n";
break;
case "suite":
failures = [];
output += "\n" + args.reduce(function(prev, curr, idx) {
var x;
padding = "";
for(x = 0; x < idx; x++) {
padding += " ";
}
return (prev ? prev + "\n" : "") + padding + "/" + curr;
}, "") + "\n";
padding += " ";
break;
case "test":
passed = true;
output += padding + test.name;
break;
case "fail":
passed = false;
failures.push({ test : test, args : args });
break;
case "test-done":
output += (passed ? " pass" : " fail") + "\n";
break;
case "suite-done":
if(failures.length) {
output += failures.reduce(function(prev, curr) {
return prev + "\n" + padding + JSON.stringify(curr);
}, "\n" + padding + "Failures:") + "\n";
}
break;
// Ignored
case "pass":
break;
default:
console.log(
":: " + status.toUpperCase(),
test ? "'" + test.name + "'" : "",
args || ""
);
}
});
(function(global) {
"use strict";
var Sweetie;
Sweetie = function() {
this.env = {
__tests : []
};
this.context = this.env;
};
Sweetie.globalize = function() {
var sweetie = new Sweetie();
[ "it", "describe", "ok" ].forEach(function(prop) {
global[prop] = sweetie[prop].bind(sweetie);
});
return sweetie;
};
Sweetie.prototype = {
describe : function(name, fn) {
var old;
if(!this.context[name]) {
this.context[name] = {
__tests : []
};
}
old = this.context;
this.context = this.context[name];
if(typeof fn === "function") {
fn();
}
this.context = old;
},
it : function(name, fn) {
this.context.__tests.push({ name : name, fn : fn });
},
ok : function(cond, msg) {
this.reporter(!!cond ? "pass" : "fail", this.test, {
condition : cond,
message : msg || "",
stack : (new Error()).stack
});
},
_collectTests : function (chain, tests) {
if(!tests.length) {
return;
}
var self = this;
// Rewrite bare test function into something a little nicer
this._tests = this._tests.concat(tests.map(function(test) {
var fn;
test.suite = chain;
if(!test.fn) {
return test;
}
fn = test.fn;
test.async = !!fn.length;
test.fn = function(next) {
self.reporter("test", test);
self.test = test;
// Doesn't handle async exceptions, but we're ok w/ that
try {
fn(next);
} catch(e) {
self.reporter("fail", test, e);
if(typeof next === "function") {
next();
}
}
};
return test;
}));
},
_collectSuite : function (chain, suite) {
var self = this;
this._collectTests(chain, suite.__tests);
Object.keys(suite).forEach(function(name) {
if(name === "__tests") {
return;
}
self._collectSuite(chain.concat(name), suite[name]);
});
},
_next : function () {
var self = this,
test = this._tests.shift();
if(!test) {
return this.reporter("finish");
}
if(test.suite !== this.suite) {
if(this.suite) {
this.reporter("suite-done", null, this.suite);
}
this.reporter("suite", null, test.suite);
this.suite = test.suite;
}
if(!test.fn) {
this.reporter("empty", test);
return this._next();
}
if(test.async) {
return test.fn(function() {
self.reporter("test-done", test);
self._next.call(self);
});
}
test.fn();
this.reporter("test-done", test);
this._next();
},
run : function (reporter) {
this._tests = [];
this._collectSuite([], this.env);
this.reporter = (typeof reporter === "function") ? reporter : function() {};
this.reporter("start", null, this._tests);
this._next();
}
};
if(typeof module !== "undefined" && module.exports) {
module.exports = Sweetie;
} else {
global.Sweetie = Sweetie;
}
}((function() { return this; }())));
/*jshint mocha:true */
/*global JS, ok */
describe("Core", function() {
"use strict";
describe("JS.Lang", function() {
var L = JS.Lang;
it("should support .isNull()", function() {
ok(L.isNull(null));
ok(!L.isNull(undefined));
ok(!L.isNull(""));
});
it("should support .isUndefined()", function() {
ok(L.isUndefined(undefined));
ok(!L.isUndefined(false));
ok(!L.isUndefined(null));
});
it("should support .isNumber()", function() {
ok(L.isNumber(0));
ok(L.isNumber(123.123));
ok(!L.isNumber("123.123"));
ok(!L.isNumber(1/0));
});
it("should support .isBoolean()", function() {
ok(L.isBoolean(false));
ok(!L.isBoolean(1));
ok(!L.isBoolean("true"));
});
it("should support .isString()", function() {
ok(L.isString("{}"));
ok(!L.isString({foo: "bar"}));
ok(!L.isString(123));
ok(!L.isString(true));
});
it("should support .isArray()", function() {
ok(L.isArray([1, 2]));
ok(!L.isArray({"one": "two"}));
var a = new Array();
a.one = "two";
ok(L.isArray(a));
ok(!L.isArray(null));
ok(!L.isArray(""));
ok(!L.isArray(undefined));
});
it("should support .isObject()", function() {
ok(L.isObject({}));
ok(L.isObject(function(){}));
ok(L.isObject([]));
ok(!L.isObject(1));
ok(!L.isObject(true));
ok(!L.isObject("{}"));
ok(!L.isObject(null));
});
it("should support .isFunction()", function() {
ok(L.isFunction(function(){}));
ok(!L.isFunction({foo: "bar"}));
});
it("should support .isDate()", function() {
ok(L.isDate(new Date()));
});
it("should support .isValue()", function() {
ok(!L.isValue(null));
ok(!L.isValue(undefined));
ok(!L.isValue(parseInt("adsf", 10)));
ok(!L.isValue(1/0));
ok(L.isValue(new Date()));
ok(L.isValue(""));
ok(L.isValue(false));
});
it("should support .type()", function() {
ok(L.type(true) === "boolean");
ok(L.type(false) === "boolean");
ok(L.type(0) === "number");
ok(L.type("") === "string");
ok(L.type([]) === "array");
ok(L.type({}) === "object");
ok(L.type(function(){}) === "function");
});
it("should support .ownProperties()", function() {
var o = { "fooga" : 1, "wooga" : 2, "looga" : 3 };
ok(L.ownProperties(o).length === 3, "Number of own properties are incorrect");
});
it("should support .mix()", function() {
var a = {
"bool" : false,
"num" : 0,
"nul" : null,
"undef": undefined,
"T" : "blabber"
},
b = {
"bool" : "oops",
"num" : "oops",
"nul" : "oops",
"undef": "oops",
"T" : "oops"
};
JS.mix(a, b, false);
ok(a.bool !== "oops");
ok(a.num !== "oops");
ok(a.nul !== "oops");
ok(a.undef !== "oops");
ok(a.T !== "oops");
JS.mix(a, b, true);
ok(a.bool === "oops");
ok(a.num === "oops");
ok(a.nul === "oops");
ok(a.undef === "oops");
ok(a.T === "oops");
});
it("should support .merge()", function() {
var o1 = { one: "one" },
o2 = { two: "two" },
o3 = { two: "twofromthree", three: "three" },
o4 = { one: "one", two: "twofromthree", three: "three" },
o123 = JS.merge(o1, o2, o3),
key;
for(key in o4) {
ok(o4[key] === o123[key]);
}
});
it("should support .sub()", function() {
var t1 = "{a}",
t2 = "a{a}a",
r1 = JS.sub(t1, { a : "a" }),
r2 = JS.sub(t2, { a : "a" });
ok(r1 === "a");
ok(r2 === "aaa");
});
it("should support an async test", function() {
setTimeout(function() {
next();
}, 100);
});
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment