tor-browser

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

browser_markup_html_edit_03.js (9866B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 // Test that outerHTML editing keybindings work as expected and that *special*
      7 // elements like <html>, <body> and <head> can be edited correctly.
      8 
      9 const TEST_URL =
     10  "data:text/html," +
     11  "<!DOCTYPE html>" +
     12  "<head><meta charset='utf-8' /></head>" +
     13  "<body>" +
     14  '<div id="keyboard"></div>' +
     15  "</body>" +
     16  "</html>";
     17 const SELECTOR = "#keyboard";
     18 const OLD_HTML = '<div id="keyboard"></div>';
     19 const NEW_HTML = '<div id="keyboard">Edited</div>';
     20 
     21 requestLongerTimeout(2);
     22 
     23 add_task(async function () {
     24  const { inspector } = await openInspectorForURL(TEST_URL);
     25 
     26  inspector.markup._frame.focus();
     27 
     28  info("Check that pressing escape cancels edits");
     29  await testEscapeCancels(inspector);
     30 
     31  info("Check that copying seletected text in editor works as expected");
     32  await testCopyTextSelection(inspector);
     33 
     34  info("Check that pressing F2 commits edits");
     35  await testF2Commits(inspector);
     36 
     37  info("Check that editing the <body> element works like other nodes");
     38  await testBody(inspector);
     39 
     40  info("Check that editing the <head> element works like other nodes");
     41  await testHead(inspector);
     42 
     43  info("Check that editing the <html> element works like other nodes");
     44  await testDocumentElement(inspector);
     45 
     46  info("Check (again) that editing the <html> element works like other nodes");
     47  await testDocumentElement2(inspector);
     48 });
     49 
     50 async function testEscapeCancels(inspector) {
     51  await selectNode(SELECTOR, inspector);
     52 
     53  const onHtmlEditorCreated = once(inspector.markup, "begin-editing");
     54  EventUtils.sendKey("F2", inspector.markup._frame.contentWindow);
     55  await onHtmlEditorCreated;
     56  ok(inspector.markup.htmlEditor.isVisible, "HTML Editor is visible");
     57 
     58  is(
     59    await getContentPageElementProperty(SELECTOR, "outerHTML"),
     60    OLD_HTML,
     61    "The node is starting with old HTML."
     62  );
     63 
     64  info("Check that copying from the editor does work as expected");
     65  inspector.markup.htmlEditor.editor.setText(NEW_HTML);
     66 
     67  const onEditorHiddem = once(inspector.markup.htmlEditor, "popuphidden");
     68  EventUtils.sendKey("ESCAPE", inspector.markup.htmlEditor.doc.defaultView);
     69  await onEditorHiddem;
     70  ok(!inspector.markup.htmlEditor.isVisible, "HTML Editor is not visible");
     71 
     72  is(
     73    await getContentPageElementProperty(SELECTOR, "outerHTML"),
     74    OLD_HTML,
     75    "Escape cancels edits"
     76  );
     77 }
     78 
     79 async function testCopyTextSelection(inspector) {
     80  await selectNode(SELECTOR, inspector);
     81 
     82  const onHtmlEditorCreated = once(inspector.markup, "begin-editing");
     83  EventUtils.sendKey("F2", inspector.markup._frame.contentWindow);
     84  await onHtmlEditorCreated;
     85  ok(inspector.markup.htmlEditor.isVisible, "HTML Editor is visible");
     86 
     87  info("Check that copying from the editor does work as expected");
     88  inspector.markup.htmlEditor.editor.setText(NEW_HTML);
     89  // Select the "div" word in the editor
     90  inspector.markup.htmlEditor.editor.setSelectionAt(
     91    { line: 1, column: 1 },
     92    { line: 1, column: 4 }
     93  );
     94  await waitForClipboardPromise(() => {
     95    EventUtils.synthesizeKey("c", { accelKey: true });
     96  }, `div`);
     97  ok(true, "Expected text was copied to clipboard");
     98 
     99  // Close the editor
    100  const onEditorHiddem = once(inspector.markup.htmlEditor, "popuphidden");
    101  EventUtils.sendKey("ESCAPE", inspector.markup.htmlEditor.doc.defaultView);
    102  await onEditorHiddem;
    103 }
    104 
    105 async function testF2Commits(inspector) {
    106  const onEditorShown = once(inspector.markup.htmlEditor, "popupshown");
    107  inspector.markup._frame.contentDocument.documentElement.focus();
    108  EventUtils.sendKey("F2", inspector.markup._frame.contentWindow);
    109  await onEditorShown;
    110  ok(inspector.markup.htmlEditor.isVisible, "HTML Editor is visible");
    111 
    112  is(
    113    await getContentPageElementProperty(SELECTOR, "outerHTML"),
    114    OLD_HTML,
    115    "The node is starting with old HTML."
    116  );
    117 
    118  const onMutations = inspector.once("markupmutation");
    119  inspector.markup.htmlEditor.editor.setText(NEW_HTML);
    120  EventUtils.sendKey("F2", inspector.markup._frame.contentWindow);
    121  await onMutations;
    122 
    123  ok(!inspector.markup.htmlEditor.isVisible, "HTML Editor is not visible");
    124 
    125  is(
    126    await getContentPageElementProperty(SELECTOR, "outerHTML"),
    127    NEW_HTML,
    128    "F2 commits edits - the node has new HTML."
    129  );
    130 }
    131 
    132 async function testBody(inspector) {
    133  const currentBodyHTML = await getContentPageElementProperty(
    134    "body",
    135    "outerHTML"
    136  );
    137  const bodyHTML = '<body id="updated"><p></p></body>';
    138  const bodyFront = await getNodeFront("body", inspector);
    139 
    140  const onUpdated = inspector.once("inspector-updated");
    141  const onReselected = inspector.markup.once("reselectedonremoved");
    142  await inspector.markup.updateNodeOuterHTML(
    143    bodyFront,
    144    bodyHTML,
    145    currentBodyHTML
    146  );
    147  await onReselected;
    148  await onUpdated;
    149 
    150  const newBodyHTML = await getContentPageElementProperty("body", "outerHTML");
    151  is(newBodyHTML, bodyHTML, "<body> HTML has been updated");
    152 
    153  const headsNum = await getNumberOfMatchingElementsInContentPage("head");
    154  is(headsNum, 1, "no extra <head>s have been added");
    155 }
    156 
    157 async function testHead(inspector) {
    158  await selectNode("head", inspector);
    159 
    160  const currentHeadHTML = await getContentPageElementProperty(
    161    "head",
    162    "outerHTML"
    163  );
    164  const headHTML =
    165    '<head id="updated"><title>New Title</title>' +
    166    '<script>window.foo="bar";</script></head>';
    167  const headFront = await getNodeFront("head", inspector);
    168 
    169  const onUpdated = inspector.once("inspector-updated");
    170  const onReselected = inspector.markup.once("reselectedonremoved");
    171  await inspector.markup.updateNodeOuterHTML(
    172    headFront,
    173    headHTML,
    174    currentHeadHTML
    175  );
    176  await onReselected;
    177  await onUpdated;
    178 
    179  is(await getDocumentTitle(), "New Title", "New title has been added");
    180  is(await getWindowFoo(), undefined, "Script has not been executed");
    181  is(
    182    await getContentPageElementProperty("head", "outerHTML"),
    183    headHTML,
    184    "<head> HTML has been updated"
    185  );
    186  is(
    187    await getNumberOfMatchingElementsInContentPage("body"),
    188    1,
    189    "no extra <body>s have been added"
    190  );
    191 }
    192 
    193 async function testDocumentElement(inspector) {
    194  const currentDocElementOuterHMTL = await getDocumentOuterHTML();
    195  const docElementHTML =
    196    '<html id="updated" foo="bar"><head>' +
    197    "<title>Updated from document element</title>" +
    198    '<script>window.foo="bar";</script></head><body>' +
    199    "<p>Hello</p></body></html>";
    200  const docElementFront = await inspector.markup.walker.documentElement();
    201 
    202  const onReselected = inspector.markup.once("reselectedonremoved");
    203  await inspector.markup.updateNodeOuterHTML(
    204    docElementFront,
    205    docElementHTML,
    206    currentDocElementOuterHMTL
    207  );
    208  await onReselected;
    209 
    210  is(
    211    await getDocumentTitle(),
    212    "Updated from document element",
    213    "New title has been added"
    214  );
    215  is(await getWindowFoo(), undefined, "Script has not been executed");
    216  is(
    217    await getContentPageElementAttribute("html", "id"),
    218    "updated",
    219    "<html> ID has been updated"
    220  );
    221  is(
    222    await getContentPageElementAttribute("html", "class"),
    223    null,
    224    "<html> class has been updated"
    225  );
    226  is(
    227    await getContentPageElementAttribute("html", "foo"),
    228    "bar",
    229    "<html> attribute has been updated"
    230  );
    231  is(
    232    await getContentPageElementProperty("html", "outerHTML"),
    233    docElementHTML,
    234    "<html> HTML has been updated"
    235  );
    236  is(
    237    await getNumberOfMatchingElementsInContentPage("head"),
    238    1,
    239    "no extra <head>s have been added"
    240  );
    241  is(
    242    await getNumberOfMatchingElementsInContentPage("body"),
    243    1,
    244    "no extra <body>s have been added"
    245  );
    246  is(
    247    await getContentPageElementProperty("body", "textContent"),
    248    "Hello",
    249    "document.body.textContent has been updated"
    250  );
    251 }
    252 
    253 async function testDocumentElement2(inspector) {
    254  const currentDocElementOuterHMTL = await getDocumentOuterHTML();
    255  const docElementHTML =
    256    '<html id="somethingelse" class="updated"><head>' +
    257    "<title>Updated again from document element</title>" +
    258    '<script>window.foo="bar";</script></head><body>' +
    259    "<p>Hello again</p></body></html>";
    260  const docElementFront = await inspector.markup.walker.documentElement();
    261 
    262  const onReselected = inspector.markup.once("reselectedonremoved");
    263  inspector.markup.updateNodeOuterHTML(
    264    docElementFront,
    265    docElementHTML,
    266    currentDocElementOuterHMTL
    267  );
    268  await onReselected;
    269 
    270  is(
    271    await getDocumentTitle(),
    272    "Updated again from document element",
    273    "New title has been added"
    274  );
    275  is(await getWindowFoo(), undefined, "Script has not been executed");
    276  is(
    277    await getContentPageElementAttribute("html", "id"),
    278    "somethingelse",
    279    "<html> ID has been updated"
    280  );
    281  is(
    282    await getContentPageElementAttribute("html", "class"),
    283    "updated",
    284    "<html> class has been updated"
    285  );
    286  is(
    287    await getContentPageElementAttribute("html", "foo"),
    288    null,
    289    "<html> attribute has been removed"
    290  );
    291  is(
    292    await getContentPageElementProperty("html", "outerHTML"),
    293    docElementHTML,
    294    "<html> HTML has been updated"
    295  );
    296  is(
    297    await getNumberOfMatchingElementsInContentPage("head"),
    298    1,
    299    "no extra <head>s have been added"
    300  );
    301  is(
    302    await getNumberOfMatchingElementsInContentPage("body"),
    303    1,
    304    "no extra <body>s have been added"
    305  );
    306  is(
    307    await getContentPageElementProperty("body", "textContent"),
    308    "Hello again",
    309    "document.body.textContent has been updated"
    310  );
    311 }
    312 
    313 function getDocumentTitle() {
    314  return SpecialPowers.spawn(
    315    gBrowser.selectedBrowser,
    316    [],
    317    () => content.document.title
    318  );
    319 }
    320 
    321 function getDocumentOuterHTML() {
    322  return SpecialPowers.spawn(
    323    gBrowser.selectedBrowser,
    324    [],
    325    () => content.document.documentElement.outerHTML
    326  );
    327 }
    328 
    329 function getWindowFoo() {
    330  return SpecialPowers.spawn(
    331    gBrowser.selectedBrowser,
    332    [],
    333    () => content.wrappedJSObject.foo
    334  );
    335 }