Comparing version 0.2.2 to 0.3.0
@@ -0,1 +1,6 @@ | ||
## 0.3.0 (20th September, 2012) | ||
* added inflect.decapitalize (thanks to ikr) | ||
* updated dependencies | ||
## 0.2.2 (19th March, 2012) | ||
@@ -2,0 +7,0 @@ |
@@ -0,2 +1,3 @@ | ||
// Generated by CoffeeScript 1.3.3 | ||
module.exports = require("./inflect"); |
@@ -0,1 +1,2 @@ | ||
// Generated by CoffeeScript 1.3.3 | ||
var inflect; | ||
@@ -2,0 +3,0 @@ |
@@ -1,13 +0,10 @@ | ||
var Inflections, inflections, methods, number_extensions, string_extensions, version; | ||
// Generated by CoffeeScript 1.3.3 | ||
var Inflections, inflections, methods, number_extensions, string_extensions; | ||
version = require('./version'); | ||
exports.package = version.package; | ||
exports.version = version.version; | ||
Inflections = require('./inflections').Inflections; | ||
inflections = function(callback) { | ||
if (callback != null) callback.call(this, Inflections.instance()); | ||
if (callback != null) { | ||
callback.call(this, Inflections.instance()); | ||
} | ||
return Inflections.instance(); | ||
@@ -32,2 +29,4 @@ }; | ||
exports.decapitalize = methods.decapitalize; | ||
exports.pluralize = methods.pluralize; | ||
@@ -34,0 +33,0 @@ |
@@ -0,3 +1,4 @@ | ||
// Generated by CoffeeScript 1.3.3 | ||
var Inflections, | ||
__slice = Array.prototype.slice; | ||
__slice = [].slice; | ||
@@ -72,3 +73,5 @@ Inflections = (function() { | ||
Inflections.prototype.clear = function(scope) { | ||
if (scope == null) scope = 'all'; | ||
if (scope == null) { | ||
scope = 'all'; | ||
} | ||
if (scope === 'all') { | ||
@@ -75,0 +78,0 @@ this.plurals = []; |
@@ -1,2 +0,3 @@ | ||
var camelize, capitalize, dasherize, humanize, inflections, ordinalize, parameterize, pluralize, singularize, titleize, underscore; | ||
// Generated by CoffeeScript 1.3.3 | ||
var camelize, capitalize, dasherize, decapitalize, humanize, inflections, ordinalize, parameterize, pluralize, singularize, titleize, underscore; | ||
@@ -7,3 +8,5 @@ inflections = require('../inflect').inflections; | ||
var rest; | ||
if (first_letter_in_uppercase == null) first_letter_in_uppercase = true; | ||
if (first_letter_in_uppercase == null) { | ||
first_letter_in_uppercase = true; | ||
} | ||
rest = lower_case_and_underscored_word.replace(/_./g, function(val) { | ||
@@ -43,2 +46,6 @@ return val.slice(1).toUpperCase(); | ||
decapitalize = function(word) { | ||
return (word[0] || '').toLowerCase() + (word.slice(1) || ''); | ||
}; | ||
pluralize = function(word) { | ||
@@ -65,3 +72,3 @@ var plural, replacement, result, rule, _i, _len, _ref; | ||
singularize = function(word) { | ||
var inflection, replacement, result, rule, singular, uncountable, _i, _j, _len, _len2, _ref, _ref2; | ||
var inflection, replacement, result, rule, singular, uncountable, _i, _j, _len, _len1, _ref, _ref1; | ||
result = word.toString(); | ||
@@ -80,5 +87,5 @@ uncountable = false; | ||
} else { | ||
_ref2 = inflections().singulars; | ||
for (_j = 0, _len2 = _ref2.length; _j < _len2; _j++) { | ||
singular = _ref2[_j]; | ||
_ref1 = inflections().singulars; | ||
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { | ||
singular = _ref1[_j]; | ||
rule = singular[0]; | ||
@@ -132,3 +139,5 @@ replacement = singular[1]; | ||
var parameterized_string; | ||
if (sep == null) sep = '-'; | ||
if (sep == null) { | ||
sep = '-'; | ||
} | ||
parameterized_string = string.toString(); | ||
@@ -153,2 +162,4 @@ parameterized_string = parameterized_string.replace(/[^a-z0-9\-_]+/gi, sep); | ||
exports.decapitalize = decapitalize; | ||
exports.pluralize = pluralize; | ||
@@ -155,0 +166,0 @@ |
@@ -0,1 +1,2 @@ | ||
// Generated by CoffeeScript 1.3.3 | ||
var enableNumberExtensions, inflect; | ||
@@ -2,0 +3,0 @@ |
@@ -0,1 +1,2 @@ | ||
// Generated by CoffeeScript 1.3.3 | ||
var enableStringExtensions, inflect; | ||
@@ -13,3 +14,5 @@ | ||
String.prototype.camelize = function(first_letter_in_uppercase) { | ||
if (first_letter_in_uppercase == null) first_letter_in_uppercase = true; | ||
if (first_letter_in_uppercase == null) { | ||
first_letter_in_uppercase = true; | ||
} | ||
return inflect.camelize(this, first_letter_in_uppercase); | ||
@@ -20,2 +23,5 @@ }; | ||
}; | ||
String.prototype.decapitalize = function() { | ||
return inflect.decapitalize(this); | ||
}; | ||
String.prototype.titleize = function() { | ||
@@ -31,3 +37,5 @@ return inflect.titleize(this); | ||
String.prototype.parameterize = function(sep) { | ||
if (sep == null) sep = '-'; | ||
if (sep == null) { | ||
sep = '-'; | ||
} | ||
return inflect.parameterize(this, sep); | ||
@@ -34,0 +42,0 @@ }; |
@@ -5,3 +5,3 @@ { | ||
"keywords": ["inflect", "activerecord", "rails", "activesupport", "string"], | ||
"version": "0.2.2", | ||
"version": "0.3.0", | ||
"author": "Stefan Huber <MSNexploder@gmail.com>", | ||
@@ -31,8 +31,7 @@ "homepage": "http://msnexploder.github.com/inflect/", | ||
"devDependencies": { | ||
"coffee-script": "~1.2.0", | ||
"docco": "~0.3.0", | ||
"vows": "~0.6.2", | ||
"browserify": "~1.10.4", | ||
"fileify": "~0.3.1", | ||
"uglify-js": "~1.2.6" | ||
"coffee-script": "~1.3.3", | ||
"docco": "~0.4.0", | ||
"vows": "~0.6.4", | ||
"browserify": "~1.16.1", | ||
"uglify-js": "~1.3.3" | ||
}, | ||
@@ -39,0 +38,0 @@ "repository": { |
@@ -27,2 +27,4 @@ # Inflect [![Build Status](https://secure.travis-ci.org/MSNexploder/inflect.png)](http://travis-ci.org/MSNexploder/inflect) | ||
inflect.decapitalize('User'); // user | ||
inflect.titleize('man from the boondocks'); // Man From The Boondocks | ||
@@ -29,0 +31,0 @@ |
/** | ||
* QUnit v1.3.0pre - A JavaScript Unit Testing Framework | ||
* QUnit v1.10.0 - A JavaScript Unit Testing Framework | ||
* | ||
* http://docs.jquery.com/QUnit | ||
* http://qunitjs.com | ||
* | ||
* Copyright (c) 2011 John Resig, Jörn Zaefferer | ||
* Dual licensed under the MIT (MIT-LICENSE.txt) | ||
* or GPL (GPL-LICENSE.txt) licenses. | ||
* Copyright 2012 jQuery Foundation and other contributors | ||
* Released under the MIT license. | ||
* http://jquery.org/license | ||
*/ | ||
(function(window) { | ||
(function( window ) { | ||
var defined = { | ||
var QUnit, | ||
config, | ||
onErrorFnPrev, | ||
testId = 0, | ||
fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""), | ||
toString = Object.prototype.toString, | ||
hasOwn = Object.prototype.hasOwnProperty, | ||
// Keep a local reference to Date (GH-283) | ||
Date = window.Date, | ||
defined = { | ||
setTimeout: typeof window.setTimeout !== "undefined", | ||
sessionStorage: (function() { | ||
var x = "qunit-test-string"; | ||
try { | ||
return !!sessionStorage.getItem; | ||
} catch(e) { | ||
sessionStorage.setItem( x, x ); | ||
sessionStorage.removeItem( x ); | ||
return true; | ||
} catch( e ) { | ||
return false; | ||
} | ||
})() | ||
}()) | ||
}; | ||
var testId = 0, | ||
toString = Object.prototype.toString, | ||
hasOwn = Object.prototype.hasOwnProperty; | ||
function Test( settings ) { | ||
extend( this, settings ); | ||
this.assertions = []; | ||
this.testNumber = ++Test.count; | ||
} | ||
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.count = 0; | ||
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.className = "running"; | ||
li.id = this.id = "test-output" + testId++; | ||
var a, b, li, | ||
tests = id( "qunit-tests" ); | ||
if ( tests ) { | ||
b = document.createElement( "strong" ); | ||
b.innerHTML = this.name; | ||
// `a` initialized at top of scope | ||
a = document.createElement( "a" ); | ||
a.innerHTML = "Rerun"; | ||
a.href = QUnit.url({ testNumber: this.testNumber }); | ||
li = document.createElement( "li" ); | ||
li.appendChild( b ); | ||
li.appendChild( a ); | ||
li.className = "running"; | ||
li.id = this.id = "qunit-test-output" + testId++; | ||
tests.appendChild( li ); | ||
@@ -51,5 +68,5 @@ } | ||
setup: function() { | ||
if (this.module != config.previousModule) { | ||
if ( this.module !== config.previousModule ) { | ||
if ( config.previousModule ) { | ||
runLoggingCallbacks('moduleDone', QUnit, { | ||
runLoggingCallbacks( "moduleDone", QUnit, { | ||
name: config.previousModule, | ||
@@ -59,21 +76,23 @@ failed: config.moduleStats.bad, | ||
total: config.moduleStats.all | ||
} ); | ||
}); | ||
} | ||
config.previousModule = this.module; | ||
config.moduleStats = { all: 0, bad: 0 }; | ||
runLoggingCallbacks( 'moduleStart', QUnit, { | ||
runLoggingCallbacks( "moduleStart", QUnit, { | ||
name: this.module | ||
} ); | ||
}); | ||
} else if ( config.autorun ) { | ||
runLoggingCallbacks( "moduleStart", QUnit, { | ||
name: this.module | ||
}); | ||
} | ||
config.current = this; | ||
this.testEnvironment = extend({ | ||
setup: function() {}, | ||
teardown: function() {} | ||
}, this.moduleTestEnvironment); | ||
if (this.testEnvironmentArg) { | ||
extend(this.testEnvironment, this.testEnvironmentArg); | ||
} | ||
}, this.moduleTestEnvironment ); | ||
runLoggingCallbacks( 'testStart', QUnit, { | ||
runLoggingCallbacks( "testStart", QUnit, { | ||
name: this.testName, | ||
@@ -87,10 +106,13 @@ module: this.module | ||
if ( !config.pollution ) { | ||
saveGlobal(); | ||
} | ||
if ( config.notrycatch ) { | ||
this.testEnvironment.setup.call( this.testEnvironment ); | ||
return; | ||
} | ||
try { | ||
if ( !config.pollution ) { | ||
saveGlobal(); | ||
} | ||
this.testEnvironment.setup.call(this.testEnvironment); | ||
} catch(e) { | ||
QUnit.ok( false, "Setup failed on " + this.testName + ": " + e.message ); | ||
this.testEnvironment.setup.call( this.testEnvironment ); | ||
} catch( e ) { | ||
QUnit.pushFailure( "Setup failed on " + this.testName + ": " + e.message, extractStacktrace( e, 1 ) ); | ||
} | ||
@@ -100,2 +122,9 @@ }, | ||
config.current = this; | ||
var running = id( "qunit-testresult" ); | ||
if ( running ) { | ||
running.innerHTML = "Running: <br/>" + this.name; | ||
} | ||
if ( this.async ) { | ||
@@ -106,10 +135,10 @@ QUnit.stop(); | ||
if ( config.notrycatch ) { | ||
this.callback.call(this.testEnvironment); | ||
this.callback.call( this.testEnvironment, QUnit.assert ); | ||
return; | ||
} | ||
try { | ||
this.callback.call(this.testEnvironment); | ||
} catch(e) { | ||
fail("Test " + this.testName + " died, exception and test follows", e, this.callback); | ||
QUnit.ok( false, "Died on test #" + (this.assertions.length + 1) + ": " + e.message + " - " + QUnit.jsDump.parse(e) ); | ||
this.callback.call( this.testEnvironment, QUnit.assert ); | ||
} catch( e ) { | ||
QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + e.message, extractStacktrace( e, 0 ) ); | ||
// else next test will carry the responsibility | ||
@@ -126,17 +155,29 @@ saveGlobal(); | ||
config.current = this; | ||
try { | ||
this.testEnvironment.teardown.call(this.testEnvironment); | ||
checkPollution(); | ||
} catch(e) { | ||
QUnit.ok( false, "Teardown failed on " + this.testName + ": " + e.message ); | ||
if ( config.notrycatch ) { | ||
this.testEnvironment.teardown.call( this.testEnvironment ); | ||
return; | ||
} else { | ||
try { | ||
this.testEnvironment.teardown.call( this.testEnvironment ); | ||
} catch( e ) { | ||
QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + e.message, extractStacktrace( e, 1 ) ); | ||
} | ||
} | ||
checkPollution(); | ||
}, | ||
finish: function() { | ||
config.current = this; | ||
if ( this.expected != null && this.expected != this.assertions.length ) { | ||
QUnit.ok( false, "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run" ); | ||
if ( config.requireExpects && this.expected == null ) { | ||
QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack ); | ||
} else if ( this.expected != null && this.expected != this.assertions.length ) { | ||
QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack ); | ||
} else if ( this.expected == null && !this.assertions.length ) { | ||
QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack ); | ||
} | ||
var good = 0, bad = 0, | ||
tests = id("qunit-tests"); | ||
var assertion, a, b, i, li, ol, | ||
test = this, | ||
good = 0, | ||
bad = 0, | ||
tests = id( "qunit-tests" ); | ||
@@ -147,10 +188,10 @@ config.stats.all += this.assertions.length; | ||
if ( tests ) { | ||
var ol = document.createElement("ol"); | ||
ol = document.createElement( "ol" ); | ||
for ( var i = 0; i < this.assertions.length; i++ ) { | ||
var assertion = this.assertions[i]; | ||
for ( i = 0; i < this.assertions.length; i++ ) { | ||
assertion = this.assertions[i]; | ||
var li = document.createElement("li"); | ||
li = document.createElement( "li" ); | ||
li.className = assertion.result ? "pass" : "fail"; | ||
li.innerHTML = assertion.message || (assertion.result ? "okay" : "failed"); | ||
li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" ); | ||
ol.appendChild( li ); | ||
@@ -169,20 +210,17 @@ | ||
if ( QUnit.config.reorder && defined.sessionStorage ) { | ||
if (bad) { | ||
sessionStorage.setItem("qunit-" + this.module + "-" + this.testName, bad); | ||
if ( bad ) { | ||
sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad ); | ||
} else { | ||
sessionStorage.removeItem("qunit-" + this.module + "-" + this.testName); | ||
sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName ); | ||
} | ||
} | ||
if (bad == 0) { | ||
if ( bad === 0 ) { | ||
ol.style.display = "none"; | ||
} | ||
var b = document.createElement("strong"); | ||
// `b` initialized at top of scope | ||
b = document.createElement( "strong" ); | ||
b.innerHTML = this.name + " <b class='counts'>(<b class='failed'>" + bad + "</b>, <b class='passed'>" + good + "</b>, " + this.assertions.length + ")</b>"; | ||
var a = document.createElement("a"); | ||
a.innerHTML = "Rerun"; | ||
a.href = QUnit.url({ filter: getText([b]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") }); | ||
addEvent(b, "click", function() { | ||
@@ -194,3 +232,3 @@ var next = b.nextSibling.nextSibling, | ||
addEvent(b, "dblclick", function(e) { | ||
addEvent(b, "dblclick", function( e ) { | ||
var target = e && e.target ? e.target : window.event.srcElement; | ||
@@ -201,15 +239,17 @@ if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) { | ||
if ( window.location && target.nodeName.toLowerCase() === "strong" ) { | ||
window.location = QUnit.url({ filter: getText([target]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") }); | ||
window.location = QUnit.url({ testNumber: test.testNumber }); | ||
} | ||
}); | ||
var li = id(this.id); | ||
// `li` initialized at top of scope | ||
li = id( this.id ); | ||
li.className = bad ? "fail" : "pass"; | ||
li.removeChild( li.firstChild ); | ||
a = li.firstChild; | ||
li.appendChild( b ); | ||
li.appendChild( a ); | ||
li.appendChild ( a ); | ||
li.appendChild( ol ); | ||
} else { | ||
for ( var i = 0; i < this.assertions.length; i++ ) { | ||
for ( i = 0; i < this.assertions.length; i++ ) { | ||
if ( !this.assertions[i].result ) { | ||
@@ -223,9 +263,3 @@ bad++; | ||
try { | ||
QUnit.reset(); | ||
} catch(e) { | ||
fail("reset() failed, following Test " + this.testName + ", exception and reset fn follows", e, QUnit.reset); | ||
} | ||
runLoggingCallbacks( 'testDone', QUnit, { | ||
runLoggingCallbacks( "testDone", QUnit, { | ||
name: this.testName, | ||
@@ -236,7 +270,13 @@ module: this.module, | ||
total: this.assertions.length | ||
} ); | ||
}); | ||
QUnit.reset(); | ||
config.current = undefined; | ||
}, | ||
queue: function() { | ||
var test = this; | ||
var bad, | ||
test = this; | ||
synchronize(function() { | ||
@@ -260,22 +300,28 @@ test.init(); | ||
} | ||
// `bad` initialized at top of scope | ||
// defer when previous test run passed, if storage is available | ||
var bad = QUnit.config.reorder && defined.sessionStorage && +sessionStorage.getItem("qunit-" + this.module + "-" + this.testName); | ||
if (bad) { | ||
bad = QUnit.config.reorder && defined.sessionStorage && | ||
+sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName ); | ||
if ( bad ) { | ||
run(); | ||
} else { | ||
synchronize(run, true); | ||
}; | ||
synchronize( run, true ); | ||
} | ||
} | ||
}; | ||
var QUnit = { | ||
// Root QUnit object. | ||
// `QUnit` initialized at top of scope | ||
QUnit = { | ||
// call on start of module test to prepend name to all tests | ||
module: function(name, testEnvironment) { | ||
module: function( name, testEnvironment ) { | ||
config.currentModule = name; | ||
config.currentModuleTestEnviroment = testEnvironment; | ||
config.currentModuleTestEnvironment = testEnvironment; | ||
config.modules[name] = true; | ||
}, | ||
asyncTest: function(testName, expected, callback) { | ||
asyncTest: function( testName, expected, callback ) { | ||
if ( arguments.length === 2 ) { | ||
@@ -286,7 +332,8 @@ callback = expected; | ||
QUnit.test(testName, expected, callback, true); | ||
QUnit.test( testName, expected, callback, true ); | ||
}, | ||
test: function(testName, expected, callback, async) { | ||
var name = '<span class="test-name">' + testName + '</span>', testEnvironmentArg; | ||
test: function( testName, expected, callback, async ) { | ||
var test, | ||
name = "<span class='test-name'>" + escapeInnerText( testName ) + "</span>"; | ||
@@ -297,43 +344,116 @@ if ( arguments.length === 2 ) { | ||
} | ||
// is 2nd argument a testEnvironment? | ||
if ( expected && typeof expected === 'object') { | ||
testEnvironmentArg = expected; | ||
expected = null; | ||
} | ||
if ( config.currentModule ) { | ||
name = '<span class="module-name">' + config.currentModule + "</span>: " + name; | ||
name = "<span class='module-name'>" + config.currentModule + "</span>: " + name; | ||
} | ||
if ( !validTest(config.currentModule + ": " + testName) ) { | ||
test = new Test({ | ||
name: name, | ||
testName: testName, | ||
expected: expected, | ||
async: async, | ||
callback: callback, | ||
module: config.currentModule, | ||
moduleTestEnvironment: config.currentModuleTestEnvironment, | ||
stack: sourceFromStacktrace( 2 ) | ||
}); | ||
if ( !validTest( test ) ) { | ||
return; | ||
} | ||
var test = new Test(name, testName, expected, testEnvironmentArg, async, callback); | ||
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.current.expected = asserts; | ||
// Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through. | ||
expect: function( asserts ) { | ||
if (arguments.length === 1) { | ||
config.current.expected = asserts; | ||
} else { | ||
return config.current.expected; | ||
} | ||
}, | ||
start: function( count ) { | ||
config.semaphore -= count || 1; | ||
// don't start until equal number of stop-calls | ||
if ( config.semaphore > 0 ) { | ||
return; | ||
} | ||
// ignore if start is called more often then stop | ||
if ( config.semaphore < 0 ) { | ||
config.semaphore = 0; | ||
} | ||
// A slight delay, to avoid any current callbacks | ||
if ( defined.setTimeout ) { | ||
window.setTimeout(function() { | ||
if ( config.semaphore > 0 ) { | ||
return; | ||
} | ||
if ( config.timeout ) { | ||
clearTimeout( config.timeout ); | ||
} | ||
config.blocking = false; | ||
process( true ); | ||
}, 13); | ||
} else { | ||
config.blocking = false; | ||
process( true ); | ||
} | ||
}, | ||
stop: function( count ) { | ||
config.semaphore += count || 1; | ||
config.blocking = true; | ||
if ( config.testTimeout && defined.setTimeout ) { | ||
clearTimeout( config.timeout ); | ||
config.timeout = window.setTimeout(function() { | ||
QUnit.ok( false, "Test timed out" ); | ||
config.semaphore = 1; | ||
QUnit.start(); | ||
}, config.testTimeout ); | ||
} | ||
} | ||
}; | ||
// Asssert helpers | ||
// All of these must call either QUnit.push() or manually do: | ||
// - runLoggingCallbacks( "log", .. ); | ||
// - config.current.assertions.push({ .. }); | ||
QUnit.assert = { | ||
/** | ||
* Asserts true. | ||
* Asserts rough true-ish result. | ||
* @name ok | ||
* @function | ||
* @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 = escapeInnerText(msg); | ||
runLoggingCallbacks( 'log', QUnit, details ); | ||
ok: function( result, msg ) { | ||
if ( !config.current ) { | ||
throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) ); | ||
} | ||
result = !!result; | ||
var source, | ||
details = { | ||
module: config.current.module, | ||
name: config.current.testName, | ||
result: result, | ||
message: msg | ||
}; | ||
msg = escapeInnerText( msg || (result ? "okay" : "failed" ) ); | ||
msg = "<span class='test-message'>" + msg + "</span>"; | ||
if ( !result ) { | ||
source = sourceFromStacktrace( 2 ); | ||
if ( source ) { | ||
details.source = source; | ||
msg += "<table><tr class='test-source'><th>Source: </th><td><pre>" + escapeInnerText( source ) + "</pre></td></tr></table>"; | ||
} | ||
} | ||
runLoggingCallbacks( "log", QUnit, details ); | ||
config.current.assertions.push({ | ||
result: a, | ||
result: result, | ||
message: msg | ||
@@ -344,41 +464,58 @@ }); | ||
/** | ||
* Checks that the first two arguments are equal, with an optional message. | ||
* Assert that the first two arguments are equal, with an optional message. | ||
* Prints out both actual and expected values. | ||
* | ||
* Prefered to ok( actual == expected, message ) | ||
* | ||
* @example equal( format("Received {0} bytes.", 2), "Received 2 bytes." ); | ||
* | ||
* @param Object actual | ||
* @param Object expected | ||
* @param String message (optional) | ||
* @name equal | ||
* @function | ||
* @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" ); | ||
*/ | ||
equal: function(actual, expected, message) { | ||
QUnit.push(expected == actual, actual, expected, message); | ||
equal: function( actual, expected, message ) { | ||
QUnit.push( expected == actual, actual, expected, message ); | ||
}, | ||
notEqual: function(actual, expected, message) { | ||
QUnit.push(expected != actual, actual, expected, message); | ||
/** | ||
* @name notEqual | ||
* @function | ||
*/ | ||
notEqual: function( actual, expected, message ) { | ||
QUnit.push( expected != actual, actual, expected, message ); | ||
}, | ||
deepEqual: function(actual, expected, message) { | ||
QUnit.push(QUnit.equiv(actual, expected), actual, expected, message); | ||
/** | ||
* @name deepEqual | ||
* @function | ||
*/ | ||
deepEqual: function( actual, expected, message ) { | ||
QUnit.push( QUnit.equiv(actual, expected), actual, expected, message ); | ||
}, | ||
notDeepEqual: function(actual, expected, message) { | ||
QUnit.push(!QUnit.equiv(actual, expected), actual, expected, message); | ||
/** | ||
* @name notDeepEqual | ||
* @function | ||
*/ | ||
notDeepEqual: function( actual, expected, message ) { | ||
QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message ); | ||
}, | ||
strictEqual: function(actual, expected, message) { | ||
QUnit.push(expected === actual, actual, expected, message); | ||
/** | ||
* @name strictEqual | ||
* @function | ||
*/ | ||
strictEqual: function( actual, expected, message ) { | ||
QUnit.push( expected === actual, actual, expected, message ); | ||
}, | ||
notStrictEqual: function(actual, expected, message) { | ||
QUnit.push(expected !== actual, actual, expected, message); | ||
/** | ||
* @name notStrictEqual | ||
* @function | ||
*/ | ||
notStrictEqual: function( actual, expected, message ) { | ||
QUnit.push( expected !== actual, actual, expected, message ); | ||
}, | ||
raises: function(block, expected, message) { | ||
var actual, ok = false; | ||
throws: function( block, expected, message ) { | ||
var actual, | ||
ok = false; | ||
if (typeof expected === 'string') { | ||
// 'expected' is optional | ||
if ( typeof expected === "string" ) { | ||
message = expected; | ||
@@ -388,86 +525,70 @@ expected = null; | ||
config.current.ignoreGlobalErrors = true; | ||
try { | ||
block(); | ||
block.call( config.current.testEnvironment ); | ||
} catch (e) { | ||
actual = e; | ||
} | ||
config.current.ignoreGlobalErrors = false; | ||
if (actual) { | ||
if ( actual ) { | ||
// we don't want to validate thrown error | ||
if (!expected) { | ||
if ( !expected ) { | ||
ok = true; | ||
// expected is a regexp | ||
} else if (QUnit.objectType(expected) === "regexp") { | ||
ok = expected.test(actual); | ||
} else if ( QUnit.objectType( expected ) === "regexp" ) { | ||
ok = expected.test( actual ); | ||
// expected is a constructor | ||
} else if (actual instanceof expected) { | ||
} else if ( actual instanceof expected ) { | ||
ok = true; | ||
// expected is a validation function which returns true is validation passed | ||
} else if (expected.call({}, actual) === true) { | ||
} else if ( expected.call( {}, actual ) === true ) { | ||
ok = true; | ||
} | ||
} | ||
QUnit.ok(ok, message); | ||
}, | ||
start: function(count) { | ||
config.semaphore -= count || 1; | ||
if (config.semaphore > 0) { | ||
// don't start until equal number of stop-calls | ||
return; | ||
} | ||
if (config.semaphore < 0) { | ||
// ignore if start is called more often then stop | ||
config.semaphore = 0; | ||
} | ||
// A slight delay, to avoid any current callbacks | ||
if ( defined.setTimeout ) { | ||
window.setTimeout(function() { | ||
if (config.semaphore > 0) { | ||
return; | ||
} | ||
if ( config.timeout ) { | ||
clearTimeout(config.timeout); | ||
} | ||
config.blocking = false; | ||
process(true); | ||
}, 13); | ||
QUnit.push( ok, actual, null, message ); | ||
} else { | ||
config.blocking = false; | ||
process(true); | ||
QUnit.pushFailure( message, null, 'No exception was thrown.' ); | ||
} | ||
}, | ||
} | ||
}; | ||
stop: function(count) { | ||
config.semaphore += count || 1; | ||
config.blocking = true; | ||
/** | ||
* @deprecate since 1.8.0 | ||
* Kept assertion helpers in root for backwards compatibility | ||
*/ | ||
extend( QUnit, QUnit.assert ); | ||
if ( config.testTimeout && defined.setTimeout ) { | ||
clearTimeout(config.timeout); | ||
config.timeout = window.setTimeout(function() { | ||
QUnit.ok( false, "Test timed out" ); | ||
config.semaphore = 1; | ||
QUnit.start(); | ||
}, config.testTimeout); | ||
} | ||
} | ||
/** | ||
* @deprecated since 1.9.0 | ||
* Kept global "raises()" for backwards compatibility | ||
*/ | ||
QUnit.raises = QUnit.assert.throws; | ||
/** | ||
* @deprecated since 1.0.0, replaced with error pushes since 1.3.0 | ||
* Kept to avoid TypeErrors for undefined methods. | ||
*/ | ||
QUnit.equals = function() { | ||
QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" ); | ||
}; | ||
QUnit.same = function() { | ||
QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" ); | ||
}; | ||
//We want access to the constructor's prototype | ||
// We want access to the constructor's prototype | ||
(function() { | ||
function F(){}; | ||
function F() {} | ||
F.prototype = QUnit; | ||
QUnit = new F(); | ||
//Make F QUnit's constructor so that we can add to the prototype later | ||
// Make F QUnit's constructor so that we can add to the prototype later | ||
QUnit.constructor = F; | ||
})(); | ||
}()); | ||
// Backwards compatibility, deprecated | ||
QUnit.equals = QUnit.equal; | ||
QUnit.same = QUnit.deepEqual; | ||
// Maintain internal state | ||
var config = { | ||
/** | ||
* Config object: Maintain internal state | ||
* Later exposed as QUnit.config | ||
* `config` initialized at top of scope | ||
*/ | ||
config = { | ||
// The queue of tests to run | ||
@@ -490,5 +611,24 @@ queue: [], | ||
urlConfig: ['noglobals', 'notrycatch'], | ||
// when enabled, all tests must call expect() | ||
requireExpects: false, | ||
//logging callback queues | ||
// add checkboxes that are persisted in the query-string | ||
// when enabled, the id is set to `true` as a `QUnit.config` property | ||
urlConfig: [ | ||
{ | ||
id: "noglobals", | ||
label: "Check for Globals", | ||
tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings." | ||
}, | ||
{ | ||
id: "notrycatch", | ||
label: "No try-catch", | ||
tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings." | ||
} | ||
], | ||
// Set of all modules. | ||
modules: {}, | ||
// logging callback queues | ||
begin: [], | ||
@@ -503,5 +643,6 @@ done: [], | ||
// Load paramaters | ||
// Initialize more QUnit.config and QUnit.urlParams | ||
(function() { | ||
var location = window.location || { search: "", protocol: "file:" }, | ||
var i, | ||
location = window.location || { search: "", protocol: "file:" }, | ||
params = location.search.slice( 1 ).split( "&" ), | ||
@@ -513,3 +654,3 @@ length = params.length, | ||
if ( params[ 0 ] ) { | ||
for ( var i = 0; i < length; i++ ) { | ||
for ( i = 0; i < length; i++ ) { | ||
current = params[ i ].split( "=" ); | ||
@@ -524,20 +665,27 @@ current[ 0 ] = decodeURIComponent( current[ 0 ] ); | ||
QUnit.urlParams = urlParams; | ||
// String search anywhere in moduleName+testName | ||
config.filter = urlParams.filter; | ||
// Exact match of the module name | ||
config.module = urlParams.module; | ||
config.testNumber = parseInt( urlParams.testNumber, 10 ) || null; | ||
// Figure out if we're running the tests from a server or not | ||
QUnit.isLocal = !!(location.protocol === 'file:'); | ||
})(); | ||
QUnit.isLocal = location.protocol === "file:"; | ||
}()); | ||
// Expose the API as global variables, unless an 'exports' | ||
// object exists, in that case we assume we're in CommonJS | ||
if ( typeof exports === "undefined" || typeof require === "undefined" ) { | ||
extend(window, QUnit); | ||
// Export global variables, unless an 'exports' object exists, | ||
// in that case we assume we're in CommonJS (dealt with on the bottom of the script) | ||
if ( typeof exports === "undefined" ) { | ||
extend( window, QUnit ); | ||
// Expose QUnit object | ||
window.QUnit = QUnit; | ||
} else { | ||
extend(exports, QUnit); | ||
exports.QUnit = QUnit; | ||
} | ||
// define these after exposing globals to keep them in these QUnit namespace only | ||
extend(QUnit, { | ||
// Extend QUnit object, | ||
// these after set here because they should not be exposed as global functions | ||
extend( QUnit, { | ||
config: config, | ||
@@ -547,6 +695,6 @@ | ||
init: function() { | ||
extend(config, { | ||
extend( config, { | ||
stats: { all: 0, bad: 0 }, | ||
moduleStats: { all: 0, bad: 0 }, | ||
started: +new Date, | ||
started: +new Date(), | ||
updateRate: 1000, | ||
@@ -561,6 +709,18 @@ blocking: false, | ||
var tests = id( "qunit-tests" ), | ||
banner = id( "qunit-banner" ), | ||
result = id( "qunit-testresult" ); | ||
var tests, banner, result, | ||
qunit = id( "qunit" ); | ||
if ( qunit ) { | ||
qunit.innerHTML = | ||
"<h1 id='qunit-header'>" + escapeInnerText( document.title ) + "</h1>" + | ||
"<h2 id='qunit-banner'></h2>" + | ||
"<div id='qunit-testrunner-toolbar'></div>" + | ||
"<h2 id='qunit-userAgent'></h2>" + | ||
"<ol id='qunit-tests'></ol>"; | ||
} | ||
tests = id( "qunit-tests" ); | ||
banner = id( "qunit-banner" ); | ||
result = id( "qunit-testresult" ); | ||
if ( tests ) { | ||
@@ -583,39 +743,25 @@ tests.innerHTML = ""; | ||
tests.parentNode.insertBefore( result, tests ); | ||
result.innerHTML = 'Running...<br/> '; | ||
result.innerHTML = "Running...<br/> "; | ||
} | ||
}, | ||
/** | ||
* Resets the test setup. Useful for tests that modify the DOM. | ||
* | ||
* If jQuery is available, uses jQuery's html(), otherwise just innerHTML. | ||
*/ | ||
// Resets the test setup. Useful for tests that modify the DOM. | ||
reset: function() { | ||
if ( window.jQuery ) { | ||
jQuery( "#qunit-fixture" ).html( config.fixture ); | ||
} else { | ||
var main = id( 'qunit-fixture' ); | ||
if ( main ) { | ||
main.innerHTML = config.fixture; | ||
} | ||
var fixture = id( "qunit-fixture" ); | ||
if ( fixture ) { | ||
fixture.innerHTML = config.fixture; | ||
} | ||
}, | ||
/** | ||
* Trigger an event on an element. | ||
* | ||
* @example triggerEvent( document.body, "click" ); | ||
* | ||
* @param DOMElement elem | ||
* @param String type | ||
*/ | ||
// Trigger an event on an element. | ||
// @example triggerEvent( document.body, "click" ); | ||
triggerEvent: function( elem, type, event ) { | ||
if ( document.createEvent ) { | ||
event = document.createEvent("MouseEvents"); | ||
event = document.createEvent( "MouseEvents" ); | ||
event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView, | ||
0, 0, 0, 0, 0, false, false, false, false, 0, null); | ||
elem.dispatchEvent( event ); | ||
} else if ( elem.fireEvent ) { | ||
elem.fireEvent("on"+type); | ||
elem.fireEvent( "on" + type ); | ||
} | ||
@@ -630,30 +776,28 @@ }, | ||
objectType: function( obj ) { | ||
if (typeof obj === "undefined") { | ||
if ( typeof obj === "undefined" ) { | ||
return "undefined"; | ||
// consider: typeof null === object | ||
} | ||
if (obj === null) { | ||
if ( obj === null ) { | ||
return "null"; | ||
} | ||
var type = toString.call( obj ).match(/^\[object\s(.*)\]$/)[1] || ''; | ||
var type = toString.call( obj ).match(/^\[object\s(.*)\]$/)[1] || ""; | ||
switch (type) { | ||
case 'Number': | ||
if (isNaN(obj)) { | ||
return "nan"; | ||
} else { | ||
return "number"; | ||
} | ||
case 'String': | ||
case 'Boolean': | ||
case 'Array': | ||
case 'Date': | ||
case 'RegExp': | ||
case 'Function': | ||
return type.toLowerCase(); | ||
switch ( type ) { | ||
case "Number": | ||
if ( isNaN(obj) ) { | ||
return "nan"; | ||
} | ||
return "number"; | ||
case "String": | ||
case "Boolean": | ||
case "Array": | ||
case "Date": | ||
case "RegExp": | ||
case "Function": | ||
return type.toLowerCase(); | ||
} | ||
if (typeof obj === "object") { | ||
return "object"; | ||
if ( typeof obj === "object" ) { | ||
return "object"; | ||
} | ||
@@ -663,29 +807,42 @@ return undefined; | ||
push: function(result, actual, expected, message) { | ||
var details = { | ||
result: result, | ||
message: message, | ||
actual: actual, | ||
expected: expected | ||
}; | ||
push: function( result, actual, expected, message ) { | ||
if ( !config.current ) { | ||
throw new Error( "assertion outside test context, was " + sourceFromStacktrace() ); | ||
} | ||
message = escapeInnerText(message) || (result ? "okay" : "failed"); | ||
message = '<span class="test-message">' + message + "</span>"; | ||
expected = escapeInnerText(QUnit.jsDump.parse(expected)); | ||
actual = escapeInnerText(QUnit.jsDump.parse(actual)); | ||
var output = message + '<table><tr class="test-expected"><th>Expected: </th><td><pre>' + expected + '</pre></td></tr>'; | ||
if (actual != expected) { | ||
output += '<tr class="test-actual"><th>Result: </th><td><pre>' + actual + '</pre></td></tr>'; | ||
output += '<tr class="test-diff"><th>Diff: </th><td><pre>' + QUnit.diff(expected, actual) +'</pre></td></tr>'; | ||
} | ||
if (!result) { | ||
var source = sourceFromStacktrace(); | ||
if (source) { | ||
var output, source, | ||
details = { | ||
module: config.current.module, | ||
name: config.current.testName, | ||
result: result, | ||
message: message, | ||
actual: actual, | ||
expected: expected | ||
}; | ||
message = escapeInnerText( message ) || ( result ? "okay" : "failed" ); | ||
message = "<span class='test-message'>" + message + "</span>"; | ||
output = message; | ||
if ( !result ) { | ||
expected = escapeInnerText( QUnit.jsDump.parse(expected) ); | ||
actual = escapeInnerText( QUnit.jsDump.parse(actual) ); | ||
output += "<table><tr class='test-expected'><th>Expected: </th><td><pre>" + expected + "</pre></td></tr>"; | ||
if ( actual != expected ) { | ||
output += "<tr class='test-actual'><th>Result: </th><td><pre>" + actual + "</pre></td></tr>"; | ||
output += "<tr class='test-diff'><th>Diff: </th><td><pre>" + QUnit.diff( expected, actual ) + "</pre></td></tr>"; | ||
} | ||
source = sourceFromStacktrace(); | ||
if ( source ) { | ||
details.source = source; | ||
output += '<tr class="test-source"><th>Source: </th><td><pre>' + escapeInnerText(source) + '</pre></td></tr>'; | ||
output += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeInnerText( source ) + "</pre></td></tr>"; | ||
} | ||
output += "</table>"; | ||
} | ||
output += "</table>"; | ||
runLoggingCallbacks( 'log', QUnit, details ); | ||
runLoggingCallbacks( "log", QUnit, details ); | ||
@@ -698,6 +855,45 @@ config.current.assertions.push({ | ||
pushFailure: function( message, source, actual ) { | ||
if ( !config.current ) { | ||
throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) ); | ||
} | ||
var output, | ||
details = { | ||
module: config.current.module, | ||
name: config.current.testName, | ||
result: false, | ||
message: message | ||
}; | ||
message = escapeInnerText( message ) || "error"; | ||
message = "<span class='test-message'>" + message + "</span>"; | ||
output = message; | ||
output += "<table>"; | ||
if ( actual ) { | ||
output += "<tr class='test-actual'><th>Result: </th><td><pre>" + escapeInnerText( actual ) + "</pre></td></tr>"; | ||
} | ||
if ( source ) { | ||
details.source = source; | ||
output += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeInnerText( source ) + "</pre></td></tr>"; | ||
} | ||
output += "</table>"; | ||
runLoggingCallbacks( "log", QUnit, details ); | ||
config.current.assertions.push({ | ||
result: false, | ||
message: output | ||
}); | ||
}, | ||
url: function( params ) { | ||
params = extend( extend( {}, QUnit.urlParams ), params ); | ||
var querystring = "?", | ||
key; | ||
var key, | ||
querystring = "?"; | ||
for ( key in params ) { | ||
@@ -716,23 +912,35 @@ if ( !hasOwn.call( params, key ) ) { | ||
addEvent: addEvent | ||
// load, equiv, jsDump, diff: Attached later | ||
}); | ||
//QUnit.constructor is set to the empty F() above so that we can add to it's prototype later | ||
//Doing this allows us to tell if the following methods have been overwritten on the actual | ||
//QUnit object, which is a deprecated way of using the callbacks. | ||
extend(QUnit.constructor.prototype, { | ||
/** | ||
* @deprecated: Created for backwards compatibility with test runner that set the hook function | ||
* into QUnit.{hook}, instead of invoking it and passing the hook function. | ||
* QUnit.constructor is set to the empty F() above so that we can add to it's prototype here. | ||
* Doing this allows us to tell if the following methods have been overwritten on the actual | ||
* QUnit object. | ||
*/ | ||
extend( QUnit.constructor.prototype, { | ||
// Logging callbacks; all receive a single argument with the listed properties | ||
// run test/logs.html for any related changes | ||
begin: registerLoggingCallback('begin'), | ||
begin: registerLoggingCallback( "begin" ), | ||
// done: { failed, passed, total, runtime } | ||
done: registerLoggingCallback('done'), | ||
done: registerLoggingCallback( "done" ), | ||
// log: { result, actual, expected, message } | ||
log: registerLoggingCallback('log'), | ||
log: registerLoggingCallback( "log" ), | ||
// testStart: { name } | ||
testStart: registerLoggingCallback('testStart'), | ||
testStart: registerLoggingCallback( "testStart" ), | ||
// testDone: { name, failed, passed, total } | ||
testDone: registerLoggingCallback('testDone'), | ||
testDone: registerLoggingCallback( "testDone" ), | ||
// moduleStart: { name } | ||
moduleStart: registerLoggingCallback('moduleStart'), | ||
moduleStart: registerLoggingCallback( "moduleStart" ), | ||
// moduleDone: { name, failed, passed, total } | ||
moduleDone: registerLoggingCallback('moduleDone') | ||
moduleDone: registerLoggingCallback( "moduleDone" ) | ||
}); | ||
@@ -745,6 +953,11 @@ | ||
QUnit.load = function() { | ||
runLoggingCallbacks( 'begin', QUnit, {} ); | ||
runLoggingCallbacks( "begin", QUnit, {} ); | ||
// Initialize the config, saving the execution queue | ||
var oldconfig = extend({}, config); | ||
var banner, filter, i, label, len, main, ol, toolbar, userAgent, val, urlConfigCheckboxes, moduleFilter, | ||
numModules = 0, | ||
moduleFilterHtml = "", | ||
urlConfigHtml = "", | ||
oldconfig = extend( {}, config ); | ||
QUnit.init(); | ||
@@ -755,46 +968,69 @@ extend(config, oldconfig); | ||
var urlConfigHtml = '', len = config.urlConfig.length; | ||
for ( var i = 0, val; i < len, val = config.urlConfig[i]; i++ ) { | ||
config[val] = QUnit.urlParams[val]; | ||
urlConfigHtml += '<label><input name="' + val + '" type="checkbox"' + ( config[val] ? ' checked="checked"' : '' ) + '>' + val + '</label>'; | ||
len = config.urlConfig.length; | ||
for ( i = 0; i < len; i++ ) { | ||
val = config.urlConfig[i]; | ||
if ( typeof val === "string" ) { | ||
val = { | ||
id: val, | ||
label: val, | ||
tooltip: "[no tooltip available]" | ||
}; | ||
} | ||
config[ val.id ] = QUnit.urlParams[ val.id ]; | ||
urlConfigHtml += "<input id='qunit-urlconfig-" + val.id + "' name='" + val.id + "' type='checkbox'" + ( config[ val.id ] ? " checked='checked'" : "" ) + " title='" + val.tooltip + "'><label for='qunit-urlconfig-" + val.id + "' title='" + val.tooltip + "'>" + val.label + "</label>"; | ||
} | ||
var userAgent = id("qunit-userAgent"); | ||
moduleFilterHtml += "<label for='qunit-modulefilter'>Module: </label><select id='qunit-modulefilter' name='modulefilter'><option value='' " + ( config.module === undefined ? "selected" : "" ) + ">< All Modules ></option>"; | ||
for ( i in config.modules ) { | ||
if ( config.modules.hasOwnProperty( i ) ) { | ||
numModules += 1; | ||
moduleFilterHtml += "<option value='" + encodeURIComponent(i) + "' " + ( config.module === i ? "selected" : "" ) + ">" + i + "</option>"; | ||
} | ||
} | ||
moduleFilterHtml += "</select>"; | ||
// `userAgent` initialized at top of scope | ||
userAgent = id( "qunit-userAgent" ); | ||
if ( userAgent ) { | ||
userAgent.innerHTML = navigator.userAgent; | ||
} | ||
var banner = id("qunit-header"); | ||
// `banner` initialized at top of scope | ||
banner = id( "qunit-header" ); | ||
if ( banner ) { | ||
banner.innerHTML = '<a href="' + QUnit.url({ filter: undefined }) + '"> ' + banner.innerHTML + '</a> ' + urlConfigHtml; | ||
addEvent( banner, "change", function( event ) { | ||
var params = {}; | ||
params[ event.target.name ] = event.target.checked ? true : undefined; | ||
window.location = QUnit.url( params ); | ||
}); | ||
banner.innerHTML = "<a href='" + QUnit.url({ filter: undefined, module: undefined, testNumber: undefined }) + "'>" + banner.innerHTML + "</a> "; | ||
} | ||
var toolbar = id("qunit-testrunner-toolbar"); | ||
// `toolbar` initialized at top of scope | ||
toolbar = id( "qunit-testrunner-toolbar" ); | ||
if ( toolbar ) { | ||
var filter = document.createElement("input"); | ||
// `filter` initialized at top of scope | ||
filter = document.createElement( "input" ); | ||
filter.type = "checkbox"; | ||
filter.id = "qunit-filter-pass"; | ||
addEvent( filter, "click", function() { | ||
var ol = document.getElementById("qunit-tests"); | ||
var tmp, | ||
ol = document.getElementById( "qunit-tests" ); | ||
if ( filter.checked ) { | ||
ol.className = ol.className + " hidepass"; | ||
} else { | ||
var tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " "; | ||
ol.className = tmp.replace(/ hidepass /, " "); | ||
tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " "; | ||
ol.className = tmp.replace( / hidepass /, " " ); | ||
} | ||
if ( defined.sessionStorage ) { | ||
if (filter.checked) { | ||
sessionStorage.setItem("qunit-filter-passed-tests", "true"); | ||
sessionStorage.setItem( "qunit-filter-passed-tests", "true" ); | ||
} else { | ||
sessionStorage.removeItem("qunit-filter-passed-tests"); | ||
sessionStorage.removeItem( "qunit-filter-passed-tests" ); | ||
} | ||
} | ||
}); | ||
if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem("qunit-filter-passed-tests") ) { | ||
if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) { | ||
filter.checked = true; | ||
var ol = document.getElementById("qunit-tests"); | ||
// `ol` initialized at top of scope | ||
ol = document.getElementById( "qunit-tests" ); | ||
ol.className = ol.className + " hidepass"; | ||
@@ -804,9 +1040,34 @@ } | ||
var label = document.createElement("label"); | ||
label.setAttribute("for", "qunit-filter-pass"); | ||
// `label` initialized at top of scope | ||
label = document.createElement( "label" ); | ||
label.setAttribute( "for", "qunit-filter-pass" ); | ||
label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." ); | ||
label.innerHTML = "Hide passed tests"; | ||
toolbar.appendChild( label ); | ||
urlConfigCheckboxes = document.createElement( 'span' ); | ||
urlConfigCheckboxes.innerHTML = urlConfigHtml; | ||
addEvent( urlConfigCheckboxes, "change", function( event ) { | ||
var params = {}; | ||
params[ event.target.name ] = event.target.checked ? true : undefined; | ||
window.location = QUnit.url( params ); | ||
}); | ||
toolbar.appendChild( urlConfigCheckboxes ); | ||
if (numModules > 1) { | ||
moduleFilter = document.createElement( 'span' ); | ||
moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' ); | ||
moduleFilter.innerHTML = moduleFilterHtml; | ||
addEvent( moduleFilter, "change", function() { | ||
var selectBox = moduleFilter.getElementsByTagName("select")[0], | ||
selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value); | ||
window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } ); | ||
}); | ||
toolbar.appendChild(moduleFilter); | ||
} | ||
} | ||
var main = id('qunit-fixture'); | ||
// `main` initialized at top of scope | ||
main = id( "qunit-fixture" ); | ||
if ( main ) { | ||
@@ -816,3 +1077,3 @@ config.fixture = main.innerHTML; | ||
if (config.autostart) { | ||
if ( config.autostart ) { | ||
QUnit.start(); | ||
@@ -822,13 +1083,34 @@ } | ||
addEvent(window, "load", QUnit.load); | ||
addEvent( window, "load", QUnit.load ); | ||
// addEvent(window, "error") gives us a useless event object | ||
window.onerror = function( message, file, line ) { | ||
if ( QUnit.config.current ) { | ||
ok( false, message + ", " + file + ":" + line ); | ||
} else { | ||
test( "global failure", function() { | ||
ok( false, message + ", " + file + ":" + line ); | ||
}); | ||
// `onErrorFnPrev` initialized at top of scope | ||
// Preserve other handlers | ||
onErrorFnPrev = window.onerror; | ||
// Cover uncaught exceptions | ||
// Returning true will surpress the default browser handler, | ||
// returning false will let it run. | ||
window.onerror = function ( error, filePath, linerNr ) { | ||
var ret = false; | ||
if ( onErrorFnPrev ) { | ||
ret = onErrorFnPrev( error, filePath, linerNr ); | ||
} | ||
// Treat return value as window.onerror itself does, | ||
// Only do our handling if not surpressed. | ||
if ( ret !== true ) { | ||
if ( QUnit.config.current ) { | ||
if ( QUnit.config.current.ignoreGlobalErrors ) { | ||
return true; | ||
} | ||
QUnit.pushFailure( error, filePath + ":" + linerNr ); | ||
} else { | ||
QUnit.test( "global failure", extend( function() { | ||
QUnit.pushFailure( error, filePath + ":" + linerNr ); | ||
}, { validTest: validTest } ) ); | ||
} | ||
return false; | ||
} | ||
return ret; | ||
}; | ||
@@ -841,3 +1123,3 @@ | ||
if ( config.currentModule ) { | ||
runLoggingCallbacks( 'moduleDone', QUnit, { | ||
runLoggingCallbacks( "moduleDone", QUnit, { | ||
name: config.currentModule, | ||
@@ -847,24 +1129,25 @@ failed: config.moduleStats.bad, | ||
total: config.moduleStats.all | ||
} ); | ||
}); | ||
} | ||
var banner = id("qunit-banner"), | ||
tests = id("qunit-tests"), | ||
runtime = +new Date - config.started, | ||
var i, key, | ||
banner = id( "qunit-banner" ), | ||
tests = id( "qunit-tests" ), | ||
runtime = +new Date() - config.started, | ||
passed = config.stats.all - config.stats.bad, | ||
html = [ | ||
'Tests completed in ', | ||
"Tests completed in ", | ||
runtime, | ||
' milliseconds.<br/>', | ||
'<span class="passed">', | ||
" milliseconds.<br/>", | ||
"<span class='passed'>", | ||
passed, | ||
'</span> tests of <span class="total">', | ||
"</span> tests of <span class='total'>", | ||
config.stats.all, | ||
'</span> passed, <span class="failed">', | ||
"</span> passed, <span class='failed'>", | ||
config.stats.bad, | ||
'</span> failed.' | ||
].join(''); | ||
"</span> failed." | ||
].join( "" ); | ||
if ( banner ) { | ||
banner.className = (config.stats.bad ? "qunit-fail" : "qunit-pass"); | ||
banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" ); | ||
} | ||
@@ -880,8 +1163,24 @@ | ||
document.title = [ | ||
(config.stats.bad ? "\u2716" : "\u2714"), | ||
document.title.replace(/^[\u2714\u2716] /i, "") | ||
].join(" "); | ||
( config.stats.bad ? "\u2716" : "\u2714" ), | ||
document.title.replace( /^[\u2714\u2716] /i, "" ) | ||
].join( " " ); | ||
} | ||
runLoggingCallbacks( 'done', QUnit, { | ||
// clear own sessionStorage items if all tests passed | ||
if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) { | ||
// `key` & `i` initialized at top of scope | ||
for ( i = 0; i < sessionStorage.length; i++ ) { | ||
key = sessionStorage.key( i++ ); | ||
if ( key.indexOf( "qunit-test-" ) === 0 ) { | ||
sessionStorage.removeItem( key ); | ||
} | ||
} | ||
} | ||
// scroll back to top to show results | ||
if ( window.scrollTo ) { | ||
window.scrollTo(0, 0); | ||
} | ||
runLoggingCallbacks( "done", QUnit, { | ||
failed: config.stats.bad, | ||
@@ -891,9 +1190,26 @@ passed: passed, | ||
runtime: runtime | ||
} ); | ||
}); | ||
} | ||
function validTest( name ) { | ||
var filter = config.filter, | ||
run = false; | ||
/** @return Boolean: true if this test should be ran */ | ||
function validTest( test ) { | ||
var include, | ||
filter = config.filter && config.filter.toLowerCase(), | ||
module = config.module && config.module.toLowerCase(), | ||
fullName = (test.module + ": " + test.testName).toLowerCase(); | ||
// Internally-generated tests are always valid | ||
if ( test.callback && test.callback.validTest === validTest ) { | ||
delete test.callback.validTest; | ||
return true; | ||
} | ||
if ( config.testNumber ) { | ||
return test.testNumber === config.testNumber; | ||
} | ||
if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) { | ||
return false; | ||
} | ||
if ( !filter ) { | ||
@@ -903,45 +1219,72 @@ return true; | ||
var not = filter.charAt( 0 ) === "!"; | ||
if ( not ) { | ||
include = filter.charAt( 0 ) !== "!"; | ||
if ( !include ) { | ||
filter = filter.slice( 1 ); | ||
} | ||
if ( name.indexOf( filter ) !== -1 ) { | ||
return !not; | ||
// If the filter matches, we need to honour include | ||
if ( fullName.indexOf( filter ) !== -1 ) { | ||
return include; | ||
} | ||
if ( not ) { | ||
run = true; | ||
// Otherwise, do the opposite | ||
return !include; | ||
} | ||
// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions) | ||
// Later Safari and IE10 are supposed to support error.stack as well | ||
// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack | ||
function extractStacktrace( e, offset ) { | ||
offset = offset === undefined ? 3 : offset; | ||
var stack, include, i, regex; | ||
if ( e.stacktrace ) { | ||
// Opera | ||
return e.stacktrace.split( "\n" )[ offset + 3 ]; | ||
} else if ( e.stack ) { | ||
// Firefox, Chrome | ||
stack = e.stack.split( "\n" ); | ||
if (/^error$/i.test( stack[0] ) ) { | ||
stack.shift(); | ||
} | ||
if ( fileName ) { | ||
include = []; | ||
for ( i = offset; i < stack.length; i++ ) { | ||
if ( stack[ i ].indexOf( fileName ) != -1 ) { | ||
break; | ||
} | ||
include.push( stack[ i ] ); | ||
} | ||
if ( include.length ) { | ||
return include.join( "\n" ); | ||
} | ||
} | ||
return stack[ offset ]; | ||
} else if ( e.sourceURL ) { | ||
// Safari, PhantomJS | ||
// hopefully one day Safari provides actual stacktraces | ||
// exclude useless self-reference for generated Error objects | ||
if ( /qunit.js$/.test( e.sourceURL ) ) { | ||
return; | ||
} | ||
// for actual exceptions, this is useful | ||
return e.sourceURL + ":" + e.line; | ||
} | ||
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() { | ||
function sourceFromStacktrace( offset ) { | ||
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]; | ||
} else if (e.sourceURL) { | ||
// Safari, PhantomJS | ||
// TODO sourceURL points at the 'throw new Error' line above, useless | ||
//return e.sourceURL + ":" + e.line; | ||
} | ||
return extractStacktrace( e, offset ); | ||
} | ||
} | ||
function escapeInnerText(s) { | ||
if (!s) { | ||
function escapeInnerText( s ) { | ||
if ( !s ) { | ||
return ""; | ||
} | ||
s = s + ""; | ||
return s.replace(/[\&<>]/g, function(s) { | ||
switch(s) { | ||
return s.replace( /[\&<>]/g, function( s ) { | ||
switch( s ) { | ||
case "&": return "&"; | ||
@@ -959,3 +1302,3 @@ case "<": return "<"; | ||
if ( config.autorun && !config.blocking ) { | ||
process(last); | ||
process( last ); | ||
} | ||
@@ -965,2 +1308,5 @@ } | ||
function process( last ) { | ||
function next() { | ||
process( last ); | ||
} | ||
var start = new Date().getTime(); | ||
@@ -973,5 +1319,3 @@ config.depth = config.depth ? config.depth + 1 : 1; | ||
} else { | ||
window.setTimeout( function(){ | ||
process( last ); | ||
}, 13 ); | ||
window.setTimeout( next, 13 ); | ||
break; | ||
@@ -991,3 +1335,4 @@ } | ||
for ( var key in window ) { | ||
if ( !hasOwn.call( window, key ) ) { | ||
// in Opera sometimes DOM element ids show up here, ignore them | ||
if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) { | ||
continue; | ||
@@ -1001,13 +1346,16 @@ } | ||
function checkPollution( name ) { | ||
var old = config.pollution; | ||
var newGlobals, | ||
deletedGlobals, | ||
old = config.pollution; | ||
saveGlobal(); | ||
var newGlobals = diff( config.pollution, old ); | ||
newGlobals = diff( config.pollution, old ); | ||
if ( newGlobals.length > 0 ) { | ||
ok( false, "Introduced global variable(s): " + newGlobals.join(", ") ); | ||
QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") ); | ||
} | ||
var deletedGlobals = diff( old, config.pollution ); | ||
deletedGlobals = diff( old, config.pollution ); | ||
if ( deletedGlobals.length > 0 ) { | ||
ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") ); | ||
QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") ); | ||
} | ||
@@ -1018,7 +1366,9 @@ } | ||
function diff( a, b ) { | ||
var result = a.slice(); | ||
for ( var i = 0; i < result.length; i++ ) { | ||
for ( var j = 0; j < b.length; j++ ) { | ||
var i, j, | ||
result = a.slice(); | ||
for ( i = 0; i < result.length; i++ ) { | ||
for ( j = 0; j < b.length; j++ ) { | ||
if ( result[i] === b[j] ) { | ||
result.splice(i, 1); | ||
result.splice( i, 1 ); | ||
i--; | ||
@@ -1032,21 +1382,10 @@ break; | ||
function fail(message, exception, callback) { | ||
if ( typeof console !== "undefined" && console.error && console.warn ) { | ||
console.error(message); | ||
console.error(exception); | ||
console.warn(callback.toString()); | ||
} else if ( window.opera && opera.postError ) { | ||
opera.postError(message, exception, callback.toString); | ||
} | ||
} | ||
function extend(a, b) { | ||
function extend( a, b ) { | ||
for ( var prop in b ) { | ||
if ( b[prop] === undefined ) { | ||
delete a[prop]; | ||
if ( b[ prop ] === undefined ) { | ||
delete a[ prop ]; | ||
// Avoid "Member not found" error in IE8 caused by setting window.constructor | ||
} else if ( prop !== "constructor" || a !== window ) { | ||
a[prop] = b[prop]; | ||
a[ prop ] = b[ prop ]; | ||
} | ||
@@ -1058,3 +1397,3 @@ } | ||
function addEvent(elem, type, fn) { | ||
function addEvent( elem, type, fn ) { | ||
if ( elem.addEventListener ) { | ||
@@ -1069,9 +1408,9 @@ elem.addEventListener( type, fn, false ); | ||
function id(name) { | ||
return !!(typeof document !== "undefined" && document && document.getElementById) && | ||
function id( name ) { | ||
return !!( typeof document !== "undefined" && document && document.getElementById ) && | ||
document.getElementById( name ); | ||
} | ||
function registerLoggingCallback(key){ | ||
return function(callback){ | ||
function registerLoggingCallback( key ) { | ||
return function( callback ) { | ||
config[key].push( callback ); | ||
@@ -1082,11 +1421,11 @@ }; | ||
// Supports deprecated method of completely overwriting logging callbacks | ||
function runLoggingCallbacks(key, scope, args) { | ||
function runLoggingCallbacks( key, scope, args ) { | ||
//debugger; | ||
var callbacks; | ||
if ( QUnit.hasOwnProperty(key) ) { | ||
QUnit[key].call(scope, args); | ||
var i, callbacks; | ||
if ( QUnit.hasOwnProperty( key ) ) { | ||
QUnit[ key ].call(scope, args ); | ||
} else { | ||
callbacks = config[key]; | ||
for( var i = 0; i < callbacks.length; i++ ) { | ||
callbacks[i].call( scope, args ); | ||
callbacks = config[ key ]; | ||
for ( i = 0; i < callbacks.length; i++ ) { | ||
callbacks[ i ].call( scope, args ); | ||
} | ||
@@ -1098,16 +1437,12 @@ } | ||
// Author: Philippe Rathé <prathe@gmail.com> | ||
QUnit.equiv = function () { | ||
QUnit.equiv = (function() { | ||
var innerEquiv; // the real equiv function | ||
var callers = []; // stack to decide between skip/abort functions | ||
var parents = []; // stack to avoiding loops from circular referencing | ||
// Call the o related callback with the given arguments. | ||
function bindCallbacks(o, callbacks, args) { | ||
var prop = QUnit.objectType(o); | ||
if (prop) { | ||
if (QUnit.objectType(callbacks[prop]) === "function") { | ||
return callbacks[prop].apply(callbacks, args); | ||
function bindCallbacks( o, callbacks, args ) { | ||
var prop = QUnit.objectType( o ); | ||
if ( prop ) { | ||
if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) { | ||
return callbacks[ prop ].apply( callbacks, args ); | ||
} else { | ||
return callbacks[prop]; // or undefined | ||
return callbacks[ prop ]; // or undefined | ||
} | ||
@@ -1117,152 +1452,159 @@ } | ||
var getProto = Object.getPrototypeOf || function (obj) { | ||
return obj.__proto__; | ||
}; | ||
// the real equiv function | ||
var innerEquiv, | ||
// stack to decide between skip/abort functions | ||
callers = [], | ||
// stack to avoiding loops from circular referencing | ||
parents = [], | ||
var callbacks = function () { | ||
getProto = Object.getPrototypeOf || function ( obj ) { | ||
return obj.__proto__; | ||
}, | ||
callbacks = (function () { | ||
// for string, boolean, number and null | ||
function useStrictEquality(b, a) { | ||
if (b instanceof a.constructor || a instanceof b.constructor) { | ||
// to catch short annotaion VS 'new' annotation of a | ||
// declaration | ||
// e.g. var i = 1; | ||
// var j = new Number(1); | ||
return a == b; | ||
} else { | ||
return a === b; | ||
// for string, boolean, number and null | ||
function useStrictEquality( b, a ) { | ||
if ( b instanceof a.constructor || a instanceof b.constructor ) { | ||
// to catch short annotaion VS 'new' annotation of a | ||
// declaration | ||
// e.g. var i = 1; | ||
// var j = new Number(1); | ||
return a == b; | ||
} else { | ||
return a === b; | ||
} | ||
} | ||
} | ||
return { | ||
"string" : useStrictEquality, | ||
"boolean" : useStrictEquality, | ||
"number" : useStrictEquality, | ||
"null" : useStrictEquality, | ||
"undefined" : useStrictEquality, | ||
return { | ||
"string": useStrictEquality, | ||
"boolean": useStrictEquality, | ||
"number": useStrictEquality, | ||
"null": useStrictEquality, | ||
"undefined": useStrictEquality, | ||
"nan" : function(b) { | ||
return isNaN(b); | ||
}, | ||
"nan": function( b ) { | ||
return isNaN( b ); | ||
}, | ||
"date" : function(b, a) { | ||
return QUnit.objectType(b) === "date" | ||
&& a.valueOf() === b.valueOf(); | ||
}, | ||
"date": function( b, a ) { | ||
return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf(); | ||
}, | ||
"regexp" : function(b, a) { | ||
return QUnit.objectType(b) === "regexp" | ||
&& a.source === b.source && // the regex itself | ||
a.global === b.global && // and its modifers | ||
// (gmi) ... | ||
a.ignoreCase === b.ignoreCase | ||
&& a.multiline === b.multiline; | ||
}, | ||
"regexp": function( b, a ) { | ||
return QUnit.objectType( b ) === "regexp" && | ||
// the regex itself | ||
a.source === b.source && | ||
// and its modifers | ||
a.global === b.global && | ||
// (gmi) ... | ||
a.ignoreCase === b.ignoreCase && | ||
a.multiline === b.multiline && | ||
a.sticky === b.sticky; | ||
}, | ||
// - skip when the property is a method of an instance (OOP) | ||
// - abort otherwise, | ||
// initial === would have catch identical references anyway | ||
"function" : function() { | ||
var caller = callers[callers.length - 1]; | ||
return caller !== Object && typeof caller !== "undefined"; | ||
}, | ||
// - skip when the property is a method of an instance (OOP) | ||
// - abort otherwise, | ||
// initial === would have catch identical references anyway | ||
"function": function() { | ||
var caller = callers[callers.length - 1]; | ||
return caller !== Object && typeof caller !== "undefined"; | ||
}, | ||
"array" : function(b, a) { | ||
var i, j, loop; | ||
var len; | ||
"array": function( b, a ) { | ||
var i, j, len, loop; | ||
// b could be an object literal here | ||
if (!(QUnit.objectType(b) === "array")) { | ||
return false; | ||
} | ||
// b could be an object literal here | ||
if ( QUnit.objectType( b ) !== "array" ) { | ||
return false; | ||
} | ||
len = a.length; | ||
if (len !== b.length) { // safe and faster | ||
return false; | ||
} | ||
len = a.length; | ||
if ( len !== b.length ) { | ||
// safe and faster | ||
return false; | ||
} | ||
// track reference to avoid circular references | ||
parents.push(a); | ||
for (i = 0; i < len; i++) { | ||
loop = false; | ||
for (j = 0; j < parents.length; j++) { | ||
if (parents[j] === a[i]) { | ||
loop = true;// dont rewalk array | ||
// track reference to avoid circular references | ||
parents.push( a ); | ||
for ( i = 0; i < len; i++ ) { | ||
loop = false; | ||
for ( j = 0; j < parents.length; j++ ) { | ||
if ( parents[j] === a[i] ) { | ||
loop = true;// dont rewalk array | ||
} | ||
} | ||
if ( !loop && !innerEquiv(a[i], b[i]) ) { | ||
parents.pop(); | ||
return false; | ||
} | ||
} | ||
if (!loop && !innerEquiv(a[i], b[i])) { | ||
parents.pop(); | ||
return false; | ||
} | ||
} | ||
parents.pop(); | ||
return true; | ||
}, | ||
parents.pop(); | ||
return true; | ||
}, | ||
"object" : function(b, a) { | ||
var i, j, loop; | ||
var eq = true; // unless we can proove it | ||
var aProperties = [], bProperties = []; // collection of | ||
// strings | ||
"object": function( b, a ) { | ||
var i, j, loop, | ||
// Default to true | ||
eq = true, | ||
aProperties = [], | ||
bProperties = []; | ||
// comparing constructors is more strict than using | ||
// instanceof | ||
if (a.constructor !== b.constructor) { | ||
// Allow objects with no prototype to be equivalent to | ||
// objects with Object as their constructor. | ||
if (!((getProto(a) === null && getProto(b) === Object.prototype) || | ||
(getProto(b) === null && getProto(a) === Object.prototype))) | ||
{ | ||
return false; | ||
// comparing constructors is more strict than using | ||
// instanceof | ||
if ( a.constructor !== b.constructor ) { | ||
// Allow objects with no prototype to be equivalent to | ||
// objects with Object as their constructor. | ||
if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) || | ||
( getProto(b) === null && getProto(a) === Object.prototype ) ) ) { | ||
return false; | ||
} | ||
} | ||
} | ||
// stack constructor before traversing properties | ||
callers.push(a.constructor); | ||
// track reference to avoid circular references | ||
parents.push(a); | ||
// stack constructor before traversing properties | ||
callers.push( a.constructor ); | ||
// track reference to avoid circular references | ||
parents.push( a ); | ||
for (i in a) { // be strict: don't ensures hasOwnProperty | ||
// and go deep | ||
loop = false; | ||
for (j = 0; j < parents.length; j++) { | ||
if (parents[j] === a[i]) | ||
loop = true; // don't go down the same path | ||
// twice | ||
for ( i in a ) { // be strict: don't ensures hasOwnProperty | ||
// and go deep | ||
loop = false; | ||
for ( j = 0; j < parents.length; j++ ) { | ||
if ( parents[j] === a[i] ) { | ||
// don't go down the same path twice | ||
loop = true; | ||
} | ||
} | ||
aProperties.push(i); // collect a's properties | ||
if (!loop && !innerEquiv( a[i], b[i] ) ) { | ||
eq = false; | ||
break; | ||
} | ||
} | ||
aProperties.push(i); // collect a's properties | ||
if (!loop && !innerEquiv(a[i], b[i])) { | ||
eq = false; | ||
break; | ||
callers.pop(); // unstack, we are done | ||
parents.pop(); | ||
for ( i in b ) { | ||
bProperties.push( i ); // collect b's properties | ||
} | ||
} | ||
callers.pop(); // unstack, we are done | ||
parents.pop(); | ||
for (i in b) { | ||
bProperties.push(i); // collect b's properties | ||
// Ensures identical properties name | ||
return eq && innerEquiv( aProperties.sort(), bProperties.sort() ); | ||
} | ||
}; | ||
}()); | ||
// Ensures identical properties name | ||
return eq | ||
&& innerEquiv(aProperties.sort(), bProperties | ||
.sort()); | ||
} | ||
}; | ||
}(); | ||
innerEquiv = function() { // can take multiple arguments | ||
var args = Array.prototype.slice.apply(arguments); | ||
if (args.length < 2) { | ||
var args = [].slice.apply( arguments ); | ||
if ( args.length < 2 ) { | ||
return true; // end transition | ||
} | ||
return (function(a, b) { | ||
if (a === b) { | ||
return (function( a, b ) { | ||
if ( a === b ) { | ||
return true; // catch the most you can | ||
} else if (a === null || b === null || typeof a === "undefined" | ||
|| typeof b === "undefined" | ||
|| QUnit.objectType(a) !== QUnit.objectType(b)) { | ||
} else if ( a === null || b === null || typeof a === "undefined" || | ||
typeof b === "undefined" || | ||
QUnit.objectType(a) !== QUnit.objectType(b) ) { | ||
return false; // don't lose time with error prone cases | ||
@@ -1274,11 +1616,8 @@ } else { | ||
// apply transition with (1..n) arguments | ||
})(args[0], args[1]) | ||
&& arguments.callee.apply(this, args.splice(1, | ||
args.length - 1)); | ||
}( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) ); | ||
}; | ||
return innerEquiv; | ||
}()); | ||
}(); | ||
/** | ||
@@ -1296,7 +1635,7 @@ * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | | ||
function quote( str ) { | ||
return '"' + str.toString().replace(/"/g, '\\"') + '"'; | ||
}; | ||
return '"' + str.toString().replace( /"/g, '\\"' ) + '"'; | ||
} | ||
function literal( o ) { | ||
return o + ''; | ||
}; | ||
return o + ""; | ||
} | ||
function join( pre, arr, post ) { | ||
@@ -1306,175 +1645,202 @@ var s = jsDump.separator(), | ||
inner = jsDump.indent(1); | ||
if ( arr.join ) | ||
arr = arr.join( ',' + s + inner ); | ||
if ( !arr ) | ||
if ( arr.join ) { | ||
arr = arr.join( "," + s + inner ); | ||
} | ||
if ( !arr ) { | ||
return pre + post; | ||
} | ||
return [ pre, inner + arr, base + post ].join(s); | ||
}; | ||
} | ||
function array( arr, stack ) { | ||
var i = arr.length, ret = Array(i); | ||
var i = arr.length, ret = new Array(i); | ||
this.up(); | ||
while ( i-- ) | ||
while ( i-- ) { | ||
ret[i] = this.parse( arr[i] , undefined , stack); | ||
} | ||
this.down(); | ||
return join( '[', ret, ']' ); | ||
}; | ||
return join( "[", ret, "]" ); | ||
} | ||
var reName = /^function (\w+)/; | ||
var reName = /^function (\w+)/, | ||
jsDump = { | ||
parse: function( obj, type, stack ) { //type is used mostly internally, you can fix a (custom)type in advance | ||
stack = stack || [ ]; | ||
var inStack, res, | ||
parser = this.parsers[ type || this.typeOf(obj) ]; | ||
var jsDump = { | ||
parse:function( obj, type, stack ) { //type is used mostly internally, you can fix a (custom)type in advance | ||
stack = stack || [ ]; | ||
var parser = this.parsers[ type || this.typeOf(obj) ]; | ||
type = typeof parser; | ||
var inStack = inArray(obj, stack); | ||
if (inStack != -1) { | ||
return 'recursion('+(inStack - stack.length)+')'; | ||
} | ||
//else | ||
if (type == 'function') { | ||
stack.push(obj); | ||
var res = parser.call( this, obj, stack ); | ||
type = typeof parser; | ||
inStack = inArray( obj, stack ); | ||
if ( inStack != -1 ) { | ||
return "recursion(" + (inStack - stack.length) + ")"; | ||
} | ||
//else | ||
if ( type == "function" ) { | ||
stack.push( obj ); | ||
res = parser.call( this, obj, stack ); | ||
stack.pop(); | ||
return res; | ||
} | ||
// else | ||
return (type == 'string') ? parser : this.parsers.error; | ||
}, | ||
typeOf:function( obj ) { | ||
var type; | ||
if ( obj === null ) { | ||
type = "null"; | ||
} else if (typeof obj === "undefined") { | ||
type = "undefined"; | ||
} else if (QUnit.is("RegExp", obj)) { | ||
type = "regexp"; | ||
} else if (QUnit.is("Date", obj)) { | ||
type = "date"; | ||
} else if (QUnit.is("Function", obj)) { | ||
type = "function"; | ||
} else if (typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined") { | ||
type = "window"; | ||
} else if (obj.nodeType === 9) { | ||
type = "document"; | ||
} else if (obj.nodeType) { | ||
type = "node"; | ||
} else if ( | ||
// native arrays | ||
toString.call( obj ) === "[object Array]" || | ||
// NodeList objects | ||
( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) ) | ||
) { | ||
type = "array"; | ||
} else { | ||
type = typeof obj; | ||
} | ||
return type; | ||
}, | ||
separator:function() { | ||
return this.multiline ? this.HTML ? '<br />' : '\n' : this.HTML ? ' ' : ' '; | ||
}, | ||
indent:function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing | ||
if ( !this.multiline ) | ||
return ''; | ||
var chr = this.indentChar; | ||
if ( this.HTML ) | ||
chr = chr.replace(/\t/g,' ').replace(/ /g,' '); | ||
return Array( this._depth_ + (extra||0) ).join(chr); | ||
}, | ||
up:function( a ) { | ||
this._depth_ += a || 1; | ||
}, | ||
down:function( a ) { | ||
this._depth_ -= a || 1; | ||
}, | ||
setParser:function( name, parser ) { | ||
this.parsers[name] = parser; | ||
}, | ||
// The next 3 are exposed so you can use them | ||
quote:quote, | ||
literal:literal, | ||
join:join, | ||
// | ||
_depth_: 1, | ||
// This is the list of parsers, to modify them, use jsDump.setParser | ||
parsers:{ | ||
window: '[Window]', | ||
document: '[Document]', | ||
error:'[ERROR]', //when no parser is found, shouldn't happen | ||
unknown: '[Unknown]', | ||
'null':'null', | ||
'undefined':'undefined', | ||
'function':function( fn ) { | ||
var ret = 'function', | ||
name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE | ||
if ( name ) | ||
ret += ' ' + name; | ||
ret += '('; | ||
ret = [ ret, QUnit.jsDump.parse( fn, 'functionArgs' ), '){'].join(''); | ||
return join( ret, QUnit.jsDump.parse(fn,'functionCode'), '}' ); | ||
} | ||
// else | ||
return ( type == "string" ) ? parser : this.parsers.error; | ||
}, | ||
array: array, | ||
nodelist: array, | ||
arguments: array, | ||
object:function( map, stack ) { | ||
var ret = [ ]; | ||
QUnit.jsDump.up(); | ||
for ( var key in map ) { | ||
var val = map[key]; | ||
ret.push( QUnit.jsDump.parse(key,'key') + ': ' + QUnit.jsDump.parse(val, undefined, stack)); | ||
} | ||
QUnit.jsDump.down(); | ||
return join( '{', ret, '}' ); | ||
typeOf: function( obj ) { | ||
var type; | ||
if ( obj === null ) { | ||
type = "null"; | ||
} else if ( typeof obj === "undefined" ) { | ||
type = "undefined"; | ||
} else if ( QUnit.is( "regexp", obj) ) { | ||
type = "regexp"; | ||
} else if ( QUnit.is( "date", obj) ) { | ||
type = "date"; | ||
} else if ( QUnit.is( "function", obj) ) { | ||
type = "function"; | ||
} else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) { | ||
type = "window"; | ||
} else if ( obj.nodeType === 9 ) { | ||
type = "document"; | ||
} else if ( obj.nodeType ) { | ||
type = "node"; | ||
} else if ( | ||
// native arrays | ||
toString.call( obj ) === "[object Array]" || | ||
// NodeList objects | ||
( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) ) | ||
) { | ||
type = "array"; | ||
} else { | ||
type = typeof obj; | ||
} | ||
return type; | ||
}, | ||
node:function( node ) { | ||
var open = QUnit.jsDump.HTML ? '<' : '<', | ||
close = QUnit.jsDump.HTML ? '>' : '>'; | ||
var tag = node.nodeName.toLowerCase(), | ||
ret = open + tag; | ||
for ( var a in QUnit.jsDump.DOMAttrs ) { | ||
var val = node[QUnit.jsDump.DOMAttrs[a]]; | ||
if ( val ) | ||
ret += ' ' + a + '=' + QUnit.jsDump.parse( val, 'attribute' ); | ||
separator: function() { | ||
return this.multiline ? this.HTML ? "<br />" : "\n" : this.HTML ? " " : " "; | ||
}, | ||
indent: function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing | ||
if ( !this.multiline ) { | ||
return ""; | ||
} | ||
return ret + close + open + '/' + tag + close; | ||
var chr = this.indentChar; | ||
if ( this.HTML ) { | ||
chr = chr.replace( /\t/g, " " ).replace( / /g, " " ); | ||
} | ||
return new Array( this._depth_ + (extra||0) ).join(chr); | ||
}, | ||
functionArgs:function( fn ) {//function calls it internally, it's the arguments part of the function | ||
var l = fn.length; | ||
if ( !l ) return ''; | ||
up: function( a ) { | ||
this._depth_ += a || 1; | ||
}, | ||
down: function( a ) { | ||
this._depth_ -= a || 1; | ||
}, | ||
setParser: function( name, parser ) { | ||
this.parsers[name] = parser; | ||
}, | ||
// The next 3 are exposed so you can use them | ||
quote: quote, | ||
literal: literal, | ||
join: join, | ||
// | ||
_depth_: 1, | ||
// This is the list of parsers, to modify them, use jsDump.setParser | ||
parsers: { | ||
window: "[Window]", | ||
document: "[Document]", | ||
error: "[ERROR]", //when no parser is found, shouldn"t happen | ||
unknown: "[Unknown]", | ||
"null": "null", | ||
"undefined": "undefined", | ||
"function": function( fn ) { | ||
var ret = "function", | ||
name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];//functions never have name in IE | ||
var args = Array(l); | ||
while ( l-- ) | ||
args[l] = String.fromCharCode(97+l);//97 is 'a' | ||
return ' ' + args.join(', ') + ' '; | ||
if ( name ) { | ||
ret += " " + name; | ||
} | ||
ret += "( "; | ||
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, stack ) { | ||
var ret = [ ], keys, key, val, i; | ||
QUnit.jsDump.up(); | ||
if ( Object.keys ) { | ||
keys = Object.keys( map ); | ||
} else { | ||
keys = []; | ||
for ( key in map ) { | ||
keys.push( key ); | ||
} | ||
} | ||
keys.sort(); | ||
for ( i = 0; i < keys.length; i++ ) { | ||
key = keys[ i ]; | ||
val = map[ key ]; | ||
ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) ); | ||
} | ||
QUnit.jsDump.down(); | ||
return join( "{", ret, "}" ); | ||
}, | ||
node: function( node ) { | ||
var a, val, | ||
open = QUnit.jsDump.HTML ? "<" : "<", | ||
close = QUnit.jsDump.HTML ? ">" : ">", | ||
tag = node.nodeName.toLowerCase(), | ||
ret = open + tag; | ||
for ( a in QUnit.jsDump.DOMAttrs ) { | ||
val = node[ QUnit.jsDump.DOMAttrs[a] ]; | ||
if ( val ) { | ||
ret += " " + a + "=" + QUnit.jsDump.parse( val, "attribute" ); | ||
} | ||
} | ||
return ret + close + open + "/" + tag + close; | ||
}, | ||
functionArgs: function( fn ) {//function calls it internally, it's the arguments part of the function | ||
var args, | ||
l = fn.length; | ||
if ( !l ) { | ||
return ""; | ||
} | ||
args = new Array(l); | ||
while ( l-- ) { | ||
args[l] = String.fromCharCode(97+l);//97 is 'a' | ||
} | ||
return " " + args.join( ", " ) + " "; | ||
}, | ||
key: quote, //object calls it internally, the key part of an item in a map | ||
functionCode: "[code]", //function calls it internally, it's the content of the function | ||
attribute: quote, //node calls it internally, it's an html attribute value | ||
string: quote, | ||
date: quote, | ||
regexp: literal, //regex | ||
number: literal, | ||
"boolean": literal | ||
}, | ||
key:quote, //object calls it internally, the key part of an item in a map | ||
functionCode:'[code]', //function calls it internally, it's the content of the function | ||
attribute:quote, //node calls it internally, it's an html attribute value | ||
string:quote, | ||
date:quote, | ||
regexp:literal, //regex | ||
number:literal, | ||
'boolean':literal | ||
}, | ||
DOMAttrs:{//attributes to dump from nodes, name=>realName | ||
id:'id', | ||
name:'name', | ||
'class':'className' | ||
}, | ||
HTML:false,//if true, entities are escaped ( <, >, \t, space and \n ) | ||
indentChar:' ',//indentation unit | ||
multiline:true //if true, items in a collection, are separated by a \n, else just a space. | ||
}; | ||
DOMAttrs: { | ||
//attributes to dump from nodes, name=>realName | ||
id: "id", | ||
name: "name", | ||
"class": "className" | ||
}, | ||
HTML: false,//if true, entities are escaped ( <, >, \t, space and \n ) | ||
indentChar: " ",//indentation unit | ||
multiline: true //if true, items in a collection, are separated by a \n, else just a space. | ||
}; | ||
return jsDump; | ||
})(); | ||
}()); | ||
// from Sizzle.js | ||
function getText( elems ) { | ||
var ret = "", elem; | ||
var i, elem, | ||
ret = ""; | ||
for ( var i = 0; elems[i]; i++ ) { | ||
for ( i = 0; elems[i]; i++ ) { | ||
elem = elems[i]; | ||
@@ -1493,5 +1859,5 @@ | ||
return ret; | ||
}; | ||
} | ||
//from jquery.js | ||
// from jquery.js | ||
function inArray( elem, array ) { | ||
@@ -1523,38 +1889,41 @@ if ( array.indexOf ) { | ||
* | ||
* QUnit.diff("the quick brown fox jumped over", "the quick fox jumps over") == "the quick <del>brown </del> fox <del>jumped </del><ins>jumps </ins> over" | ||
* QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick <del>brown </del> fox <del>jumped </del><ins>jumps </ins> over" | ||
*/ | ||
QUnit.diff = (function() { | ||
function diff(o, n) { | ||
var ns = {}; | ||
var os = {}; | ||
function diff( o, n ) { | ||
var i, | ||
ns = {}, | ||
os = {}; | ||
for (var i = 0; i < n.length; i++) { | ||
if (ns[n[i]] == null) | ||
ns[n[i]] = { | ||
for ( i = 0; i < n.length; i++ ) { | ||
if ( ns[ n[i] ] == null ) { | ||
ns[ n[i] ] = { | ||
rows: [], | ||
o: null | ||
}; | ||
ns[n[i]].rows.push(i); | ||
} | ||
ns[ n[i] ].rows.push( i ); | ||
} | ||
for (var i = 0; i < o.length; i++) { | ||
if (os[o[i]] == null) | ||
os[o[i]] = { | ||
for ( i = 0; i < o.length; i++ ) { | ||
if ( os[ o[i] ] == null ) { | ||
os[ o[i] ] = { | ||
rows: [], | ||
n: null | ||
}; | ||
os[o[i]].rows.push(i); | ||
} | ||
os[ o[i] ].rows.push( i ); | ||
} | ||
for (var i in ns) { | ||
for ( i in ns ) { | ||
if ( !hasOwn.call( ns, i ) ) { | ||
continue; | ||
} | ||
if (ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1) { | ||
n[ns[i].rows[0]] = { | ||
text: n[ns[i].rows[0]], | ||
if ( ns[i].rows.length == 1 && typeof os[i] != "undefined" && os[i].rows.length == 1 ) { | ||
n[ ns[i].rows[0] ] = { | ||
text: n[ ns[i].rows[0] ], | ||
row: os[i].rows[0] | ||
}; | ||
o[os[i].rows[0]] = { | ||
text: o[os[i].rows[0]], | ||
o[ os[i].rows[0] ] = { | ||
text: o[ os[i].rows[0] ], | ||
row: ns[i].rows[0] | ||
@@ -1565,11 +1934,12 @@ }; | ||
for (var i = 0; i < n.length - 1; i++) { | ||
if (n[i].text != null && n[i + 1].text == null && n[i].row + 1 < o.length && o[n[i].row + 1].text == null && | ||
n[i + 1] == o[n[i].row + 1]) { | ||
n[i + 1] = { | ||
text: n[i + 1], | ||
for ( i = 0; i < n.length - 1; i++ ) { | ||
if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null && | ||
n[ i + 1 ] == o[ n[i].row + 1 ] ) { | ||
n[ i + 1 ] = { | ||
text: n[ i + 1 ], | ||
row: n[i].row + 1 | ||
}; | ||
o[n[i].row + 1] = { | ||
text: o[n[i].row + 1], | ||
o[ n[i].row + 1 ] = { | ||
text: o[ n[i].row + 1 ], | ||
row: i + 1 | ||
@@ -1580,11 +1950,12 @@ }; | ||
for (var i = n.length - 1; i > 0; i--) { | ||
if (n[i].text != null && n[i - 1].text == null && n[i].row > 0 && o[n[i].row - 1].text == null && | ||
n[i - 1] == o[n[i].row - 1]) { | ||
n[i - 1] = { | ||
text: n[i - 1], | ||
for ( i = n.length - 1; i > 0; i-- ) { | ||
if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null && | ||
n[ i - 1 ] == o[ n[i].row - 1 ]) { | ||
n[ i - 1 ] = { | ||
text: n[ i - 1 ], | ||
row: n[i].row - 1 | ||
}; | ||
o[n[i].row - 1] = { | ||
text: o[n[i].row - 1], | ||
o[ n[i].row - 1 ] = { | ||
text: o[ n[i].row - 1 ], | ||
row: i - 1 | ||
@@ -1601,45 +1972,48 @@ }; | ||
return function(o, n) { | ||
o = o.replace(/\s+$/, ''); | ||
n = n.replace(/\s+$/, ''); | ||
var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/)); | ||
return function( o, n ) { | ||
o = o.replace( /\s+$/, "" ); | ||
n = n.replace( /\s+$/, "" ); | ||
var str = ""; | ||
var i, pre, | ||
str = "", | ||
out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ), | ||
oSpace = o.match(/\s+/g), | ||
nSpace = n.match(/\s+/g); | ||
var oSpace = o.match(/\s+/g); | ||
if (oSpace == null) { | ||
oSpace = [" "]; | ||
if ( oSpace == null ) { | ||
oSpace = [ " " ]; | ||
} | ||
else { | ||
oSpace.push(" "); | ||
oSpace.push( " " ); | ||
} | ||
var nSpace = n.match(/\s+/g); | ||
if (nSpace == null) { | ||
nSpace = [" "]; | ||
if ( nSpace == null ) { | ||
nSpace = [ " " ]; | ||
} | ||
else { | ||
nSpace.push(" "); | ||
nSpace.push( " " ); | ||
} | ||
if (out.n.length == 0) { | ||
for (var i = 0; i < out.o.length; i++) { | ||
str += '<del>' + out.o[i] + oSpace[i] + "</del>"; | ||
if ( out.n.length === 0 ) { | ||
for ( i = 0; i < out.o.length; i++ ) { | ||
str += "<del>" + out.o[i] + oSpace[i] + "</del>"; | ||
} | ||
} | ||
else { | ||
if (out.n[0].text == null) { | ||
for (n = 0; n < out.o.length && out.o[n].text == null; n++) { | ||
str += '<del>' + out.o[n] + oSpace[n] + "</del>"; | ||
if ( out.n[0].text == null ) { | ||
for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) { | ||
str += "<del>" + out.o[n] + oSpace[n] + "</del>"; | ||
} | ||
} | ||
for (var i = 0; i < out.n.length; i++) { | ||
for ( i = 0; i < out.n.length; i++ ) { | ||
if (out.n[i].text == null) { | ||
str += '<ins>' + out.n[i] + nSpace[i] + "</ins>"; | ||
str += "<ins>" + out.n[i] + nSpace[i] + "</ins>"; | ||
} | ||
else { | ||
var pre = ""; | ||
// `pre` initialized at top of scope | ||
pre = ""; | ||
for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++) { | ||
pre += '<del>' + out.o[n] + oSpace[n] + "</del>"; | ||
for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) { | ||
pre += "<del>" + out.o[n] + oSpace[n] + "</del>"; | ||
} | ||
@@ -1653,4 +2027,10 @@ str += " " + out.n[i].text + nSpace[i] + pre; | ||
}; | ||
})(); | ||
}()); | ||
})(this); | ||
// for CommonJS enviroments, export everything | ||
if ( typeof exports !== "undefined" ) { | ||
extend(exports, QUnit); | ||
} | ||
// get at whatever the global object is, like window in browsers | ||
}( (function() {return this;}.call()) )); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
303339
5
2278
57
6
26