tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

upgrading.html (13578B)


      1 <!DOCTYPE html>
      2 <html>
      3 <head>
      4 <title>Custom Elements: Enqueue a custom element upgrade reaction</title>
      5 <meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org">
      6 <meta name="assert" content="Enqueue a custom element upgrade reaction must upgrade a custom element">
      7 <link rel="help" href="https://dom.spec.whatwg.org/#concept-create-element">
      8 <link rel="help" href="https://html.spec.whatwg.org/multipage/scripting.html#concept-try-upgrade">
      9 <link rel="help" href="https://html.spec.whatwg.org/multipage/scripting.html#enqueue-a-custom-element-upgrade-reaction">
     10 <script src="/resources/testharness.js"></script>
     11 <script src="/resources/testharnessreport.js"></script>
     12 <script src="resources/custom-elements-helpers.js"></script>
     13 </head>
     14 <body>
     15 <infinite-cloning-element-1></infinite-cloning-element-1>
     16 <infinite-cloning-element-2 id="a"></infinite-cloning-element-2>
     17 <infinite-cloning-element-2 id="b"></infinite-cloning-element-2>
     18 <div id="log"></div>
     19 <script>
     20 setup({allow_uncaught_exception:true});
     21 
     22 class PredefinedCustomElement extends HTMLElement {}
     23 customElements.define('predefined-custom-element', PredefinedCustomElement);
     24 
     25 var customElementNumber = 1;
     26 function generateNextCustomElementName() { return 'custom-' + customElementNumber++; }
     27 
     28 // Tests for documents without a browsing context.
     29 document_types().filter(function (entry) { return !entry.isOwner && !entry.hasBrowsingContext; }).forEach(function (entry) {
     30    var documentName = entry.name;
     31    var getDocument = entry.create;
     32 
     33    promise_test(function () {
     34        return getDocument().then(function (doc) {
     35            assert_false(doc.createElement('predefined-custom-element') instanceof PredefinedCustomElement);
     36        });
     37    }, 'Creating an element in ' + documentName + ' must not enqueue a custom element upgrade reaction'
     38        + ' because the document does not have a browsing context');
     39 
     40    promise_test(function () {
     41        var name = generateNextCustomElementName();
     42        var unresolvedElement = document.createElement(name);
     43 
     44        assert_equals(Object.getPrototypeOf(unresolvedElement), HTMLElement.prototype,
     45            '[[Prototype]] internal slot of the unresolved custom element must be the HTMLElement prototype');
     46 
     47        return getDocument().then(function (doc) {
     48            var unresolvedElementInDoc = doc.createElement(name);
     49            var prototype = (unresolvedElementInDoc.namespaceURI == 'http://www.w3.org/1999/xhtml' ? HTMLElement : Element).prototype;
     50 
     51            assert_equals(Object.getPrototypeOf(unresolvedElementInDoc), prototype,
     52                '[[Prototype]] internal slot of the unresolved custom element must be the ' + prototype.toString() + ' prototype');
     53            var someCustomElement = class extends HTMLElement {};
     54            customElements.define(name, someCustomElement);
     55            assert_equals(Object.getPrototypeOf(unresolvedElementInDoc), prototype, '"define" must not upgrade a disconnected unresolved custom elements');
     56            doc.documentElement.appendChild(unresolvedElementInDoc);
     57            assert_equals(Object.getPrototypeOf(unresolvedElementInDoc), prototype,
     58                'Inserting an element into a document without a browsing context must not enqueue a custom element upgrade reaction');
     59        });
     60    }, 'Creating an element in ' + documentName + ' and inserting into the document must not enqueue a custom element upgrade reaction');
     61 
     62    promise_test(function () {
     63        var name = generateNextCustomElementName();
     64        var unresolvedElement = document.createElement(name);
     65 
     66        assert_equals(Object.getPrototypeOf(unresolvedElement), HTMLElement.prototype,
     67            '[[Prototype]] internal slot of the unresolved custom element must be the HTMLElement prototype');
     68 
     69        return getDocument().then(function (doc) {
     70            var unresolvedElementInDoc = doc.createElement(name);
     71            var prototype = (unresolvedElementInDoc.namespaceURI == 'http://www.w3.org/1999/xhtml' ? HTMLElement : Element).prototype;
     72 
     73            assert_equals(Object.getPrototypeOf(unresolvedElementInDoc), prototype,
     74                '[[Prototype]] internal slot of the unresolved custom element must be the ' + prototype.toString() + ' prototype');
     75            var someCustomElement = class extends HTMLElement {};
     76            customElements.define(name, someCustomElement);
     77            assert_equals(Object.getPrototypeOf(unresolvedElementInDoc), prototype, '"define" must not upgrade a disconnected unresolved custom elements');
     78            document.body.appendChild(unresolvedElementInDoc);
     79 
     80            if (unresolvedElementInDoc.namespaceURI == 'http://www.w3.org/1999/xhtml') {
     81                assert_equals(Object.getPrototypeOf(unresolvedElementInDoc), someCustomElement.prototype,
     82                    'Inserting an element into a document with a browsing context must enqueue a custom element upgrade reaction');
     83            } else {
     84                assert_equals(Object.getPrototypeOf(unresolvedElementInDoc), prototype,
     85                    'Looking up a custom element definition must return null if the element is not in the HTML namespace');
     86            }
     87        });
     88    }, 'Creating an element in ' + documentName + ' and adopting back to a document with browsing context must enqueue a custom element upgrade reaction');
     89 
     90 });
     91 
     92 // Tests for documents with a browsing context.
     93 document_types().filter(function (entry) { return !entry.isOwner && entry.hasBrowsingContext; }).forEach(function (entry) {
     94    var documentName = entry.name;
     95    var getDocument = entry.create;
     96 
     97    promise_test(function () {
     98        return getDocument().then(function (doc) {
     99            assert_false(doc.createElement('predefined-custom-element') instanceof PredefinedCustomElement);
    100        });
    101    }, 'Creating an element in ' + documentName + ' must not enqueue a custom element upgrade reaction if there is no matching definition');
    102 
    103    promise_test(function () {
    104        return getDocument().then(function (doc) {
    105            var docWindow = doc.defaultView;
    106            class DistinctPredefinedCustomElement extends docWindow.HTMLElement { };
    107            docWindow.customElements.define('predefined-custom-element', DistinctPredefinedCustomElement);
    108            assert_true(doc.createElement('predefined-custom-element') instanceof DistinctPredefinedCustomElement);
    109        });
    110    }, 'Creating an element in ' + documentName + ' must enqueue a custom element upgrade reaction if there is a matching definition');
    111 
    112    promise_test(function () {
    113        var unresolvedElement = document.createElement('unresolved-element');
    114        return getDocument().then(function (doc) {
    115            var docWindow = doc.defaultView;
    116            class UnresolvedElement extends docWindow.HTMLElement { };
    117            var unresolvedElementInDoc = doc.createElement('unresolved-element');
    118 
    119            assert_equals(Object.getPrototypeOf(unresolvedElement), HTMLElement.prototype);
    120            assert_equals(Object.getPrototypeOf(unresolvedElementInDoc), docWindow.HTMLElement.prototype);
    121 
    122            docWindow.customElements.define('unresolved-element', UnresolvedElement);
    123 
    124            assert_equals(Object.getPrototypeOf(unresolvedElement), HTMLElement.prototype);
    125            assert_equals(Object.getPrototypeOf(unresolvedElementInDoc), docWindow.HTMLElement.prototype);
    126 
    127        });
    128    }, '"define" in ' + documentName + ' must not enqueue a custom element upgrade reaction on a disconnected unresolved custom element');
    129 
    130    promise_test(function () {
    131        var unresolvedElement = document.createElement('unresolved-element');
    132        return getDocument().then(function (doc) {
    133            var docWindow = doc.defaultView;
    134            class UnresolvedElement extends docWindow.HTMLElement { };
    135            var unresolvedElementInDoc = doc.createElement('unresolved-element');
    136 
    137            assert_equals(Object.getPrototypeOf(unresolvedElement), HTMLElement.prototype);
    138            assert_equals(Object.getPrototypeOf(unresolvedElementInDoc), docWindow.HTMLElement.prototype);
    139 
    140            docWindow.customElements.define('unresolved-element', UnresolvedElement);
    141            doc.documentElement.appendChild(unresolvedElementInDoc);
    142 
    143            assert_equals(Object.getPrototypeOf(unresolvedElement), HTMLElement.prototype);
    144            assert_equals(Object.getPrototypeOf(unresolvedElementInDoc), UnresolvedElement.prototype);
    145        });
    146    }, 'Inserting an unresolved custom element into ' + documentName + ' must enqueue a custom element upgrade reaction');
    147 
    148    promise_test(function () {
    149        var unresolvedElement = document.createElement('unresolved-element');
    150        return getDocument().then(function (doc) {
    151            var docWindow = doc.defaultView;
    152            class UnresolvedElement extends docWindow.HTMLElement { };
    153            var unresolvedElementInDoc = doc.createElement('unresolved-element');
    154            doc.documentElement.appendChild(unresolvedElementInDoc);
    155 
    156            assert_equals(Object.getPrototypeOf(unresolvedElement), HTMLElement.prototype);
    157            assert_equals(Object.getPrototypeOf(unresolvedElementInDoc), docWindow.HTMLElement.prototype);
    158 
    159            docWindow.customElements.define('unresolved-element', UnresolvedElement);
    160 
    161            assert_equals(Object.getPrototypeOf(unresolvedElement), HTMLElement.prototype);
    162            assert_equals(Object.getPrototypeOf(unresolvedElementInDoc), UnresolvedElement.prototype);
    163        });
    164    }, '"define" in ' + documentName + ' must enqueue a custom element upgrade reaction on a connected unresolved custom element');
    165 
    166    promise_test(function () {
    167        var unresolvedElement = document.createElement('unresolved-element');
    168        return getDocument().then(function (doc) {
    169            var docWindow = doc.defaultView;
    170            class UnresolvedElement extends docWindow.HTMLElement { };
    171            assert_false(unresolvedElement instanceof UnresolvedElement);
    172            docWindow.customElements.define('unresolved-element', UnresolvedElement);
    173            doc.adoptNode(unresolvedElement);
    174            assert_false(unresolvedElement instanceof UnresolvedElement);
    175        });
    176    }, 'Adopting (and leaving disconnceted) an unresolved custom element into ' + documentName + ' must not enqueue a custom element upgrade reaction');
    177 
    178    promise_test(function () {
    179        var unresolvedElement = document.createElement('unresolved-element');
    180        return getDocument().then(function (doc) {
    181            var docWindow = doc.defaultView;
    182            class UnresolvedElement extends docWindow.HTMLElement { };
    183            assert_false(unresolvedElement instanceof UnresolvedElement);
    184            docWindow.customElements.define('unresolved-element', UnresolvedElement);
    185            doc.documentElement.appendChild(unresolvedElement);
    186            assert_true(unresolvedElement instanceof UnresolvedElement);
    187        });
    188    }, 'Adopting and inserting an unresolved custom element into ' + documentName + ' must enqueue a custom element upgrade reaction');
    189 
    190 });
    191 
    192 test(() => {
    193    class ShadowDisabledElement extends HTMLElement {
    194      static get disabledFeatures() { return ['shadow']; }
    195    }
    196    let error = null;
    197    window.addEventListener('error', e => { error = e.error; }, {once: true});
    198    let element = document.createElement('shadow-disabled');
    199    element.attachShadow({mode: 'open'});
    200    customElements.define('shadow-disabled', ShadowDisabledElement);
    201    customElements.upgrade(element);
    202    assert_false(element instanceof ShadowDisabledElement,
    203                 'Upgrading should fail.');
    204    assert_true(error instanceof DOMException);
    205    assert_equals(error.name, 'NotSupportedError');
    206 }, 'If definition\'s disable shadow is true and element\'s shadow root is ' +
    207    'non-null, then throw a "NotSupportedError" DOMException.');
    208 
    209 test(() => {
    210    var log = [];
    211 
    212    customElements.define('infinite-cloning-element-1',class extends HTMLElement {
    213        constructor() {
    214            super();
    215            log.push([this, 'begin']);
    216            // Potential infinite recursion:
    217            customElements.upgrade(this);
    218            log.push([this, 'end']);
    219        }
    220    });
    221 
    222    assert_equals(log.length, 2);
    223    const instance = document.querySelector("infinite-cloning-element-1");
    224    assert_array_equals(log[0], [instance, 'begin']);
    225    assert_array_equals(log[1], [instance, 'end']);
    226 }, 'Infinite constructor recursion with upgrade(this) should not be possible');
    227 
    228 test(() => {
    229    var log = [];
    230 
    231    customElements.define('infinite-cloning-element-2',class extends HTMLElement {
    232        constructor() {
    233            super();
    234            log.push([this, 'begin']);
    235            const b = document.querySelector("#b");
    236            b.remove();
    237            // While this constructor is running for "a", "b" is still
    238            // undefined, and so inserting it into the document will enqueue a
    239            // second upgrade reaction for "b" in addition to the one enqueued
    240            // by defining x-foo.
    241            document.body.appendChild(b);
    242            log.push([this, 'end']);
    243        }
    244    });
    245 
    246    assert_equals(log.length, 4);
    247    const instanceA = document.querySelector("#a");
    248    const instanceB = document.querySelector("#b");
    249    assert_array_equals(log[0], [instanceA, 'begin']);
    250    assert_array_equals(log[1], [instanceB, 'begin']);
    251    assert_array_equals(log[2], [instanceB, 'end']);
    252    assert_array_equals(log[3], [instanceA, 'end']);
    253 }, 'Infinite constructor recursion with appendChild should not be possible');
    254 
    255 
    256 </script>
    257 </body>
    258 </html>