diff --git a/test/asset/qunit-extras.js b/test/asset/qunit-extras.js new file mode 100644 index 000000000..89d8221db --- /dev/null +++ b/test/asset/qunit-extras.js @@ -0,0 +1,164 @@ +;(function(root, undefined) { + 'use strict'; + + /** Native method shortcut */ + var unshift = Array.prototype.unshift; + + /** Used to match HTML entities */ + var reEscapedHtml = /(&|<|>|"|')/g; + + /** Used to match parts of the assert message */ + var reDied = /^Died on test #\d+/, + reExpected = /Expected: *<\/th>
([\s\S]*?)<\/pre>/,
+ reMessage = /^([\s\S]*?)<\/span>/;
+
+ /** Used to convert HTML entities to characters */
+ var htmlUnescapes = {
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ ''': "'"
+ };
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * Checks if a given value is present in an array using strict equality
+ * for comparisons, i.e. `===`.
+ *
+ * @oruvate
+ * @param {Array} array The array to iterate over.
+ * @param {*} target The value to check for.
+ * @returns {boolean} Returns `true` if the `target` element is found, else `false`.
+ */
+ function contains(array, value) {
+ var index = -1,
+ length = array ? array.length : 0;
+
+ while (++index < length) {
+ if (array[index] === value) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Resolves the value of `property` on `object`. If `object` is falsey then
+ * `undefined` is returned.
+ *
+ * @private
+ * @param {Object} object The object to inspect.
+ * @param {string} property The property to get the value of.
+ * @returns {*} Returns the resolved value.
+ */
+ function result(object, property) {
+ return object ? object[property] : undefined;
+ }
+
+ /**
+ * Converts the HTML entities `&`, `<`, `>`, `"`, and `'`
+ * in `string` to their corresponding characters.
+ *
+ * @private
+ * @param {string} string The string to unescape.
+ * @returns {string} Returns the unescaped string.
+ */
+ function unescape(string) {
+ return string == null ? '' : String(string).replace(reEscapedHtml, unescapeHtmlChar);
+ }
+
+ /**
+ * Used by `unescape` to convert HTML entities to characters.
+ *
+ * @private
+ * @param {string} match The matched character to unescape.
+ * @returns {string} Returns the unescaped character.
+ */
+ function unescapeHtmlChar(match) {
+ return htmlUnescapes[match];
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ /** The number of retries async tests have to succeed */
+ QUnit.config.asyncRetries = 0;
+
+ /** An object of excused tests and assertions */
+ QUnit.config.excused = {};
+
+ /**
+ * A callback triggered at the start of every test.
+ *
+ * @memberOf QUnit
+ * @param {Object} details An object with `module` and `name` properties.
+ */
+ QUnit.testStart(function(details) {
+ var excused = QUnit.config.excused || {},
+ excusedTests = excused[details.module],
+ excusedAsserts = excusedTests && excusedTests[details.name];
+
+ var test = QUnit.config.current,
+ finish = test.finish;
+
+ // allow async tests to retry
+ if (test.async && !test.retries) {
+ test.retries = 0;
+ test.finish = function() {
+ var asserts = this.assertions,
+ index = -1,
+ length = asserts.length,
+ queue = QUnit.config.queue;
+
+ while (++index < length) {
+ var assert = asserts[index];
+ if (!assert.result && this.retries < QUnit.config.asyncRetries) {
+ this.retries++;
+ asserts.length = 0;
+
+ var oldLength = queue.length;
+ this.queue();
+ unshift.apply(queue, queue.splice(oldLength, queue.length - oldLength));
+ return;
+ }
+ }
+ finish.call(this);
+ };
+ }
+ // nothing to excuse
+ if (!excusedAsserts) {
+ return;
+ }
+ // excuse the entire test
+ if (excusedAsserts === true) {
+ test.async = false;
+ test.callback = function() {};
+ test.expected = 0;
+ return;
+ }
+ // excuse specific assertions
+ test.finish = function() {
+ var asserts = this.assertions,
+ index = -1,
+ length = asserts.length;
+
+ while (++index < length) {
+ var assert = asserts[index],
+ message = unescape(result(reMessage.exec(assert.message), 1)),
+ died = result(reDied.exec(message), 0),
+ expected = unescape(result(reExpected.exec(assert.message), 1));
+
+ if ((message && contains(excusedAsserts, message)) ||
+ (died && contains(excusedAsserts, died)) ||
+ (expected && (
+ contains(excusedAsserts, expected) ||
+ contains(excusedAsserts, expected.replace(/\s+/g, ''))
+ ))) {
+ assert.result = true;
+ }
+ }
+ finish.call(this);
+ };
+ });
+}(this));
diff --git a/test/backbone.html b/test/backbone.html
index 8b9fa6be6..c9c56e7db 100644
--- a/test/backbone.html
+++ b/test/backbone.html
@@ -22,75 +22,37 @@
+
diff --git a/test/index.html b/test/index.html
index 70c74330d..963e4c684 100644
--- a/test/index.html
+++ b/test/index.html
@@ -13,6 +13,7 @@
+
@@ -72,6 +73,7 @@
delete Object._defineProperty;
delete Object._keys;
+ QUnit.config.asyncRetries = 3;
QUnit.config.hidepassed = true;
// assign results to `global_test_results` for Sauce Labs
diff --git a/test/underscore.html b/test/underscore.html
index d74021998..35d5e6eda 100644
--- a/test/underscore.html
+++ b/test/underscore.html
@@ -22,150 +22,94 @@
+