mar10/fancytree

View on GitHub
lib/qunit-composite.js

Summary

Maintainability
B
5 hrs
Test Coverage
/**
 * 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;
    });
});