chromium/third_party/blink/web_tests/accessibility/details-summary-crash.html

<!DOCTYPE html>

This test passes if it doesn't crash.

<script>
  if (window.testRunner)
    testRunner.dumpAsText();
</script>

<script>
class CustomDetails extends HTMLElement {
  constructor() {
    super();
    const shadowRoot = this.attachShadow({mode: 'open', slotAssignment: 'manual'});

    this.summarySlot = document.createElement('slot');
    this.summarySlot.id = 'details-summary';
    shadowRoot.appendChild(this.summarySlot);

    const defaultSummary = document.createElement('summary');
    defaultSummary.textContent = 'Details';
    this.summarySlot.appendChild(defaultSummary);

    this.contentSlot = document.createElement('slot');
    this.contentSlot.id = 'details-content';
    this.contentSlot.style = `content-visibility:hidden; display:block;`;
    shadowRoot.appendChild(this.contentSlot);

    const style = document.createElement('style');
    style.textContent = `
:host summary {
  display: list-item;
  counter-increment: list-item 0;
  list-style: disclosure-closed inside;
}
:host([open]) summary {
  list-style-type: disclosure-open;
}
`;
    shadowRoot.appendChild(style);
  }

  connectedCallback() {
    this.updateOpen();
    this.updateAssignment();
    this.addEventListener('DOMNodeInserted', this.updateAssignment);
    this.addEventListener('DOMNodeRemoved', this.updateAssignment);
  }

  disconnectedCallback() {
    this.removeEventListener('DOMNodeInserted', this.updateAssignment);
    this.removeEventListener('DOMNodeRemoved', this.updateAssignment);
  }

  attributeChangedCallback(name, oldValue, newValue) {
    this.updateOpen();
  }

  static get observedAttributes() {
    return ['open'];
  }

  updateOpen() {
    if (this.hasAttribute('open')) {
      this.contentSlot.style = ``;
    } else {
      this.contentSlot.style = `content-visibility: hidden; display:block`;
    }
  }

  updateAssignment() {
    let summary = null;
    const content = [];

    for (let child = this.firstChild; child; child = child.nextSibling) {
      if (!summary && child.tagName === 'SUMMARY') {
        summary = child;
      } else {
        content.push(child);
      }
    }

    if (summary)
      this.summarySlot.assign(summary);
    if (content.length)
      this.contentSlot.assign(...content);
  }
};
customElements.define('x-details', CustomDetails);
</script>

<script>
function clickOn(element, x, y) {
  const rect = element.getBoundingClientRect();
  return new Promise((resolve, reject) => {
    chrome.gpuBenchmarking.pointerActionSequence([
        {source: 'mouse',
         actions: [
             {name: 'pointerMove', x: rect.x + x, y: rect.y + y},
             {name: 'pointerDown', x: rect.x + x, y: rect.y + y, button: 0},
             {name: 'pointerUp', button: 0}]
        }], resolve);
  });
}

const $ = document.querySelector.bind(document);

async function runTests() {
  $('#dt1').removeChild($('#dt1 > summary'));

  $('#dt1c').removeChild($('#dt1c > summary'));
  await clickOn($('#dt1c'), 2, 2);

  $('#dt2').removeChild($('#dt2 > summary'));

  $('#dt2c').removeChild($('#dt2c > summary'));
  await clickOn($('#dt2c'), 2, 2);

  $('#dt3').removeChild($('#dt3 > summary:last-of-type'));

  $('#dt3c').removeChild($('#dt3c > summary:last-of-type'));
  await clickOn($('#dt3c'), 2, 2);

  $('#dt4').removeChild($('#dt4 > summary'));

  $('#dt4c').removeChild($('#dt4c > summary'));
  await clickOn($('#dt4c'), 2, 2);

  $('#dt5').removeChild($('#dt5 > summary'));

  $('#dt5c').removeChild($('#dt5c > summary'));
  await clickOn($('#dt5c'), 2, 2);

  $('#dt6').removeChild($('#dt6 > summary:last-of-type'));

  $('#dt6c').removeChild($('#dt6c > summary:last-of-type'));
  await clickOn($('#dt6c'), 2, 2);

  testRunner.notifyDone();
}

testRunner.waitUntilDone();

</script>
<body onload="runTests()">
<x-details id="dt1"><summary>summary</summary></x-details>
<x-details id="dt1c"><summary>summary</summary></x-details>
<x-details id="dt2"><summary>summary 1</summary><summary>summary 2</summary></x-details>
<x-details id="dt2c"><summary>summary 1</summary><summary>summary 2</summary></x-details>
<x-details id="dt3"><summary>summary 1</summary><summary>summary 2</summary></x-details>
<x-details id="dt3c"><summary>summary 1</summary><summary>summary 2</summary></x-details>
<x-details id="dt4" open><summary>summary</summary></x-details>
<x-details id="dt4c" open><summary>summary</summary></x-details>
<x-details id="dt5" open><summary>summary 1</summary><summary>summary 2</summary></x-details>
<x-details id="dt5c" open><summary>summary 1</summary><summary>summary 2</summary></x-details>
<x-details id="dt6" open><summary>summary 1</summary><summary>summary 2</summary></x-details>
<x-details id="dt6c" open><summary>summary 1</summary><summary>summary 2</summary></x-details>
</body>