tor-browser

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

selectedcontent-mutations.html (19380B)


      1 <!DOCTYPE html>
      2 <link rel=author href="mailto:jarhar@chromium.org">
      3 <link rel=help href="https://github.com/whatwg/html/issues/9799">
      4 <script src="/resources/testharness.js"></script>
      5 <script src="/resources/testharnessreport.js"></script>
      6 
      7 <script>
      8 window.testIdToMutationRecords = new Map();
      9 function startTest(testId) {
     10  const mutationRecords = [];
     11  window.testIdToMutationRecords.set(testId, mutationRecords);
     12  const mutationObserver = new MutationObserver(mutations => {
     13    mutationRecords.push(...mutations);
     14  });
     15  const config = {attributes: true, childList: true, subtree: true};
     16  mutationObserver.observe(document.getElementById(testId), config);
     17 }
     18 </script>
     19 
     20 <div id=test1>
     21  <script>
     22    startTest('test1');
     23  </script>
     24  <select>
     25    <button>
     26      <selectedcontent></selectedcontent>
     27    </button>
     28    <option><span>span</span> one</option>
     29    <option><span>span</span> two</option>
     30    <option selected><span>span</span> three</option>
     31  </select>
     32 </div>
     33 
     34 <div id=test2>
     35  <script>
     36    startTest('test2');
     37  </script>
     38  <select>
     39    <selectedcontent></selectedcontent>
     40    <option>option</option>
     41  </select>
     42 </div>
     43 
     44 <div id=test3>
     45  <script>
     46    startTest('test3');
     47  </script>
     48  <select>
     49    <button>
     50      <selectedcontent>outer1
     51        <selectedcontent>inner1</selectedcontent>
     52      </selectedcontent>
     53      <selectedcontent>outer2
     54        <selectedcontent>inner2</selectedcontent>
     55      </selectedcontent>
     56    </button>
     57    <option>option</option>
     58  </select>
     59 </div>
     60 
     61 <div id=test4>
     62  <script>
     63    startTest('test4');
     64  </script>
     65  <select>
     66    <button>
     67      <selectedcontent></selectedcontent>
     68    </button>
     69    <div>
     70      <option>one</option>
     71    </div>
     72    <div>
     73      <option selected>two</option>
     74    </div>
     75  </select>
     76 </div>
     77 
     78 <div id=test5>
     79  <script>
     80    startTest('test5');
     81  </script>
     82  <select>
     83    <option>option</option>
     84    <button>
     85      <selectedcontent></selectedcontent>
     86    </button>
     87  </select>
     88 </div>
     89 
     90 <div id=test6>
     91  <script>
     92    startTest('test6');
     93  </script>
     94  <select multiple size=1>
     95    <button>
     96      <selectedcontent>
     97        <selectedcontent></selectedcontent>
     98      </selectedcontent>
     99      <selectedcontent>
    100        <selectedcontent></selectedcontent>
    101      </selectedcontent>
    102    </button>
    103    <option>option</option>
    104  </select>
    105 </div>
    106 
    107 <div id=test7>
    108  <script>
    109    startTest('test7');
    110  </script>
    111  <select>
    112    <button>
    113      <selectedcontent></selectedcontent>
    114    </button>
    115    <option>one</option>
    116    <div></div>
    117  </select>
    118 </div>
    119 <script>
    120 const select = document.getElementById('test7').querySelector('select');
    121 
    122 const optionTwo = document.createElement('option');
    123 optionTwo.textContent = 'two';
    124 optionTwo.setAttribute('selected', '');
    125 select.appendChild(optionTwo);
    126 
    127 const selectDiv = select.querySelector('div');
    128 const optionThree = document.createElement('option');
    129 optionThree.textContent = 'three';
    130 optionThree.setAttribute('selected', '');
    131 select.appendChild(optionThree);
    132 
    133 select.value = 'one';
    134 </script>
    135 
    136 <script>
    137 function getNodeRepresentation(node) {
    138  if (!node) {
    139    return 'null';
    140  }
    141  switch (node.nodeType) {
    142    case Node.ELEMENT_NODE:
    143      let representation = node.tagName.toLowerCase();
    144      if (node.id) {
    145        representation += `#${node.id}`;
    146      }
    147      if (node.classList && node.classList.length > 0) {
    148        representation += `.${Array.from(node.classList).join('.')}`;
    149      }
    150      return representation;
    151    case Node.TEXT_NODE:
    152      const text = node.textContent.trim();
    153      return `#text: "${text.length > 50 ? text.substring(0, 47) + '...' : text}"`;
    154    case Node.COMMENT_NODE:
    155      return '';
    156    default:
    157      return `[Node type ${node.nodeType}]`;
    158  }
    159 }
    160 
    161 function mutationRecordToString(record) {
    162  if (!record) {
    163    return '[Invalid MutationRecord]';
    164  }
    165 
    166  const targetStr = getNodeRepresentation(record.target);
    167  let summary = `Type: ${record.type} | Target: ${targetStr}`;
    168 
    169  switch (record.type) {
    170    case 'attributes':
    171      const attrName = record.attributeName;
    172      const oldValue = record.oldValue !== null ? `"${record.oldValue}"` : 'null';
    173      const newValue = record.target.getAttribute(attrName);
    174      const newValueStr = newValue !== null ? `"${newValue}"` : 'null';
    175      summary += ` | Attribute: '${attrName}' changed from ${oldValue} to ${newValueStr}`;
    176      if (record.attributeNamespace) {
    177         summary += ` (Namespace: ${record.attributeNamespace})`;
    178      }
    179      break;
    180 
    181    case 'characterData':
    182      const oldText = record.oldValue !== null ? `"${record.oldValue}"` : 'null';
    183      const newText = record.target.textContent !== null ? `"${record.target.textContent}"` : 'null';
    184      summary += ` | Data changed from ${oldText} to ${newText}`;
    185      break;
    186 
    187    case 'childList':
    188      if (record.addedNodes.length > 0) {
    189        const added = Array.from(record.addedNodes).map(getNodeRepresentation).join(', ');
    190        summary += ` | Added: [${added}]`;
    191      }
    192      if (record.removedNodes.length > 0) {
    193        const removed = Array.from(record.removedNodes).map(getNodeRepresentation).join(', ');
    194        summary += ` | Removed: [${removed}]`;
    195      }
    196      if (record.previousSibling) {
    197         summary += ` | After: ${getNodeRepresentation(record.previousSibling)}`;
    198      }
    199      if (record.nextSibling) {
    200          summary += ` | Before: ${getNodeRepresentation(record.nextSibling)}`;
    201      }
    202      break;
    203 
    204    default:
    205      summary += ' | [Unknown mutation type]';
    206      break;
    207  }
    208 
    209  return summary;
    210 }
    211 
    212 function convertMutationRecords(records) {
    213  const output = [];
    214  for (const record of records) {
    215    output.push(mutationRecordToString(record));
    216  }
    217  return output;
    218 }
    219 
    220 const testIdToExpectations = {
    221  test1: {
    222    html:
    223 `<select>
    224    <button>
    225      <selectedcontent><span>span</span> three</selectedcontent>
    226    </button>
    227    <option><span>span</span> one</option>
    228    <option><span>span</span> two</option>
    229    <option selected=""><span>span</span> three</option>
    230  </select>`,
    231    mutations: [
    232      "Type: childList | Target: div#test1 | Added: [#text: \"\"] | After: script",
    233      "Type: childList | Target: div#test1 | Added: [select] | After: #text: \"\"",
    234      "Type: childList | Target: select | Added: [#text: \"\"]",
    235      "Type: childList | Target: select | Added: [button] | After: #text: \"\"",
    236      "Type: childList | Target: button | Added: [#text: \"\"]",
    237      "Type: childList | Target: button | Added: [selectedcontent] | After: #text: \"\"",
    238      "Type: childList | Target: button | Added: [#text: \"\"] | After: selectedcontent",
    239      "Type: childList | Target: select | Added: [#text: \"\"] | After: button",
    240      "Type: childList | Target: select | Added: [option] | After: #text: \"\"",
    241      "Type: childList | Target: option | Added: [span]",
    242      "Type: childList | Target: span | Added: [#text: \"span\"]",
    243      "Type: childList | Target: option | Added: [#text: \"one\"] | After: span",
    244      "Type: childList | Target: selectedcontent | Added: [span, #text: \"one\"]",
    245      "Type: childList | Target: select | Added: [#text: \"\"] | After: option",
    246      "Type: childList | Target: select | Added: [option] | After: #text: \"\"",
    247      "Type: childList | Target: option | Added: [span]",
    248      "Type: childList | Target: span | Added: [#text: \"span\"]",
    249      "Type: childList | Target: option | Added: [#text: \"two\"] | After: span",
    250      "Type: childList | Target: select | Added: [#text: \"\"] | After: option",
    251      "Type: childList | Target: select | Added: [option] | After: #text: \"\"",
    252      "Type: childList | Target: selectedcontent | Removed: [span, #text: \"one\"]",
    253      "Type: childList | Target: option | Added: [span]",
    254      "Type: childList | Target: span | Added: [#text: \"span\"]",
    255      "Type: childList | Target: option | Added: [#text: \"three\"] | After: span",
    256      "Type: childList | Target: selectedcontent | Added: [span, #text: \"three\"]",
    257      "Type: childList | Target: select | Added: [#text: \"\"] | After: option",
    258      "Type: childList | Target: div#test1 | Added: [#text: \"\"] | After: select"
    259    ]
    260  },
    261  test2: {
    262    html:
    263 `<select>
    264    <selectedcontent>option</selectedcontent>
    265    <option>option</option>
    266  </select>`,
    267    mutations: [
    268      "Type: childList | Target: div#test2 | Added: [#text: \"\"] | After: script",
    269      "Type: childList | Target: div#test2 | Added: [select] | After: #text: \"\"",
    270      "Type: childList | Target: select | Added: [#text: \"\"]",
    271      "Type: childList | Target: select | Added: [selectedcontent] | After: #text: \"\"",
    272      "Type: childList | Target: select | Added: [#text: \"\"] | After: selectedcontent",
    273      "Type: childList | Target: select | Added: [option] | After: #text: \"\"",
    274      "Type: childList | Target: option | Added: [#text: \"option\"]",
    275      "Type: childList | Target: selectedcontent | Added: [#text: \"option\"]",
    276      "Type: childList | Target: select | Added: [#text: \"\"] | After: option",
    277      "Type: childList | Target: div#test2 | Added: [#text: \"\"] | After: select"
    278    ]
    279  },
    280  test3: {
    281    html:
    282 `<select>
    283    <button>
    284      <selectedcontent>option</selectedcontent>
    285      <selectedcontent>outer2
    286        <selectedcontent>inner2</selectedcontent>
    287      </selectedcontent>
    288    </button>
    289    <option>option</option>
    290  </select>`,
    291    mutations: [
    292      "Type: childList | Target: div#test3 | Added: [#text: \"\"] | After: script",
    293      "Type: childList | Target: div#test3 | Added: [select] | After: #text: \"\"",
    294      "Type: childList | Target: select | Added: [#text: \"\"]",
    295      "Type: childList | Target: select | Added: [button] | After: #text: \"\"",
    296      "Type: childList | Target: button | Added: [#text: \"\"]",
    297      "Type: childList | Target: button | Added: [selectedcontent] | After: #text: \"\"",
    298      "Type: childList | Target: selectedcontent | Added: [#text: \"outer1\"]",
    299      "Type: childList | Target: selectedcontent | Added: [selectedcontent] | After: #text: \"outer1\"",
    300      "Type: childList | Target: selectedcontent | Added: [#text: \"inner1\"]",
    301      "Type: childList | Target: selectedcontent | Added: [#text: \"\"] | After: selectedcontent",
    302      "Type: childList | Target: button | Added: [#text: \"\"] | After: selectedcontent",
    303      "Type: childList | Target: button | Added: [selectedcontent] | After: #text: \"\"",
    304      "Type: childList | Target: selectedcontent | Added: [#text: \"outer2\"]",
    305      "Type: childList | Target: selectedcontent | Added: [selectedcontent] | After: #text: \"outer2\"",
    306      "Type: childList | Target: selectedcontent | Added: [#text: \"inner2\"]",
    307      "Type: childList | Target: selectedcontent | Added: [#text: \"\"] | After: selectedcontent",
    308      "Type: childList | Target: button | Added: [#text: \"\"] | After: selectedcontent",
    309      "Type: childList | Target: select | Added: [#text: \"\"] | After: button",
    310      "Type: childList | Target: select | Added: [option] | After: #text: \"\"",
    311      "Type: childList | Target: selectedcontent | Removed: [#text: \"outer1\", selectedcontent, #text: \"\"]",
    312      "Type: childList | Target: option | Added: [#text: \"option\"]",
    313      "Type: childList | Target: selectedcontent | Added: [#text: \"option\"]",
    314      "Type: childList | Target: select | Added: [#text: \"\"] | After: option",
    315      "Type: childList | Target: div#test3 | Added: [#text: \"\"] | After: select"
    316    ]
    317  },
    318  test4: {
    319    html:
    320 `<select>
    321    <button>
    322      <selectedcontent>two</selectedcontent>
    323    </button>
    324    <div>
    325      <option>one</option>
    326    </div>
    327    <div>
    328      <option selected="">two</option>
    329    </div>
    330  </select>`,
    331    mutations: [
    332      "Type: childList | Target: div#test4 | Added: [#text: \"\"] | After: script",
    333      "Type: childList | Target: div#test4 | Added: [select] | After: #text: \"\"",
    334      "Type: childList | Target: select | Added: [#text: \"\"]",
    335      "Type: childList | Target: select | Added: [button] | After: #text: \"\"",
    336      "Type: childList | Target: button | Added: [#text: \"\"]",
    337      "Type: childList | Target: button | Added: [selectedcontent] | After: #text: \"\"",
    338      "Type: childList | Target: button | Added: [#text: \"\"] | After: selectedcontent",
    339      "Type: childList | Target: select | Added: [#text: \"\"] | After: button",
    340      "Type: childList | Target: select | Added: [div] | After: #text: \"\"",
    341      "Type: childList | Target: div | Added: [#text: \"\"]",
    342      "Type: childList | Target: div | Added: [option] | After: #text: \"\"",
    343      "Type: childList | Target: option | Added: [#text: \"one\"]",
    344      "Type: childList | Target: selectedcontent | Added: [#text: \"one\"]",
    345      "Type: childList | Target: div | Added: [#text: \"\"] | After: option",
    346      "Type: childList | Target: select | Added: [#text: \"\"] | After: div",
    347      "Type: childList | Target: select | Added: [div] | After: #text: \"\"",
    348      "Type: childList | Target: div | Added: [#text: \"\"]",
    349      "Type: childList | Target: div | Added: [option] | After: #text: \"\"",
    350      "Type: childList | Target: selectedcontent | Removed: [#text: \"one\"]",
    351      "Type: childList | Target: option | Added: [#text: \"two\"]",
    352      "Type: childList | Target: selectedcontent | Added: [#text: \"two\"]",
    353      "Type: childList | Target: div | Added: [#text: \"\"] | After: option",
    354      "Type: childList | Target: select | Added: [#text: \"\"] | After: div",
    355      "Type: childList | Target: div#test4 | Added: [#text: \"\"] | After: select"
    356    ]
    357  },
    358  test5: {
    359    html:
    360 `<select>
    361    <option>option</option>
    362    <button>
    363      <selectedcontent>option</selectedcontent>
    364    </button>
    365  </select>`,
    366    mutations: [
    367      "Type: childList | Target: div#test5 | Added: [#text: \"\"] | After: script",
    368      "Type: childList | Target: div#test5 | Added: [select] | After: #text: \"\"",
    369      "Type: childList | Target: select | Added: [#text: \"\"]",
    370      "Type: childList | Target: select | Added: [option] | After: #text: \"\"",
    371      "Type: childList | Target: option | Added: [#text: \"option\"]",
    372      "Type: childList | Target: select | Added: [#text: \"\"] | After: option",
    373      "Type: childList | Target: select | Added: [button] | After: #text: \"\"",
    374      "Type: childList | Target: button | Added: [#text: \"\"]",
    375      "Type: childList | Target: button | Added: [selectedcontent] | After: #text: \"\"",
    376      "Type: childList | Target: selectedcontent | Added: [#text: \"option\"]",
    377      "Type: childList | Target: button | Added: [#text: \"\"] | After: selectedcontent",
    378      "Type: childList | Target: select | Added: [#text: \"\"] | After: button",
    379      "Type: childList | Target: div#test5 | Added: [#text: \"\"] | After: select"
    380    ]
    381  },
    382  test6: {
    383    html:
    384 `<select multiple="" size="1">
    385    <button>
    386      <selectedcontent>
    387        <selectedcontent></selectedcontent>
    388      </selectedcontent>
    389      <selectedcontent>
    390        <selectedcontent></selectedcontent>
    391      </selectedcontent>
    392    </button>
    393    <option>option</option>
    394  </select>`,
    395    mutations: [
    396      "Type: childList | Target: div#test6 | Added: [#text: \"\"] | After: script",
    397      "Type: childList | Target: div#test6 | Added: [select] | After: #text: \"\"",
    398      "Type: childList | Target: select | Added: [#text: \"\"]",
    399      "Type: childList | Target: select | Added: [button] | After: #text: \"\"",
    400      "Type: childList | Target: button | Added: [#text: \"\"]",
    401      "Type: childList | Target: button | Added: [selectedcontent] | After: #text: \"\"",
    402      "Type: childList | Target: selectedcontent | Added: [#text: \"\"]",
    403      "Type: childList | Target: selectedcontent | Added: [selectedcontent] | After: #text: \"\"",
    404      "Type: childList | Target: selectedcontent | Added: [#text: \"\"] | After: selectedcontent",
    405      "Type: childList | Target: button | Added: [#text: \"\"] | After: selectedcontent",
    406      "Type: childList | Target: button | Added: [selectedcontent] | After: #text: \"\"",
    407      "Type: childList | Target: selectedcontent | Added: [#text: \"\"]",
    408      "Type: childList | Target: selectedcontent | Added: [selectedcontent] | After: #text: \"\"",
    409      "Type: childList | Target: selectedcontent | Added: [#text: \"\"] | After: selectedcontent",
    410      "Type: childList | Target: button | Added: [#text: \"\"] | After: selectedcontent",
    411      "Type: childList | Target: select | Added: [#text: \"\"] | After: button",
    412      "Type: childList | Target: select | Added: [option] | After: #text: \"\"",
    413      "Type: childList | Target: option | Added: [#text: \"option\"]",
    414      "Type: childList | Target: select | Added: [#text: \"\"] | After: option",
    415      "Type: childList | Target: div#test6 | Added: [#text: \"\"] | After: select"
    416    ]
    417  },
    418  test7: {
    419    html:
    420 `<select>
    421    <button>
    422      <selectedcontent>one</selectedcontent>
    423    </button>
    424    <option>one</option>
    425    <div></div>
    426  <option selected="">two</option><option selected="">three</option></select>`,
    427    mutations: [
    428      "Type: childList | Target: div#test7 | Added: [#text: \"\"] | After: script",
    429      "Type: childList | Target: div#test7 | Added: [select] | After: #text: \"\"",
    430      "Type: childList | Target: select | Added: [#text: \"\"]",
    431      "Type: childList | Target: select | Added: [button] | After: #text: \"\"",
    432      "Type: childList | Target: button | Added: [#text: \"\"]",
    433      "Type: childList | Target: button | Added: [selectedcontent] | After: #text: \"\"",
    434      "Type: childList | Target: button | Added: [#text: \"\"] | After: selectedcontent",
    435      "Type: childList | Target: select | Added: [#text: \"\"] | After: button",
    436      "Type: childList | Target: select | Added: [option] | After: #text: \"\"",
    437      "Type: childList | Target: option | Added: [#text: \"one\"]",
    438      "Type: childList | Target: selectedcontent | Added: [#text: \"one\"]",
    439      "Type: childList | Target: select | Added: [#text: \"\"] | After: option",
    440      "Type: childList | Target: select | Added: [div] | After: #text: \"\"",
    441      "Type: childList | Target: select | Added: [#text: \"\"] | After: div",
    442      "Type: childList | Target: div#test7 | Added: [#text: \"\"] | After: select",
    443      "Type: childList | Target: selectedcontent | Added: [#text: \"two\"] | Removed: [#text: \"one\"]",
    444      "Type: childList | Target: select | Added: [option] | After: #text: \"\"",
    445      "Type: childList | Target: selectedcontent | Added: [#text: \"three\"] | Removed: [#text: \"two\"]",
    446      "Type: childList | Target: select | Added: [option] | After: option",
    447      "Type: childList | Target: selectedcontent | Added: [#text: \"one\"] | Removed: [#text: \"three\"]"
    448    ]
    449  }
    450 };
    451 
    452 for (const testId of Object.keys(testIdToExpectations)) {
    453  test(() => {
    454    const testContainer = document.getElementById(testId);
    455    // Remove the script element to minimize the expectations a bit.
    456    testContainer.querySelector('script').remove();
    457    const actualHtml = testContainer.innerHTML.trim();
    458    const actualMutations = convertMutationRecords(window.testIdToMutationRecords.get(testId));
    459 
    460    const expectedHtml = testIdToExpectations[testId].html.trim();
    461    const expectedMutations = testIdToExpectations[testId].mutations;
    462 
    463    assert_equals(actualHtml, expectedHtml, testId);
    464    assert_array_equals(actualMutations, expectedMutations, testId);
    465  }, `MutationObserver records during parsing of <select> with <selectedcontent>: ${testId}`);
    466 }
    467 </script>