Infobar material design refresh: layout
[chromium-blink-merge.git] / chrome / browser / ui / views / select_file_dialog_extension_browsertest.cc
blob28a03e50fe4973cb45d1b3fa021734c12b30627a
1 // Copyright (c) 2012 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.
5 #include "chrome/browser/ui/views/select_file_dialog_extension.h"
7 #include "base/files/file_util.h"
8 #include "base/files/scoped_temp_dir.h"
9 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/path_service.h"
12 #include "base/prefs/pref_service.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/threading/platform_thread.h"
15 #include "build/build_config.h"
16 #include "chrome/browser/chromeos/file_manager/volume_manager.h"
17 #include "chrome/browser/extensions/component_loader.h"
18 #include "chrome/browser/extensions/extension_browsertest.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/ui/browser.h"
21 #include "chrome/browser/ui/browser_navigator.h"
22 #include "chrome/browser/ui/browser_window.h"
23 #include "chrome/common/chrome_paths.h"
24 #include "chrome/common/pref_names.h"
25 #include "content/public/browser/render_frame_host.h"
26 #include "content/public/browser/render_view_host.h"
27 #include "content/public/test/test_utils.h"
28 #include "extensions/test/extension_test_message_listener.h"
29 #include "ui/shell_dialogs/select_file_dialog.h"
30 #include "ui/shell_dialogs/selected_file_info.h"
32 using content::BrowserContext;
34 // Mock listener used by test below.
35 class MockSelectFileDialogListener : public ui::SelectFileDialog::Listener {
36 public:
37 MockSelectFileDialogListener()
38 : file_selected_(false),
39 canceled_(false),
40 params_(NULL) {
43 bool file_selected() const { return file_selected_; }
44 bool canceled() const { return canceled_; }
45 base::FilePath path() const { return path_; }
46 void* params() const { return params_; }
48 // ui::SelectFileDialog::Listener implementation.
49 void FileSelected(const base::FilePath& path,
50 int index,
51 void* params) override {
52 file_selected_ = true;
53 path_ = path;
54 params_ = params;
55 QuitMessageLoop();
57 void FileSelectedWithExtraInfo(const ui::SelectedFileInfo& selected_file_info,
58 int index,
59 void* params) override {
60 FileSelected(selected_file_info.local_path, index, params);
62 void MultiFilesSelected(const std::vector<base::FilePath>& files,
63 void* params) override {
64 QuitMessageLoop();
66 void FileSelectionCanceled(void* params) override {
67 canceled_ = true;
68 params_ = params;
69 QuitMessageLoop();
72 void WaitForCalled() {
73 message_loop_runner_ = new content::MessageLoopRunner();
74 message_loop_runner_->Run();
77 private:
78 void QuitMessageLoop() {
79 if (message_loop_runner_.get())
80 message_loop_runner_->Quit();
83 bool file_selected_;
84 bool canceled_;
85 base::FilePath path_;
86 void* params_;
87 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
89 DISALLOW_COPY_AND_ASSIGN(MockSelectFileDialogListener);
92 class SelectFileDialogExtensionBrowserTest : public ExtensionBrowserTest {
93 public:
94 enum DialogButtonType {
95 DIALOG_BTN_OK,
96 DIALOG_BTN_CANCEL
99 void SetUp() override {
100 extensions::ComponentLoader::EnableBackgroundExtensionsForTesting();
102 // Create the dialog wrapper object, but don't show it yet.
103 listener_.reset(new MockSelectFileDialogListener());
104 dialog_ = new SelectFileDialogExtension(listener_.get(), NULL);
106 // We have to provide at least one mount point.
107 // File manager looks for "Downloads" mount point, so use this name.
108 base::FilePath tmp_path;
109 PathService::Get(base::DIR_TEMP, &tmp_path);
110 ASSERT_TRUE(tmp_dir_.CreateUniqueTempDirUnderPath(tmp_path));
111 downloads_dir_ = tmp_dir_.path().Append("Downloads");
112 base::CreateDirectory(downloads_dir_);
114 // Must run after our setup because it actually runs the test.
115 ExtensionBrowserTest::SetUp();
118 void TearDown() override {
119 ExtensionBrowserTest::TearDown();
121 // Delete the dialog first, as it holds a pointer to the listener.
122 dialog_ = NULL;
123 listener_.reset();
125 second_dialog_ = NULL;
126 second_listener_.reset();
129 // Creates a file system mount point for a directory.
130 void AddMountPoint(const base::FilePath& path) {
131 EXPECT_TRUE(file_manager::VolumeManager::Get(
132 browser()->profile())->RegisterDownloadsDirectoryForTesting(path));
133 browser()->profile()->GetPrefs()->SetFilePath(
134 prefs::kDownloadDefaultDirectory, downloads_dir_);
137 void CheckJavascriptErrors() {
138 content::RenderFrameHost* host =
139 dialog_->GetRenderViewHost()->GetMainFrame();
140 scoped_ptr<base::Value> value =
141 content::ExecuteScriptAndGetValue(host, "window.JSErrorCount");
142 int js_error_count = 0;
143 ASSERT_TRUE(value->GetAsInteger(&js_error_count));
144 ASSERT_EQ(0, js_error_count);
147 void OpenDialog(ui::SelectFileDialog::Type dialog_type,
148 const base::FilePath& file_path,
149 const gfx::NativeWindow& owning_window,
150 const std::string& additional_message) {
151 // Spawn a dialog to open a file. The dialog will signal that it is ready
152 // via chrome.test.sendMessage() in the extension JavaScript.
153 ExtensionTestMessageListener init_listener("ready", false /* will_reply */);
155 scoped_ptr<ExtensionTestMessageListener> additional_listener;
156 if (!additional_message.empty()) {
157 additional_listener.reset(
158 new ExtensionTestMessageListener(additional_message, false));
161 dialog_->SelectFile(dialog_type,
162 base::string16() /* title */,
163 file_path,
164 NULL /* file_types */,
165 0 /* file_type_index */,
166 FILE_PATH_LITERAL("") /* default_extension */,
167 owning_window,
168 this /* params */);
170 LOG(INFO) << "Waiting for JavaScript ready message.";
171 ASSERT_TRUE(init_listener.WaitUntilSatisfied());
173 if (additional_listener.get()) {
174 LOG(INFO) << "Waiting for JavaScript " << additional_message
175 << " message.";
176 ASSERT_TRUE(additional_listener->WaitUntilSatisfied());
179 // Dialog should be running now.
180 ASSERT_TRUE(dialog_->IsRunning(owning_window));
182 ASSERT_NO_FATAL_FAILURE(CheckJavascriptErrors());
185 void TryOpeningSecondDialog(const gfx::NativeWindow& owning_window) {
186 second_listener_.reset(new MockSelectFileDialogListener());
187 second_dialog_ = new SelectFileDialogExtension(second_listener_.get(),
188 NULL);
190 // At the moment we don't really care about dialog type, but we have to put
191 // some dialog type.
192 second_dialog_->SelectFile(ui::SelectFileDialog::SELECT_OPEN_FILE,
193 base::string16() /* title */,
194 base::FilePath() /* default_path */,
195 NULL /* file_types */,
196 0 /* file_type_index */,
197 FILE_PATH_LITERAL("") /* default_extension */,
198 owning_window,
199 this /* params */);
202 void CloseDialog(DialogButtonType button_type,
203 const gfx::NativeWindow& owning_window) {
204 // Inject JavaScript to click the cancel button and wait for notification
205 // that the window has closed.
206 content::RenderViewHost* host = dialog_->GetRenderViewHost();
207 std::string button_class =
208 (button_type == DIALOG_BTN_OK) ? ".button-panel .ok" :
209 ".button-panel .cancel";
210 base::string16 script = base::ASCIIToUTF16(
211 "console.log(\'Test JavaScript injected.\');"
212 "document.querySelector(\'" + button_class + "\').click();");
213 // The file selection handler closes the dialog and does not return control
214 // to JavaScript, so do not wait for return values.
215 host->GetMainFrame()->ExecuteJavaScriptForTests(script);
216 LOG(INFO) << "Waiting for window close notification.";
217 listener_->WaitForCalled();
219 // Dialog no longer believes it is running.
220 ASSERT_FALSE(dialog_->IsRunning(owning_window));
223 scoped_ptr<MockSelectFileDialogListener> listener_;
224 scoped_refptr<SelectFileDialogExtension> dialog_;
226 scoped_ptr<MockSelectFileDialogListener> second_listener_;
227 scoped_refptr<SelectFileDialogExtension> second_dialog_;
229 base::ScopedTempDir tmp_dir_;
230 base::FilePath downloads_dir_;
233 IN_PROC_BROWSER_TEST_F(SelectFileDialogExtensionBrowserTest, CreateAndDestroy) {
234 // Browser window must be up for us to test dialog window parent.
235 gfx::NativeWindow native_window = browser()->window()->GetNativeWindow();
236 ASSERT_TRUE(native_window != NULL);
238 // Before we call SelectFile, dialog is not running/visible.
239 ASSERT_FALSE(dialog_->IsRunning(native_window));
242 IN_PROC_BROWSER_TEST_F(SelectFileDialogExtensionBrowserTest, DestroyListener) {
243 // Some users of SelectFileDialog destroy their listener before cleaning
244 // up the dialog. Make sure we don't crash.
245 dialog_->ListenerDestroyed();
246 listener_.reset();
249 // TODO(jamescook): Add a test for selecting a file for an <input type='file'/>
250 // page element, as that uses different memory management pathways.
251 // crbug.com/98791
253 // Flaky on Chrome OS, see: http://crbug.com/477360
254 #if defined(OS_CHROMEOS)
255 #define MAYBE_SelectFileAndCancel DISABLED_SelectFileAndCancel
256 #else
257 #define MAYBE_SelectFileAndCancel SelectFileAndCancel
258 #endif
259 IN_PROC_BROWSER_TEST_F(SelectFileDialogExtensionBrowserTest,
260 MAYBE_SelectFileAndCancel) {
261 AddMountPoint(downloads_dir_);
263 gfx::NativeWindow owning_window = browser()->window()->GetNativeWindow();
265 // base::FilePath() for default path.
266 ASSERT_NO_FATAL_FAILURE(OpenDialog(ui::SelectFileDialog::SELECT_OPEN_FILE,
267 base::FilePath(), owning_window, ""));
269 // Press cancel button.
270 CloseDialog(DIALOG_BTN_CANCEL, owning_window);
272 // Listener should have been informed of the cancellation.
273 ASSERT_FALSE(listener_->file_selected());
274 ASSERT_TRUE(listener_->canceled());
275 ASSERT_EQ(this, listener_->params());
278 // Flaky on Chrome OS, see: http://crbug.com/477360
279 #if defined(OS_CHROMEOS)
280 #define MAYBE_SelectFileAndOpen DISABLED_SelectFileAndOpen
281 #else
282 #define MAYBE_SelectFileAndOpen SelectFileAndOpen
283 #endif
284 IN_PROC_BROWSER_TEST_F(SelectFileDialogExtensionBrowserTest,
285 MAYBE_SelectFileAndOpen) {
286 AddMountPoint(downloads_dir_);
288 base::FilePath test_file =
289 downloads_dir_.AppendASCII("file_manager_test.html");
291 // Create an empty file to give us something to select.
292 FILE* fp = base::OpenFile(test_file, "w");
293 ASSERT_TRUE(fp != NULL);
294 ASSERT_TRUE(base::CloseFile(fp));
296 gfx::NativeWindow owning_window = browser()->window()->GetNativeWindow();
298 // Spawn a dialog to open a file. Provide the path to the file so the dialog
299 // will automatically select it. Ensure that the OK button is enabled by
300 // waiting for chrome.test.sendMessage('selection-change-complete').
301 ASSERT_NO_FATAL_FAILURE(OpenDialog(ui::SelectFileDialog::SELECT_OPEN_FILE,
302 test_file, owning_window,
303 "dialog-ready"));
305 // Click open button.
306 CloseDialog(DIALOG_BTN_OK, owning_window);
308 // Listener should have been informed that the file was opened.
309 ASSERT_TRUE(listener_->file_selected());
310 ASSERT_FALSE(listener_->canceled());
311 ASSERT_EQ(test_file, listener_->path());
312 ASSERT_EQ(this, listener_->params());
315 // Flaky on Chrome OS, see: http://crbug.com/477360
316 #if defined(OS_CHROMEOS)
317 #define MAYBE_SelectFileAndSave DISABLED_SelectFileAndSave
318 #else
319 #define MAYBE_SelectFileAndSave SelectFileAndSave
320 #endif
321 IN_PROC_BROWSER_TEST_F(SelectFileDialogExtensionBrowserTest,
322 MAYBE_SelectFileAndSave) {
323 AddMountPoint(downloads_dir_);
325 base::FilePath test_file =
326 downloads_dir_.AppendASCII("file_manager_test.html");
328 gfx::NativeWindow owning_window = browser()->window()->GetNativeWindow();
330 // Spawn a dialog to save a file, providing a suggested path.
331 // Ensure "Save" button is enabled by waiting for notification from
332 // chrome.test.sendMessage().
333 ASSERT_NO_FATAL_FAILURE(OpenDialog(ui::SelectFileDialog::SELECT_SAVEAS_FILE,
334 test_file, owning_window,
335 "dialog-ready"));
337 // Click save button.
338 CloseDialog(DIALOG_BTN_OK, owning_window);
340 // Listener should have been informed that the file was selected.
341 ASSERT_TRUE(listener_->file_selected());
342 ASSERT_FALSE(listener_->canceled());
343 ASSERT_EQ(test_file, listener_->path());
344 ASSERT_EQ(this, listener_->params());
347 // Flaky on Chrome OS, see: http://crbug.com/477360
348 #if defined(OS_CHROMEOS)
349 #define MAYBE_OpenSingletonTabAndCancel DISABLED_OpenSingletonTabAndCancel
350 #else
351 #define MAYBE_OpenSingletonTabAndCancel OpenSingletonTabAndCancel
352 #endif
353 IN_PROC_BROWSER_TEST_F(SelectFileDialogExtensionBrowserTest,
354 MAYBE_OpenSingletonTabAndCancel) {
355 AddMountPoint(downloads_dir_);
357 gfx::NativeWindow owning_window = browser()->window()->GetNativeWindow();
359 ASSERT_NO_FATAL_FAILURE(OpenDialog(ui::SelectFileDialog::SELECT_OPEN_FILE,
360 base::FilePath(), owning_window, ""));
362 // Open a singleton tab in background.
363 chrome::NavigateParams p(browser(), GURL("http://www.google.com"),
364 ui::PAGE_TRANSITION_LINK);
365 p.window_action = chrome::NavigateParams::SHOW_WINDOW;
366 p.disposition = SINGLETON_TAB;
367 chrome::Navigate(&p);
369 // Press cancel button.
370 CloseDialog(DIALOG_BTN_CANCEL, owning_window);
372 // Listener should have been informed of the cancellation.
373 ASSERT_FALSE(listener_->file_selected());
374 ASSERT_TRUE(listener_->canceled());
375 ASSERT_EQ(this, listener_->params());
378 // Flaky on Chrome OS, see: http://crbug.com/477360
379 #if defined(OS_CHROMEOS)
380 #define MAYBE_OpenTwoDialogs DISABLED_OpenTwoDialogs
381 #else
382 #define MAYBE_OpenTwoDialogs OpenTwoDialogs
383 #endif
384 IN_PROC_BROWSER_TEST_F(SelectFileDialogExtensionBrowserTest,
385 MAYBE_OpenTwoDialogs) {
386 AddMountPoint(downloads_dir_);
388 gfx::NativeWindow owning_window = browser()->window()->GetNativeWindow();
390 ASSERT_NO_FATAL_FAILURE(OpenDialog(ui::SelectFileDialog::SELECT_OPEN_FILE,
391 base::FilePath(), owning_window, ""));
393 TryOpeningSecondDialog(owning_window);
395 // Second dialog should not be running.
396 ASSERT_FALSE(second_dialog_->IsRunning(owning_window));
398 // Click cancel button.
399 CloseDialog(DIALOG_BTN_CANCEL, owning_window);
401 // Listener should have been informed of the cancellation.
402 ASSERT_FALSE(listener_->file_selected());
403 ASSERT_TRUE(listener_->canceled());
404 ASSERT_EQ(this, listener_->params());