browser_persist_cross_origin_iframe.js (6001B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 const TEST_PATH = getRootDirectory(gTestPath).replace( 7 "chrome://mochitests/content", 8 "https://example.org" 9 ); 10 const TEST_PATH2 = getRootDirectory(gTestPath).replace( 11 "chrome://mochitests/content", 12 "https://example.com" 13 ); 14 15 var MockFilePicker = SpecialPowers.MockFilePicker; 16 MockFilePicker.init(window.browsingContext); 17 18 registerCleanupFunction(async function () { 19 info("Running the cleanup code"); 20 MockFilePicker.cleanup(); 21 if (gTestDir && gTestDir.exists()) { 22 // On Windows, sometimes nsIFile.remove() throws, probably because we're 23 // still writing to the directory we're trying to remove, despite 24 // waiting for the download to complete. Just retry a bit later... 25 let succeeded = false; 26 while (!succeeded) { 27 try { 28 gTestDir.remove(true); 29 succeeded = true; 30 } catch (ex) { 31 await new Promise(requestAnimationFrame); 32 } 33 } 34 } 35 }); 36 37 let gTestDir = null; 38 39 function createTemporarySaveDirectory() { 40 var saveDir = Services.dirsvc.get("TmpD", Ci.nsIFile); 41 saveDir.append("testsavedir"); 42 if (!saveDir.exists()) { 43 saveDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755); 44 } 45 return saveDir; 46 } 47 48 function canonicalizeExtension(str) { 49 return str.replace(/\.htm$/, ".html"); 50 } 51 52 function checkContents(dir, expected, str) { 53 let stack = [dir]; 54 let files = []; 55 while (stack.length) { 56 for (let file of stack.pop().directoryEntries) { 57 if (file.isDirectory()) { 58 stack.push(file); 59 } 60 61 let path = canonicalizeExtension(file.getRelativePath(dir)); 62 files.push(path); 63 } 64 } 65 66 SimpleTest.isDeeply( 67 files.sort(), 68 expected.sort(), 69 str + "Should contain downloaded files in correct place." 70 ); 71 } 72 73 async function addFrame(browser, path, selector) { 74 await SpecialPowers.spawn( 75 browser, 76 [path, selector], 77 async function (path, selector) { 78 let document = content.document; 79 let target = document.querySelector(selector); 80 if (content.HTMLIFrameElement.isInstance(target)) { 81 document = target.contentDocument; 82 target = document.body; 83 } 84 let element = document.createElement("iframe"); 85 element.src = path; 86 await new Promise(resolve => { 87 element.onload = resolve; 88 target.appendChild(element); 89 }); 90 } 91 ); 92 } 93 94 async function handleResult(expected, str) { 95 let dls = await Downloads.getList(Downloads.PUBLIC); 96 return new Promise((resolve, reject) => { 97 dls.addView({ 98 onDownloadChanged(download) { 99 if (download.succeeded) { 100 checkContents(gTestDir, expected, str); 101 102 dls.removeView(this); 103 dls.removeFinished(); 104 resolve(); 105 } else if (download.error) { 106 reject("Download failed"); 107 } 108 }, 109 }); 110 }); 111 } 112 113 add_task(async function () { 114 await BrowserTestUtils.withNewTab( 115 TEST_PATH + "image.html", 116 async function (browser) { 117 await addFrame(browser, TEST_PATH + "image.html", "body"); 118 await addFrame(browser, TEST_PATH2 + "image.html", "body>iframe"); 119 120 gTestDir = createTemporarySaveDirectory(); 121 122 MockFilePicker.displayDirectory = gTestDir; 123 MockFilePicker.showCallback = function () { 124 let destFile = gTestDir.clone(); 125 destFile.append("first.html"); 126 MockFilePicker.setFiles([destFile]); 127 MockFilePicker.filterIndex = 0; // kSaveAsType_Complete 128 }; 129 130 let expected = [ 131 "first.html", 132 "first_files", 133 "first_files/image.html", 134 "first_files/dummy.png", 135 "first_files/image_data", 136 "first_files/image_data/image.html", 137 "first_files/image_data/image_data", 138 "first_files/image_data/image_data/dummy.png", 139 ]; 140 141 // This saves the top-level document contained in `browser` 142 saveBrowser(browser); 143 await handleResult(expected, "Check toplevel: "); 144 145 // Instead of deleting previously saved files, we update our list 146 // of expected files for the next part of the test. To not clash 147 // we make sure to save to a different file name. 148 expected = expected.concat([ 149 "second.html", 150 "second_files", 151 "second_files/dummy.png", 152 "second_files/image.html", 153 "second_files/image_data", 154 "second_files/image_data/dummy.png", 155 ]); 156 157 MockFilePicker.showCallback = function () { 158 let destFile = gTestDir.clone(); 159 destFile.append("second.html"); 160 MockFilePicker.setFiles([destFile]); 161 MockFilePicker.filterIndex = 0; // kSaveAsType_Complete 162 }; 163 164 // This saves the sub-document of the iframe contained in the 165 // top-level document, as indicated by passing a child browsing 166 // context as target for the save. 167 saveBrowser(browser, false, browser.browsingContext.children[0]); 168 await handleResult(expected, "Check subframe: "); 169 170 // Instead of deleting previously saved files, we update our list 171 // of expected files for the next part of the test. To not clash 172 // we make sure to save to a different file name. 173 expected = expected.concat([ 174 "third.html", 175 "third_files", 176 "third_files/dummy.png", 177 ]); 178 179 MockFilePicker.showCallback = function () { 180 let destFile = gTestDir.clone(); 181 destFile.append("third.html"); 182 MockFilePicker.setFiles([destFile]); 183 MockFilePicker.filterIndex = 0; // kSaveAsType_Complete 184 }; 185 186 // This saves the sub-document of the iframe contained in the 187 // first sub-document, as indicated by passing a child browsing 188 // context as target for the save. That frame is special, because 189 // it's cross-process. 190 saveBrowser( 191 browser, 192 false, 193 browser.browsingContext.children[0].children[0] 194 ); 195 await handleResult(expected, "Check subframe: "); 196 } 197 ); 198 });