View Javadoc
1   /*
2    * Copyright (c) 2002-2025 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.javascript.host.file;
16  
17  import static java.nio.charset.StandardCharsets.ISO_8859_1;
18  
19  import java.io.File;
20  import java.util.Locale;
21  import java.util.TimeZone;
22  
23  import org.apache.commons.io.FileUtils;
24  import org.htmlunit.BrowserVersion;
25  import org.htmlunit.WebDriverTestCase;
26  import org.htmlunit.junit.annotation.Alerts;
27  import org.htmlunit.util.MimeType;
28  import org.junit.jupiter.api.Test;
29  import org.openqa.selenium.By;
30  import org.openqa.selenium.WebDriver;
31  
32  /**
33   * Tests for {@link org.htmlunit.javascript.host.file.File}.
34   *
35   * @author Ronald Brill
36   */
37  public class FileTest extends WebDriverTestCase {
38  
39      /**
40       * @throws Exception if the test fails
41       */
42      @Test
43      @Alerts(DEFAULT = {"1", "ScriptExceptionTest1.txt",
44                         "Sun Jul 26 2015 10:21:47 GMT-0400 (Eastern Daylight Time)",
45                         "1437920507000", "", "14", MimeType.TEXT_PLAIN},
46              FF = {"1", "ScriptExceptionTest1.txt", "undefined",
47                    "1437920507000", "", "14", MimeType.TEXT_PLAIN},
48              FF_ESR = {"1", "ScriptExceptionTest1.txt", "undefined",
49                        "1437920507000", "", "14", MimeType.TEXT_PLAIN})
50      public void properties() throws Exception {
51          final String html = DOCTYPE_HTML
52              + "<html>\n"
53              + "<head>\n"
54              + "<script>\n"
55              + LOG_TITLE_FUNCTION
56              + "function test() {\n"
57              + "  if (document.testForm.fileupload.files) {\n"
58              + "    var files = document.testForm.fileupload.files;\n"
59              + "    log(files.length);\n"
60  
61              + "    var file = files[0];\n"
62              + "    log(file.name);\n"
63              + "    log(file.lastModifiedDate);\n"
64              + "    log(file.lastModified);\n"
65              + "    log(file.webkitRelativePath);\n"
66              + "    log(file.size);\n"
67              + "    log(file.type);\n"
68              + "  }\n"
69              + "}\n"
70              + "</script>\n"
71              + "</head>\n"
72              + "<body>\n"
73              + "  <form name='testForm'>\n"
74              + "    <input type='file' id='fileupload' name='fileupload'>\n"
75              + "  </form>\n"
76              + "  <button id='testBtn' onclick='test()'>Tester</button>\n"
77              + "</body>\n"
78              + "</html>";
79  
80          final WebDriver driver = loadPage2(html);
81  
82          final File tstFile = File.createTempFile("HtmlUnitUploadTest", ".txt");
83          try {
84              FileUtils.writeStringToFile(tstFile, "Hello HtmlUnit", ISO_8859_1);
85  
86              // do not use millis here because different file systems
87              // have different precisions
88              assertTrue(tstFile.setLastModified(1437920507000L));
89  
90              final String path = tstFile.getCanonicalPath();
91              driver.findElement(By.name("fileupload")).sendKeys(path);
92  
93              driver.findElement(By.id("testBtn")).click();
94  
95              final String[] expected = getExpectedAlerts();
96              if (expected.length > 1) {
97                  expected[1] = tstFile.getName();
98              }
99  
100             verifyTitle2(driver, getExpectedAlerts());
101         }
102         finally {
103             FileUtils.deleteQuietly(tstFile);
104         }
105     }
106 
107     /**
108      * @throws Exception if the test fails
109      */
110     @Test
111     @Alerts({"1", "function", "Hello HtmlUnit"})
112     public void text() throws Exception {
113         final String html = DOCTYPE_HTML
114             + "<html>\n"
115             + "<head>\n"
116             + "<script>\n"
117             + LOG_TITLE_FUNCTION
118             + "function test() {\n"
119             + "  if (document.testForm.fileupload.files) {\n"
120             + "    var files = document.testForm.fileupload.files;\n"
121             + "    log(files.length);\n"
122 
123             + "    var file = files[0];\n"
124             + "    log(typeof file.text);\n"
125 
126             + "    try {\n"
127             + "      file.text().then(function(text) { log(text); });\n"
128             + "    } catch(e) { log('TypeError ' + (e instanceof TypeError)); }\n"
129             + "  }\n"
130             + "}\n"
131             + "</script>\n"
132             + "</head>\n"
133             + "<body>\n"
134             + "  <form name='testForm'>\n"
135             + "    <input type='file' id='fileupload' name='fileupload'>\n"
136             + "  </form>\n"
137             + "  <button id='testBtn' onclick='test()'>Tester</button>\n"
138             + "</body>\n"
139             + "</html>";
140 
141         final WebDriver driver = loadPage2(html);
142 
143         final File tstFile = File.createTempFile("HtmlUnitUploadTest", ".txt");
144         try {
145             FileUtils.writeStringToFile(tstFile, "Hello HtmlUnit", ISO_8859_1);
146 
147             final String path = tstFile.getCanonicalPath();
148             driver.findElement(By.name("fileupload")).sendKeys(path);
149 
150             driver.findElement(By.id("testBtn")).click();
151 
152             verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
153         }
154         finally {
155             FileUtils.deleteQuietly(tstFile);
156         }
157     }
158 
159     /**
160      * @throws Exception if the test fails
161      */
162     @Test
163     @Alerts("text/plain")
164     public void typeTxt() throws Exception {
165         type(".txt");
166         type(".tXT");
167     }
168 
169     /**
170      * @throws Exception if the test fails
171      */
172     @Test
173     @Alerts("")
174     public void typeHtmlUnit() throws Exception {
175         type(".htmlunit");
176     }
177 
178     /**
179      * @throws Exception if the test fails
180      */
181     @Test
182     @Alerts("")
183     public void typeEmpty() throws Exception {
184         type("");
185     }
186 
187     private void type(final String extension) throws Exception {
188         final String html = DOCTYPE_HTML
189             + "<html>\n"
190             + "<head>\n"
191             + "<script>\n"
192             + LOG_TITLE_FUNCTION
193             + "function test() {\n"
194             + "  if (document.testForm.fileupload.files) {\n"
195             + "    var files = document.testForm.fileupload.files;\n"
196 
197             + "    var file = files[0];\n"
198             + "    log(file.type);\n"
199             + "  }\n"
200             + "}\n"
201             + "</script>\n"
202             + "</head>\n"
203             + "<body>\n"
204             + "  <form name='testForm'>\n"
205             + "    <input type='file' id='fileupload' name='fileupload'>\n"
206             + "  </form>\n"
207             + "  <button id='testBtn' onclick='test()'>Tester</button>\n"
208             + "</body>\n"
209             + "</html>";
210 
211         final WebDriver driver = loadPage2(html);
212 
213         final File tstFile = File.createTempFile("HtmlUnitUploadTest", extension);
214         try {
215             final String path = tstFile.getCanonicalPath();
216             driver.findElement(By.name("fileupload")).sendKeys(path);
217 
218             driver.findElement(By.id("testBtn")).click();
219 
220             verifyTitle2(driver, getExpectedAlerts());
221         }
222         finally {
223             FileUtils.deleteQuietly(tstFile);
224         }
225     }
226 
227     /**
228      * @throws Exception if the test fails
229      */
230     @Test
231     @Alerts({"false", "TypeError true"})
232     public void ctorNoArgs() throws Exception {
233         final String html = DOCTYPE_HTML
234                 + "<html>\n"
235                 + "<head>\n"
236                 + "<script>\n"
237                 + LOG_TITLE_FUNCTION
238                 + "  function test() {\n"
239                 + "    log(File in window);\n"
240 
241                 + "    try {\n"
242                 + "      log(new File());\n"
243                 + "    } catch(e) { log('TypeError ' + (e instanceof TypeError)); }\n"
244                 + "  }\n"
245                 + "</script>\n"
246                 + "</head>\n"
247                 + "<body onload='test()'>\n"
248                 + "</body>\n"
249                 + "</html>";
250 
251         loadPageVerifyTitle2(html);
252     }
253 
254     /**
255      * @throws Exception if the test fails
256      */
257     @Test
258     @Alerts({"[object File]", "htMluniT.txt", "", "true", "0", ""})
259     public void ctorEmpty() throws Exception {
260         final String html = DOCTYPE_HTML
261                 + "<html>\n"
262                 + "<head>\n"
263                 + "<script>\n"
264                 + LOG_TITLE_FUNCTION
265                 + "  function test() {\n"
266                 + "    try {\n"
267                 + "      var now = Date.now();\n"
268                 + "      var file = new File([], 'htMluniT.txt');\n"
269                 + "      log(file);\n"
270                 + "      log(file.name);\n"
271                 + "      log(file.type);\n"
272                 + "      log(file.lastModified >= now);\n"
273                 + "      log(file.size);\n"
274 
275                 + "      file.text().then(function(text) { log(text); });\n"
276                 + "    } catch(e) { log('TypeError ' + (e instanceof TypeError)); }\n"
277                 + "  }\n"
278                 + "</script>\n"
279                 + "</head>\n"
280                 + "<body onload='test()'>\n"
281                 + "</body>\n"
282                 + "</html>";
283 
284         loadPage2(html);
285         verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
286     }
287 
288     /**
289      * @throws Exception if the test fails
290      */
291     @Test
292     @Alerts({"[object File]", "htMluniT.txt", "", "true", "8", "HtmlUnit"})
293     public void ctorString() throws Exception {
294         final String html = DOCTYPE_HTML
295                 + "<html>\n"
296                 + "<head>\n"
297                 + "<script>\n"
298                 + LOG_TITLE_FUNCTION
299                 + "  function test() {\n"
300                 + "    try {\n"
301                 + "      var now = Date.now();\n"
302                 + "      var file = new File(['HtmlUnit'], 'htMluniT.txt');\n"
303                 + "      log(file);\n"
304                 + "      log(file.name);\n"
305                 + "      log(file.type);\n"
306                 + "      log(file.lastModified >= now);\n"
307                 + "      log(file.size);\n"
308 
309                 + "      file.text().then(function(text) { log(text); });\n"
310                 + "    } catch(e) { log('TypeError ' + (e instanceof TypeError)); }\n"
311                 + "  }\n"
312                 + "</script>\n"
313                 + "</head>\n"
314                 + "<body onload='test()'>\n"
315                 + "</body>\n"
316                 + "</html>";
317 
318         loadPage2(html);
319         verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
320     }
321 
322     /**
323      * @throws Exception if the test fails
324      */
325     @Test
326     @Alerts({"[object File]", "htMluniT.txt", "application/octet-stream", "1234567", "8",
327              "HtmlUnit"})
328     public void ctorStringWithOptions() throws Exception {
329         final String html = DOCTYPE_HTML
330                 + "<html>\n"
331                 + "<head>\n"
332                 + "<script>\n"
333                 + LOG_TITLE_FUNCTION
334                 + "  function test() {\n"
335                 + "    try {\n"
336                 + "      var now = Date.now();\n"
337                 + "      var file = new File(['HtmlUnit'], 'htMluniT.txt',"
338                               + "{type: 'application/octet-stream', lastModified: '1234567'});\n"
339                 + "      log(file);\n"
340                 + "      log(file.name);\n"
341                 + "      log(file.type);\n"
342                 + "      log(file.lastModified);\n"
343                 + "      log(file.size);\n"
344 
345                 + "      file.text().then(function(text) { log(text); });\n"
346                 + "    } catch(e) { log('TypeError ' + (e instanceof TypeError)); }\n"
347                 + "  }\n"
348                 + "</script>\n"
349                 + "</head>\n"
350                 + "<body onload='test()'>\n"
351                 + "</body>\n"
352                 + "</html>";
353 
354         loadPage2(html);
355         verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
356     }
357 
358     /**
359      * @throws Exception if the test fails
360      */
361     @Test
362     @Alerts({"[object File]", "htMluniT.txt", "", "true", "16",
363              "HtmlUnitis great"})
364     public void ctorStrings() throws Exception {
365         final String html = DOCTYPE_HTML
366                 + "<html>\n"
367                 + "<head>\n"
368                 + "<script>\n"
369                 + LOG_TITLE_FUNCTION
370                 + "  function test() {\n"
371                 + "    try {\n"
372                 + "      var now = Date.now();\n"
373                 + "      var file = new File(['Html', 'Unit', 'is great'], 'htMluniT.txt');\n"
374                 + "      log(file);\n"
375                 + "      log(file.name);\n"
376                 + "      log(file.type);\n"
377                 + "      log(file.lastModified >= now);\n"
378                 + "      log(file.size);\n"
379 
380                 + "      file.text().then(function(text) { log(text); });\n"
381                 + "    } catch(e) { log('TypeError ' + (e instanceof TypeError)); }\n"
382                 + "  }\n"
383                 + "</script>\n"
384                 + "</head>\n"
385                 + "<body onload='test()'>\n"
386                 + "</body>\n"
387                 + "</html>";
388 
389         loadPage2(html);
390         verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
391     }
392 
393     /**
394      * @throws Exception if the test fails
395      */
396     @Test
397     @Alerts({"[object File]", "htMluniT.txt", "", "true", "12", "HtmlUnitMMMK"})
398     public void ctorMixed() throws Exception {
399         final String html = DOCTYPE_HTML
400                 + "<html>\n"
401                 + "<head>\n"
402                 + "<script>\n"
403                 + LOG_TITLE_FUNCTION
404                 + "  function test() {\n"
405                 + "    try {\n"
406                 + "      var now = Date.now();\n"
407                 + "      var nab = new ArrayBuffer(2);\n"
408                 + "      var nabv = new Uint8Array(nab, 0, 2);\n"
409                 + "      nabv.set([77, 77], 0);\n"
410                 + "      var file = new File(['HtmlUnit',"
411                                       + "nab, new Int8Array([77,75])], 'htMluniT.txt');\n"
412                 + "      log(file);\n"
413                 + "      log(file.name);\n"
414                 + "      log(file.type);\n"
415                 + "      log(file.lastModified >= now);\n"
416                 + "      log(file.size);\n"
417 
418                 + "      file.text().then(function(text) { log(text); });\n"
419                 + "    } catch(e) { log('TypeError ' + (e instanceof TypeError)); }\n"
420                 + "  }\n"
421                 + "</script>\n"
422                 + "</head>\n"
423                 + "<body onload='test()'>\n"
424                 + "</body>\n"
425                 + "</html>";
426 
427         loadPage2(html);
428         verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
429     }
430 
431     /**
432      * @throws Exception if the test fails
433      */
434     @Test
435     @Alerts(DEFAULT = "Sun Jul 26 2015 10:21:47 GMT-0400 (Eastern Daylight Time)",
436             FF = "undefined",
437             FF_ESR = "undefined")
438     public void lastModifiedDate() throws Exception {
439         lastModifiedDate(getBrowserVersion().getSystemTimezone().getID(), getBrowserVersion().getBrowserLocale());
440     }
441 
442     /**
443      * @throws Exception if the test fails
444      */
445     @Test
446     @Alerts(DEFAULT = "Sun Jul 26 2015 14:21:47 GMT+0000 (Greenwich Mean Time)",
447             FF = "undefined",
448             FF_ESR = "undefined")
449     public void lastModifiedDateGMT() throws Exception {
450         lastModifiedDate("GMT", getBrowserVersion().getBrowserLocale());
451     }
452 
453     /**
454      * @throws Exception if the test fails
455      */
456     @Test
457     @Alerts(DEFAULT = "Sun Jul 26 2015 14:21:47 GMT+0000 (Coordinated Universal Time)",
458             FF = "undefined",
459             FF_ESR = "undefined")
460     public void lastModifiedDateUTC() throws Exception {
461         lastModifiedDate("UTC", getBrowserVersion().getBrowserLocale());
462     }
463 
464     /**
465      * @throws Exception if the test fails
466      */
467     @Test
468     @Alerts(DEFAULT = "Sun Jul 26 2015 16:21:47 GMT+0200 (Mitteleuropäische Sommerzeit)",
469             FF = "undefined",
470             FF_ESR = "undefined")
471     public void lastModifiedDateBerlin() throws Exception {
472         lastModifiedDate("Europe/Berlin", Locale.GERMANY);
473     }
474 
475     /**
476      * @throws Exception if the test fails
477      */
478     @Test
479     @Alerts(DEFAULT = "Sun Jul 26 2015 23:21:47 GMT+0900 (日本標準時)",
480             FF = "undefined",
481             FF_ESR = "undefined")
482     public void lastModifiedDateJST() throws Exception {
483         lastModifiedDate("JST", Locale.JAPAN);
484     }
485 
486     private void lastModifiedDate(final String tz, final Locale locale) throws Exception {
487         final String html = DOCTYPE_HTML
488             + "<html>\n"
489             + "<head>\n"
490             + "<script>\n"
491             + LOG_TITLE_FUNCTION
492             + "function test() {\n"
493             + "  if (document.testForm.fileupload.files) {\n"
494             + "    var files = document.testForm.fileupload.files;\n"
495             + "    var file = files[0];\n"
496             + "    log(file.lastModifiedDate);\n"
497             + "  }\n"
498             + "}\n"
499             + "</script>\n"
500             + "</head>\n"
501             + "<body>\n"
502             + "  <form name='testForm'>\n"
503             + "    <input type='file' id='fileupload' name='fileupload'>\n"
504             + "  </form>\n"
505             + "  <button id='testBtn' onclick='test()'>Tester</button>\n"
506             + "</body>\n"
507             + "</html>";
508 
509         final File tstFile = File.createTempFile("HtmlUnitUploadTest", ".txt");
510         try {
511             FileUtils.writeStringToFile(tstFile, "Hello HtmlUnit", ISO_8859_1);
512 
513             // do not use millis here because different file systems
514             // have different precisions
515             assertTrue(tstFile.setLastModified(1437920507000L));
516 
517             final String path = tstFile.getCanonicalPath();
518 
519             shutDownAll();
520             try {
521                 final BrowserVersion.BrowserVersionBuilder builder
522                     = new BrowserVersion.BrowserVersionBuilder(getBrowserVersion());
523                 builder.setSystemTimezone(TimeZone.getTimeZone(tz));
524                 builder.setBrowserLanguage(locale.toLanguageTag());
525                 setBrowserVersion(builder.build());
526 
527                 final WebDriver driver = loadPage2(html);
528                 driver.findElement(By.name("fileupload")).sendKeys(path);
529 
530                 driver.findElement(By.id("testBtn")).click();
531 
532                 final String[] expected = getExpectedAlerts();
533                 if (expected.length > 1) {
534                     expected[1] = tstFile.getName();
535                 }
536 
537                 verifyTitle2(driver, getExpectedAlerts());
538             }
539             finally {
540                 shutDownAll();
541             }
542         }
543         finally {
544             FileUtils.deleteQuietly(tstFile);
545         }
546     }
547 }