lib/qunit-composite.js
/**
* QUnit Composite
*
* https://github.com/JamesMGreene/qunit-composite
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* https://jquery.org/license/
*/
/*
* PATCHED
* 2021-04-02 Use pushResult to silence QUnit
* (https://github.com/JamesMGreene/qunit-composite/pull/25)
*/
(function(factory) {
if (typeof define === "function" && define.amd) {
define(["qunit"], factory);
} else {
factory(QUnit);
}
})(function(QUnit) {
var iframe,
hasBound,
resumeTests,
suiteAssert,
modules = 1,
executingComposite = false;
function hasClass(elem, name) {
return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
}
function addClass(elem, name) {
if (!hasClass(elem, name)) {
elem.className += (elem.className ? " " : "") + name;
}
}
function addEvent(elem, type, fn) {
if (elem.addEventListener) {
// Standards-based browsers
elem.addEventListener(type, fn, false);
} else if (elem.attachEvent) {
// support: IE <9
elem.attachEvent("on" + type, fn);
}
}
function runSuite(suite) {
var path;
if (QUnit.is("object", suite)) {
path = suite.path;
suite = suite.name;
} else {
path = suite;
}
QUnit.test(suite, function(assert) {
resumeTests = assert.async();
suiteAssert = assert;
iframe.setAttribute("src", path);
// QUnit.start is called from the child iframe's QUnit.done hook.
});
}
function initIframe() {
var iframeWin,
body = document.body;
function onIframeLoad() {
var moduleName,
testName,
count = 0;
if (!iframe.src) {
return;
}
// Deal with QUnit being loaded asynchronously via AMD
if (!iframeWin.QUnit && iframeWin.define && iframeWin.define.amd) {
return iframeWin.require(["qunit"], onIframeLoad);
}
iframeWin.QUnit.moduleStart(function(data) {
// Capture module name for messages
moduleName = data.name;
});
iframeWin.QUnit.testStart(function(data) {
// Capture test name for messages
testName = data.name;
});
iframeWin.QUnit.testDone(function() {
testName = undefined;
});
iframeWin.QUnit.log(function(data) {
if (testName === undefined) {
return;
}
// Pass all test details through to the main page
var message =
(moduleName ? moduleName + ": " : "") +
testName +
": " +
(data.message || (data.result ? "okay" : "failed"));
suiteAssert.expect(++count);
// PATCHED to silence QUnit (https://github.com/JamesMGreene/qunit-composite/pull/25)
suiteAssert.pushResult({
result: data.result,
actual: data.actual,
expected: data.expected,
message: message,
});
});
// Continue the outer test when the iframe's test is done
iframeWin.QUnit.done(function() {
resumeTests();
});
}
iframe = document.createElement("iframe");
iframe.className = "qunit-composite-suite";
body.appendChild(iframe);
addEvent(iframe, "load", onIframeLoad);
iframeWin = iframe.contentWindow;
}
function appendSuitesToHeader(suites) {
var i,
suitesLen,
suite,
path,
name,
suitesEl,
testResultEl,
newSuiteListItemEl,
newSuiteLinkEl;
suitesEl = document.getElementById("qunit-testsuites");
if (!suitesEl) {
testResultEl = document.getElementById("qunit-testresult");
if (!testResultEl) {
// QUnit has not been set up yet. Defer until QUnit is ready.
QUnit.begin(function() {
appendSuitesToHeader(suites);
});
return;
}
suitesEl = document.createElement("ul");
suitesEl.id = "qunit-testsuites";
testResultEl.parentNode.insertBefore(suitesEl, testResultEl);
}
for (i = 0, suitesLen = suites.length; i < suitesLen; ++i) {
suite = suites[i];
newSuiteLinkEl = document.createElement("a");
newSuiteLinkEl.innerHTML = suite.name || suite;
newSuiteLinkEl.href = suite.path || suite;
newSuiteListItemEl = document.createElement("li");
newSuiteListItemEl.appendChild(newSuiteLinkEl);
suitesEl.appendChild(newSuiteListItemEl);
}
}
/**
* @param {string} [name] Module name to group these test suites.
* @param {Array} suites List of suites where each suite
* may either be a string (path to the html test page),
* or an object with a path and name property.
*/
QUnit.testSuites = function(name, suites) {
var i, suitesLen;
if (arguments.length === 1) {
suites = name;
name = "Composition #" + modules++;
}
suitesLen = suites.length;
appendSuitesToHeader(suites);
if (!hasBound) {
hasBound = true;
QUnit.begin(initIframe);
// TODO: Would be better to use something like QUnit.once( 'moduleDone' )
// after the last test suite.
QUnit.moduleDone(function() {
executingComposite = false;
});
QUnit.done(function() {
iframe.style.display = "none";
});
}
QUnit.module(name, {
beforeEach: function() {
executingComposite = true;
},
});
for (i = 0; i < suitesLen; i++) {
runSuite(suites[i]);
}
};
QUnit.testDone(function(data) {
if (!executingComposite) {
return;
}
var i,
len,
testId = data.testId,
current = document.getElementById("qunit-test-output-" + testId),
children = current && current.children,
src = iframe.src;
if (!(current && children)) {
return;
}
addEvent(current, "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 = src;
}
});
// Undo QUnit's auto-expansion for bad tests
for (i = 0, len = children.length; i < len; i++) {
if (children[i].nodeName.toLowerCase() === "ol") {
addClass(children[i], "qunit-collapsed");
}
}
// Update Rerun link to point to the standalone test suite page
current.getElementsByTagName("a")[0].href = src;
});
});