tor-browser

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

newtarget-customized-builtins.html (4919B)


      1 <!DOCTYPE html>
      2 <title>Custom Elements: [HTMLConstructor] derives prototype from NewTarget</title>
      3 <meta name="author" title="Domenic Denicola" href="mailto:d@domenic.me">
      4 <meta name="help" content="https://html.spec.whatwg.org/multipage/dom.html#htmlconstructor">
      5 <script src="/resources/testharness.js"></script>
      6 <script src="/resources/testharnessreport.js"></script>
      7 <script src="../resources/custom-elements-helpers.js"></script>
      8 <body>
      9 <script>
     10 "use strict";
     11 
     12 [null, undefined, 5, "string"].forEach(function (notAnObject) {
     13  test_with_window(w => {
     14    // We have to return an object during define(), but not during super()
     15    let returnNotAnObject = false;
     16 
     17    function TestElement() {
     18      const o = Reflect.construct(w.HTMLParagraphElement, [], new.target);
     19 
     20      assert_equals(Object.getPrototypeOf(o), window.HTMLParagraphElement.prototype,
     21        "Must use the HTMLParagraphElement from the realm of NewTarget");
     22      assert_not_equals(Object.getPrototypeOf(o), w.HTMLParagraphElement.prototype,
     23        "Must not use the HTMLParagraphElement from the realm of the active function object (w.HTMLParagraphElement)");
     24 
     25      return o;
     26    }
     27 
     28    const ElementWithDynamicPrototype = new Proxy(TestElement, {
     29      get: function (target, name) {
     30        if (name == "prototype")
     31          return returnNotAnObject ? notAnObject : {};
     32        return target[name];
     33      }
     34    });
     35 
     36    w.customElements.define("test-element", ElementWithDynamicPrototype, { extends: "p" });
     37 
     38    returnNotAnObject = true;
     39    new ElementWithDynamicPrototype();
     40  }, "If prototype is not object (" + notAnObject + "), derives the fallback from NewTarget's realm (customized built-in elements)");
     41 
     42  test_with_window(w => {
     43    // We have to return an object during define(), but not during super()
     44    let returnNotAnObject = false;
     45 
     46    function TestElement() {
     47      const o = Reflect.construct(w.HTMLParagraphElement, [], new.target);
     48 
     49      assert_equals(Object.getPrototypeOf(o), window.HTMLParagraphElement.prototype,
     50        "Must use the HTMLParagraphElement from the realm of NewTarget");
     51      assert_not_equals(Object.getPrototypeOf(o), w.HTMLParagraphElement.prototype,
     52        "Must not use the HTMLParagraphElement from the realm of the active function object (w.HTMLParagraphElement)");
     53 
     54      return o;
     55    }
     56 
     57    // Create the proxy in the subframe, which should not affect what our
     58    // prototype ends up as.
     59    const ElementWithDynamicPrototype = new w.Proxy(TestElement, {
     60      get: function (target, name) {
     61        if (name == "prototype")
     62          return returnNotAnObject ? notAnObject : {};
     63        return target[name];
     64      }
     65    });
     66 
     67    w.customElements.define("test-element", ElementWithDynamicPrototype, { extends: "p" });
     68 
     69    returnNotAnObject = true;
     70    new ElementWithDynamicPrototype();
     71  }, "If prototype is not object (" + notAnObject + "), derives the fallback from NewTarget's GetFunctionRealm (customized built-in elements)");
     72 });
     73 
     74 test_with_window(w => {
     75    class SomeCustomElement extends HTMLParagraphElement {};
     76    var getCount = 0;
     77    var countingProxy = new Proxy(SomeCustomElement, {
     78        get: function(target, prop, receiver) {
     79            if (prop == "prototype") {
     80                ++getCount;
     81            }
     82            return Reflect.get(target, prop, receiver);
     83        }
     84    });
     85    w.customElements.define("failure-counting-element", countingProxy);
     86    // define() gets the prototype of the constructor it's passed, so
     87    // reset the counter.
     88    getCount = 0;
     89    assert_throws_js(TypeError,
     90                     function () { new countingProxy() },
     91                     "Should not be able to construct an HTMLParagraphElement not named 'p'");
     92    assert_equals(getCount, 0, "Should never have gotten .prototype");
     93 }, 'HTMLParagraphElement constructor must not get .prototype until it finishes its extends sanity checks, calling proxy constructor directly');
     94 
     95 test_with_window(w => {
     96    class SomeCustomElement extends HTMLParagraphElement {};
     97    var getCount = 0;
     98    var countingProxy = new Proxy(SomeCustomElement, {
     99        get: function(target, prop, receiver) {
    100            if (prop == "prototype") {
    101                ++getCount;
    102            }
    103            return Reflect.get(target, prop, receiver);
    104        }
    105    });
    106    w.customElements.define("failure-counting-element", countingProxy);
    107    // define() gets the prototype of the constructor it's passed, so
    108    // reset the counter.
    109    getCount = 0;
    110    assert_throws_js(TypeError,
    111                     function () { Reflect.construct(HTMLParagraphElement, [], countingProxy) },
    112                     "Should not be able to construct an HTMLParagraphElement not named 'p'");
    113    assert_equals(getCount, 0, "Should never have gotten .prototype");
    114 }, 'HTMLParagraphElement constructor must not get .prototype until it finishes its extends sanity checks, calling via Reflect');
    115 </script>
    116 </body>