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 }