Bug 1892041 - Part 1: Update test262 features. r=spidermonkey-reviewers,dminor
[gecko.git] / dom / filesystem / tests / test_webkitdirectory.html
blob982887cbcf9aa2ebb2abad0abe6d5d20aff1d5b9
1 <!DOCTYPE HTML>
2 <html>
3 <head>
4 <title>Test for webkitdirectory and webkitRelativePath</title>
5 <script src="/tests/SimpleTest/SimpleTest.js"></script>
6 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
7 </head>
9 <body>
10 <input id="inputFileWebkitDirectory" type="file" webkitdirectory></input>
11 <input id="inputFileWebkitFile" type="file"></input>
12 <input id="inputFileDirectoryChange" type="file" webkitdirectory></input>
14 <script type="application/javascript">
16 const { AppConstants } = SpecialPowers.ChromeUtils.importESModule(
17 "resource://gre/modules/AppConstants.sys.mjs"
20 let promptHandler;
22 function waitForEvent(element, eventName) {
23 return new Promise(function(resolve) {
24 element.addEventListener(eventName, e => resolve(e.detail), { once: true });
25 });
28 function waitForPromptHandled() {
29 return new Promise(resolve => promptHandler.addMessageListener("promptAccepted", resolve));
32 // Populate the given input type=file `aInputFile`'s `files` attribute by:
33 // - loading `script_fileList.js` in the parent process
34 // - telling it to generate the "test" template directory pattern which will
35 // create "foo.txt", "subdir/bar.txt", and if symlinks are available on the
36 // platform, "symlink.txt" which will be a symlink to "foo.txt". (Note that
37 // we explicitly expect the symlink to be filtered out if generated, and
38 // during the enhancement of the test we verified the file was created on
39 // linux by running the test before fixing the GetFilesHelper logic to filter
40 // the symlink out and verifying the subsequent `test_fileList` check failed.)
41 // - Triggering the mock file picker with the base directory of the "test"
42 // template directory.
44 // It's expected that `test_fileList` will be used after this step completes in
45 // order to validate the results.
46 function populateInputFile(aInputFile) {
47 var url = SimpleTest.getTestFileURL("script_fileList.js");
48 var script = SpecialPowers.loadChromeScript(url);
50 var MockFilePicker = SpecialPowers.MockFilePicker;
51 MockFilePicker.init(SpecialPowers.wrap(window).browsingContext, "A Mock File Picker", SpecialPowers.Ci.nsIFilePicker.modeGetFolder);
53 async function onOpened(message) {
54 MockFilePicker.useDirectory(message.dir);
56 let input = document.getElementById(aInputFile);
57 input.setAttribute("data-name", message.name);
59 let promptHandled = waitForPromptHandled();
60 let changeEvent = waitForEvent(input, "change");
62 input.click();
64 await promptHandled;
65 await changeEvent;
67 MockFilePicker.cleanup();
68 script.destroy();
69 next();
72 script.addMessageListener("dir.opened", onOpened);
73 script.sendAsyncMessage("dir.open", { path: "test" });
76 function checkFile(file, fileList, dirName) {
77 for (var i = 0; i < fileList.length; ++i) {
78 ok(fileList[i] instanceof File, "We want just files.");
79 if (fileList[i].name == file.name) {
80 is(fileList[i].webkitRelativePath, dirName + file.path, "Path matches");
81 return;
85 ok(false, "File not found.");
88 // Validate the contents of the given input type=file `aInputFile`'s' `files`
89 // property against the expected list of files `aWhat`.
90 function test_fileList(aInputFile, aWhat) {
91 var input = document.getElementById(aInputFile);
92 var fileList = input.files;
94 if (aWhat == null) {
95 is(fileList, null, "We want a null fileList for " + aInputFile);
96 next();
97 return;
100 is(fileList.length, aWhat.length, "We want just " + aWhat.length + " elements for " + aInputFile);
101 for (var i = 0; i < aWhat.length; ++i) {
102 checkFile(aWhat[i], fileList, input.dataset.name);
105 next();
108 // Verify that we can explicitly select a symlink and it will not be filtered
109 // out. This is really a verification that GetFileHelper's file-handling logic
110 // https://searchfox.org/mozilla-central/rev/065102493dfc49234120c37fc6a334a5b1d86d9e/dom/filesystem/GetFilesHelper.cpp#81-86
111 // does not proactively take an action to filter out a selected symlink.
113 // This is a glass box test that is not entirely realistic for our actual system
114 // file pickers but does reflect what will happen in the drag-and-drop case
115 // for `HTMLInputElement::MozSetDndFilesAndDirectories` and this helps ensure
116 // that future implementation changes will behave as expected. Specifically,
117 // the presence of webkitdirectory will result in the file picker using
118 // `modeGetFolder` which will only allow selection of a directory and forbid
119 // file selection.
121 // This test explicitly does not validate HTMLInputElement's non-webkitdirectory
122 // file selection mechanism because it does not involve GetFileHelper.
123 async function test_individualSymlink(aInputFile) {
124 const input = document.getElementById(aInputFile);
126 // -- Create the symlink and get a `File` instance pointing at it.
127 const url = SimpleTest.getTestFileURL("script_fileList.js");
128 const script = SpecialPowers.loadChromeScript(url);
130 let opened = new Promise(resolve => script.addMessageListener("symlink.opened", resolve));
131 script.sendAsyncMessage("symlink.open", {});
132 let { dir, file: symlinkFile } = await opened;
133 info(`symlink.open provided dir: ${dir}`)
135 // -- Have the picker pick it
136 var MockFilePicker = SpecialPowers.MockFilePicker;
137 MockFilePicker.init(SpecialPowers.wrap(window).browsingContext, "A Mock File Picker", SpecialPowers.Ci.nsIFilePicker.modeOpen);
139 MockFilePicker.displayDirectory = dir;
140 let pickerShown = new Promise(resolve => {
141 MockFilePicker.showCallback = function() {
142 // This is where we are diverging from a realistic scenario in order to get
143 // the expected coverage.
144 MockFilePicker.setFiles([symlinkFile]);
145 resolve();
148 MockFilePicker.returnValue = MockFilePicker.returnOK;
150 let changeEvent = waitForEvent(input, "change");
152 input.click();
154 await pickerShown;
155 await changeEvent;
157 MockFilePicker.cleanup();
158 script.destroy();
160 // -- Verify that we see the symlink.
161 let fileList = input.files;
162 is(fileList.length, 1, "There should be 1 file.");
163 is(fileList[0].name, "symlink.txt", "The file should be the symlink.");
164 next();
167 function test_webkitdirectory_attribute() {
168 var a = document.createElement("input");
169 a.setAttribute("type", "file");
171 ok("webkitdirectory" in a, "HTMLInputElement.webkitdirectory exists");
173 ok(!a.hasAttribute("webkitdirectory"), "No webkitdirectory DOM attribute by default");
174 ok(!a.webkitdirectory, "No webkitdirectory attribute by default");
176 a.webkitdirectory = true;
178 ok(a.hasAttribute("webkitdirectory"), "Webkitdirectory DOM attribute is set");
179 ok(a.webkitdirectory, "Webkitdirectory attribute is set");
181 next();
184 function test_changeDataWhileWorking() {
185 var url = SimpleTest.getTestFileURL("script_fileList.js");
186 var script = SpecialPowers.loadChromeScript(url);
188 var MockFilePicker = SpecialPowers.MockFilePicker;
189 MockFilePicker.init(SpecialPowers.wrap(window).browsingContext, "A Mock File Picker", SpecialPowers.Ci.nsIFilePicker.modeGetFolder);
190 let promptHandled;
192 // Let's start retrieving the root nsIFile object
193 new Promise(function(resolve) {
194 function onOpened(message) {
195 script.removeMessageListener("dir.opened", onOpened);
196 resolve(message.dir);
199 script.addMessageListener("dir.opened", onOpened);
200 script.sendAsyncMessage("dir.open", { path: "root" });
203 // input.click() pointing to the root dir
204 .then(async function(aDir) {
205 MockFilePicker.cleanup();
206 MockFilePicker.init(SpecialPowers.wrap(window).browsingContext, "A Mock File Picker", SpecialPowers.Ci.nsIFilePicker.modeGetFolder);
207 MockFilePicker.useDirectory(aDir);
208 var input = document.getElementById("inputFileDirectoryChange");
210 promptHandled = waitForPromptHandled();
211 input.click();
214 // Before onchange, let's take the 'test' directory
215 .then(function() {
216 return new Promise(function(resolve) {
217 function onOpened(message) {
218 script.removeMessageListener("dir.opened", onOpened);
219 script.destroy();
220 resolve(message.dir);
223 script.addMessageListener("dir.opened", onOpened);
224 script.sendAsyncMessage("dir.open", { path: "test" });
228 // Now let's click again and wait for onchange.
229 .then(async function(aDir) {
230 MockFilePicker.cleanup();
231 MockFilePicker.init(SpecialPowers.wrap(window).browsingContext, "A Mock File Picker", SpecialPowers.Ci.nsIFilePicker.modeGetFolder);
232 MockFilePicker.useDirectory(aDir);
234 let input = document.getElementById("inputFileDirectoryChange");
235 let changeEvent = waitForEvent(input, "change");
237 input.click();
239 await promptHandled;
240 await changeEvent;
242 MockFilePicker.cleanup();
244 .then(function() {
245 test_fileList("inputFileWebkitDirectory", testDirData);
249 async function test_setup() {
250 let promptHandlerUrl = SimpleTest.getTestFileURL("script_promptHandler.js")
251 promptHandler = SpecialPowers.loadChromeScript(promptHandlerUrl);
253 let promptHandlerReady = new Promise(resolve => promptHandler.addMessageListener("initDone", resolve));
254 promptHandler.sendAsyncMessage("init");
255 await promptHandlerReady;
257 SpecialPowers.pushPrefEnv({"set": [["dom.filesystem.pathcheck.disabled", true],
258 ["dom.webkitBlink.dirPicker.enabled", true]]}, next);
261 async function test_cleanup() {
262 let promptHandlerDone = new Promise(resolve => promptHandler.addMessageListener("cleanupDone", resolve));
263 promptHandler.sendAsyncMessage("cleanup");
264 await promptHandlerDone;
265 promptHandler.destroy();
268 var testDirData = [ { name: "foo.txt", path: "/foo.txt" },
269 { name: "bar.txt", path: "/subdir/bar.txt" }];
271 var tests = [
272 test_setup,
274 function() { populateInputFile("inputFileWebkitDirectory"); },
276 function() { test_fileList("inputFileWebkitDirectory", testDirData); },
278 function() {
279 // Symlinks are not available on Windows and so will not be created.
280 if (AppConstants.platform === "win" || AppConstants.platform === "android") {
281 info("Skipping individual symlink check on Windows and Android.");
282 next();
283 return;
286 test_individualSymlink("inputFileWebkitFile").catch(err => ok(false, `Problem in symlink case: ${err}`));
289 test_webkitdirectory_attribute,
291 test_changeDataWhileWorking,
294 async function next() {
295 if (!tests.length) {
296 await test_cleanup();
297 SimpleTest.finish();
298 return;
301 var test = tests.shift();
302 await test();
305 SimpleTest.waitForExplicitFinish();
306 next();
307 </script>
308 </body>
309 </html>