15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/select_file_dialog_extension.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/scoped_temp_dir.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/path_service.h"
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/prefs/pref_service.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/platform_thread.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "build/build_config.h"
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/chromeos/file_manager/volume_manager.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/component_loader.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_browsertest.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser_navigator.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser_window.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_paths.h"
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/common/pref_names.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_service.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_types.h"
27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/public/browser/render_frame_host.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_view_host.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/test/test_utils.h"
301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/test/extension_test_message_listener.h"
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/shell_dialogs/select_file_dialog.h"
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/shell_dialogs/selected_file_info.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserContext;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Mock listener used by test below.
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MockSelectFileDialogListener : public ui::SelectFileDialog::Listener {
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MockSelectFileDialogListener()
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : file_selected_(false),
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      canceled_(false),
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      params_(NULL) {
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool file_selected() const { return file_selected_; }
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool canceled() const { return canceled_; }
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath path() const { return path_; }
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void* params() const { return params_; }
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ui::SelectFileDialog::Listener implementation.
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void FileSelected(const base::FilePath& path,
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            int index,
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            void* params) OVERRIDE {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    file_selected_ = true;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    path_ = path;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    params_ = params;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void FileSelectedWithExtraInfo(
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const ui::SelectedFileInfo& selected_file_info,
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int index,
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      void* params) OVERRIDE {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FileSelected(selected_file_info.local_path, index, params);
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void MultiFilesSelected(
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const std::vector<base::FilePath>& files, void* params) OVERRIDE {}
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void FileSelectionCanceled(void* params) OVERRIDE {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    canceled_ = true;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    params_ = params;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool file_selected_;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool canceled_;
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath path_;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void* params_;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(MockSelectFileDialogListener);
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SelectFileDialogExtensionBrowserTest : public ExtensionBrowserTest {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enum DialogButtonType {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DIALOG_BTN_OK,
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DIALOG_BTN_CANCEL
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void SetUp() OVERRIDE {
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    extensions::ComponentLoader::EnableBackgroundExtensionsForTesting();
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Create the dialog wrapper object, but don't show it yet.
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    listener_.reset(new MockSelectFileDialogListener());
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dialog_ = new SelectFileDialogExtension(listener_.get(), NULL);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We have to provide at least one mount point.
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // File manager looks for "Downloads" mount point, so use this name.
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath tmp_path;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PathService::Get(base::DIR_TEMP, &tmp_path);
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT_TRUE(tmp_dir_.CreateUniqueTempDirUnderPath(tmp_path));
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    downloads_dir_ = tmp_dir_.path().Append("Downloads");
100a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    base::CreateDirectory(downloads_dir_);
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Must run after our setup because it actually runs the test.
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ExtensionBrowserTest::SetUp();
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void TearDown() OVERRIDE {
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ExtensionBrowserTest::TearDown();
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Delete the dialog first, as it holds a pointer to the listener.
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dialog_ = NULL;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    listener_.reset();
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    second_dialog_ = NULL;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    second_listener_.reset();
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Creates a file system mount point for a directory.
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void AddMountPoint(const base::FilePath& path) {
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_TRUE(file_manager::VolumeManager::Get(
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        browser()->profile())->RegisterDownloadsDirectoryForTesting(path));
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    browser()->profile()->GetPrefs()->SetFilePath(
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        prefs::kDownloadDefaultDirectory, downloads_dir_);
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void CheckJavascriptErrors() {
126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    content::RenderFrameHost* host =
127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        dialog_->GetRenderViewHost()->GetMainFrame();
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<base::Value> value =
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        content::ExecuteScriptAndGetValue(host, "window.JSErrorCount");
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int js_error_count = 0;
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ASSERT_TRUE(value->GetAsInteger(&js_error_count));
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ASSERT_EQ(0, js_error_count);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void OpenDialog(ui::SelectFileDialog::Type dialog_type,
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                  const base::FilePath& file_path,
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  const gfx::NativeWindow& owning_window,
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  const std::string& additional_message) {
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Spawn a dialog to open a file.  The dialog will signal that it is ready
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // via chrome.test.sendMessage() in the extension JavaScript.
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ExtensionTestMessageListener init_listener("worker-initialized",
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               false /* will_reply */);
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<ExtensionTestMessageListener> additional_listener;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!additional_message.empty()) {
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      additional_listener.reset(
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          new ExtensionTestMessageListener(additional_message, false));
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dialog_->SelectFile(dialog_type,
151a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                        base::string16() /* title */,
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        file_path,
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        NULL /* file_types */,
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         0 /* file_type_index */,
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        FILE_PATH_LITERAL("") /* default_extension */,
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        owning_window,
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        this /* params */);
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(INFO) << "Waiting for JavaScript ready message.";
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT_TRUE(init_listener.WaitUntilSatisfied());
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (additional_listener.get()) {
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(INFO) << "Waiting for JavaScript " << additional_message
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                << " message.";
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ASSERT_TRUE(additional_listener->WaitUntilSatisfied());
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Dialog should be running now.
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT_TRUE(dialog_->IsRunning(owning_window));
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ASSERT_NO_FATAL_FAILURE(CheckJavascriptErrors());
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void TryOpeningSecondDialog(const gfx::NativeWindow& owning_window) {
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    second_listener_.reset(new MockSelectFileDialogListener());
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    second_dialog_ = new SelectFileDialogExtension(second_listener_.get(),
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   NULL);
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // At the moment we don't really care about dialog type, but we have to put
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // some dialog type.
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    second_dialog_->SelectFile(ui::SelectFileDialog::SELECT_OPEN_FILE,
182a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                               base::string16() /* title */,
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               base::FilePath() /* default_path */,
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               NULL /* file_types */,
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               0 /* file_type_index */,
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               FILE_PATH_LITERAL("") /* default_extension */,
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               owning_window,
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               this /* params */);
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void CloseDialog(DialogButtonType button_type,
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   const gfx::NativeWindow& owning_window) {
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Inject JavaScript to click the cancel button and wait for notification
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // that the window has closed.
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::WindowedNotificationObserver host_destroyed(
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED,
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::NotificationService::AllSources());
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::RenderViewHost* host = dialog_->GetRenderViewHost();
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string button_class =
200eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        (button_type == DIALOG_BTN_OK) ? ".button-panel .ok" :
201eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                         ".button-panel .cancel";
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::string16 script = base::ASCIIToUTF16(
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "console.log(\'Test JavaScript injected.\');"
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "document.querySelector(\'" + button_class + "\').click();");
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The file selection handler closes the dialog and does not return control
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // to JavaScript, so do not wait for return values.
207a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    host->GetMainFrame()->ExecuteJavaScript(script);
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(INFO) << "Waiting for window close notification.";
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    host_destroyed.Wait();
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Dialog no longer believes it is running.
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT_FALSE(dialog_->IsRunning(owning_window));
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<MockSelectFileDialogListener> listener_;
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<SelectFileDialogExtension> dialog_;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<MockSelectFileDialogListener> second_listener_;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<SelectFileDialogExtension> second_dialog_;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ScopedTempDir tmp_dir_;
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath downloads_dir_;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(SelectFileDialogExtensionBrowserTest, CreateAndDestroy) {
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Browser window must be up for us to test dialog window parent.
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::NativeWindow native_window = browser()->window()->GetNativeWindow();
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(native_window != NULL);
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Before we call SelectFile, dialog is not running/visible.
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_FALSE(dialog_->IsRunning(native_window));
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(SelectFileDialogExtensionBrowserTest, DestroyListener) {
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Some users of SelectFileDialog destroy their listener before cleaning
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // up the dialog.  Make sure we don't crash.
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dialog_->ListenerDestroyed();
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  listener_.reset();
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(jamescook): Add a test for selecting a file for an <input type='file'/>
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// page element, as that uses different memory management pathways.
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// crbug.com/98791
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(SelectFileDialogExtensionBrowserTest,
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       SelectFileAndCancel) {
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddMountPoint(downloads_dir_);
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::NativeWindow owning_window = browser()->window()->GetNativeWindow();
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // base::FilePath() for default path.
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_NO_FATAL_FAILURE(OpenDialog(ui::SelectFileDialog::SELECT_OPEN_FILE,
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     base::FilePath(), owning_window, ""));
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Press cancel button.
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseDialog(DIALOG_BTN_CANCEL, owning_window);
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Listener should have been informed of the cancellation.
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_FALSE(listener_->file_selected());
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(listener_->canceled());
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_EQ(this, listener_->params());
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(SelectFileDialogExtensionBrowserTest,
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       SelectFileAndOpen) {
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddMountPoint(downloads_dir_);
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath test_file =
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      downloads_dir_.AppendASCII("file_manager_test.html");
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create an empty file to give us something to select.
272a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  FILE* fp = base::OpenFile(test_file, "w");
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(fp != NULL);
274a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ASSERT_TRUE(base::CloseFile(fp));
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::NativeWindow owning_window = browser()->window()->GetNativeWindow();
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Spawn a dialog to open a file.  Provide the path to the file so the dialog
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will automatically select it.  Ensure that the OK button is enabled by
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // waiting for chrome.test.sendMessage('selection-change-complete').
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The extension starts a Web Worker to read file metadata, so it may send
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 'selection-change-complete' before 'worker-initialized'.  This is OK.
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_NO_FATAL_FAILURE(OpenDialog(ui::SelectFileDialog::SELECT_OPEN_FILE,
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     test_file, owning_window,
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     "selection-change-complete"));
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Click open button.
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseDialog(DIALOG_BTN_OK, owning_window);
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Listener should have been informed that the file was opened.
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(listener_->file_selected());
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_FALSE(listener_->canceled());
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_EQ(test_file, listener_->path());
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_EQ(this, listener_->params());
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(SelectFileDialogExtensionBrowserTest,
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       SelectFileAndSave) {
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddMountPoint(downloads_dir_);
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath test_file =
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      downloads_dir_.AppendASCII("file_manager_test.html");
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::NativeWindow owning_window = browser()->window()->GetNativeWindow();
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Spawn a dialog to save a file, providing a suggested path.
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Ensure "Save" button is enabled by waiting for notification from
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // chrome.test.sendMessage().
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The extension starts a Web Worker to read file metadata, so it may send
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 'directory-change-complete' before 'worker-initialized'.  This is OK.
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_NO_FATAL_FAILURE(OpenDialog(ui::SelectFileDialog::SELECT_SAVEAS_FILE,
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     test_file, owning_window,
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     "directory-change-complete"));
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Click save button.
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseDialog(DIALOG_BTN_OK, owning_window);
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Listener should have been informed that the file was selected.
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(listener_->file_selected());
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_FALSE(listener_->canceled());
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_EQ(test_file, listener_->path());
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_EQ(this, listener_->params());
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(SelectFileDialogExtensionBrowserTest,
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       OpenSingletonTabAndCancel) {
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddMountPoint(downloads_dir_);
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::NativeWindow owning_window = browser()->window()->GetNativeWindow();
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_NO_FATAL_FAILURE(OpenDialog(ui::SelectFileDialog::SELECT_OPEN_FILE,
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     base::FilePath(), owning_window, ""));
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Open a singleton tab in background.
335cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  chrome::NavigateParams p(browser(), GURL("http://www.google.com"),
3361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                           ui::PAGE_TRANSITION_LINK);
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p.window_action = chrome::NavigateParams::SHOW_WINDOW;
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p.disposition = SINGLETON_TAB;
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  chrome::Navigate(&p);
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Press cancel button.
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseDialog(DIALOG_BTN_CANCEL, owning_window);
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Listener should have been informed of the cancellation.
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_FALSE(listener_->file_selected());
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(listener_->canceled());
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_EQ(this, listener_->params());
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(SelectFileDialogExtensionBrowserTest,
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       OpenTwoDialogs) {
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddMountPoint(downloads_dir_);
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::NativeWindow owning_window = browser()->window()->GetNativeWindow();
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_NO_FATAL_FAILURE(OpenDialog(ui::SelectFileDialog::SELECT_OPEN_FILE,
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     base::FilePath(), owning_window, ""));
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TryOpeningSecondDialog(owning_window);
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Second dialog should not be running.
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_FALSE(second_dialog_->IsRunning(owning_window));
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Click cancel button.
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseDialog(DIALOG_BTN_CANCEL, owning_window);
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Listener should have been informed of the cancellation.
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_FALSE(listener_->file_selected());
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(listener_->canceled());
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_EQ(this, listener_->params());
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
372