UNPKG

mithril

Version:

A framework for building brilliant applications

739 lines (660 loc) 17.9 kB
"use strict" var callAsync = require("../../test-utils/callAsync") var o = require("../ospec") // this throws an async error that can't be caught in browsers if (typeof process !== "undefined") { o("incomplete assertion", function(done) { var stackMatcher = /([\w\.\\\/\-]+):(\d+):/ // /!\ this test relies on the `new Error` expression being six lines // above the `oo("test", function(){...})` call. var matches = (new Error).stack.match(stackMatcher) if (matches != null) { var name = matches[1] var num = Number(matches[2]) } var oo = o.new() oo("test", function() { oo("incomplete") }) oo.run(function(results) { o(results.length).equals(1) o(results[0].message).equals("Incomplete assertion in the test definition starting at...") o(results[0].pass).equals(null) var stack = o.cleanStackTrace(results[0].testError) var matches2 = stack && stack.match(stackMatcher) if (matches != null && matches2 != null) { o(matches[1]).equals(name) o(Number(matches2[2])).equals(num + 6) } done() }) }) } o("o.only", function(done) { var oo = o.new() oo.spec("won't run", function() { oo("nope, skipped", function() { o(true).equals(false) }) }) oo.spec("ospec", function() { oo("skipped as well", function() { oo(true).equals(false) }) oo.only(".only()", function() { oo(2).equals(2) }, true) oo.only("another .only()", function(done) { done("that fails") }, true) }) oo.run(function(results){ o(results.length).equals(2) o(results[0].pass).equals(true) o(results[1].pass).equals(false) done() }) }) // Predicate test passing on clone results o.spec("reporting", function() { var oo o.beforeEach(function(){ oo = o.new() oo.spec("clone", function() { oo("fail", function() { oo(true).equals(false) }) oo("pass", function() { oo(true).equals(true) }) }) }) o("reports per instance", function(done, timeout) { timeout(100) // Waiting on clone oo.run(function(results) { o(typeof results).equals("object") o("length" in results).equals(true) o(results.length).equals(2)("Two results") o("error" in results[0] && "pass" in results[0]).equals(true)("error and pass keys present in failing result") o("message" in results[0] && "context" in results[0]).equals(true)("message and context keys present in failing result") o("message" in results[1] && "context" in results[1]).equals(true)("message and context keys present in passing result") o(results[0].pass).equals(false)("Test meant to fail has failed") o(results[1].pass).equals(true)("Test meant to pass has passed") done() }) }) o("o.report() returns the number of failures", function () { var log = console.log, error = console.error console.log = o.spy() console.error = o.spy() function makeError(msg) {try{throw msg ? new Error(msg) : new Error} catch(e){return e}} try { var errCount = o.report([{pass: true}, {pass: true}]) o(errCount).equals(0) o(console.log.callCount).equals(1) o(console.error.callCount).equals(0) errCount = o.report([ {pass: false, error: makeError("hey"), message: "hey"} ]) o(errCount).equals(1) o(console.log.callCount).equals(2) o(console.error.callCount).equals(1) errCount = o.report([ {pass: false, error: makeError("hey"), message: "hey"}, {pass: true}, {pass: false, error: makeError("ho"), message: "ho"} ]) o(errCount).equals(2) o(console.log.callCount).equals(3) o(console.error.callCount).equals(3) } catch (e) { o(1).equals(0)("Error while testing the reporter") } console.log = log console.error = error }) }) o.spec("ospec", function() { o.spec("sync", function() { var a = 0, b = 0, illegalAssertionThrows = false var reservedTestNameTrows = false o.before(function() {a = 1}) o.after(function() {a = 0}) o.beforeEach(function() {b = 1}) o.afterEach(function() {b = 0}) try {o("illegal assertion")} catch (e) {illegalAssertionThrows = true} try {o("\x01reserved test name", function(){})} catch (e) {reservedTestNameTrows = true} o("assertions", function() { var nestedTestDeclarationThrows = false try {o("illegal nested test", function(){})} catch (e) {nestedTestDeclarationThrows = true} o(illegalAssertionThrows).equals(true) o(nestedTestDeclarationThrows).equals(true) o(reservedTestNameTrows).equals(true) var spy = o.spy() spy(a) o(a).equals(b) o(a).notEquals(2) o({a: [1, 2], b: 3}).deepEquals({a: [1, 2], b: 3}) o([{a: 1, b: 2}, {c: 3}]).deepEquals([{a: 1, b: 2}, {c: 3}]) o(function(){throw new Error()}).throws(Error) o(function(){"ayy".foo()}).throws(TypeError) o(function(){Math.PI.toFixed(Math.pow(10,20))}).throws(RangeError) o(function(){decodeURIComponent("%")}).throws(URIError) o(function(){"ayy".foo()}).notThrows(SyntaxError) o(function(){throw new Error("foo")}).throws("foo") o(function(){throw new Error("foo")}).notThrows("bar") var undef1 = {undef: void 0} var undef2 = {UNDEF: void 0} o(undef1).notDeepEquals(undef2) o(undef1).notDeepEquals({}) o({}).notDeepEquals(undef1) var sparse1 = [void 1, void 2, void 3] delete sparse1[0] var sparse2 = [void 1, void 2, void 3] delete sparse2[1] o(sparse1).notDeepEquals(sparse2) var monkeypatch1 = [1, 2] monkeypatch1.field = 3 var monkeypatch2 = [1, 2] monkeypatch2.field = 4 o(monkeypatch1).notDeepEquals([1, 2]) o(monkeypatch1).notDeepEquals(monkeypatch2) monkeypatch2.field = 3 o(monkeypatch1).deepEquals(monkeypatch2) monkeypatch1.undef = undefined monkeypatch2.UNDEF = undefined o(monkeypatch1).notDeepEquals(monkeypatch2) var values = ["a", "", 1, 0, true, false, null, undefined, Date(0), ["a"], [], function() {return arguments}.call(), new Uint8Array(), {a: 1}, {}] for (var i = 0; i < values.length; i++) { for (var j = 0; j < values.length; j++) { if (i === j) o(values[i]).deepEquals(values[j]) else o(values[i]).notDeepEquals(values[j]) } } o(spy.callCount).equals(1) o(spy.args.length).equals(1) o(spy.args[0]).equals(1) o(spy.calls.length).equals(1) o(spy.calls[0]).deepEquals({this: undefined, args: [1]}) }) o("spy wrapping", function() { var spy = o.spy(function view(vnode){ this.drawn = true return {tag: "div", children: vnode.children} }) var children = [""] var state = {} var output = spy.call(state, {children: children}) o(spy.length).equals(1) o(spy.name).equals("view") o(spy.callCount).equals(1) o(spy.args.length).equals(1) o(spy.args[0]).deepEquals({children: children}) o(spy.calls.length).equals(1) o(spy.calls[0]).deepEquals({this: state, args: [{children: children}]}) o(state).deepEquals({drawn: true}) o(output).deepEquals({tag: "div", children: children}) }) }) o.spec("async callback", function() { var a = 0, b = 0 o.after(function() { o(a).equals(0) o(b).equals(0) }) o.spec("", function(){ o.before(function(done) { callAsync(function() { a = 1 done() }) }) o.after(function(done) { callAsync(function() { a = 0 done() }) }) o.beforeEach(function(done) { o(b).equals(0) callAsync(function() { b = 1 done() }) }) o.afterEach(function(done) { callAsync(function() { b = 0 done() }) }) o("hooks work as intended the first time", function(done) { callAsync(function() { var spy = o.spy() spy(a) o(a).equals(1) o(b).equals(1) done() }) }) o("hooks work as intended the second time", function(done) { callAsync(function() { var spy = o.spy() spy(a) o(a).equals(1) o(b).equals(1) done() }) }) }) }) o.spec("throwing in test context is recoreded as a failure", function() { var oo o.beforeEach(function(){oo = o.new()}) o.afterEach(function() { oo.run(function(results) { o(results.length).equals(1) o(results[0].pass).equals(false) }) }) o("sync test", function() { oo("throw in sync test", function() {throw new Error}) }) o("async test", function() { oo("throw in async test", function(done) { throw new Error done() // eslint-disable-line no-unreachable }) }) }) o.spec("timeout", function () { o("when using done()", function(done) { var oo = o.new() var err // the success of this test is dependent on having the // oo() call three linew below this one try {throw new Error} catch(e) {err = e} if (err.stack) { var line = Number(err.stack.match(/:(\d+):/)[1]) oo("", function(oodone, timeout) { // oodone() keep this line for now timeout(1) }) oo.run((function(results) { o(results.length).equals(1) o(results[0].pass).equals(false) // todo test cleaned up results[0].error stack trace for the presence // of the timeout stack entry o(results[0].testError instanceof Error).equals(true) o(o.cleanStackTrace(results[0].testError).indexOf("test-ospec.js:" + (line + 3) + ":")).notEquals(-1) done() })) } else { done() } }) o("when using a thenable", function(done) { var oo = o.new() var err // the success of this test is dependent on having the // oo() call three linew below this one try {throw new Error} catch(e) {err = e} if (err.stack) { var line = Number(err.stack.match(/:(\d+):/)[1]) oo("", function() { oo.timeout(1) return {then: function(){}} }) oo.run((function(results) { o(results.length).equals(1) o(results[0].pass).equals(false) o(results[0].testError instanceof Error).equals(true) o(o.cleanStackTrace(results[0].testError).indexOf("test-ospec.js:" + (line + 3) + ":")).notEquals(-1) done() })) } else { done() } }) }) o.spec("o.timeout", function() { o("throws when called out of test definitions", function(done) { var oo = o.new() var count = 0 try { oo.timeout(1) } catch (e) { count++ } oo.spec("a spec", function() { try { oo.timeout(1) } catch (e) { count++ } }) oo("", function() { oo.timeout(30) return {then: function(f) {setTimeout(f)}} }) oo.run(function(){ o(count).equals(2) done() }) }) o("works", function(done) { var oo = o.new() var t = new Date oo("", function() { oo.timeout(10) return {then: function() {}} }) oo.run(function(){ o(new Date - t >= 10).equals(true) o(200 > new Date - t).equals(true) done() }) }) }) o.spec("o.specTimeout", function() { o("throws when called inside of test definitions", function(done) { var err var oo = o.new() oo("", function() { try { oo.specTimeout(5) } catch (e) {err = e} return {then: function(f) {setTimeout(f)}} }) oo.run(function(){ o(err instanceof Error).equals(true) done() }) }) o("works", function(done) { var oo = o.new() var t oo.specTimeout(10) oo.beforeEach(function () { t = new Date }) oo.afterEach(function () { var diff = new Date - t o(diff >= 10).equals(true) o(diff < 200).equals(true) }) oo("", function() { oo(true).equals(true) return {then: function() {}} }) oo.run(function(results) { o(results.length).equals(2) o(results[0].pass).equals(true) o(results[1].pass).equals(false) done() }) }) o("The parent and sibling suites are not affected by the specTimeout", function(done) { var oo = o.new() var t oo.specTimeout(50) oo.beforeEach(function () { t = new Date }) oo.afterEach(function () { var diff = new Date - t o(diff >= 50).equals(true) o(diff < 80).equals(true) }) oo.spec("nested 1", function () { oo.specTimeout(80) }) oo("", function() { oo(true).equals(true) return {then: function() {}} }) oo.spec("nested 2", function () { oo.specTimeout(80) }) oo.spec("nested 3", function () { oo("", function() { oo(true).equals(true) return {then: function() {}} }) }) oo.run(function(results) { o(results.length).equals(4) o(results[0].pass).equals(true) o(results[1].pass).equals(false) o(results[2].pass).equals(true) o(results[3].pass).equals(false) done() }) }) o("nested suites inherit the specTimeout", function(done) { var oo = o.new() oo.specTimeout(50) oo.spec("nested", function () { oo.spec("deeply", function() { var t oo.beforeEach(function () { t = new Date }) oo.afterEach(function () { var diff = new Date - t o(diff >= 50).equals(true) o(diff < 80).equals(true) }) oo("", function() { oo(true).equals(true) return {then: function() {}} }) }) }) oo.run(function(results) { o(results.length).equals(2) o(results[0].pass).equals(true) o(results[1].pass).equals(false) done() }) }) }) o.spec("calling done() twice throws", function () { o("two successes", function(done) { var oo = o.new() var err = null oo("foo", function(oodone) { try { oodone() oodone() } catch (e) { err = e } o(err instanceof Error).equals(true) o(err.message).equals("`oodone()` should only be called once") }) oo.run(function(results) { o(results.length).equals(1) o(results[0].pass).equals(true) done() }) }) o("a success followed by an error", function(done) { var oo = o.new() var err = null oo("foo", function(oodone) { try { oodone() oodone("error") } catch (e) { err = e } o(err instanceof Error).equals(true) o(err.message).equals("`oodone()` should only be called once") }) oo.run(function(results) { o(results.length).equals(1) o(results[0].pass).equals(true) done() }) }) o("two errors", function(done) { var oo = o.new() var err = null oo("foo", function(oodone) { try { oodone("bar") oodone("baz") } catch (e) { err = e } o(err instanceof Error).equals(true) o(err.message).equals("`oodone()` should only be called once") }) oo.run(function(results) { o(results.length).equals(1) o(results[0].pass).equals(false) o(results[0].message).equals("bar") done() }) }) o("an error followed by a success", function(done) { var oo = o.new() var err = null oo("foo", function(oodone) { try { oodone("bar") oodone() } catch (e) { err = e } o(err instanceof Error).equals(true) o(err.message).equals("`oodone()` should only be called once") }) oo.run(function(results) { o(results.length).equals(1) o(results[0].pass).equals(false) o(results[0].message).equals("bar") done() }) }) }) o.spec("stack trace cleaner", function() { o("handles line breaks", function() { try { throw new Error("line\nbreak") } catch(error) { var trace = o.cleanStackTrace(error) o(trace).notEquals("break") o(trace.indexOf("test-ospec.js") !== -1).equals(true) } }) }) o.spec("async promise", function() { var a = 0, b = 0 function wrapPromise(fn) { return new Promise((resolve, reject) => { callAsync(() => { try { fn() resolve() } catch(e) { reject(e) } }) }) } o.before(function() { return wrapPromise(() => { a = 1 }) }) o.after(function() { return wrapPromise(function() { a = 0 }) }) o.beforeEach(function() { return wrapPromise(function() { b = 1 }) }) o.afterEach(function() { return wrapPromise(function() { b = 0 }) }) o("promise functions", function() { return wrapPromise(function() { o(a).equals(b) o(a).equals(1)("a and b should be initialized") }) }) }) }) o.spec("the done parser", function() { o("accepts non-English names", function() { var oo = o.new() var threw = false oo("test", function(完了) { oo(true).equals(true) 完了() }) try {oo.run(function(){})} catch(e) {threw = true} o(threw).equals(false) }) o("tolerates comments", function() { var oo = o.new() var threw = false oo("test", function(/*hey */ /**/ //ho done /*hey */ /**/ //huuu , timeout ) { timeout(5) oo(true).equals(true) done() }) try {oo.run(function(){})} catch(e) {threw = true} o(threw).equals(false) }) /*eslint-disable no-eval*/ try {eval("(()=>{})()"); o.spec("with ES6 arrow functions", function() { function getCommentContent(f) { f = f.toString() return f.slice(f.indexOf("/*") + 2, f.lastIndexOf("*/")) } o("has no false positives 1", function(){ var oo = o.new() var threw = false eval(getCommentContent(function(){/* oo( 'Async test parser mistakenly identified 1st token after a parens to be `done` reference', done => { oo(threw).equals(false) done() } ) */})) try {oo.run(function(){})} catch(e) {threw = true} o(threw).equals(false) }) o("has no false negatives", function(){ var oo = o.new() var threw = false eval(getCommentContent(function(){/* oo( "Multiple references to the wrong thing doesn't fool the checker", done => { oo(threw).equals(false) oo(threw).equals(false) } ) */})) try {oo.run(function(){})} catch(e) {threw = true} o(threw).equals(true) }) o("isn't fooled by comments", function(){ var oo = o.new() var threw = false oo( "comments won't throw the parser off", eval("done /*hey*/ /**/ => {oo(threw).equals(false);done()}") ) try {oo.run(function(){})} catch(e) {threw = true} o(threw).equals(false) }) })} catch (e) {/*ES5 env, or no eval, ignore*/} /*eslint-enable no-eval*/ })