diff --git a/.gitignore b/.gitignore index acdb6593..e46285d5 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ .DS_Store cache/ combined/ +combine/ diff --git a/external/qunit.css b/external/qunit.css index a4daa27e..87a5f820 100644 --- a/external/qunit.css +++ b/external/qunit.css @@ -10,7 +10,7 @@ /** Resets */ -#qunit-tests, #qunit-tests li ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult { +#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult { margin: 0; padding: 0; } @@ -20,10 +20,13 @@ #qunit-header { padding: 0.5em 0 0.5em 1em; - - color: #fff; - text-shadow: rgba(0, 0, 0, 0.5) 4px 4px 1px; + + color: #8699a4; background-color: #0d3349; + + font-size: 1.5em; + line-height: 1em; + font-weight: normal; border-radius: 15px 15px 0 0; -moz-border-radius: 15px 15px 0 0; @@ -33,7 +36,12 @@ #qunit-header a { text-decoration: none; - color: white; + color: #c2ccd1; +} + +#qunit-header a:hover, +#qunit-header a:focus { + color: #fff; } #qunit-banner { @@ -68,7 +76,7 @@ cursor: pointer; } -#qunit-tests li ol { +#qunit-tests ol { margin-top: 0.5em; padding: 0.5em; @@ -83,6 +91,45 @@ -webkit-box-shadow: inset 0px 2px 13px #999; } +#qunit-tests table { + border-collapse: collapse; + margin-top: .2em; +} + +#qunit-tests th { + text-align: right; + vertical-align: top; + padding: 0 .5em 0 0; +} + +#qunit-tests td { + vertical-align: top; +} + +#qunit-tests pre { + margin: 0; + white-space: pre-wrap; + word-wrap: break-word; +} + +#qunit-tests del { + background-color: #e0f2be; + color: #374e0c; + text-decoration: none; +} + +#qunit-tests ins { + background-color: #ffcaca; + color: #500; + text-decoration: none; +} + +/*** Test Counts */ + +#qunit-tests b.counts { color: black; } +#qunit-tests b.passed { color: #5E740B; } +#qunit-tests b.failed { color: #710909; } + #qunit-tests li li { margin: 0.5em; padding: 0.4em 0.5em 0.4em 0.5em; @@ -99,13 +146,11 @@ border-left: 26px solid #C6E746; } -#qunit-tests li.pass { color: #528CE0; background-color: #D2E0E6; } -#qunit-tests li.pass span.test-name { color: #366097; } +#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } +#qunit-tests .pass .test-name { color: #366097; } -#qunit-tests li li.pass span.test-actual, -#qunit-tests li li.pass span.test-expected { color: #999999; } - -strong b.pass { color: #5E740B; } +#qunit-tests .pass .test-actual, +#qunit-tests .pass .test-expected { color: #999999; } #qunit-banner.qunit-pass { background-color: #C6E746; } @@ -117,14 +162,12 @@ strong b.pass { color: #5E740B; } border-left: 26px solid #EE5757; } -#qunit-tests li.fail { color: #000000; background-color: #EE5757; } -#qunit-tests li.fail span.test-name, -#qunit-tests li.fail span.module-name { color: #000000; } +#qunit-tests .fail { color: #000000; background-color: #EE5757; } +#qunit-tests .fail .test-name, +#qunit-tests .fail .module-name { color: #000000; } -#qunit-tests li li.fail span.test-actual { color: #EE5757; } -#qunit-tests li li.fail span.test-expected { color: green; } - -strong b.fail { color: #710909; } +#qunit-tests .fail .test-actual { color: #EE5757; } +#qunit-tests .fail .test-expected { color: green; } #qunit-banner.qunit-fail, #qunit-testrunner-toolbar { background-color: #EE5757; } @@ -134,14 +177,14 @@ strong b.fail { color: #710909; } #qunit-testresult { padding: 0.5em 0.5em 0.5em 2.5em; - + color: #2b81af; background-color: #D2E0E6; border-radius: 0 0 15px 15px; -moz-border-radius: 0 0 15px 15px; -webkit-border-bottom-right-radius: 15px; - -webkit-border-bottom-left-radius: 15px; + -webkit-border-bottom-left-radius: 15px; } /** Fixture */ diff --git a/external/qunit.js b/external/qunit.js index 45ad1dcf..caf47331 100644 --- a/external/qunit.js +++ b/external/qunit.js @@ -10,23 +10,234 @@ (function(window) { +var defined = { + setTimeout: typeof window.setTimeout !== "undefined", + sessionStorage: (function() { + try { + return !!sessionStorage.getItem; + } catch(e){ + return false; + } + })() +} + +var testId = 0; + +var Test = function(name, testName, expected, testEnvironmentArg, async, callback) { + this.name = name; + this.testName = testName; + this.expected = expected; + this.testEnvironmentArg = testEnvironmentArg; + this.async = async; + this.callback = callback; + this.assertions = []; +}; +Test.prototype = { + init: function() { + var tests = id("qunit-tests"); + if (tests) { + var b = document.createElement("strong"); + b.innerHTML = "Running " + this.name; + var li = document.createElement("li"); + li.appendChild( b ); + li.id = this.id = "test-output" + testId++; + tests.appendChild( li ); + } + }, + setup: function() { + if (this.module != config.previousModule) { + if ( this.previousModule ) { + QUnit.moduleDone( this.module, config.moduleStats.bad, config.moduleStats.all ); + } + config.previousModule = this.module; + config.moduleStats = { all: 0, bad: 0 }; + QUnit.moduleStart( this.module, this.moduleTestEnvironment ); + } + + config.current = this; + this.testEnvironment = extend({ + setup: function() {}, + teardown: function() {} + }, this.moduleTestEnvironment); + if (this.testEnvironmentArg) { + extend(this.testEnvironment, this.testEnvironmentArg); + } + + QUnit.testStart( this.testName, this.testEnvironment ); + + // allow utility functions to access the current test environment + // TODO why?? + QUnit.current_testEnvironment = this.testEnvironment; + + try { + if ( !config.pollution ) { + saveGlobal(); + } + + this.testEnvironment.setup.call(this.testEnvironment); + } catch(e) { + // TODO use testName instead of name for no-markup message? + QUnit.ok( false, "Setup failed on " + this.name + ": " + e.message ); + } + }, + run: function() { + if ( this.async ) { + QUnit.stop(); + } + + try { + this.callback.call(this.testEnvironment); + } catch(e) { + // TODO use testName instead of name for no-markup message? + fail("Test " + this.name + " died, exception and test follows", e, this.callback); + QUnit.ok( false, "Died on test #" + (this.assertions.length + 1) + ": " + e.message + " - " + QUnit.jsDump.parse(e) ); + // else next test will carry the responsibility + saveGlobal(); + + // Restart the tests if they're blocking + if ( config.blocking ) { + start(); + } + } + }, + teardown: function() { + try { + checkPollution(); + this.testEnvironment.teardown.call(this.testEnvironment); + } catch(e) { + // TODO use testName instead of name for no-markup message? + QUnit.ok( false, "Teardown failed on " + this.name + ": " + e.message ); + } + }, + finish: function() { + if ( this.expected && this.expected != this.assertions.length ) { + QUnit.ok( false, "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run" ); + } + + var good = 0, bad = 0, + tests = id("qunit-tests"); + + config.stats.all += this.assertions.length; + config.moduleStats.all += this.assertions.length; + + if ( tests ) { + var ol = document.createElement("ol"); + + for ( var i = 0; i < this.assertions.length; i++ ) { + var assertion = this.assertions[i]; + + var li = document.createElement("li"); + li.className = assertion.result ? "pass" : "fail"; + li.innerHTML = assertion.message || (assertion.result ? "okay" : "failed"); + ol.appendChild( li ); + + if ( assertion.result ) { + good++; + } else { + bad++; + config.stats.bad++; + config.moduleStats.bad++; + } + } + + // store result when possible + defined.sessionStorage && sessionStorage.setItem("qunit-" + this.testName, bad); + + if (bad == 0) { + ol.style.display = "none"; + } + + var b = document.createElement("strong"); + b.innerHTML = this.name + " (" + bad + ", " + good + ", " + this.assertions.length + ")"; + + addEvent(b, "click", function() { + var next = b.nextSibling, display = next.style.display; + next.style.display = display === "none" ? "block" : "none"; + }); + + addEvent(b, "dblclick", function(e) { + var target = e && e.target ? e.target : window.event.srcElement; + if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) { + target = target.parentNode; + } + if ( window.location && target.nodeName.toLowerCase() === "strong" ) { + window.location.search = "?" + encodeURIComponent(getText([target]).replace(/\(.+\)$/, "").replace(/(^\s*|\s*$)/g, "")); + } + }); + + var li = id(this.id); + li.className = bad ? "fail" : "pass"; + li.style.display = resultDisplayStyle(!bad); + li.removeChild( li.firstChild ); + li.appendChild( b ); + li.appendChild( ol ); + + if ( bad ) { + var toolbar = id("qunit-testrunner-toolbar"); + if ( toolbar ) { + toolbar.style.display = "block"; + id("qunit-filter-pass").disabled = null; + } + } + + } else { + for ( var i = 0; i < this.assertions.length; i++ ) { + if ( !this.assertions[i].result ) { + bad++; + config.stats.bad++; + config.moduleStats.bad++; + } + } + } + + try { + QUnit.reset(); + } catch(e) { + // TODO use testName instead of name for no-markup message? + fail("reset() failed, following Test " + this.name + ", exception and reset fn follows", e, QUnit.reset); + } + + QUnit.testDone( this.testName, bad, this.assertions.length ); + }, + + queue: function() { + var test = this; + synchronize(function() { + test.init(); + }); + function run() { + // each of these can by async + synchronize(function() { + test.setup(); + }); + synchronize(function() { + test.run(); + }); + synchronize(function() { + test.teardown(); + }); + synchronize(function() { + test.finish(); + }); + } + // defer when previous test run passed, if storage is available + var bad = defined.sessionStorage && +sessionStorage.getItem("qunit-" + this.testName); + if (bad) { + run(); + } else { + synchronize(run); + }; + } + +} + var QUnit = { // call on start of module test to prepend name to all tests module: function(name, testEnvironment) { + config.previousModule = config.currentModule; config.currentModule = name; - - synchronize(function() { - if ( config.currentModule ) { - QUnit.moduleDone( config.currentModule, config.moduleStats.bad, config.moduleStats.all ); - } - - config.currentModule = name; - config.moduleTestEnvironment = testEnvironment; - config.moduleStats = { all: 0, bad: 0 }; - - QUnit.moduleStart( name, testEnvironment ); - }); + config.currentModuleTestEnviroment = testEnvironment; }, asyncTest: function(testName, expected, callback) { @@ -39,7 +250,7 @@ var QUnit = { }, test: function(testName, expected, callback, async) { - var name = '' + testName + '', testEnvironment, testEnvironmentArg; + var name = '' + testName + '', testEnvironmentArg; if ( arguments.length === 2 ) { callback = expected; @@ -58,174 +269,19 @@ var QUnit = { if ( !validTest(config.currentModule + ": " + testName) ) { return; } - - synchronize(function() { - - testEnvironment = extend({ - setup: function() {}, - teardown: function() {} - }, config.moduleTestEnvironment); - if (testEnvironmentArg) { - extend(testEnvironment,testEnvironmentArg); - } - - QUnit.testStart( testName, testEnvironment ); - - // allow utility functions to access the current test environment - QUnit.current_testEnvironment = testEnvironment; - - config.assertions = []; - config.expected = expected; - - var tests = id("qunit-tests"); - if (tests) { - var b = document.createElement("strong"); - b.innerHTML = "Running " + name; - var li = document.createElement("li"); - li.appendChild( b ); - li.id = "current-test-output"; - tests.appendChild( li ) - } - - try { - if ( !config.pollution ) { - saveGlobal(); - } - - testEnvironment.setup.call(testEnvironment); - } catch(e) { - QUnit.ok( false, "Setup failed on " + name + ": " + e.message ); - } - }); - - synchronize(function() { - if ( async ) { - QUnit.stop(); - } - - try { - callback.call(testEnvironment); - } catch(e) { - fail("Test " + name + " died, exception and test follows", e, callback); - QUnit.ok( false, "Died on test #" + (config.assertions.length + 1) + ": " + e.message ); - // else next test will carry the responsibility - saveGlobal(); - - // Restart the tests if they're blocking - if ( config.blocking ) { - start(); - } - } - }); - - synchronize(function() { - try { - checkPollution(); - testEnvironment.teardown.call(testEnvironment); - } catch(e) { - QUnit.ok( false, "Teardown failed on " + name + ": " + e.message ); - } - }); - - synchronize(function() { - try { - QUnit.reset(); - } catch(e) { - fail("reset() failed, following Test " + name + ", exception and reset fn follows", e, reset); - } - - if ( config.expected && config.expected != config.assertions.length ) { - QUnit.ok( false, "Expected " + config.expected + " assertions, but " + config.assertions.length + " were run" ); - } - - var good = 0, bad = 0, - tests = id("qunit-tests"); - - config.stats.all += config.assertions.length; - config.moduleStats.all += config.assertions.length; - - if ( tests ) { - var ol = document.createElement("ol"); - - for ( var i = 0; i < config.assertions.length; i++ ) { - var assertion = config.assertions[i]; - - var li = document.createElement("li"); - li.className = assertion.result ? "pass" : "fail"; - li.innerHTML = assertion.message || "(no message)"; - ol.appendChild( li ); - - if ( assertion.result ) { - good++; - } else { - bad++; - config.stats.bad++; - config.moduleStats.bad++; - } - } - if (bad == 0) { - ol.style.display = "none"; - } - - var b = document.createElement("strong"); - b.innerHTML = name + " (" + bad + ", " + good + ", " + config.assertions.length + ")"; - - addEvent(b, "click", function() { - var next = b.nextSibling, display = next.style.display; - next.style.display = display === "none" ? "block" : "none"; - }); - - addEvent(b, "dblclick", function(e) { - var target = e && e.target ? e.target : window.event.srcElement; - if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) { - target = target.parentNode; - } - if ( window.location && target.nodeName.toLowerCase() === "strong" ) { - window.location.search = "?" + encodeURIComponent(getText([target]).replace(/\(.+\)$/, "").replace(/(^\s*|\s*$)/g, "")); - } - }); - - var li = id("current-test-output"); - li.id = ""; - li.className = bad ? "fail" : "pass"; - li.removeChild( li.firstChild ); - li.appendChild( b ); - li.appendChild( ol ); - - if ( bad ) { - var toolbar = id("qunit-testrunner-toolbar"); - if ( toolbar ) { - toolbar.style.display = "block"; - id("qunit-filter-pass").disabled = null; - id("qunit-filter-missing").disabled = null; - } - } - - } else { - for ( var i = 0; i < config.assertions.length; i++ ) { - if ( !config.assertions[i].result ) { - bad++; - config.stats.bad++; - config.moduleStats.bad++; - } - } - } - - QUnit.testDone( testName, bad, config.assertions.length ); - - if ( !window.setTimeout && !config.queue.length ) { - done(); - } - }); - - synchronize( done ); + + var test = new Test(name, testName, expected, testEnvironmentArg, async, callback); + test.previousModule = config.previousModule; + test.module = config.currentModule; + test.moduleTestEnvironment = config.currentModuleTestEnviroment; + test.queue(); }, /** * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through. */ expect: function(asserts) { - config.expected = asserts; + config.current.expected = asserts; }, /** @@ -233,11 +289,15 @@ var QUnit = { * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); */ ok: function(a, msg) { + a = !!a; + var details = { + result: a, + message: msg + }; msg = escapeHtml(msg); - QUnit.log(a, msg); - - config.assertions.push({ - result: !!a, + QUnit.log(a, msg, details); + config.current.assertions.push({ + result: a, message: msg }); }, @@ -255,42 +315,42 @@ var QUnit = { * @param String message (optional) */ equal: function(actual, expected, message) { - push(expected == actual, actual, expected, message); + QUnit.push(expected == actual, actual, expected, message); }, notEqual: function(actual, expected, message) { - push(expected != actual, actual, expected, message); + QUnit.push(expected != actual, actual, expected, message); }, deepEqual: function(actual, expected, message) { - push(QUnit.equiv(actual, expected), actual, expected, message); + QUnit.push(QUnit.equiv(actual, expected), actual, expected, message); }, notDeepEqual: function(actual, expected, message) { - push(!QUnit.equiv(actual, expected), actual, expected, message); + QUnit.push(!QUnit.equiv(actual, expected), actual, expected, message); }, strictEqual: function(actual, expected, message) { - push(expected === actual, actual, expected, message); + QUnit.push(expected === actual, actual, expected, message); }, notStrictEqual: function(actual, expected, message) { - push(expected !== actual, actual, expected, message); + QUnit.push(expected !== actual, actual, expected, message); }, raises: function(fn, message) { try { fn(); - ok( false, message ); + QUnit.ok( false, message ); } catch (e) { - ok( true, message ); + QUnit.ok( true, message ); } }, start: function() { // A slight delay, to avoid any current callbacks - if ( window.setTimeout ) { + if ( defined.setTimeout ) { window.setTimeout(function() { if ( config.timeout ) { clearTimeout(config.timeout); @@ -308,7 +368,7 @@ var QUnit = { stop: function(timeout) { config.blocking = true; - if ( timeout && window.setTimeout ) { + if ( timeout && defined.setTimeout ) { config.timeout = window.setTimeout(function() { QUnit.ok( false, "Test timed out" ); QUnit.start(); @@ -379,7 +439,6 @@ extend(QUnit, { blocking: false, autostart: true, autorun: false, - assertions: [], filters: [], queue: [] }); @@ -403,10 +462,17 @@ extend(QUnit, { /** * Resets the test setup. Useful for tests that modify the DOM. + * + * If jQuery is available, uses jQuery's html(), otherwise just innerHTML. */ reset: function() { if ( window.jQuery ) { - jQuery("#main, #qunit-fixture").html( config.fixture ); + jQuery( "#main, #qunit-fixture" ).html( config.fixture ); + } else { + var main = id( 'main' ) || id( 'qunit-fixture' ); + if ( main ) { + main.innerHTML = config.fixture; + } } }, @@ -469,6 +535,40 @@ extend(QUnit, { return undefined; }, + push: function(result, actual, expected, message) { + var details = { + result: result, + message: message, + actual: actual, + expected: expected + }; + + message = escapeHtml(message) || (result ? "okay" : "failed"); + message = '' + message + ""; + expected = escapeHtml(QUnit.jsDump.parse(expected)); + actual = escapeHtml(QUnit.jsDump.parse(actual)); + var output = message + ''; + if (actual != expected) { + output += ''; + output += ''; + } + if (!result) { + var source = sourceFromStacktrace(); + if (source) { + details.source = source; + output += ''; + } + } + output += "
Expected:
' + expected + '
Result:
' + actual + '
Diff:
' + QUnit.diff(expected, actual) +'
Source:
' + source +'
"; + + QUnit.log(result, message, details); + + config.current.assertions.push({ + result: !!result, + message: output + }); + }, + // Logging callbacks begin: function() {}, done: function(failures, total) {}, @@ -499,7 +599,16 @@ addEvent(window, "load", function() { } var banner = id("qunit-header"); if ( banner ) { - banner.innerHTML = '' + banner.innerHTML + ''; + var paramsIndex = location.href.lastIndexOf(location.search); + if ( paramsIndex > -1 ) { + var mainPageLocation = location.href.slice(0, paramsIndex); + if ( mainPageLocation == location.href ) { + banner.innerHTML = ' ' + banner.innerHTML + ' '; + } else { + var testName = decodeURIComponent(location.search.slice(1)); + banner.innerHTML = '' + banner.innerHTML + '' + testName + ''; + } + } } var toolbar = id("qunit-testrunner-toolbar"); @@ -524,25 +633,6 @@ addEvent(window, "load", function() { label.setAttribute("for", "qunit-filter-pass"); label.innerHTML = "Hide passed tests"; toolbar.appendChild( label ); - - var missing = document.createElement("input"); - missing.type = "checkbox"; - missing.id = "qunit-filter-missing"; - missing.disabled = true; - addEvent( missing, "click", function() { - var li = document.getElementsByTagName("li"); - for ( var i = 0; i < li.length; i++ ) { - if ( li[i].className.indexOf("fail") > -1 && li[i].innerHTML.indexOf('missing test - untested code is broken code') > - 1 ) { - li[i].parentNode.parentNode.style.display = missing.checked ? "none" : "block"; - } - } - }); - toolbar.appendChild( missing ); - - label = document.createElement("label"); - label.setAttribute("for", "qunit-filter-missing"); - label.innerHTML = "Hide missing tests (untested code is broken code)"; - toolbar.appendChild( label ); } var main = id('main') || id('qunit-fixture'); @@ -556,23 +646,6 @@ addEvent(window, "load", function() { }); function done() { - if ( config.doneTimer && window.clearTimeout ) { - window.clearTimeout( config.doneTimer ); - config.doneTimer = null; - } - - if ( config.queue.length ) { - config.doneTimer = window.setTimeout(function(){ - if ( !config.queue.length ) { - done(); - } else { - synchronize( done ); - } - }, 13); - - return; - } - config.autorun = true; // Log the last module results @@ -634,8 +707,31 @@ function validTest( name ) { return run; } +// so far supports only Firefox, Chrome and Opera (buggy) +// could be extended in the future to use something like https://github.com/csnover/TraceKit +function sourceFromStacktrace() { + try { + throw new Error(); + } catch ( e ) { + if (e.stacktrace) { + // Opera + return e.stacktrace.split("\n")[6]; + } else if (e.stack) { + // Firefox, Chrome + return e.stack.split("\n")[4]; + } + } +} + +function resultDisplayStyle(passed) { + return passed && id("qunit-filter-pass") && id("qunit-filter-pass").checked ? 'none' : ''; +} + function escapeHtml(s) { - s = s === null ? "" : s + ""; + if (!s) { + return ""; + } + s = s + ""; return s.replace(/[\&"<>\\]/g, function(s) { switch(s) { case "&": return "&"; @@ -648,24 +744,6 @@ function escapeHtml(s) { }); } -function push(result, actual, expected, message) { - message = escapeHtml(message) || (result ? "okay" : "failed"); - message = '' + message + ""; - expected = escapeHtml(QUnit.jsDump.parse(expected)); - actual = escapeHtml(QUnit.jsDump.parse(actual)); - var output = message + ', expected: ' + expected + ''; - if (actual != expected) { - output += ' result: ' + actual + ', diff: ' + QUnit.diff(expected, actual); - } - - // can't use ok, as that would double-escape messages - QUnit.log(result, output); - config.assertions.push({ - result: !!result, - message: output - }); -} - function synchronize( callback ) { config.queue.push( callback ); @@ -680,12 +758,14 @@ function process() { while ( config.queue.length && !config.blocking ) { if ( config.updateRate <= 0 || (((new Date()).getTime() - start) < config.updateRate) ) { config.queue.shift()(); - } else { - setTimeout( process, 13 ); + window.setTimeout( process, 13 ); break; } } + if (!config.blocking && !config.queue.length) { + done(); + } } function saveGlobal() { @@ -705,13 +785,13 @@ function checkPollution( name ) { var newGlobals = diff( old, config.pollution ); if ( newGlobals.length > 0 ) { ok( false, "Introduced global variable(s): " + newGlobals.join(", ") ); - config.expected++; + config.current.expected++; } var deletedGlobals = diff( config.pollution, old ); if ( deletedGlobals.length > 0 ) { ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") ); - config.expected++; + config.current.expected++; } } @@ -988,7 +1068,7 @@ QUnit.jsDump = (function() { type = "date"; } else if (QUnit.is("Function", obj)) { type = "function"; - } else if (obj.setInterval && obj.document && !obj.nodeType) { + } else if (typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined") { type = "window"; } else if (obj.nodeType === 9) { type = "document"; @@ -1042,31 +1122,31 @@ QUnit.jsDump = (function() { ret += ' ' + name; ret += '('; - ret = [ ret, this.parse( fn, 'functionArgs' ), '){'].join(''); - return join( ret, this.parse(fn,'functionCode'), '}' ); + ret = [ ret, QUnit.jsDump.parse( fn, 'functionArgs' ), '){'].join(''); + return join( ret, QUnit.jsDump.parse(fn,'functionCode'), '}' ); }, array: array, nodelist: array, arguments: array, object:function( map ) { var ret = [ ]; - this.up(); + QUnit.jsDump.up(); for ( var key in map ) - ret.push( this.parse(key,'key') + ': ' + this.parse(map[key]) ); - this.down(); + ret.push( QUnit.jsDump.parse(key,'key') + ': ' + QUnit.jsDump.parse(map[key]) ); + QUnit.jsDump.down(); return join( '{', ret, '}' ); }, node:function( node ) { - var open = this.HTML ? '<' : '<', - close = this.HTML ? '>' : '>'; + var open = QUnit.jsDump.HTML ? '<' : '<', + close = QUnit.jsDump.HTML ? '>' : '>'; var tag = node.nodeName.toLowerCase(), ret = open + tag; - for ( var a in this.DOMAttrs ) { - var val = node[this.DOMAttrs[a]]; + for ( var a in QUnit.jsDump.DOMAttrs ) { + var val = node[QUnit.jsDump.DOMAttrs[a]]; if ( val ) - ret += ' ' + a + '=' + this.parse( val, 'attribute' ); + ret += ' ' + a + '=' + QUnit.jsDump.parse( val, 'attribute' ); } return ret + close + open + '/' + tag + close; }, @@ -1094,8 +1174,8 @@ QUnit.jsDump = (function() { 'class':'className' }, HTML:false,//if true, entities are escaped ( <, >, \t, space and \n ) - indentChar:' ',//indentation unit - multiline:false //if true, items in a collection, are separated by a \n, else just a space. + indentChar:' ',//indentation unit + multiline:true //if true, items in a collection, are separated by a \n, else just a space. }; return jsDump; @@ -1255,7 +1335,7 @@ QUnit.diff = (function() { } return str; - } + }; })(); })(this); diff --git a/tests/unit/core/core.js b/tests/unit/core/core.js index ceadf207..3d8e7a09 100644 --- a/tests/unit/core/core.js +++ b/tests/unit/core/core.js @@ -2,150 +2,148 @@ * mobile core unit tests */ -(function( $ ) { - var libName = "jquery.mobile.core.js", - setGradeA = function(value) { $.support.mediaquery = value; }, - extendFn = $.extend; +var libName = "jquery.mobile.core.js", + setGradeA = function(value) { $.support.mediaquery = value; }, + extendFn = $.extend; - module(libName, { - setup: function(){ - // NOTE reset for gradeA tests - $('html').removeClass('ui-mobile'); +module(libName, { + setup: function(){ + // NOTE reset for gradeA tests + $('html').removeClass('ui-mobile'); - // NOTE reset for pageLoading tests - $('.ui-loader').remove(); - }, - teardown: function(){ - $.extend = extendFn; - } + // NOTE reset for pageLoading tests + $('.ui-loader').remove(); + }, + teardown: function(){ + $.extend = extendFn; + } +}); + +$.testHelper.excludeFileProtocol(function(){ + test( "grade A browser support media queries", function(){ + setGradeA(false); + $.testHelper.reloadLib(libName); + ok(!$.mobile.gradeA()); + + setGradeA(true); + $.testHelper.reloadLib(libName); + ok($.mobile.gradeA()); }); - $.testHelper.excludeFileProtocol(function(){ - test( "grade A browser support media queries", function(){ - setGradeA(false); - $.testHelper.reloadLib(libName); - ok(!$.mobile.gradeA()); + test( "loading the core library triggers mobilinit on the document", function(){ + expect( 1 ); - setGradeA(true); - $.testHelper.reloadLib(libName); - ok($.mobile.gradeA()); + $(window.document).bind('mobileinit', function(event){ + ok(true); }); - test( "loading the core library triggers mobilinit on the document", function(){ - expect( 1 ); - - $(window.document).bind('mobileinit', function(event){ - ok(true); - }); - - $.testHelper.reloadLib(libName); - }); - - test( "enhancments are skipped when the browser is not grade A", function(){ - setGradeA(false); - $.testHelper.reloadLib(libName); - - //NOTE easiest way to check for enhancements, not the most obvious - ok(!$("html").hasClass("ui-mobile")); - }); - - test( "enhancments are added when the browser is grade A", function(){ - setGradeA(true); - $.testHelper.reloadLib(libName); - - ok($("html").hasClass("ui-mobile")); - }); - - - //TODO lots of duplication - test( "pageLoading doesn't add the dialog to the page when loading message is false", function(){ - $.testHelper.alterExtend({loadingMessage: false}); - $.testHelper.reloadLib(libName); - $.mobile.pageLoading(false); - ok(!$(".ui-loader").length); - }); - - test( "pageLoading doesn't add the dialog to the page when done is passed as true", function(){ - $.testHelper.alterExtend({loadingMessage: true}); - $.testHelper.reloadLib(libName); - - // TODO add post reload callback - $('.ui-loader').remove(); - - $.mobile.pageLoading(true); - ok(!$(".ui-loader").length); - }); - - test( "pageLoading adds the dialog to the page when done is true", function(){ - $.testHelper.alterExtend({loadingMessage: true}); - $.testHelper.reloadLib(libName); - $.mobile.pageLoading(false); - ok($(".ui-loader").length); - }); - - var metaViewportSelector = "head meta[name=viewport]", - setViewPortContent = function(value){ - $(metaViewportSelector).remove(); - $.testHelper.alterExtend({metaViewportContent: value}); - $.testHelper.reloadLib(libName); - }; - - test( "meta view port element is added to head when defined on mobile", function(){ - setViewPortContent("width=device-width"); - same($(metaViewportSelector).length, 1); - }); - - test( "meta view port element not added to head when not defined on mobile", function(){ - setViewPortContent(false); - same($(metaViewportSelector).length, 0); - }); - - var findFirstPage = function() { - return $("[data-role='page']").first(); - }; - - test( "active page and start page should be set to the fist page in the selected set", function(){ - var firstPage = findFirstPage(); - $.testHelper.reloadLib(libName); - - same($.mobile.startPage, firstPage); - same($.mobile.activePage, firstPage); - }); - - test( "mobile viewport class is defined on the first page's parent", function(){ - var firstPage = findFirstPage(); - $.testHelper.reloadLib(libName); - - ok(firstPage.parent().hasClass('ui-mobile-viewport')); - }); - - test( "mobile page container is the first page's parent", function(){ - var firstPage = findFirstPage(); - $.testHelper.reloadLib(libName); - - same($.mobile.pageContainer, firstPage.parent()); - }); - - test( "page loading is called on document ready", function(){ - expect( 2 ); - - $.testHelper.alterExtend({ pageLoading: function(){ - ok("called"); - }}); - - $.testHelper.reloadLib(libName); - }); - - test( "hashchange triggered on document ready with single argument: true", function(){ - expect( 2 ); - - $(window).bind("hashchange", function(ev, arg){ - same(arg, true); - }); - - $.testHelper.reloadLib(libName); - }); - - //TODO test that silentScroll is called on window load + $.testHelper.reloadLib(libName); }); -})(jQuery); + + test( "enhancments are skipped when the browser is not grade A", function(){ + setGradeA(false); + $.testHelper.reloadLib(libName); + + //NOTE easiest way to check for enhancements, not the most obvious + ok(!$("html").hasClass("ui-mobile")); + }); + + test( "enhancments are added when the browser is grade A", function(){ + setGradeA(true); + $.testHelper.reloadLib(libName); + + ok($("html").hasClass("ui-mobile")); + }); + + + //TODO lots of duplication + test( "pageLoading doesn't add the dialog to the page when loading message is false", function(){ + $.testHelper.alterExtend({loadingMessage: false}); + $.testHelper.reloadLib(libName); + $.mobile.pageLoading(false); + ok(!$(".ui-loader").length); + }); + + test( "pageLoading doesn't add the dialog to the page when done is passed as true", function(){ + $.testHelper.alterExtend({loadingMessage: true}); + $.testHelper.reloadLib(libName); + + // TODO add post reload callback + $('.ui-loader').remove(); + + $.mobile.pageLoading(true); + ok(!$(".ui-loader").length); + }); + + test( "pageLoading adds the dialog to the page when done is true", function(){ + $.testHelper.alterExtend({loadingMessage: true}); + $.testHelper.reloadLib(libName); + $.mobile.pageLoading(false); + ok($(".ui-loader").length); + }); + + var metaViewportSelector = "head meta[name=viewport]", + setViewPortContent = function(value){ + $(metaViewportSelector).remove(); + $.testHelper.alterExtend({metaViewportContent: value}); + $.testHelper.reloadLib(libName); + }; + + test( "meta view port element is added to head when defined on mobile", function(){ + setViewPortContent("width=device-width"); + same($(metaViewportSelector).length, 1); + }); + + test( "meta view port element not added to head when not defined on mobile", function(){ + setViewPortContent(false); + same($(metaViewportSelector).length, 0); + }); + + var findFirstPage = function() { + return $("[data-role='page']").first(); + }; + + test( "active page and start page should be set to the fist page in the selected set", function(){ + var firstPage = findFirstPage(); + $.testHelper.reloadLib(libName); + + same($.mobile.startPage, firstPage); + same($.mobile.activePage, firstPage); + }); + + test( "mobile viewport class is defined on the first page's parent", function(){ + var firstPage = findFirstPage(); + $.testHelper.reloadLib(libName); + + ok(firstPage.parent().hasClass('ui-mobile-viewport')); + }); + + test( "mobile page container is the first page's parent", function(){ + var firstPage = findFirstPage(); + $.testHelper.reloadLib(libName); + + same($.mobile.pageContainer, firstPage.parent()); + }); + + test( "page loading is called on document ready", function(){ + expect( 2 ); + + $.testHelper.alterExtend({ pageLoading: function(){ + ok("called"); + }}); + + $.testHelper.reloadLib(libName); + }); + + test( "hashchange triggered on document ready with single argument: true", function(){ + expect( 2 ); + + $(window).bind("hashchange", function(ev, arg){ + same(arg, true); + }); + + $.testHelper.reloadLib(libName); + }); + + //TODO test that silentScroll is called on window load +}); diff --git a/tests/unit/core/core_scroll.js b/tests/unit/core/core_scroll.js index 6737cb82..ba3a007d 100644 --- a/tests/unit/core/core_scroll.js +++ b/tests/unit/core/core_scroll.js @@ -2,73 +2,71 @@ * mobile core unit tests */ -(function( $ ) { - var libName = "jquery.mobile.core.js", - scrollTimeout = 20, // TODO expose timing as an attribute - scrollStartEnabledTimeout = 150; +var libName = "jquery.mobile.core.js", + scrollTimeout = 20, // TODO expose timing as an attribute + scrollStartEnabledTimeout = 150; - module(libName, { - setup: function(){ - $("
").appendTo("body"); - }, +module(libName, { + setup: function(){ + $("
").appendTo("body"); + }, - teardown: function(){ - $("#scroll-testing").remove(); - } - }); + teardown: function(){ + $("#scroll-testing").remove(); + } +}); - var scrollUp = function( pos ){ - $(window).scrollTop(1000); - ok($(window).scrollTop() > 0); +var scrollUp = function( pos ){ + $(window).scrollTop(1000); + ok($(window).scrollTop() > 0); - if(pos) { - $.mobile.silentScroll(pos); - } else { - $.mobile.silentScroll(); - } - }; + if(pos) { + $.mobile.silentScroll(pos); + } else { + $.mobile.silentScroll(); + } +}; - test( "silent scroll scrolls the page to the top by default", function(){ - scrollUp(); +test( "silent scroll scrolls the page to the top by default", function(){ + scrollUp(); - stop(); - setTimeout(function(){ - same($(window).scrollTop(), 0); - start(); - }, scrollTimeout); - }); + stop(); + setTimeout(function(){ + same($(window).scrollTop(), 0); + start(); + }, scrollTimeout); +}); - test( "silent scroll scrolls the page to the passed y position", function(){ - var pos = 10; - scrollUp(pos); +test( "silent scroll scrolls the page to the passed y position", function(){ + var pos = 10; + scrollUp(pos); - stop(); - setTimeout(function(){ - same($(window).scrollTop(), pos); - start(); - }, scrollTimeout); - }); + stop(); + setTimeout(function(){ + same($(window).scrollTop(), pos); + start(); + }, scrollTimeout); +}); - // NOTE may be brittle depending on timing - test( "silent scroll takes at least 20 ms to scroll to the top", function(){ - scrollUp(); +// NOTE may be brittle depending on timing +test( "silent scroll takes at least 20 ms to scroll to the top", function(){ + scrollUp(); - stop(); - setTimeout(function(){ - ok($(window).scrollTop() != 0); - start(); - }, scrollTimeout - 1); - }); + stop(); + setTimeout(function(){ + ok($(window).scrollTop() != 0); + start(); + }, scrollTimeout - 1); +}); - test( "scrolling marks scrollstart as disabled for 150 ms", function(){ - $.event.special.scrollstart.enabled = true; - scrollUp(); - ok(!$.event.special.scrollstart.enabled); +test( "scrolling marks scrollstart as disabled for 150 ms", function(){ + $.event.special.scrollstart.enabled = true; + scrollUp(); + ok(!$.event.special.scrollstart.enabled); - stop(); - setTimeout(function(){ - ok($.event.special.scrollstart.enabled); - start(); - }, scrollStartEnabledTimeout); - }); -})(jQuery); + stop(); + setTimeout(function(){ + ok($.event.special.scrollstart.enabled); + start(); + }, scrollStartEnabledTimeout); +}); diff --git a/tests/unit/core/index.html b/tests/unit/core/index.html index 23d85838..c9adc415 100644 --- a/tests/unit/core/index.html +++ b/tests/unit/core/index.html @@ -38,7 +38,7 @@
-
+
diff --git a/tests/unit/event/event_core.js b/tests/unit/event/event_core.js index e02eb742..f56a2ad1 100644 --- a/tests/unit/event/event_core.js +++ b/tests/unit/event/event_core.js @@ -2,350 +2,348 @@ * mobile event unit tests */ -(function( $ ) { - var libName = "jquery.mobile.event.js", - absFn = Math.abs, - originalEventFn = $.Event.prototype.originalEvent, - preventDefaultFn = $.Event.prototype.preventDefault, - events = ("touchstart touchmove touchend orientationchange tap taphold " + - "swipe swipeleft swiperight scrollstart scrollstop").split( " " ); +var libName = "jquery.mobile.event.js", + absFn = Math.abs, + originalEventFn = $.Event.prototype.originalEvent, + preventDefaultFn = $.Event.prototype.preventDefault, + events = ("touchstart touchmove touchend orientationchange tap taphold " + + "swipe swipeleft swiperight scrollstart scrollstop").split( " " ); - module(libName, { - teardown: function(){ - $.each(events, function(i, name){ - $("#main").unbind(name); - }); - - $($.event.special.scrollstart).unbind("scrollstart"); - $($.event.special.tap).unbind("tap"); - $($.event.special.tap).unbind("taphold"); - $($.event.special.swipe).unbind("swipe"); - - //NOTE unmock - Math.abs = absFn; - $.Event.prototype.originalEvent = originalEventFn; - $.Event.prototype.preventDefault = preventDefaultFn; - } - }); - - $.testHelper.excludeFileProtocol(function(){ - test( "new events defined on the jquery object", function(){ - $.each(events, function( i, name ) { - delete $.fn[name]; - same($.fn[name], undefined); - }); - - $.testHelper.reloadLib(libName); - - $.each($.fn.clone(events), function( i, name ) { - ok($.fn[name] !== undefined, name + "is not undefined"); - }); - }); - }); - - test( "defined event functions bind a closure when passed", function(){ - expect( 1 ); - - $('#main')[events[0]](function(){ - ok(true, "event fired"); - }); - - $('#main').trigger(events[0]); - }); - - test( "defined event functions trigger the event with no arguments", function(){ - expect( 1 ); - - $('#main')[events[0]](function(){ - ok(true, "event fired"); - }); - - $('#main')[events[0]](); - }); - - test( "defining event functions sets the attrFn to true", function(){ +module(libName, { + teardown: function(){ $.each(events, function(i, name){ - ok($.attrFn[name], "attribute function is true"); + $("#qunit-fixture").unbind(name); + }); + + $($.event.special.scrollstart).unbind("scrollstart"); + $($.event.special.tap).unbind("tap"); + $($.event.special.tap).unbind("taphold"); + $($.event.special.swipe).unbind("swipe"); + + //NOTE unmock + Math.abs = absFn; + $.Event.prototype.originalEvent = originalEventFn; + $.Event.prototype.preventDefault = preventDefaultFn; + } +}); + +$.testHelper.excludeFileProtocol(function(){ + test( "new events defined on the jquery object", function(){ + $.each(events, function( i, name ) { + delete $.fn[name]; + same($.fn[name], undefined); }); - }); - test( "scrollstart enabled defaults to true", function(){ - $.event.special.scrollstart.enabled = false; $.testHelper.reloadLib(libName); - ok($.event.special.scrollstart.enabled, "scrollstart enabled"); + + $.each($.fn.clone(events), function( i, name ) { + ok($.fn[name] !== undefined, name + "is not undefined"); + }); + }); +}); + +test( "defined event functions bind a closure when passed", function(){ + expect( 1 ); + + $('#qunit-fixture')[events[0]](function(){ + ok(true, "event fired"); }); - test( "scrollstart setup binds a function that returns when its disabled", function(){ - expect( 1 ); - $.event.special.scrollstart.enabled = false; + $('#qunit-fixture').trigger(events[0]); +}); - $($.event.special.scrollstart).bind("scrollstart", function(){ - ok(false, "scrollstart fired"); - }); +test( "defined event functions trigger the event with no arguments", function(){ + expect( 1 ); - $($.event.special.scrollstart).bind("touchmove", function(){ - ok(true, "touchmove fired"); - }); - - $($.event.special.scrollstart).trigger("touchmove"); + $('#qunit-fixture')[events[0]](function(){ + ok(true, "event fired"); }); - test( "scrollstart setup binds a function that triggers scroll start when enabled", function(){ - $.event.special.scrollstart.enabled = true; + $('#qunit-fixture')[events[0]](); +}); - $($.event.special.scrollstart).bind("scrollstart", function(){ - ok(true, "scrollstart fired"); - }); +test( "defining event functions sets the attrFn to true", function(){ + $.each(events, function(i, name){ + ok($.attrFn[name], "attribute function is true"); + }); +}); - $($.event.special.scrollstart).trigger("touchmove"); +test( "scrollstart enabled defaults to true", function(){ + $.event.special.scrollstart.enabled = false; + $.testHelper.reloadLib(libName); + ok($.event.special.scrollstart.enabled, "scrollstart enabled"); +}); + +test( "scrollstart setup binds a function that returns when its disabled", function(){ + expect( 1 ); + $.event.special.scrollstart.enabled = false; + + $($.event.special.scrollstart).bind("scrollstart", function(){ + ok(false, "scrollstart fired"); }); - test( "scrollstart setup binds a function that triggers scroll stop after 50 ms", function(){ - var triggered = false; - $.event.special.scrollstart.enabled = true; - - $($.event.special.scrollstart).bind("scrollstop", function(){ - triggered = true; - }); - - ok(!triggered, "not triggered"); - - $($.event.special.scrollstart).trigger("touchmove"); - - stop(); - setTimeout(function(){ - ok(triggered, "triggered"); - start(); - }, 50); + $($.event.special.scrollstart).bind("touchmove", function(){ + ok(true, "touchmove fired"); }); - var forceTouchSupport = function(){ - $.support.touch = true; - $.testHelper.reloadLib(libName); + $($.event.special.scrollstart).trigger("touchmove"); +}); + +test( "scrollstart setup binds a function that triggers scroll start when enabled", function(){ + $.event.special.scrollstart.enabled = true; + + $($.event.special.scrollstart).bind("scrollstart", function(){ + ok(true, "scrollstart fired"); + }); + + $($.event.special.scrollstart).trigger("touchmove"); +}); + +test( "scrollstart setup binds a function that triggers scroll stop after 50 ms", function(){ + var triggered = false; + $.event.special.scrollstart.enabled = true; + + $($.event.special.scrollstart).bind("scrollstop", function(){ + triggered = true; + }); + + ok(!triggered, "not triggered"); + + $($.event.special.scrollstart).trigger("touchmove"); + + stop(); + setTimeout(function(){ + ok(triggered, "triggered"); + start(); + }, 50); +}); + +var forceTouchSupport = function(){ + $.support.touch = true; + $.testHelper.reloadLib(libName); +}; + +test( "long press fires tap hold after 750 ms", function(){ + var taphold = false; + + forceTouchSupport(); + + $($.event.special.tap).bind("taphold", function(){ + taphold = true; + }); + + $($.event.special.tap).trigger("touchstart"); + + stop(); + setTimeout(function(){ + ok(taphold); + start(); + }, 751); +}); + +//NOTE used to simulate movement when checked +//TODO find a better way ... +var mockAbs = function(value){ + Math.abs = function(){ + return value; }; +}; - test( "long press fires tap hold after 750 ms", function(){ - var taphold = false; +test( "touchmove prevents taphold", function(){ + var taphold = false; - forceTouchSupport(); + forceTouchSupport(); + mockAbs(100); - $($.event.special.tap).bind("taphold", function(){ - taphold = true; - }); - - $($.event.special.tap).trigger("touchstart"); - - stop(); - setTimeout(function(){ - ok(taphold); - start(); - }, 751); + //NOTE record taphold event + stop(); + $($.event.special.tap).bind("taphold", function(){ + taphold = true; }); - //NOTE used to simulate movement when checked - //TODO find a better way ... - var mockAbs = function(value){ - Math.abs = function(){ - return value; - }; - }; + //NOTE start the touch events + $($.event.special.tap).trigger("touchstart"); - test( "touchmove prevents taphold", function(){ - var taphold = false; - - forceTouchSupport(); - mockAbs(100); - - //NOTE record taphold event - stop(); - $($.event.special.tap).bind("taphold", function(){ - taphold = true; - }); - - //NOTE start the touch events - $($.event.special.tap).trigger("touchstart"); - - //NOTE fire touchmove to push back taphold - setTimeout(function(){ - $($.event.special.tap).trigger("touchmove"); - }, 100); - - //NOTE verify that the taphold hasn't been fired - // with the normal timing - setTimeout(function(){ - ok(!taphold, "taphold not fired"); - start(); - }, 751); - }); - - test( "tap event fired without movement", function(){ - var tap = false; - - forceTouchSupport(); - - //NOTE record the tap event - $($.event.special.tap).bind("tap", function(){ - start(); - tap = true; - }); - - stop(); - $($.event.special.tap).trigger("touchstart"); - $($.event.special.tap).trigger("touchend"); - - ok(tap, "tapped"); - }); - - test( "tap event not fired when there is movement", function(){ - var tap = false; - forceTouchSupport(); - - //NOTE record tap event - $($.event.special.tap).bind("tap", function(){ - tap = true; - }); - - //NOTE make sure movement is recorded - mockAbs(100); - - //NOTE start and move right away - $($.event.special.tap).trigger("touchstart"); + //NOTE fire touchmove to push back taphold + setTimeout(function(){ $($.event.special.tap).trigger("touchmove"); + }, 100); - //NOTE end touch sequence after 20 ms - stop(); - setTimeout(function(){ - $($.event.special.tap).trigger("touchend"); - start(); - }, 20); + //NOTE verify that the taphold hasn't been fired + // with the normal timing + setTimeout(function(){ + ok(!taphold, "taphold not fired"); + start(); + }, 751); +}); - ok(!tap, "not tapped"); +test( "tap event fired without movement", function(){ + var tap = false; + + forceTouchSupport(); + + //NOTE record the tap event + $($.event.special.tap).bind("tap", function(){ + start(); + tap = true; }); - var swipeTimedTest = function(opts){ - var swipe = false; + stop(); + $($.event.special.tap).trigger("touchstart"); + $($.event.special.tap).trigger("touchend"); - forceTouchSupport(); + ok(tap, "tapped"); +}); - $($.event.special.swipe).bind('swipe', function(){ - swipe = true; - start(); - }); +test( "tap event not fired when there is movement", function(){ + var tap = false; + forceTouchSupport(); - //NOTE bypass the trigger source check - $.Event.prototype.originalEvent = { - touches: false - }; + //NOTE record tap event + $($.event.special.tap).bind("tap", function(){ + tap = true; + }); - $($.event.special.swipe).trigger("touchstart"); + //NOTE make sure movement is recorded + mockAbs(100); - //NOTE make sure the coordinates are calculated within range - // to be registered as a swipe - mockAbs(opts.coordChange); + //NOTE start and move right away + $($.event.special.tap).trigger("touchstart"); + $($.event.special.tap).trigger("touchmove"); - setTimeout(function(){ - $($.event.special.swipe).trigger("touchmove"); - $($.event.special.swipe).trigger("touchend"); - }, opts.timeout); + //NOTE end touch sequence after 20 ms + stop(); + setTimeout(function(){ + $($.event.special.tap).trigger("touchend"); + start(); + }, 20); - stop(); - setTimeout(function(){ - same(swipe, opts.expected, "swipe expected"); + ok(!tap, "not tapped"); +}); - //NOTE the start in the event closure won't be fired, fire it here - if(!opts.expected) { start(); } - }, opts.timeout + 10); +var swipeTimedTest = function(opts){ + var swipe = false; + + forceTouchSupport(); + + $($.event.special.swipe).bind('swipe', function(){ + swipe = true; + start(); + }); + + //NOTE bypass the trigger source check + $.Event.prototype.originalEvent = { + touches: false }; - test( "swipe fired when coordinate change in less than a second", function(){ - swipeTimedTest({ timeout: 10, coordChange: 35, expected: true }); - }); + $($.event.special.swipe).trigger("touchstart"); - test( "swipe not fired when coordinate change takes more than a second", function(){ - swipeTimedTest({ timeout: 1000, coordChange: 35, expected: false }); - }); + //NOTE make sure the coordinates are calculated within range + // to be registered as a swipe + mockAbs(opts.coordChange); - test( "swipe not fired when coordinate change <= 30", function(){ - swipeTimedTest({ timeout: 1000, coordChange: 30, expected: false }); - }); - - test( "swipe not fired when coordinate change >= 75", function(){ - swipeTimedTest({ timeout: 1000, coordChange: 75, expected: false }); - }); - - test( "scrolling prevented when coordinate change > 10", function(){ - expect( 1 ); - - //NOTE bypass the trigger source check - $.Event.prototype.originalEvent = { - touches: false - }; - - $.Event.prototype.preventDefault = function(){ - ok(true, "prevent default called"); - }; - - mockAbs(11); - - $($.event.special.swipe).trigger("touchstart"); + setTimeout(function(){ $($.event.special.swipe).trigger("touchmove"); - }); - - test( "move handler returns when touchstart has been fired since touchstop", function(){ - expect( 1 ); - - $.Event.prototype.originalEvent = { - touches: false - }; - - $($.event.special.swipe).trigger("touchstart"); $($.event.special.swipe).trigger("touchend"); + }, opts.timeout); - $($.event.special.swipe).bind("touchmove", function(){ - ok(true, "touchmove bound functions are fired"); - }); + stop(); + setTimeout(function(){ + same(swipe, opts.expected, "swipe expected"); - Math.abs = function(){ - ok(false, "shouldn't compare coordinates"); - }; + //NOTE the start in the event closure won't be fired, fire it here + if(!opts.expected) { start(); } + }, opts.timeout + 10); +}; - $($.event.special.swipe).trigger("touchmove"); - }); +test( "swipe fired when coordinate change in less than a second", function(){ + swipeTimedTest({ timeout: 10, coordChange: 35, expected: true }); +}); - var nativeSupportTest = function(opts){ - $.support.orientation = opts.orientationSupport; - same($.event.special.orientationchange[opts.method](), opts.returnValue); +test( "swipe not fired when coordinate change takes more than a second", function(){ + swipeTimedTest({ timeout: 1000, coordChange: 35, expected: false }); +}); + +test( "swipe not fired when coordinate change <= 30", function(){ + swipeTimedTest({ timeout: 1000, coordChange: 30, expected: false }); +}); + +test( "swipe not fired when coordinate change >= 75", function(){ + swipeTimedTest({ timeout: 1000, coordChange: 75, expected: false }); +}); + +test( "scrolling prevented when coordinate change > 10", function(){ + expect( 1 ); + + //NOTE bypass the trigger source check + $.Event.prototype.originalEvent = { + touches: false }; - test( "orientation change setup should do nothing when natively supported", function(){ - nativeSupportTest({ - method: 'setup', - orientationSupport: true, - returnValue: false - }); + $.Event.prototype.preventDefault = function(){ + ok(true, "prevent default called"); + }; + + mockAbs(11); + + $($.event.special.swipe).trigger("touchstart"); + $($.event.special.swipe).trigger("touchmove"); +}); + +test( "move handler returns when touchstart has been fired since touchstop", function(){ + expect( 1 ); + + $.Event.prototype.originalEvent = { + touches: false + }; + + $($.event.special.swipe).trigger("touchstart"); + $($.event.special.swipe).trigger("touchend"); + + $($.event.special.swipe).bind("touchmove", function(){ + ok(true, "touchmove bound functions are fired"); }); - test( "orientation change setup should bind resize when not supported natively", function(){ - nativeSupportTest({ - method: 'setup', - orientationSupport: false, - returnValue: undefined //NOTE result of bind function call - }); - }); + Math.abs = function(){ + ok(false, "shouldn't compare coordinates"); + }; - test( "orientation change teardown should do nothing when natively supported", function(){ - nativeSupportTest({ - method: 'teardown', - orientationSupport: true, - returnValue: false - }); - }); + $($.event.special.swipe).trigger("touchmove"); +}); - test( "orientation change teardown should unbind resize when not supported natively", function(){ - nativeSupportTest({ - method: 'teardown', - orientationSupport: false, - returnValue: undefined //NOTE result of unbind function call - }); +var nativeSupportTest = function(opts){ + $.support.orientation = opts.orientationSupport; + same($.event.special.orientationchange[opts.method](), opts.returnValue); +}; + +test( "orientation change setup should do nothing when natively supported", function(){ + nativeSupportTest({ + method: 'setup', + orientationSupport: true, + returnValue: false }); -})(jQuery); \ No newline at end of file +}); + +test( "orientation change setup should bind resize when not supported natively", function(){ + nativeSupportTest({ + method: 'setup', + orientationSupport: false, + returnValue: undefined //NOTE result of bind function call + }); +}); + +test( "orientation change teardown should do nothing when natively supported", function(){ + nativeSupportTest({ + method: 'teardown', + orientationSupport: true, + returnValue: false + }); +}); + +test( "orientation change teardown should unbind resize when not supported natively", function(){ + nativeSupportTest({ + method: 'teardown', + orientationSupport: false, + returnValue: undefined //NOTE result of unbind function call + }); +}); diff --git a/tests/unit/event/index.html b/tests/unit/event/index.html index b3be1ed5..09d22545 100644 --- a/tests/unit/event/index.html +++ b/tests/unit/event/index.html @@ -25,8 +25,7 @@
-
-
+
diff --git a/tests/unit/media/index.html b/tests/unit/media/index.html index 920d80a2..8eff77e4 100644 --- a/tests/unit/media/index.html +++ b/tests/unit/media/index.html @@ -22,8 +22,7 @@
-
-
+
diff --git a/tests/unit/media/media_core.js b/tests/unit/media/media_core.js index cf63d11b..bfe901e8 100644 --- a/tests/unit/media/media_core.js +++ b/tests/unit/media/media_core.js @@ -2,96 +2,94 @@ * mobile media unit tests */ -(function( $ ) { - var cssFn = $.fn.css, - widthFn = $.fn.width; +var cssFn = $.fn.css, + widthFn = $.fn.width; - // make sure original definitions are reset - module('jquery.mobile.media.js', { - teardown: function(){ - $.fn.css = cssFn; - $.fn.width = widthFn; - } +// make sure original definitions are reset +module('jquery.mobile.media.js', { + teardown: function(){ + $.fn.css = cssFn; + $.fn.width = widthFn; + } +}); + +test( "media query check returns true when the position is absolute", function(){ + $.fn.css = function(){ return "absolute"; }; + same($.mobile.media("screen 1"), true); +}); + +test( "media query check returns false when the position is not absolute", function(){ + $.fn.css = function(){ return "not absolute"; }; + same($.mobile.media("screen 2"), false); +}); + +test( "media query check is cached", function(){ + $.fn.css = function(){ return "absolute"; }; + same($.mobile.media("screen 3"), true); + + $.fn.css = function(){ return "not absolute"; }; + same($.mobile.media("screen 3"), true); +}); + +test( "window widths smaller than the break points set max-width classes", function(){ + $.fn.width = function(){ return 120; }; + + $.mobile.addResolutionBreakpoints([125]); + ok($("html").hasClass("max-width-125px")); +}); + +test( "window widths larger than the break points set min-width classes", function(){ + $.fn.width = function(){ return 1900; }; + + $.mobile.addResolutionBreakpoints([125]); + ok($("html").hasClass("min-width-125px")); +}); + +test( "many break points result in many class additions", function(){ + $.fn.width = function(){ return 1900; }; + $.mobile.addResolutionBreakpoints([1, 2]); + + ok($("html").hasClass("min-width-1px")); + ok($("html").hasClass("min-width-2px")); +}); + +test( "adds all classes for default res breakpoints", function(){ + expect( 4 ); + $.fn.width = function(){ return 1900; }; + $.mobile.addResolutionBreakpoints([]); + + // TODO should expose the defaults to prevent brittle tests + $.each([320, 480, 768, 1024], function(i, element){ + ok($("html").hasClass("min-width-" + element + "px")); + }); +}); + +test( "triggering mobile init triggers orientationchange.htmlclass", function(){ + expect( 1 ); + + $(window).bind("orientationchange.htmlclass", function(event){ + ok(event); }); - test( "media query check returns true when the position is absolute", function(){ - $.fn.css = function(){ return "absolute"; }; - same($.mobile.media("screen 1"), true); - }); + $(document).trigger("mobileinit.htmlclass"); +}); - test( "media query check returns false when the position is not absolute", function(){ - $.fn.css = function(){ return "not absolute"; }; - same($.mobile.media("screen 2"), false); - }); +test( "binds remove of portrait and landscape classes resize/orientation fired", function(){ + $.Event.prototype.orientation = true; - test( "media query check is cached", function(){ - $.fn.css = function(){ return "absolute"; }; - same($.mobile.media("screen 3"), true); + $("html").addClass("portrait landscape"); + $(window).trigger("resize.htmlclass"); + ok(!$("html").hasClass("portrait landscape")); - $.fn.css = function(){ return "not absolute"; }; - same($.mobile.media("screen 3"), true); - }); + $("html").addClass("portrait landscape"); + $(window).trigger("resize.htmlclass"); + ok(!$("html").hasClass("portrait landscape")); +}); - test( "window widths smaller than the break points set max-width classes", function(){ - $.fn.width = function(){ return 120; }; +test( "sets break point class additions on resize/orientation change", function(){ + $.fn.width = function(){ return 1900; }; - $.mobile.addResolutionBreakpoints([125]); - ok($("html").hasClass("max-width-125px")); - }); - - test( "window widths larger than the break points set min-width classes", function(){ - $.fn.width = function(){ return 1900; }; - - $.mobile.addResolutionBreakpoints([125]); - ok($("html").hasClass("min-width-125px")); - }); - - test( "many break points result in many class additions", function(){ - $.fn.width = function(){ return 1900; }; - $.mobile.addResolutionBreakpoints([1, 2]); - - ok($("html").hasClass("min-width-1px")); - ok($("html").hasClass("min-width-2px")); - }); - - test( "adds all classes for default res breakpoints", function(){ - expect( 4 ); - $.fn.width = function(){ return 1900; }; - $.mobile.addResolutionBreakpoints([]); - - // TODO should expose the defaults to prevent brittle tests - $.each([320, 480, 768, 1024], function(i, element){ - ok($("html").hasClass("min-width-" + element + "px")); - }); - }); - - test( "triggering mobile init triggers orientationchange.htmlclass", function(){ - expect( 1 ); - - $(window).bind("orientationchange.htmlclass", function(event){ - ok(event); - }); - - $(document).trigger("mobileinit.htmlclass"); - }); - - test( "binds remove of portrait and landscape classes resize/orientation fired", function(){ - $.Event.prototype.orientation = true; - - $("html").addClass("portrait landscape"); - $(window).trigger("resize.htmlclass"); - ok(!$("html").hasClass("portrait landscape")); - - $("html").addClass("portrait landscape"); - $(window).trigger("resize.htmlclass"); - ok(!$("html").hasClass("portrait landscape")); - }); - - test( "sets break point class additions on resize/orientation change", function(){ - $.fn.width = function(){ return 1900; }; - - $("html").removeClass("min-width-320px"); - $(window).trigger("resize.htmlclass"); - ok($("html").hasClass("min-width-320px")); - }); -})(jQuery); \ No newline at end of file + $("html").removeClass("min-width-320px"); + $(window).trigger("resize.htmlclass"); + ok($("html").hasClass("min-width-320px")); +}); diff --git a/tests/unit/navigation/navigation_core.js b/tests/unit/navigation/navigation_core.js index a51a3124..7ebb72d6 100644 --- a/tests/unit/navigation/navigation_core.js +++ b/tests/unit/navigation/navigation_core.js @@ -1,48 +1,46 @@ /* * mobile navigation unit tests */ -(function( $ ) { - var perspective = "ui-mobile-viewport-perspective", - transitioning = "ui-mobile-viewport-transitioning", - animationCompleteFn = $.fn.animationComplete, +var perspective = "ui-mobile-viewport-perspective", + transitioning = "ui-mobile-viewport-transitioning", + animationCompleteFn = $.fn.animationComplete, - removeClasses = function(){ - $("body").removeClass([perspective, transitioning].join(" ")); - }; + removeClasses = function(){ + $("body").removeClass([perspective, transitioning].join(" ")); + }; - module('jquery.mobile.navigation.js', { - teardown: function(){ - // unmock animation complete - $.fn.animationComplete = animationCompleteFn; +module('jquery.mobile.navigation.js', { + teardown: function(){ + // unmock animation complete + $.fn.animationComplete = animationCompleteFn; - removeClasses(); - }}); + removeClasses(); + }}); - test( "changePage applys perspective class to mobile viewport for flip", function(){ - //stub to prevent class removal - $.fn.animationComplete = function(){}; +test( "changePage applys perspective class to mobile viewport for flip", function(){ + //stub to prevent class removal + $.fn.animationComplete = function(){}; - $("#foo > a").click(); + $("#foo > a").click(); - ok($("body").hasClass(perspective), "has perspective class"); - }); + ok($("body").hasClass(perspective), "has perspective class"); +}); - test( "changePage applys does not apply perspective class to mobile viewport for transitions other than flip", function(){ - //stub to prevent class removal - $.fn.animationComplete = function(){}; +test( "changePage applys does not apply perspective class to mobile viewport for transitions other than flip", function(){ + //stub to prevent class removal + $.fn.animationComplete = function(){}; - $("#bar > a").click(); + $("#bar > a").click(); - ok(!$("body").hasClass(perspective), "doesn't have perspective class"); - }); + ok(!$("body").hasClass(perspective), "doesn't have perspective class"); +}); - test( "changePage applys transition class to mobile viewport for default transition", function(){ - //stub to prevent class removal - $.fn.animationComplete = function(){}; +test( "changePage applys transition class to mobile viewport for default transition", function(){ + //stub to prevent class removal + $.fn.animationComplete = function(){}; - $("#baz > a").click(); + $("#baz > a").click(); - ok($("body").hasClass(transitioning), "has transitioning class"); - }); -})(jQuery); \ No newline at end of file + ok($("body").hasClass(transitioning), "has transitioning class"); +}); diff --git a/tests/unit/page/index.html b/tests/unit/page/index.html index ced9b641..4f4970bb 100644 --- a/tests/unit/page/index.html +++ b/tests/unit/page/index.html @@ -46,7 +46,7 @@
-
+
diff --git a/tests/unit/page/page_core.js b/tests/unit/page/page_core.js index de967326..bc610320 100644 --- a/tests/unit/page/page_core.js +++ b/tests/unit/page/page_core.js @@ -1,31 +1,29 @@ /* * mobile page unit tests */ -(function( $ ) { - module('jquery.mobile.page.js'); +module('jquery.mobile.page.js'); - test( "nested header anchors aren't altered", function(){ - ok(!$('.ui-header > div > a').hasClass('ui-btn')); - }); +test( "nested header anchors aren't altered", function(){ + ok(!$('.ui-header > div > a').hasClass('ui-btn')); +}); - test( "nested footer anchors aren't altered", function(){ - ok(!$('.ui-footer > div > a').hasClass('ui-btn')); - }); +test( "nested footer anchors aren't altered", function(){ + ok(!$('.ui-footer > div > a').hasClass('ui-btn')); +}); - test( "nested bar anchors aren't styled", function(){ - ok(!$('.ui-bar > div > a').hasClass('ui-btn')); - }); +test( "nested bar anchors aren't styled", function(){ + ok(!$('.ui-bar > div > a').hasClass('ui-btn')); +}); - test( "unnested footer anchors are styled", function(){ - ok($('.ui-footer > a').hasClass('ui-btn')); - }); +test( "unnested footer anchors are styled", function(){ + ok($('.ui-footer > a').hasClass('ui-btn')); +}); - test( "unnested footer anchors are styled", function(){ - ok($('.ui-footer > a').hasClass('ui-btn')); - }); +test( "unnested footer anchors are styled", function(){ + ok($('.ui-footer > a').hasClass('ui-btn')); +}); - test( "unnested bar anchors are styled", function(){ - ok($('.ui-bar > a').hasClass('ui-btn')); - }); +test( "unnested bar anchors are styled", function(){ + ok($('.ui-bar > a').hasClass('ui-btn')); +}); -})(jQuery); \ No newline at end of file diff --git a/tests/unit/support/index.html b/tests/unit/support/index.html index 157139d4..42c80af9 100644 --- a/tests/unit/support/index.html +++ b/tests/unit/support/index.html @@ -24,8 +24,7 @@
-
-
+
diff --git a/tests/unit/support/support_core.js b/tests/unit/support/support_core.js index 54d0f7df..36c80fa3 100644 --- a/tests/unit/support/support_core.js +++ b/tests/unit/support/support_core.js @@ -2,76 +2,74 @@ * mobile support unit tests */ -(function( $ ) { - $.testHelper.excludeFileProtocol(function(){ - var prependToFn = $.fn.prependTo, - libName = "jquery.mobile.support.js"; +$.testHelper.excludeFileProtocol(function(){ + var prependToFn = $.fn.prependTo, + libName = "jquery.mobile.support.js"; - module(libName, { - teardown: function(){ - //NOTE undo any mocking - $.fn.prependTo = prependToFn; - } - }); - - // NOTE following two tests have debatable value as they only - // prevent property name changes and improper attribute checks - test( "detects functionality from basic affirmative properties and attributes", function(){ - // TODO expose properties for less brittle tests - $.extend(window, { - WebKitTransitionEvent: true, - orientation: true - }); - - document.ontouchend = true; - - history.pushState = function(){}; - $.mobile.media = function(){ return true; }; - - $.testHelper.reloadLib(libName); - - ok($.support.orientation); - ok($.support.touch); - ok($.support.cssTransitions); - ok($.support.pushState); - ok($.support.mediaquery); - }); - - test( "detects functionality from basic negative properties and attributes (where possible)", function(){ - delete window["orientation"]; - delete document["ontouchend"]; - - $.testHelper.reloadLib(libName); - - ok(!$.support.orientation); - ok(!$.support.touch); - }); - - // NOTE mocks prependTo to simulate base href updates or lack thereof - var mockBaseCheck = function( url ){ - var prependToFn = $.fn.prependTo; - - $.fn.prependTo = function( selector ){ - var result = prependToFn.call(this, selector); - if(this[0].href && this[0].href.indexOf("testurl") != -1) - result = [{href: url}]; - return result; - }; - }; - - test( "detects dynamic base tag when new base element added and base href updates", function(){ - mockBaseCheck(location.protocol + '//' + location.host + location.pathname + "ui-dir/"); - $.testHelper.reloadLib(libName); - ok($.support.dynamicBaseTag); - }); - - test( "detects no dynamic base tag when new base element added and base href unchanged", function(){ - mockBaseCheck('testurl'); - $.testHelper.reloadLib(libName); - ok(!$.support.dynamicBaseTag); - }); - - //TODO propExists testing, refactor propExists into mockable method - //TODO scrollTop testing, refactor scrollTop logic into mockable method + module(libName, { + teardown: function(){ + //NOTE undo any mocking + $.fn.prependTo = prependToFn; + } }); -})(jQuery); \ No newline at end of file + + // NOTE following two tests have debatable value as they only + // prevent property name changes and improper attribute checks + test( "detects functionality from basic affirmative properties and attributes", function(){ + // TODO expose properties for less brittle tests + $.extend(window, { + WebKitTransitionEvent: true, + orientation: true + }); + + document.ontouchend = true; + + history.pushState = function(){}; + $.mobile.media = function(){ return true; }; + + $.testHelper.reloadLib(libName); + + ok($.support.orientation); + ok($.support.touch); + ok($.support.cssTransitions); + ok($.support.pushState); + ok($.support.mediaquery); + }); + + test( "detects functionality from basic negative properties and attributes (where possible)", function(){ + delete window["orientation"]; + delete document["ontouchend"]; + + $.testHelper.reloadLib(libName); + + ok(!$.support.orientation); + ok(!$.support.touch); + }); + + // NOTE mocks prependTo to simulate base href updates or lack thereof + var mockBaseCheck = function( url ){ + var prependToFn = $.fn.prependTo; + + $.fn.prependTo = function( selector ){ + var result = prependToFn.call(this, selector); + if(this[0].href && this[0].href.indexOf("testurl") != -1) + result = [{href: url}]; + return result; + }; + }; + + test( "detects dynamic base tag when new base element added and base href updates", function(){ + mockBaseCheck(location.protocol + '//' + location.host + location.pathname + "ui-dir/"); + $.testHelper.reloadLib(libName); + ok($.support.dynamicBaseTag); + }); + + test( "detects no dynamic base tag when new base element added and base href unchanged", function(){ + mockBaseCheck('testurl'); + $.testHelper.reloadLib(libName); + ok(!$.support.dynamicBaseTag); + }); + + //TODO propExists testing, refactor propExists into mockable method + //TODO scrollTop testing, refactor scrollTop logic into mockable method +}); diff --git a/tests/unit/widget/index.html b/tests/unit/widget/index.html index 64edaded..edc14612 100644 --- a/tests/unit/widget/index.html +++ b/tests/unit/widget/index.html @@ -21,7 +21,7 @@
-
+
diff --git a/tests/unit/widget/widget_core.js b/tests/unit/widget/widget_core.js index a7cc8aa9..1da03185 100644 --- a/tests/unit/widget/widget_core.js +++ b/tests/unit/widget/widget_core.js @@ -2,33 +2,31 @@ * mobile widget unit tests */ -(function( $ ) { - module('jquery.mobile.widget.js'); +module('jquery.mobile.widget.js'); - test( "getting data from creation options", function(){ - var expected = "bizzle"; +test( "getting data from creation options", function(){ + var expected = "bizzle"; - $.mobile.widget.prototype.options = { "fooBar" : true }; - $.mobile.widget.prototype.element = $("
"); - same($.mobile.widget.prototype._getCreateOptions()["fooBar"], - expected); - }); + $.mobile.widget.prototype.options = { "fooBar" : true }; + $.mobile.widget.prototype.element = $("
"); + same($.mobile.widget.prototype._getCreateOptions()["fooBar"], + expected); +}); - test( "getting no data when the options are empty", function(){ - var expected = {}; +test( "getting no data when the options are empty", function(){ + var expected = {}; - $.mobile.widget.prototype.options = {}; - $.mobile.widget.prototype.element = $("
"); - same($.mobile.widget.prototype._getCreateOptions(), - expected); - }); + $.mobile.widget.prototype.options = {}; + $.mobile.widget.prototype.element = $("
"); + same($.mobile.widget.prototype._getCreateOptions(), + expected); +}); - test( "getting no data when the element has none", function(){ - var expected = {}; +test( "getting no data when the element has none", function(){ + var expected = {}; - $.mobile.widget.prototype.options = { "fooBar" : true }; - $.mobile.widget.prototype.element = $("
"); - same($.mobile.widget.prototype._getCreateOptions(), - expected); - }); -})(jQuery); \ No newline at end of file + $.mobile.widget.prototype.options = { "fooBar" : true }; + $.mobile.widget.prototype.element = $("
"); + same($.mobile.widget.prototype._getCreateOptions(), + expected); +});