From f84a7c1bccb51d919a9c9497d974c7a3e6f2f8bf Mon Sep 17 00:00:00 2001 From: Jeremy Wall Date: Tue, 2 Apr 2024 19:41:50 -0400 Subject: [PATCH] fix: Working browser harness --- src/TAP.mjs | 36 +++++++++- src/Tap.d.js | 2 +- tests/01_tap.t.js | 147 +------------------------------------- tests/TapHarness.html | 26 ++----- tests/suite.mjs | 162 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 206 insertions(+), 167 deletions(-) create mode 100644 tests/suite.mjs diff --git a/src/TAP.mjs b/src/TAP.mjs index ee11de2..d7f53ae 100644 --- a/src/TAP.mjs +++ b/src/TAP.mjs @@ -36,12 +36,44 @@ class NodeRenderer { /** @implements TapRenderer */ class BrowserRenderer { + #target = document.body; + + /** @param {HtmlElement=} target */ + constructor(target) { + if (target) { + this.#target = target; + } + } + + /** @returns TextNode */ + #createText(text) { + return document.createTextNode(text); + } + + /** + * @param {Node} nodes + * @returns HTMLDivElement + */ + #createDiv(nodes) { + const div = document.createElement("div"); + div.append(...nodes); + return div; + } + out(text) { - // TODO(jeremy): + const textNode = this.#createText(text); + this.#target.appendChild(this.#createDiv([textNode])); } comment(lines) { // TODO(jeremy): + var elems = []; + for (var line of lines) { + elems.push(this.#createText(line), document.createElement("br")); + } + var commentDiv = this.#createDiv(elems); + commentDiv.setAttribute("class", "tap-comment"); + this.#target.appendChild(commentDiv); } } @@ -379,5 +411,5 @@ function runSuite(t, suite) { summarize(t); } -export { Tap, runTest, runSuite }; +export { Tap, runTest, runSuite, BrowserRenderer, NodeRenderer }; diff --git a/src/Tap.d.js b/src/Tap.d.js index 46723bc..aae8a36 100644 --- a/src/Tap.d.js +++ b/src/Tap.d.js @@ -10,7 +10,7 @@ class TapRenderer { * * @param {Array} lines */ - diag(lines) { + comment(lines) { } } diff --git a/tests/01_tap.t.js b/tests/01_tap.t.js index eaf3f7d..10f1cf1 100644 --- a/tests/01_tap.t.js +++ b/tests/01_tap.t.js @@ -14,149 +14,6 @@ class FakeRenderer { } } -import('../src/TAP.mjs').then(m => { - function tapSuite(t) { - t.plan(23); - - var renderer = new FakeRenderer(); - var testCan = function () { - // setup fake test object - var f = new m.Tap(renderer); // the TAP thats failing - f.plan(4); - - //mock a fake object to run test against - var obj = new Object; - obj.run = function() {}; - var method = 'run'; - - // begin real tests! - f.can_ok(obj, 'not_there'); - t.like(renderer.output, /not ok 1 - object can \[ not_there \]/, 'can_ok failed'); - f.can_ok(obj, method); - diag = ''; - t.like(renderer.output, /ok 2 - object can \[ run \]/, 'can_ok passed'); - - //Now we need to test the whole prototype method assignment thing - - function MockObj() { - this.attr = 1; - } - - MockObj.prototype.fakeme = function () {}; - - f.can_ok(MockObj, 'fakeme'); - renderer.commentOutput = ''; - t.like(renderer.output, /^ok .* \[ fakeme \]/, - 'can_ok recognized prototype methods'); - f.can_ok(MockObj, 'fakeme2'); - renderer.commentOutput = ''; - t.like(renderer.output, /^not ok .* \[ fakeme2 \]/, - 'can_ok prototype recognization doesnt break methods'); - }; - testCan(); - - var testLike = function() { - // setup fake test object - var f = new m.Tap(renderer); // the TAP that's failing - f.plan(1); - - // begin real tests! - f.like("hello", /hello/, "hello matches hello"); - t.like(renderer.output, /ok 1 - hello matches hello/, 'got description in TAP output'); - }; - testLike() - - var testDiag = function() { - // setup fake test object - var f = new m.Tap(renderer); // the TAP that's failing - f.plan(10); - // begin real tests! - f.comment("hello"); - t.comment(renderer.commentOutput); - t.like(renderer.commentOutput, /hello/, 'got hello'); - }; - testDiag(); - - var testException = function() { - // setup fake test object - var f = new m.Tap(renderer); // the TAP that's failing - f.plan(2); - - // begin real tests! - f.throws_ok(function() {throw new Error('I made a boo boo')}, 'I made a boo boo'); - //t.comment(renderer.output); - t.like(renderer.output, /ok 1 - code threw \[Error: I made a boo boo\]/, 'uncaught exception'); - f.throws_ok(function() {}, 'I made a boo boo'); - //t.comment(renderer.output); - t.like(renderer.output, /not ok 2 - code threw \[ \]/, 'false failed'); - }; - testException(); - - var testFails = function() { - // setup fake test object - var f = new m.Tap(renderer); // the TAP that's failing - f.plan(3); - - // begin real tests! - f.ok(false, 'false fails'); - t.like(renderer.output, /not ok 1 - false fails/, 'false failed'); - - f.ok(0, 'zero fails'); - t.like(renderer.output, /not ok 2 - zero fails/, '0 failed'); - - f.is(0, 1, 'zero is one'); - t.like(renderer.output, /not ok 3 - zero is one/, '0 != 1'); - }; - testFails(); - - var testPass = function() { - t.ok(true, 'true is true'); - t.is(1,1, '1 is 1'); - t.pass('pass passes'); - t.like("hello world", /hel+o/, 'regexen work'); - t.unlike("hello there", /world/, 'no world'); - }; - testPass(); - - var testPlan = function() { - // setup fake test object - var f = new m.Tap(renderer); // the TAP that's failing - f.plan(2); - - // begin real tests! - f.ok(false, 'false fails'); - t.is(f.counter, 1, 'counter increments by one'); - t.is(f.planned, 2, 'planned = 2'); - }; - testPlan(); - - var testTodoSkip = function() { - t.can_ok(m.Tap, 'todo', 'skip'); - var f = new m.Tap(renderer); // the TAP that's failing - f.plan(4); - - f.todo(function() { - f.ok(true, 'true is true'); - }); - t.like(renderer.output, /ok 1 - # TODO: true is true/g, - 'the non todo output is suitably formatted'); - f.ok(!false, 'not false is true'); - t.like(renderer.output, /ok 2 -/g, 'the regular output is suitably formatted'); - - f.skip(true, 'because I said so', 1, - function() { - f.is(1, 2, 'one is two'); - } - ); - t.like(renderer.output, /^not ok 3 - # SKIP because I said so$/, - 'the skipped output is suitably formatted'); - f.is(1, 1, 'one is one'); - t.like(renderer.output, /ok 4 - one is one/, - 'the non skipped output is suitable formatted'); - }; - testTodoSkip(); - - return t; - } - m.runTest(m.Tap.Node(), "Tap dogfood test suite", tapSuite); +import('./suite.mjs').then(m => { + m.runTest(m.Tap.Node(), "Tap dogfood test suite", m.tapSuite); }); diff --git a/tests/TapHarness.html b/tests/TapHarness.html index 9c9785b..6bfbf89 100644 --- a/tests/TapHarness.html +++ b/tests/TapHarness.html @@ -1,11 +1,6 @@ - - + - - - - -This is the Test.TAP.Class and company test harness for the browser. - - diff --git a/tests/suite.mjs b/tests/suite.mjs new file mode 100644 index 0000000..ef71055 --- /dev/null +++ b/tests/suite.mjs @@ -0,0 +1,162 @@ +/** @implements TapRenderer */ +import {Tap, runTest} from '../src/TAP.mjs'; + +class FakeRenderer { + output = "nothing yet"; + commentOutput = ""; + + out(text) { + this.output = text; + } + + comment(lines) { + for (var line of lines) { + this.commentOutput += line; + } + } +} + +function tapSuite(t) { + t.plan(23); + + var renderer = new FakeRenderer(); + var testCan = function() { + // setup fake test object + var f = new Tap(renderer); // the TAP thats failing + f.plan(4); + + //mock a fake object to run test against + var obj = new Object; + obj.run = function() { }; + var method = 'run'; + + // begin real tests! + f.can_ok(obj, 'not_there'); + t.like(renderer.output, /not ok 1 - object can \[ not_there \]/, 'can_ok failed'); + f.can_ok(obj, method); + t.like(renderer.output, /ok 2 - object can \[ run \]/, 'can_ok passed'); + + //Now we need to test the whole prototype method assignment thing + + function MockObj() { + this.attr = 1; + } + + MockObj.prototype.fakeme = function() { }; + + f.can_ok(MockObj, 'fakeme'); + renderer.commentOutput = ''; + t.like(renderer.output, /^ok .* \[ fakeme \]/, + 'can_ok recognized prototype methods'); + f.can_ok(MockObj, 'fakeme2'); + renderer.commentOutput = ''; + t.like(renderer.output, /^not ok .* \[ fakeme2 \]/, + 'can_ok prototype recognization doesnt break methods'); + }; + testCan(); + + var testLike = function() { + // setup fake test object + var f = new Tap(renderer); // the TAP that's failing + f.plan(1); + + // begin real tests! + f.like("hello", /hello/, "hello matches hello"); + t.like(renderer.output, /ok 1 - hello matches hello/, 'got description in TAP output'); + }; + testLike() + + var testDiag = function() { + // setup fake test object + var f = new Tap(renderer); // the TAP that's failing + f.plan(10); + // begin real tests! + f.comment("hello"); + t.comment(renderer.commentOutput); + t.like(renderer.commentOutput, /hello/, 'got hello'); + }; + testDiag(); + + var testException = function() { + // setup fake test object + var f = new Tap(renderer); // the TAP that's failing + f.plan(2); + + // begin real tests! + f.throws_ok(function() { throw new Error('I made a boo boo') }, 'I made a boo boo'); + //t.comment(renderer.output); + t.like(renderer.output, /ok 1 - code threw \[Error: I made a boo boo\]/, 'uncaught exception'); + f.throws_ok(function() { }, 'I made a boo boo'); + //t.comment(renderer.output); + t.like(renderer.output, /not ok 2 - code threw \[ \]/, 'false failed'); + }; + testException(); + + var testFails = function() { + // setup fake test object + var f = new Tap(renderer); // the TAP that's failing + f.plan(3); + + // begin real tests! + f.ok(false, 'false fails'); + t.like(renderer.output, /not ok 1 - false fails/, 'false failed'); + + f.ok(0, 'zero fails'); + t.like(renderer.output, /not ok 2 - zero fails/, '0 failed'); + + f.is(0, 1, 'zero is one'); + t.like(renderer.output, /not ok 3 - zero is one/, '0 != 1'); + }; + testFails(); + + var testPass = function() { + t.ok(true, 'true is true'); + t.is(1, 1, '1 is 1'); + t.pass('pass passes'); + t.like("hello world", /hel+o/, 'regexen work'); + t.unlike("hello there", /world/, 'no world'); + }; + testPass(); + + var testPlan = function() { + // setup fake test object + var f = new Tap(renderer); // the TAP that's failing + f.plan(2); + + // begin real tests! + f.ok(false, 'false fails'); + t.is(f.counter, 1, 'counter increments by one'); + t.is(f.planned, 2, 'planned = 2'); + }; + testPlan(); + + var testTodoSkip = function() { + t.can_ok(Tap, 'todo', 'skip'); + var f = new Tap(renderer); // the TAP that's failing + f.plan(4); + + f.todo(function() { + f.ok(true, 'true is true'); + }); + t.like(renderer.output, /ok 1 - # TODO: true is true/g, + 'the non todo output is suitably formatted'); + f.ok(!false, 'not false is true'); + t.like(renderer.output, /ok 2 -/g, 'the regular output is suitably formatted'); + + f.skip(true, 'because I said so', 1, + function() { + f.is(1, 2, 'one is two'); + } + ); + t.like(renderer.output, /^not ok 3 - # SKIP because I said so$/, + 'the skipped output is suitably formatted'); + f.is(1, 1, 'one is one'); + t.like(renderer.output, /ok 4 - one is one/, + 'the non skipped output is suitable formatted'); + }; + testTodoSkip(); + + return t; +} + +export { tapSuite, runTest, Tap };