summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/shadow-dom/declarative/gethtml.tentative.html
blob: c48230c17017cf6909bc281557c6acffbbbcb28b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
<!DOCTYPE html>
<title>getHTML behavior</title>
<link rel='author' href='mailto:masonf@chromium.org'>
<link rel='help' href='https://github.com/whatwg/html/issues/8867'>
<script src='/resources/testharness.js'></script>
<script src='/resources/testharnessreport.js'></script>
<script src='../../html/resources/common.js'></script>

<body>

<script>
function testElementType(allowsShadowDom, elementType, runGetHTMLOnShadowRoot, declarativeShadowDom, mode, delegatesFocus, serializable, clonable) {
  const t = test(t => {
    // Create and attach element
    let wrapper;
    if (runGetHTMLOnShadowRoot) {
      // This ensures we're testing both Element.getHTML() and ShadowRoot.getHTML().
      const host = document.createElement('div');
      t.add_cleanup(function() { host.remove(); });
      document.body.appendChild(host);
      wrapper = host.attachShadow({mode: 'open'});
    } else {
      wrapper = document.createElement('div');
      t.add_cleanup(function() { wrapper.remove(); });
      document.body.appendChild(wrapper);
    }

    let shadowRoot;
    const isOpen = mode === 'open';
    let initDict = {mode: mode, delegatesFocus: delegatesFocus, clonable};
    let expectedSerializable = null;
    switch (serializable) {
      case undefined: expectedSerializable = false; break;
      case "true": initDict.serializable = expectedSerializable = true; break;
      case "false": initDict.serializable = expectedSerializable = false; break;
      default: throw new Error(`Invalid serializable ${serializable}`);
    }
    const delegatesAttr = delegatesFocus ? ' shadowrootdelegatesfocus=""' : '';
    const serializableAttr = expectedSerializable ? ' serializable=""' : '';
    const clonableAttr = clonable ? ' shadowrootclonable=""' : '';

    if (allowsShadowDom && declarativeShadowDom) {
      const html = `<${elementType}><template shadowrootmode=${mode}${delegatesAttr}${serializableAttr}${clonableAttr}>`;
      wrapper.setHTMLUnsafe(html);
      if (isOpen) {
        shadowRoot = wrapper.firstElementChild.shadowRoot;
      } else {
        // For closed shadow root, we rely on the behavior of attachShadow to return it to us
        shadowRoot = wrapper.firstElementChild.attachShadow(initDict);
      }
    } else {
      // Imperative shadow dom
      const element = document.createElement(elementType);
      wrapper.appendChild(element);
      if (allowsShadowDom) {
        shadowRoot = element.attachShadow(initDict);
      }
    }
    assert_true(!allowsShadowDom || !!shadowRoot);

    if (allowsShadowDom) {
      const correctShadowHtml = `<template shadowrootmode="${mode}"${delegatesAttr}${serializableAttr}${clonableAttr}><slot></slot></template>`;
      const correctHtml = `<${elementType}>${correctShadowHtml}</${elementType}>`;
      assert_equals(shadowRoot.mode,mode);
      assert_equals(shadowRoot.delegatesFocus,delegatesFocus);
      assert_equals(shadowRoot.serializable,expectedSerializable);
      assert_equals(shadowRoot.clonable,clonable);
      shadowRoot.appendChild(document.createElement('slot'));
      const emptyElement = `<${elementType}></${elementType}>`;
      if (isOpen) {
        if (expectedSerializable) {
          assert_equals(wrapper.getHTML({includeShadowRoots: true}), correctHtml);
        } else {
          assert_equals(wrapper.getHTML({includeShadowRoots: true}), emptyElement);
        }
      } else {
        // Closed shadow roots should not be returned unless shadowRoots specifically contains the shadow root:
        assert_equals(wrapper.getHTML({includeShadowRoots: true}), emptyElement);
        assert_equals(wrapper.getHTML({includeShadowRoots: true, shadowRoots: []}), emptyElement);
      }
      // If we provide the shadow root, serialize it, regardless of includeShadowRoots.
      assert_equals(wrapper.getHTML({includeShadowRoots: true, shadowRoots: [shadowRoot]}),correctHtml);
      assert_equals(wrapper.getHTML({shadowRoots: [shadowRoot]}),correctHtml);
      // This should always throw - includeShadowRoots false, but we've provided roots.
      assert_throws_dom("NotSupportedError",() => wrapper.getHTML({includeShadowRoots: false, shadowRoots: [shadowRoot]}));
    } else {
      // For non-shadow hosts, getHTML() should also match .innerHTML
      assert_equals(wrapper.getHTML({includeShadowRoots: true}),wrapper.innerHTML);
    }

    // Either way, make sure getHTML({includeShadowRoots: false}) matches .innerHTML
    assert_equals(wrapper.getHTML({includeShadowRoots: false}),wrapper.innerHTML,'getHTML() with includeShadowRoots false should return the same as .innerHTML');
    // ...and that the default for includeShadowRoots is false.
    assert_equals(wrapper.getHTML(),wrapper.innerHTML,'The default for includeShadowRoots should be false');

  }, `${runGetHTMLOnShadowRoot ? 'ShadowRoot' : 'Element'}.getHTML() on <${elementType}>${allowsShadowDom ? `, with ${declarativeShadowDom ? 'declarative' : 'imperative'} shadow, mode=${mode}, delegatesFocus=${delegatesFocus}, serializable=${serializable}, clonable=${clonable}.` : ''}`);
}

function runAllTests() {
  const allElements = [...HTML5_ELEMENTS, 'htmlunknown'];
  const safelisted = HTML5_SHADOW_ALLOWED_ELEMENTS.filter(el => el != 'body');
  for (const elementName of allElements) {
    const allowsShadowDom = safelisted.includes(elementName);
    for (const runGetHTMLOnShadowRoot of [false, true]) {
      if (allowsShadowDom) {
        for (const declarativeShadowDom of [false, true]) {
          for (const delegatesFocus of [false, true]) {
            for (const clonable of [false, true]) {
              for (const mode of ['open', 'closed']) {
                for (const serializable of [undefined, 'false', 'true']) {
                  testElementType(true, elementName, runGetHTMLOnShadowRoot, declarativeShadowDom, mode, delegatesFocus, serializable, clonable);
                }
              }
            }
          }
        }
      } else {
        testElementType(false, elementName, runGetHTMLOnShadowRoot);
      }
    }
  }
}

runAllTests();

</script>