<!doctype html>
<title>createContextualFragment() tests</title>
<div id=log></div>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script>
// We are not testing XML documents here, because apparently it's not clear
// what we want to happen there.  We also aren't testing the HTML parser in any
// depth, just some basic sanity checks.

// Exception-throwing
test(function() {
        var range = document.createRange();
        range.detach();
        range.createContextualFragment("");
}, "Must not throw INVALID_STATE_ERR for a detached node.");

test(function() {
        var range = document.createRange();
        assert_throws_js(TypeError, function() {
                range.createContextualFragment();
        });
}, "Must throw TypeError when calling without arguments");

test(function() {
        // Simple test
        var range = document.createRange();
        range.selectNodeContents(document.body);

        var fragment = "<p CLaSs=testclass> Hi! <p>Hi!";
        var expected = document.createDocumentFragment();
        var tmpNode = document.createElement("p");
        tmpNode.setAttribute("class", "testclass");
        tmpNode.appendChild(document.createTextNode(" Hi! "));
        expected.appendChild(tmpNode);

        tmpNode = document.createElement("p");
        tmpNode.appendChild(document.createTextNode("Hi!"));
        expected.appendChild(tmpNode);

        var result = range.createContextualFragment(fragment);
        assert_true(expected.isEqualNode(result),
                "Unexpected result (collapsed Range)");

        // Token test that the end node makes no difference
        range.setEnd(document.body.getElementsByTagName("script")[0], 0);
        result = range.createContextualFragment(fragment);
        assert_true(expected.isEqualNode(result),
                "Unexpected result (Range ends in <script>)");
}, "Simple test with paragraphs");

test(function() {
        // This test based on https://bugzilla.mozilla.org/show_bug.cgi?id=585819,
        // from a real-world compat bug
        var range = document.createRange();
        range.selectNodeContents(document.documentElement);
        var fragment = "<span>Hello world</span>";
        var expected = document.createDocumentFragment();
        var tmpNode = document.createElement("span");
        tmpNode.appendChild(document.createTextNode("Hello world"));
        expected.appendChild(tmpNode);

        var result = range.createContextualFragment(fragment);
        assert_true(expected.isEqualNode(result),
                "Unexpected result (collapsed Range)");

        // Another token test that the end node makes no difference
        range.setEnd(document.head, 0);
        result = range.createContextualFragment(fragment);
        assert_true(expected.isEqualNode(result),
                "Unexpected result (Range ends in <head>)");
}, "Don't auto-create <body> when applied to <html>");

// Scripts should be run if inserted (that's what the "Unmark all scripts
// . . ." line means, I'm told)
var passed = false;
test(function() {
        assert_false(passed, "Sanity check");
        var range = document.createRange();
        range.selectNodeContents(document.documentElement);
        var fragment = range.createContextualFragment("<script>passed = true</s" + "cript>");
        assert_false(passed, "Fragment created but not yet added to document, should not have run");
        document.body.appendChild(fragment);
        assert_true(passed, "Fragment created and added to document, should run");
}, "<script>s should be run when appended to the document (but not before)");

// Historical bugs in browsers; see https://github.com/whatwg/html/issues/2222

[
        // Void
        "area",
        "base",
        "basefont",
        "bgsound",
        "br",
        "col",
        "embed",
        "frame",
        "hr",
        "img",
        "input",
        "keygen",
        "link",
        "meta",
        "param",
        "source",
        "track",
        "wbr",

        // Historical
        "menuitem",
        "image"
].forEach(name => {
        test(() => {
                const range = document.createRange();
                const contextNode = document.createElement(name);
                const selectedNode = document.createElement("div");
                contextNode.appendChild(selectedNode);
                range.selectNode(selectedNode);

                range.createContextualFragment("some text");
        }, `createContextualFragment should work even when the context is <${name}>`);
});


// Now that we've established basic sanity, let's do equivalence tests.  Those
// are easier to write anyway.
function testEquivalence(element1, fragment1, element2, fragment2) {
        var range1 = element1.ownerDocument.createRange();
        range1.selectNodeContents(element1);
        var range2 = element2.ownerDocument.createRange();
        range2.selectNodeContents(element2);

        var result1 = range1.createContextualFragment(fragment1);
        var result2 = range2.createContextualFragment(fragment2);

        assert_true(result1.isEqualNode(result2), "Results are supposed to be equivalent");

        // Throw in partial ownerDocument tests on the side, since the algorithm
        // does specify that and we don't want to completely not test it.
        if (result1.firstChild != null) {
                assert_equals(result1.firstChild.ownerDocument, element1.ownerDocument,
                        "ownerDocument must be set to that of the reference node");
        }
        if (result2.firstChild != null) {
                assert_equals(result2.firstChild.ownerDocument, element2.ownerDocument,
                        "ownerDocument must be set to that of the reference node");
        }
}

var doc_fragment = document.createDocumentFragment();
var comment = document.createComment("~o~");
doc_fragment.appendChild(comment);

var tests = [
        ["<html> and <body> must work the same, 1", document.documentElement, "<span>Hello world</span>", document.body, "<span>Hello world</span>"],
        ["<html> and <body> must work the same, 2", document.documentElement, "<body><p>Hello world", document.body, "<body><p>Hello world"],
        ["Implicit <body> creation", document.documentElement, "<body><p>", document.documentElement, "<p>"],
        ["Namespace generally shouldn't matter",
                document.createElementNS("http://fake-namespace", "div"), "<body><p><span>Foo",
                document.createElement("div"), "<body><p><span>Foo"],
        ["<html> in a different namespace shouldn't be special",
                document.createElementNS("http://fake-namespace", "html"), "<body><p>",
                document.createElement("div"), "<body><p>"],
        ["SVG namespace shouldn't be special",
                document.createElementNS("http://www.w3.org/2000/svg", "div"), "<body><p>",
                document.createElement("div"), "<body><p>"],
        ["null should be stringified", document.createElement("span"), null, document.createElement("span"), "null"],
        ["undefined should be stringified", document.createElement("span"), undefined, document.createElement("span"), "undefined"],
        ["Text nodes shouldn't be special",
                document.createTextNode("?"), "<body><p>",
                document.createElement("div"), "<body><p>"],
        ["Non-Element parent should not be special",
                comment, "<body><p>",
                document.createElement("div"), "<body><p>"]
];

generate_tests(testEquivalence, tests);
</script>
