<!DOCTYPE html>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="resources/custom-elements-helpers.js"></script>
<body>
<script>
'use strict';

// Looks up the preceeding element (which should be a template
// element) and creates a Promise test. The test name is taken from
// the template's data-test attribute.
//
// The content of the template is loaded into an iframe. On load, f
// is passed the frame's content window to run assertions.
function test_with_content(f) {
  let t = document.currentScript.previousElementSibling;
  test_with_window(f, t.dataset.test, t.innerHTML);
}

// Searches the document for an iframe with the specified content window.
function findFrameWithWindow(w) {
  return Array.prototype.find.call(document.querySelectorAll('iframe'), (f) => {
    return f.contentWindow === w;
  });
}

test_with_window((w) => {
  assert_equals(findFrameWithWindow(w).contentWindow, w,
                'should find the frame with this window');
  assert_equals(findFrameWithWindow(window), undefined,
                'should return undefined if there is no such frame');
}, 'sanity check the findFrameWithWindow function');
</script>

<template data-test="the parser synchronously creates elements">
  <script>
  'use strict';

  window.invocations = [];
  customElements.define('a-a', class extends HTMLElement {
    constructor() {
      super();
      invocations.push('constructor');
    }
    static get observedAttributes() { return ['x']; }
    attributeChangedCallback(name, oldValue, newValue, nsuri) {
      invocations.push(`${name}="${newValue}"`);
    }
    connectedCallback() {
      invocations.push('connected');
    }
  });
  </script>
  <a-a x="y">
    <script>
    'use strict';

    invocations.push('script');
    </script>
  </a-a>
</template>
<script>
'use strict';

test_with_content((w) => {
  assert_array_equals(w.invocations,
                      ['constructor', 'x="y"', 'connected', 'script']);
});
</script>

<template data-test="element creation failure produces unknown element">
  <script>
  'use strict';

  customElements.define('a-a', class extends HTMLElement {
    constructor() {
      super();

      // Returning this different, in-use element causes element
      // creation to fail in
      // https://dom.spec.whatwg.org/#concept-create-element steps
      // 6.4-9, eg: "If result has children then then throw a
      // NotSupportedError."
      return document.documentElement;
    }
  });
  </script>
  <a-a>
</template>
<script>
'use strict';

test_with_content((w) => {
  let e = w.document.querySelector('a-a');
  assert_true(e.matches(':not(:defined)'));
  assert_equals(Object.getPrototypeOf(e), w.HTMLUnknownElement.prototype);
});
</script>

<template data-test="modify tree during creation">
  <script>
  'use strict';

  customElements.define('a-a', class extends HTMLElement {
    constructor() {
      super();
      document.querySelector('b').remove();
    }
  });
  </script>
  <b>
    <a-a>
  </b>
</template>
<script>
'use strict';

test_with_content((w) => {
  assert_equals(w.document.querySelectorAll('b').length, 0);
});
</script>

<template data-test="destructive writes are blocked during construction">
  <script>
  // Custom element constructors do not set the insertion point, which
  // makes document.write() "destructive." However they increment the
  // ignore-destructive-writes counter, which blocks document.write.
  // https://html.spec.whatwg.org/#create-an-element-for-the-token
  // https://github.com/whatwg/html/issues/1630
  // https://html.spec.whatwg.org/#document.write()
  'use strict';

  window.invocations = [];
  customElements.define('a-a', class extends HTMLElement {
    constructor() {
      super();
      invocations.push('constructor');
      document.write(
          `<script>'use strict'; invocations.push('written');</scr${'i'}pt>`);
    }
    connectedCallback() {
      invocations.push('connected');
    }
  });
  </script>
  <a-a>
  <script>
  'use strict';
  invocations.push('parsed');
  </script>
</template>
<script>
'use strict';

test_with_content((w) => {
  assert_array_equals(
      w.invocations,
      ['constructor', 'connected', 'parsed'],
      'the destructive document.write content should have been ignored');
});
</script>

<template data-test="non-destructive writes are not blocked">
  <script>
  // Script running sets the insertion point, which makes makes
  // document.write() "non-destructive." Custom elements do not block
  // non-destructive writes.
  // https://html.spec.whatwg.org/#create-an-element-for-the-token
  // https://html.spec.whatwg.org/#document.write()
  'use strict';

  window.invocations = [];
  customElements.define('a-a', class extends HTMLElement {
    constructor() {
      super();
      invocations.push('constructor');
      document.write(
          `<script>'use strict'; invocations.push('written');</scr${'i'}pt>`);
    }
    connectedCallback() {
      invocations.push('connected');
    }
  });
  document.write('<a-a>');
  invocations.push('post write');
  </script>
  <script>
  'use strict';
  invocations.push('parsed');
  </script>
</template>
<script>
'use strict';

test_with_content((w) => {
  assert_array_equals(
      w.invocations,
      ['constructor', 'connected', 'post write', 'written', 'parsed'],
      'the non-destructive document.write content should have been inserted');
});
</script>

<template data-test="innerHTML is not blocked by custom element constructors">
  <script>
  'use strict';

  window.invocations = [];
  customElements.define('a-a', class extends HTMLElement {
    constructor() {
      super();
      invocations.push(`construct ${this.id}`);
      if (!this.id) {
        // If the ID attribute is not set, this was created
        // synchronously by the parser. Adding children at this point
        // would cause creation to fail, so embiggen the previous
        // element instead.
        document.querySelector('span').innerHTML = `<a-a id="r">`;
      }
    }
    connectedCallback() {
      invocations.push(`connected ${this.parentNode.localName}/${this.id}`);
    }
  });
  </script>
  <span></span>
  <a-a id="q"></a-a>
  <script>
  'use strict';
  invocations.push('parsed');
  </script>
</template>
<script>
'use strict';

test_with_content((w) => {
  assert_array_equals(
      w.invocations,
      ['construct ', 'construct r', 'connected span/r', 'connected body/q',
       'parsed'],
      'custom element constructors should not block innerHTML');
});
</script>


<template data-test="parsing without a browsing context should not create custom elements">
  <body>
  <script>
  'use strict';

  let f = parent.findFrameWithWindow(window);
  f.invocations = [];

  customElements.define('a-a', class extends HTMLElement {
    constructor() {
      super();
      f.invocations.push(this);
    }
  });
  </script>
  <a-a></a-a>
  <script>
  f.detached = document.implementation.createHTMLDocument();
  f.detached.documentElement.appendChild(document.body);
  </script>
  <a-a></a-a>
</template>
<script>
'use strict';

test_with_content((w) => {
  let f = findFrameWithWindow(w);
  assert_array_equals(f.invocations,
                      [f.detached.querySelector('a-a:first-of-type')],
                      'one element should have been constructed');
  assert_true(f.invocations[0].matches(':defined'),
              'the element should have been created successfully');

  let elements = f.detached.querySelectorAll('a-a');
  console.log(f.invocations[0].parentNode);
  assert_equals(elements.length, 2,
                'two elements should have been created');
  assert_equals(Object.getPrototypeOf(elements[1]), w.HTMLElement.prototype,
                'the second element should be un-upgraded, not failed');
});
</script>
