1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/files/file_util.h"
6 #include "base/files/scoped_temp_dir.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "base/test/gmock_callback_support.h"
9 #include "base/test/scoped_feature_list.h"
10 #include "base/threading/thread_restrictions.h"
11 #include "content/browser/native_file_system/file_system_chooser_test_helpers.h"
12 #include "content/browser/native_file_system/mock_native_file_system_permission_context.h"
13 #include "content/browser/native_file_system/native_file_system_manager_impl.h"
14 #include "content/browser/web_contents/web_contents_impl.h"
15 #include "content/public/browser/browser_context.h"
16 #include "content/public/browser/render_process_host.h"
17 #include "content/public/browser/storage_partition.h"
18 #include "content/public/common/content_switches.h"
19 #include "content/public/test/back_forward_cache_util.h"
20 #include "content/public/test/browser_test_utils.h"
21 #include "content/public/test/content_browser_test.h"
22 #include "content/public/test/content_browser_test_utils.h"
23 #include "content/shell/browser/shell.h"
24 #include "net/test/embedded_test_server/embedded_test_server.h"
25 #include "third_party/blink/public/common/features.h"
26 #include "third_party/blink/public/mojom/frame/fullscreen.mojom.h"
27 #include "ui/shell_dialogs/select_file_dialog.h"
28 #include "ui/shell_dialogs/select_file_dialog_factory.h"
29 #include "ui/shell_dialogs/select_file_policy.h"
30 
31 namespace content {
32 
33 using base::test::RunOnceCallback;
34 using blink::mojom::PermissionStatus;
35 using SensitiveDirectoryResult =
36     NativeFileSystemPermissionContext::SensitiveDirectoryResult;
37 
38 // This browser test implements end-to-end tests for the chooseFileSystemEntry
39 // API.
40 class FileSystemChooserBrowserTest : public ContentBrowserTest {
41  public:
SetUp()42   void SetUp() override {
43     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
44     scoped_feature_list_.InitAndEnableFeature(
45         blink::features::kNativeFileSystemAPI);
46 
47     ASSERT_TRUE(embedded_test_server()->Start());
48 
49     ContentBrowserTest::SetUp();
50   }
51 
SetUpCommandLine(base::CommandLine * command_line)52   void SetUpCommandLine(base::CommandLine* command_line) override {
53     // Enable experimental web platform features to enable write access.
54     command_line->AppendSwitch(
55         switches::kEnableExperimentalWebPlatformFeatures);
56   }
57 
TearDown()58   void TearDown() override {
59     ContentBrowserTest::TearDown();
60     ASSERT_TRUE(temp_dir_.Delete());
61     ui::SelectFileDialog::SetFactory(nullptr);
62   }
63 
IsFullscreen()64   bool IsFullscreen() {
65     WebContents* web_contents = shell()->web_contents();
66     return web_contents->IsFullscreenForCurrentTab();
67   }
68 
EnterFullscreen(GURL url)69   void EnterFullscreen(GURL url) {
70     WebContentsImpl* web_contents_impl =
71         static_cast<WebContentsImpl*>(shell()->web_contents());
72     web_contents_impl->EnterFullscreenMode(url,
73                                            blink::mojom::FullscreenOptions());
74   }
75 
CreateTestFile(const std::string & contents)76   base::FilePath CreateTestFile(const std::string& contents) {
77     base::ScopedAllowBlockingForTesting allow_blocking;
78     base::FilePath result;
79     EXPECT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &result));
80     EXPECT_EQ(int{contents.size()},
81               base::WriteFile(result, contents.data(), contents.size()));
82     return result;
83   }
84 
CreateTestDir()85   base::FilePath CreateTestDir() {
86     base::ScopedAllowBlockingForTesting allow_blocking;
87     base::FilePath result;
88     EXPECT_TRUE(base::CreateTemporaryDirInDir(
89         temp_dir_.GetPath(), FILE_PATH_LITERAL("test"), &result));
90     return result;
91   }
92 
93  private:
94   base::test::ScopedFeatureList scoped_feature_list_;
95   base::ScopedTempDir temp_dir_;
96 };
97 
IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest,CancelDialog)98 IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest, CancelDialog) {
99   ui::SelectFileDialog::SetFactory(new CancellingSelectFileDialogFactory);
100   ASSERT_TRUE(
101       NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
102   auto result = EvalJs(shell(), "self.chooseFileSystemEntries()");
103   EXPECT_TRUE(result.error.find("aborted") != std::string::npos)
104       << result.error;
105 }
106 
IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest,OpenFile)107 IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest, OpenFile) {
108   const std::string file_contents = "hello world!";
109   const base::FilePath test_file = CreateTestFile(file_contents);
110   SelectFileDialogParams dialog_params;
111   ui::SelectFileDialog::SetFactory(
112       new FakeSelectFileDialogFactory({test_file}, &dialog_params));
113   ASSERT_TRUE(
114       NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
115   EXPECT_EQ(test_file.BaseName().AsUTF8Unsafe(),
116             EvalJs(shell(),
117                    "(async () => {"
118                    "  let e = await self.chooseFileSystemEntries();"
119                    "  self.selected_entry = e;"
120                    "  return e.name; })()"));
121   EXPECT_EQ(ui::SelectFileDialog::SELECT_OPEN_FILE, dialog_params.type);
122   EXPECT_EQ(shell()->web_contents()->GetTopLevelNativeWindow(),
123             dialog_params.owning_window);
124   EXPECT_EQ(
125       file_contents,
126       EvalJs(shell(),
127              "(async () => { const file = await self.selected_entry.getFile(); "
128              "return await file.text(); })()"));
129 }
130 
IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest,FullscreenOpenFile)131 IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest, FullscreenOpenFile) {
132   const std::string file_contents = "hello world!";
133   const base::FilePath test_file = CreateTestFile(file_contents);
134   SelectFileDialogParams dialog_params;
135   ui::SelectFileDialog::SetFactory(
136       new FakeSelectFileDialogFactory({test_file}, &dialog_params));
137   ASSERT_TRUE(
138       NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
139   EnterFullscreen(embedded_test_server()->GetURL("/title1.html"));
140   EXPECT_TRUE(IsFullscreen());
141   EXPECT_EQ(test_file.BaseName().AsUTF8Unsafe(),
142             EvalJs(shell(),
143                    "(async () => {"
144                    "  let e = await self.chooseFileSystemEntries();"
145                    "  self.selected_entry = e;"
146                    "  return e.name; })()"));
147   EXPECT_FALSE(IsFullscreen());
148 }
149 
IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest,SaveFile_NonExistingFile)150 IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest, SaveFile_NonExistingFile) {
151   const std::string file_contents = "file contents to write";
152   const base::FilePath test_file = CreateTestFile("");
153   {
154     // Delete file, since SaveFile should be able to deal with non-existing
155     // files.
156     base::ScopedAllowBlockingForTesting allow_blocking;
157     ASSERT_TRUE(base::DeleteFile(test_file, false));
158   }
159   SelectFileDialogParams dialog_params;
160   ui::SelectFileDialog::SetFactory(
161       new FakeSelectFileDialogFactory({test_file}, &dialog_params));
162   ASSERT_TRUE(
163       NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
164   EXPECT_EQ(test_file.BaseName().AsUTF8Unsafe(),
165             EvalJs(shell(),
166                    "(async () => {"
167                    "  let e = await self.chooseFileSystemEntries("
168                    "      {type: 'save-file'});"
169                    "  self.entry = e;"
170                    "  return e.name; })()"));
171   EXPECT_EQ(ui::SelectFileDialog::SELECT_SAVEAS_FILE, dialog_params.type);
172   EXPECT_EQ(int{file_contents.size()},
173             EvalJs(shell(),
174                    JsReplace("(async () => {"
175                              "  const w = await self.entry.createWritable();"
176                              "  await w.write(new Blob([$1]));"
177                              "  await w.close();"
178                              "  return (await self.entry.getFile()).size; })()",
179                              file_contents)));
180   {
181     base::ScopedAllowBlockingForTesting allow_blocking;
182     std::string read_contents;
183     EXPECT_TRUE(base::ReadFileToString(test_file, &read_contents));
184     EXPECT_EQ(file_contents, read_contents);
185   }
186 }
187 
IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest,SaveFile_TruncatesExistingFile)188 IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest,
189                        SaveFile_TruncatesExistingFile) {
190   const base::FilePath test_file = CreateTestFile("Hello World");
191 
192   SelectFileDialogParams dialog_params;
193   ui::SelectFileDialog::SetFactory(
194       new FakeSelectFileDialogFactory({test_file}, &dialog_params));
195   ASSERT_TRUE(
196       NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
197   EXPECT_EQ(test_file.BaseName().AsUTF8Unsafe(),
198             EvalJs(shell(),
199                    "(async () => {"
200                    "  let e = await self.chooseFileSystemEntries("
201                    "      {type: 'save-file'});"
202                    "  self.entry = e;"
203                    "  return e.name; })()"));
204   EXPECT_EQ(ui::SelectFileDialog::SELECT_SAVEAS_FILE, dialog_params.type);
205   EXPECT_EQ("",
206             EvalJs(shell(),
207                    "(async () => { const file = await self.entry.getFile(); "
208                    "return await file.text(); })()"));
209 }
210 
IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest,SaveFile_BlockedPermission)211 IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest,
212                        SaveFile_BlockedPermission) {
213   const base::FilePath test_file = CreateTestFile("Save File");
214   SelectFileDialogParams dialog_params;
215   ui::SelectFileDialog::SetFactory(
216       new FakeSelectFileDialogFactory({test_file}, &dialog_params));
217 
218   testing::StrictMock<MockNativeFileSystemPermissionContext> permission_context;
219   static_cast<NativeFileSystemManagerImpl*>(
220       BrowserContext::GetStoragePartition(
221           shell()->web_contents()->GetBrowserContext(),
222           shell()->web_contents()->GetSiteInstance())
223           ->GetNativeFileSystemEntryFactory())
224       ->SetPermissionContextForTesting(&permission_context);
225 
226   EXPECT_CALL(permission_context,
227               CanObtainWritePermission(url::Origin::Create(
228                   embedded_test_server()->GetURL("/title1.html"))))
229       .WillOnce(testing::Return(false));
230 
231   ASSERT_TRUE(
232       NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
233   auto result =
234       EvalJs(shell(), "self.chooseFileSystemEntries({type: 'save-file'})");
235   EXPECT_TRUE(result.error.find("not allowed") != std::string::npos)
236       << result.error;
237   EXPECT_EQ(ui::SelectFileDialog::SELECT_NONE, dialog_params.type);
238 }
239 
IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest,FullscreenSaveFile)240 IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest, FullscreenSaveFile) {
241   const base::FilePath test_file = CreateTestFile("Hello World");
242 
243   SelectFileDialogParams dialog_params;
244   ui::SelectFileDialog::SetFactory(
245       new FakeSelectFileDialogFactory({test_file}, &dialog_params));
246   ASSERT_TRUE(
247       NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
248   EnterFullscreen(embedded_test_server()->GetURL("/title1.html"));
249   EXPECT_EQ(test_file.BaseName().AsUTF8Unsafe(),
250             EvalJs(shell(),
251                    "(async () => {"
252                    "  let e = await self.chooseFileSystemEntries("
253                    "      {type: 'save-file'});"
254                    "  self.entry = e;"
255                    "  return e.name; })()"));
256   EXPECT_FALSE(IsFullscreen());
257 }
258 
IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest,OpenMultipleFiles)259 IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest, OpenMultipleFiles) {
260   const base::FilePath test_file1 = CreateTestFile("file1");
261   const base::FilePath test_file2 = CreateTestFile("file2");
262   SelectFileDialogParams dialog_params;
263   ui::SelectFileDialog::SetFactory(new FakeSelectFileDialogFactory(
264       {test_file1, test_file2}, &dialog_params));
265   ASSERT_TRUE(
266       NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
267   EXPECT_EQ(ListValueOf(test_file1.BaseName().AsUTF8Unsafe(),
268                         test_file2.BaseName().AsUTF8Unsafe()),
269             EvalJs(shell(),
270                    "(async () => {"
271                    "  let e = await self.chooseFileSystemEntries("
272                    "      {multiple: true});"
273                    "  return e.map(x => x.name); })()"));
274   EXPECT_EQ(ui::SelectFileDialog::SELECT_OPEN_MULTI_FILE, dialog_params.type);
275 }
276 
IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest,FullscreenOpenMultipleFiles)277 IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest,
278                        FullscreenOpenMultipleFiles) {
279   const base::FilePath test_file1 = CreateTestFile("file1");
280   const base::FilePath test_file2 = CreateTestFile("file2");
281   SelectFileDialogParams dialog_params;
282   ui::SelectFileDialog::SetFactory(new FakeSelectFileDialogFactory(
283       {test_file1, test_file2}, &dialog_params));
284   ASSERT_TRUE(
285       NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
286   EnterFullscreen(embedded_test_server()->GetURL("/title1.html"));
287   EXPECT_EQ(ListValueOf(test_file1.BaseName().AsUTF8Unsafe(),
288                         test_file2.BaseName().AsUTF8Unsafe()),
289             EvalJs(shell(),
290                    "(async () => {"
291                    "  let e = await self.chooseFileSystemEntries("
292                    "      {multiple: true});"
293                    "  return e.map(x => x.name); })()"));
294   EXPECT_FALSE(IsFullscreen());
295 }
296 
IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest,OpenDirectory)297 IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest, OpenDirectory) {
298   base::FilePath test_dir = CreateTestDir();
299   SelectFileDialogParams dialog_params;
300   ui::SelectFileDialog::SetFactory(
301       new FakeSelectFileDialogFactory({test_dir}, &dialog_params));
302   ASSERT_TRUE(
303       NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
304   EXPECT_EQ(test_dir.BaseName().AsUTF8Unsafe(),
305             EvalJs(shell(),
306                    "(async () => {"
307                    "  let e = await self.chooseFileSystemEntries("
308                    "      {type: 'open-directory'});"
309                    "  self.selected_entry = e;"
310                    "  return e.name; })()"));
311   EXPECT_EQ(ui::SelectFileDialog::SELECT_FOLDER, dialog_params.type);
312 }
313 
IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest,FullscreenOpenDirectory)314 IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest, FullscreenOpenDirectory) {
315   base::FilePath test_dir = CreateTestDir();
316   SelectFileDialogParams dialog_params;
317   ui::SelectFileDialog::SetFactory(
318       new FakeSelectFileDialogFactory({test_dir}, &dialog_params));
319   ASSERT_TRUE(
320       NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
321   EnterFullscreen(embedded_test_server()->GetURL("/title1.html"));
322   EXPECT_EQ(test_dir.BaseName().AsUTF8Unsafe(),
323             EvalJs(shell(),
324                    "(async () => {"
325                    "  let e = await self.chooseFileSystemEntries("
326                    "      {type: 'open-directory'});"
327                    "  self.selected_entry = e;"
328                    "  return e.name; })()"));
329   EXPECT_FALSE(IsFullscreen());
330 }
331 
IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest,OpenDirectory_DenyAccess)332 IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest, OpenDirectory_DenyAccess) {
333   base::FilePath test_dir = CreateTestDir();
334   SelectFileDialogParams dialog_params;
335   ui::SelectFileDialog::SetFactory(
336       new FakeSelectFileDialogFactory({test_dir}, &dialog_params));
337 
338   testing::StrictMock<MockNativeFileSystemPermissionContext> permission_context;
339   static_cast<NativeFileSystemManagerImpl*>(
340       BrowserContext::GetStoragePartition(
341           shell()->web_contents()->GetBrowserContext(),
342           shell()->web_contents()->GetSiteInstance())
343           ->GetNativeFileSystemEntryFactory())
344       ->SetPermissionContextForTesting(&permission_context);
345 
346   EXPECT_CALL(permission_context, ConfirmSensitiveDirectoryAccess_(
347                                       testing::_, testing::_, testing::_,
348                                       testing::_, testing::_, testing::_))
349       .WillOnce(RunOnceCallback<5>(SensitiveDirectoryResult::kAllowed));
350 
351   EXPECT_CALL(
352       permission_context,
353       ConfirmDirectoryReadAccess_(
354           url::Origin::Create(embedded_test_server()->GetURL("/title1.html")),
355           test_dir,
356           shell()->web_contents()->GetMainFrame()->GetProcess()->GetID(),
357           shell()->web_contents()->GetMainFrame()->GetRoutingID(), testing::_))
358       .WillOnce(RunOnceCallback<4>(PermissionStatus::DENIED));
359 
360   ASSERT_TRUE(
361       NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
362   auto result =
363       EvalJs(shell(), "self.chooseFileSystemEntries({type: 'open-directory'})");
364   EXPECT_TRUE(result.error.find("aborted") != std::string::npos)
365       << result.error;
366 }
367 
IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest,SaveFile_SensitiveDirectory_ExistingFile)368 IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest,
369                        SaveFile_SensitiveDirectory_ExistingFile) {
370   const std::string file_contents = "Hello World";
371   const base::FilePath test_file = CreateTestFile(file_contents);
372 
373   SelectFileDialogParams dialog_params;
374   ui::SelectFileDialog::SetFactory(
375       new FakeSelectFileDialogFactory({test_file}, &dialog_params));
376 
377   testing::StrictMock<MockNativeFileSystemPermissionContext> permission_context;
378   static_cast<NativeFileSystemManagerImpl*>(
379       BrowserContext::GetStoragePartition(
380           shell()->web_contents()->GetBrowserContext(),
381           shell()->web_contents()->GetSiteInstance())
382           ->GetNativeFileSystemEntryFactory())
383       ->SetPermissionContextForTesting(&permission_context);
384 
385   EXPECT_CALL(permission_context, ConfirmSensitiveDirectoryAccess_(
386                                       testing::_, testing::_, testing::_,
387                                       testing::_, testing::_, testing::_))
388       .WillOnce(RunOnceCallback<5>(SensitiveDirectoryResult::kAbort));
389 
390   EXPECT_CALL(permission_context,
391               CanObtainWritePermission(url::Origin::Create(
392                   embedded_test_server()->GetURL("/title1.html"))))
393       .WillOnce(testing::Return(true));
394 
395   ASSERT_TRUE(
396       NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
397   auto result =
398       EvalJs(shell(), "self.chooseFileSystemEntries({type: 'save-file'})");
399   EXPECT_TRUE(result.error.find("aborted") != std::string::npos)
400       << result.error;
401 
402   {
403     // File should still exist, and be unmodified.
404     base::ScopedAllowBlockingForTesting allow_blocking;
405     std::string read_contents;
406     EXPECT_TRUE(base::ReadFileToString(test_file, &read_contents));
407     EXPECT_EQ(file_contents, read_contents);
408   }
409 }
410 
IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest,SaveFile_SensitiveDirectory_NonExistingFile)411 IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest,
412                        SaveFile_SensitiveDirectory_NonExistingFile) {
413   const base::FilePath test_file = CreateTestFile("");
414   {
415     // Delete file, since SaveFile should be able to deal with non-existing
416     // files.
417     base::ScopedAllowBlockingForTesting allow_blocking;
418     ASSERT_TRUE(base::DeleteFile(test_file, false));
419   }
420 
421   SelectFileDialogParams dialog_params;
422   ui::SelectFileDialog::SetFactory(
423       new FakeSelectFileDialogFactory({test_file}, &dialog_params));
424 
425   testing::StrictMock<MockNativeFileSystemPermissionContext> permission_context;
426   static_cast<NativeFileSystemManagerImpl*>(
427       BrowserContext::GetStoragePartition(
428           shell()->web_contents()->GetBrowserContext(),
429           shell()->web_contents()->GetSiteInstance())
430           ->GetNativeFileSystemEntryFactory())
431       ->SetPermissionContextForTesting(&permission_context);
432 
433   EXPECT_CALL(permission_context, ConfirmSensitiveDirectoryAccess_(
434                                       testing::_, testing::_, testing::_,
435                                       testing::_, testing::_, testing::_))
436       .WillOnce(RunOnceCallback<5>(SensitiveDirectoryResult::kAbort));
437 
438   EXPECT_CALL(permission_context,
439               CanObtainWritePermission(url::Origin::Create(
440                   embedded_test_server()->GetURL("/title1.html"))))
441       .WillOnce(testing::Return(true));
442 
443   ASSERT_TRUE(
444       NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
445   auto result =
446       EvalJs(shell(), "self.chooseFileSystemEntries({type: 'save-file'})");
447   EXPECT_TRUE(result.error.find("aborted") != std::string::npos)
448       << result.error;
449 
450   {
451     // File should not have been created.
452     base::ScopedAllowBlockingForTesting allow_blocking;
453     EXPECT_FALSE(base::PathExists(test_file));
454   }
455 }
456 
IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest,AcceptsOptions)457 IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest, AcceptsOptions) {
458   SelectFileDialogParams dialog_params;
459   ui::SelectFileDialog::SetFactory(
460       new CancellingSelectFileDialogFactory(&dialog_params));
461   ASSERT_TRUE(
462       NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
463   auto result = EvalJs(shell(),
464                        "self.chooseFileSystemEntries({accepts: ["
465                        "  {description: 'no-extensions'},"
466                        "  {description: 'foo', extensions: ['txt', 'Js']},"
467                        "  {mimeTypes: ['image/jpeg']}"
468                        "]})");
469   EXPECT_TRUE(result.error.find("aborted") != std::string::npos)
470       << result.error;
471 
472   ASSERT_TRUE(dialog_params.file_types);
473   EXPECT_TRUE(dialog_params.file_types->include_all_files);
474   ASSERT_EQ(2u, dialog_params.file_types->extensions.size());
475   ASSERT_EQ(2u, dialog_params.file_types->extensions[0].size());
476   EXPECT_EQ(FILE_PATH_LITERAL("Js"),
477             dialog_params.file_types->extensions[0][0]);
478   EXPECT_EQ(FILE_PATH_LITERAL("txt"),
479             dialog_params.file_types->extensions[0][1]);
480   EXPECT_TRUE(base::Contains(dialog_params.file_types->extensions[1],
481                              FILE_PATH_LITERAL("jpg")));
482   EXPECT_TRUE(base::Contains(dialog_params.file_types->extensions[1],
483                              FILE_PATH_LITERAL("jpeg")));
484 
485   ASSERT_EQ(2u,
486             dialog_params.file_types->extension_description_overrides.size());
487   EXPECT_EQ(base::ASCIIToUTF16("foo"),
488             dialog_params.file_types->extension_description_overrides[0]);
489   EXPECT_EQ(base::ASCIIToUTF16(""),
490             dialog_params.file_types->extension_description_overrides[1]);
491 }
492 
IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest,NativeFileSystemUsageDisablesBackForwardCache)493 IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest,
494                        NativeFileSystemUsageDisablesBackForwardCache) {
495   BackForwardCacheDisabledTester tester;
496 
497   const base::FilePath test_file = CreateTestFile("file contents");
498   SelectFileDialogParams dialog_params;
499   ui::SelectFileDialog::SetFactory(
500       new FakeSelectFileDialogFactory({test_file}, &dialog_params));
501   ASSERT_TRUE(
502       NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
503   EXPECT_EQ(test_file.BaseName().AsUTF8Unsafe(),
504             EvalJs(shell(),
505                    "(async () => {"
506                    "  let e = await self.chooseFileSystemEntries();"
507                    "  self.selected_entry = e;"
508                    "  return e.name; })()"));
509   EXPECT_TRUE(tester.IsDisabledForFrameWithReason(
510       shell()->web_contents()->GetMainFrame()->GetProcess()->GetID(),
511       shell()->web_contents()->GetMainFrame()->GetRoutingID(),
512       "NativeFileSystem"));
513 }
514 
515 }  // namespace content
516