tor-browser

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

browser_markup_shadowdom.js (8658B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 requestLongerTimeout(2);
      7 
      8 // Test a few static pages using webcomponents and check that they are displayed as
      9 // expected in the markup view.
     10 
     11 const TEST_DATA = [
     12  {
     13    // Test that expanding a shadow host shows a shadow root node and direct children.
     14    // Test that expanding a shadow root shows the shadow dom.
     15    // Test that slotted elements are visible in the shadow dom.
     16    title: "generic shadow dom test",
     17    url: `data:text/html;charset=utf-8,
     18      <test-component>
     19        <div slot="slot1">slotted-1<div>inner</div></div>
     20        <div slot="slot2">slotted-2<div>inner</div></div>
     21        <div class="no-slot-class">no-slot-text<div>inner</div></div>
     22      </test-component>
     23 
     24      <script>
     25        'use strict';
     26        customElements.define('test-component', class extends HTMLElement {
     27          constructor() {
     28            super();
     29            let shadowRoot = this.attachShadow({mode: "#MODE#"});
     30            shadowRoot.innerHTML = \`
     31                <slot name="slot1"></slot>
     32                <slot name="slot2"></slot>
     33                <slot></slot>
     34              \`;
     35          }
     36        });
     37      </script>`,
     38    tree: `
     39      test-component
     40        #shadow-root
     41          name="slot1"
     42            div!slotted
     43          name="slot2"
     44            div!slotted
     45          slot
     46            div!slotted
     47        slot="slot1"
     48          slotted-1
     49          inner
     50        slot="slot2"
     51          slotted-2
     52          inner
     53        class="no-slot-class"
     54          no-slot-text
     55          inner`,
     56  },
     57  {
     58    // Test that components without any direct children still display a shadow root node,
     59    // if a shadow root is attached to the host.
     60    title: "shadow root without direct children",
     61    url: `data:text/html;charset=utf-8,
     62      <test-component></test-component>
     63      <script>
     64        "use strict";
     65        customElements.define("test-component", class extends HTMLElement {
     66          constructor() {
     67            super();
     68            let shadowRoot = this.attachShadow({mode: "#MODE#"});
     69            shadowRoot.innerHTML = "<slot><div>fallback-content</div></slot>";
     70          }
     71        });
     72      </script>`,
     73    tree: `
     74      test-component
     75        #shadow-root
     76          slot
     77            fallback-content`,
     78  },
     79  {
     80    // Test that markup view is correctly displayed for non-trivial shadow DOM nesting.
     81    title: "nested components",
     82    url: `data:text/html;charset=utf-8,
     83      <test-component >
     84        <div slot="slot1">slot1-1</div>
     85        <third-component slot="slot2"></third-component>
     86      </test-component>
     87 
     88      <script>
     89      (function() {
     90        'use strict';
     91 
     92        function defineComponent(name, html) {
     93          customElements.define(name, class extends HTMLElement {
     94            constructor() {
     95              super();
     96              let shadowRoot = this.attachShadow({mode: "#MODE#"});
     97              shadowRoot.innerHTML = html;
     98            }
     99          });
    100        }
    101 
    102        defineComponent('test-component', \`
    103          <div id="test-container">
    104            <slot name="slot1"></slot>
    105            <slot name="slot2"></slot>
    106            <other-component><div slot="other1">other1-content</div></other-component>
    107          </div>\`);
    108        defineComponent('other-component',
    109          '<div id="other-container"><slot id="other1" name="other1"></slot></div>');
    110        defineComponent('third-component', '<div>Third component</div>');
    111      })();
    112      </script>`,
    113    tree: `
    114      test-component
    115        #shadow-root
    116          test-container
    117            slot
    118              div!slotted
    119            slot
    120              third-component!slotted
    121            other-component
    122              #shadow-root
    123                div
    124                  slot
    125                    div!slotted
    126              div
    127        div
    128        third-component
    129          #shadow-root
    130            div`,
    131  },
    132  {
    133    // Test that ::before and ::after pseudo elements are correctly displayed in host
    134    // components and in slot elements.
    135    title: "pseudo elements",
    136    url: `data:text/html;charset=utf-8,
    137      <style>
    138        test-component::before { content: "before-host" }
    139        test-component::after { content: "after-host" }
    140      </style>
    141 
    142      <test-component>
    143        <div class="light-dom"></div>
    144      </test-component>
    145 
    146      <script>
    147        "use strict";
    148        customElements.define("test-component", class extends HTMLElement {
    149          constructor() {
    150            super();
    151            let shadowRoot = this.attachShadow({mode: "#MODE#"});
    152            shadowRoot.innerHTML = \`
    153              <style>
    154                slot { display: block } /* avoid whitespace nodes */
    155                slot::before { content: "before-slot" }
    156                slot::after { content: "after-slot" }
    157              </style>
    158              <slot>default content</slot>
    159            \`;
    160          }
    161        });
    162      </script>`,
    163    tree: `
    164      test-component
    165        #shadow-root
    166          style
    167            slot { display: block }
    168          slot
    169            ::before
    170            div!slotted
    171            default content
    172            ::after
    173        ::before
    174        class="light-dom"
    175        ::after`,
    176  },
    177  {
    178    // Test empty web components are still displayed correctly.
    179    title: "empty components",
    180    url: `data:text/html;charset=utf-8,
    181      <test-component></test-component>
    182 
    183      <script>
    184        "use strict";
    185        customElements.define("test-component", class extends HTMLElement {
    186          constructor() {
    187            super();
    188            let shadowRoot = this.attachShadow({mode: "#MODE#"});
    189            shadowRoot.innerHTML = "";
    190          }
    191        });
    192      </script>`,
    193    tree: `
    194      test-component
    195        #shadow-root`,
    196  },
    197  {
    198    // Test shadow hosts show their shadow root even if they contain just a short text.
    199    title: "shadow host with inline-text-child",
    200    url: `data:text/html;charset=utf-8,
    201      <test-component>
    202        <inner-component>short-text-outside</inner-component>
    203      </test-component>
    204 
    205      <script>
    206        "use strict";
    207 
    208        customElements.define("test-component", class extends HTMLElement {
    209          constructor() {
    210            super();
    211            let shadowRoot = this.attachShadow({mode: "#MODE#"});
    212            shadowRoot.innerHTML = "<div><slot></slot></div>";
    213          }
    214        });
    215 
    216        customElements.define("inner-component", class extends HTMLElement {
    217          constructor() {
    218            super();
    219            let shadowRoot = this.attachShadow({mode: "#MODE#"});
    220            shadowRoot.innerHTML = "short-text-inside";
    221          }
    222        });
    223      </script>`,
    224    tree: `
    225      test-component
    226        #shadow-root
    227          div
    228            slot
    229              inner-component!slotted
    230        inner-component
    231          #shadow-root
    232            short-text-inside
    233          short-text-outside`,
    234  },
    235  {
    236    // Test for Bug 1537877, crash with nested custom elements without slot.
    237    title: "nested components without slot",
    238    url: `data:text/html;charset=utf-8,
    239      <test-component>
    240        <inner-component slot="non-existing-slot"></inner-component>
    241      </test-component>
    242 
    243      <script>
    244        "use strict";
    245 
    246        customElements.define('test-component', class extends HTMLElement {
    247          constructor() {
    248            super();
    249            let shadowRoot = this.attachShadow({mode: "#MODE#"});
    250            shadowRoot.innerHTML = '<div>test-component-content</div>'
    251          }
    252        });
    253 
    254        customElements.define('inner-component', class extends HTMLElement {
    255          constructor() {
    256            super();
    257            let shadowRoot = this.attachShadow({mode: "#MODE#"});
    258            shadowRoot.innerHTML = 'inner-component-content'
    259          }
    260        });
    261      </script>`,
    262    tree: `
    263      test-component
    264        #shadow-root
    265          div
    266        inner-component
    267          #shadow-root
    268            inner-component-content`,
    269  },
    270 ];
    271 
    272 for (const { url, tree, title } of TEST_DATA) {
    273  // Test each configuration in both open and closed modes
    274  add_task(async function () {
    275    info(`Testing: [${title}] in OPEN mode`);
    276    const { inspector, tab } = await openInspectorForURL(
    277      url.replace(/#MODE#/g, "open")
    278    );
    279    await assertMarkupViewAsTree(tree, "test-component", inspector);
    280    await removeTab(tab);
    281  });
    282  add_task(async function () {
    283    info(`Testing: [${title}] in CLOSED mode`);
    284    const { inspector, tab } = await openInspectorForURL(
    285      url.replace(/#MODE#/g, "closed")
    286    );
    287    await assertMarkupViewAsTree(tree, "test-component", inspector);
    288    await removeTab(tab);
    289  });
    290 }