// Copyright (c) 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Browser test for basic Chrome OS file manager functionality: // - The file list is updated when a file is added externally to the Downloads // folder. // - Selecting a file and copy-pasting it with the keyboard copies the file. // - Selecting a file and pressing delete deletes it. #include #include #include "base/bind.h" #include "base/callback.h" #include "base/file_util.h" #include "base/files/file_path.h" #include "base/json/json_reader.h" #include "base/json/json_value_converter.h" #include "base/json/json_writer.h" #include "base/strings/string_piece.h" #include "base/time/time.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/chromeos/drive/drive_integration_service.h" #include "chrome/browser/chromeos/drive/file_system_interface.h" #include "chrome/browser/chromeos/drive/test_util.h" #include "chrome/browser/chromeos/file_manager/drive_test_util.h" #include "chrome/browser/chromeos/file_manager/path_util.h" #include "chrome/browser/drive/fake_drive_service.h" #include "chrome/browser/extensions/api/test/test_api.h" #include "chrome/browser/extensions/component_loader.h" #include "chrome/browser/extensions/extension_apitest.h" #include "chrome/browser/extensions/extension_test_message_listener.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/chrome_switches.h" #include "chromeos/chromeos_switches.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/notification_service.h" #include "content/public/test/test_utils.h" #include "extensions/common/extension.h" #include "google_apis/drive/gdata_wapi_parser.h" #include "google_apis/drive/test_util.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "webkit/browser/fileapi/external_mount_points.h" using drive::DriveIntegrationServiceFactory; namespace file_manager { namespace { enum EntryType { FILE, DIRECTORY, }; enum TargetVolume { LOCAL_VOLUME, DRIVE_VOLUME, }; enum SharedOption { NONE, SHARED, }; enum GuestMode { NOT_IN_GUEST_MODE, IN_GUEST_MODE, }; // This global operator is used from Google Test to format error messages. std::ostream& operator<<(std::ostream& os, const GuestMode& guest_mode) { return os << (guest_mode == IN_GUEST_MODE ? "IN_GUEST_MODE" : "NOT_IN_GUEST_MODE"); } // Maps the given string to EntryType. Returns true on success. bool MapStringToEntryType(const base::StringPiece& value, EntryType* output) { if (value == "file") *output = FILE; else if (value == "directory") *output = DIRECTORY; else return false; return true; } // Maps the given string to SharedOption. Returns true on success. bool MapStringToSharedOption(const base::StringPiece& value, SharedOption* output) { if (value == "shared") *output = SHARED; else if (value == "none") *output = NONE; else return false; return true; } // Maps the given string to TargetVolume. Returns true on success. bool MapStringToTargetVolume(const base::StringPiece& value, TargetVolume* output) { if (value == "drive") *output = DRIVE_VOLUME; else if (value == "local") *output = LOCAL_VOLUME; else return false; return true; } // Maps the given string to base::Time. Returns true on success. bool MapStringToTime(const base::StringPiece& value, base::Time* time) { return base::Time::FromString(value.as_string().c_str(), time); } // Test data of file or directory. struct TestEntryInfo { TestEntryInfo() : type(FILE), shared_option(NONE) {} TestEntryInfo(EntryType type, const std::string& source_file_name, const std::string& target_path, const std::string& mime_type, SharedOption shared_option, const base::Time& last_modified_time) : type(type), source_file_name(source_file_name), target_path(target_path), mime_type(mime_type), shared_option(shared_option), last_modified_time(last_modified_time) { } EntryType type; std::string source_file_name; // Source file name to be used as a prototype. std::string target_path; // Target file or directory path. std::string mime_type; SharedOption shared_option; base::Time last_modified_time; // Registers the member information to the given converter. static void RegisterJSONConverter( base::JSONValueConverter* converter); }; // static void TestEntryInfo::RegisterJSONConverter( base::JSONValueConverter* converter) { converter->RegisterCustomField("type", &TestEntryInfo::type, &MapStringToEntryType); converter->RegisterStringField("sourceFileName", &TestEntryInfo::source_file_name); converter->RegisterStringField("targetPath", &TestEntryInfo::target_path); converter->RegisterStringField("mimeType", &TestEntryInfo::mime_type); converter->RegisterCustomField("sharedOption", &TestEntryInfo::shared_option, &MapStringToSharedOption); converter->RegisterCustomField("lastModifiedTime", &TestEntryInfo::last_modified_time, &MapStringToTime); } // Message from JavaScript to add entries. struct AddEntriesMessage { // Target volume to be added the |entries|. TargetVolume volume; // Entries to be added. ScopedVector entries; // Registers the member information to the given converter. static void RegisterJSONConverter( base::JSONValueConverter* converter); }; // static void AddEntriesMessage::RegisterJSONConverter( base::JSONValueConverter* converter) { converter->RegisterCustomField("volume", &AddEntriesMessage::volume, &MapStringToTargetVolume); converter->RegisterRepeatedMessage( "entries", &AddEntriesMessage::entries); } // The local volume class for test. // This class provides the operations for a test volume that simulates local // drive. class LocalTestVolume { public: // Adds this volume to the file system as a local volume. Returns true on // success. bool Mount(Profile* profile) { if (local_path_.empty()) { if (!tmp_dir_.CreateUniqueTempDir()) return false; local_path_ = tmp_dir_.path().Append("Downloads"); } return util::RegisterDownloadsMountPoint(profile, local_path_) && base::CreateDirectory(local_path_); } void CreateEntry(const TestEntryInfo& entry) { const base::FilePath target_path = local_path_.AppendASCII(entry.target_path); entries_.insert(std::make_pair(target_path, entry)); switch (entry.type) { case FILE: { const base::FilePath source_path = google_apis::test_util::GetTestFilePath("chromeos/file_manager"). AppendASCII(entry.source_file_name); ASSERT_TRUE(base::CopyFile(source_path, target_path)) << "Copy from " << source_path.value() << " to " << target_path.value() << " failed."; break; } case DIRECTORY: ASSERT_TRUE(base::CreateDirectory(target_path)) << "Failed to create a directory: " << target_path.value(); break; } ASSERT_TRUE(UpdateModifiedTime(entry)); } private: // Updates ModifiedTime of the entry and its parents by referring // TestEntryInfo. Returns true on success. bool UpdateModifiedTime(const TestEntryInfo& entry) { const base::FilePath path = local_path_.AppendASCII(entry.target_path); if (!base::TouchFile(path, entry.last_modified_time, entry.last_modified_time)) return false; // Update the modified time of parent directories because it may be also // affected by the update of child items. if (path.DirName() != local_path_) { const std::map::iterator it = entries_.find(path.DirName()); if (it == entries_.end()) return false; return UpdateModifiedTime(it->second); } return true; } base::FilePath local_path_; base::ScopedTempDir tmp_dir_; std::map entries_; }; // The drive volume class for test. // This class provides the operations for a test volume that simulates Google // drive. class DriveTestVolume { public: DriveTestVolume() : fake_drive_service_(NULL), integration_service_(NULL) { } // Sends request to add this volume to the file system as Google drive. // This method must be called at SetUp method of FileManagerBrowserTestBase. // Returns true on success. bool SetUp() { if (!test_cache_root_.CreateUniqueTempDir()) return false; create_drive_integration_service_ = base::Bind(&DriveTestVolume::CreateDriveIntegrationService, base::Unretained(this)); service_factory_for_test_.reset( new DriveIntegrationServiceFactory::ScopedFactoryForTest( &create_drive_integration_service_)); return true; } void CreateEntry(const TestEntryInfo& entry) { const base::FilePath path = base::FilePath::FromUTF8Unsafe(entry.target_path); const std::string target_name = path.BaseName().AsUTF8Unsafe(); // Obtain the parent entry. drive::FileError error = drive::FILE_ERROR_OK; scoped_ptr parent_entry(new drive::ResourceEntry); integration_service_->file_system()->GetResourceEntry( drive::util::GetDriveMyDriveRootPath().Append(path).DirName(), google_apis::test_util::CreateCopyResultCallback( &error, &parent_entry)); drive::test_util::RunBlockingPoolTask(); ASSERT_EQ(drive::FILE_ERROR_OK, error); ASSERT_TRUE(parent_entry); switch (entry.type) { case FILE: CreateFile(entry.source_file_name, parent_entry->resource_id(), target_name, entry.mime_type, entry.shared_option == SHARED, entry.last_modified_time); break; case DIRECTORY: CreateDirectory(parent_entry->resource_id(), target_name, entry.last_modified_time); break; } } // Creates an empty directory with the given |name| and |modification_time|. void CreateDirectory(const std::string& parent_id, const std::string& target_name, const base::Time& modification_time) { google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; scoped_ptr resource_entry; fake_drive_service_->AddNewDirectory( parent_id, target_name, drive::DriveServiceInterface::AddNewDirectoryOptions(), google_apis::test_util::CreateCopyResultCallback(&error, &resource_entry)); base::MessageLoop::current()->RunUntilIdle(); ASSERT_EQ(google_apis::HTTP_CREATED, error); ASSERT_TRUE(resource_entry); fake_drive_service_->SetLastModifiedTime( resource_entry->resource_id(), modification_time, google_apis::test_util::CreateCopyResultCallback(&error, &resource_entry)); base::MessageLoop::current()->RunUntilIdle(); ASSERT_TRUE(error == google_apis::HTTP_SUCCESS); ASSERT_TRUE(resource_entry); CheckForUpdates(); } // Creates a test file with the given spec. // Serves |test_file_name| file. Pass an empty string for an empty file. void CreateFile(const std::string& source_file_name, const std::string& parent_id, const std::string& target_name, const std::string& mime_type, bool shared_with_me, const base::Time& modification_time) { google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; std::string content_data; if (!source_file_name.empty()) { base::FilePath source_file_path = google_apis::test_util::GetTestFilePath("chromeos/file_manager"). AppendASCII(source_file_name); ASSERT_TRUE(base::ReadFileToString(source_file_path, &content_data)); } scoped_ptr resource_entry; fake_drive_service_->AddNewFile( mime_type, content_data, parent_id, target_name, shared_with_me, google_apis::test_util::CreateCopyResultCallback(&error, &resource_entry)); base::MessageLoop::current()->RunUntilIdle(); ASSERT_EQ(google_apis::HTTP_CREATED, error); ASSERT_TRUE(resource_entry); fake_drive_service_->SetLastModifiedTime( resource_entry->resource_id(), modification_time, google_apis::test_util::CreateCopyResultCallback(&error, &resource_entry)); base::MessageLoop::current()->RunUntilIdle(); ASSERT_EQ(google_apis::HTTP_SUCCESS, error); ASSERT_TRUE(resource_entry); CheckForUpdates(); } // Notifies FileSystem that the contents in FakeDriveService are // changed, hence the new contents should be fetched. void CheckForUpdates() { if (integration_service_ && integration_service_->file_system()) { integration_service_->file_system()->CheckForUpdates(); } } // Sets the url base for the test server to be used to generate share urls // on the files and directories. void ConfigureShareUrlBase(const GURL& share_url_base) { fake_drive_service_->set_share_url_base(share_url_base); } drive::DriveIntegrationService* CreateDriveIntegrationService( Profile* profile) { fake_drive_service_ = new drive::FakeDriveService; fake_drive_service_->LoadResourceListForWapi( "gdata/empty_feed.json"); fake_drive_service_->LoadAccountMetadataForWapi( "gdata/account_metadata.json"); fake_drive_service_->LoadAppListForDriveApi("drive/applist.json"); integration_service_ = new drive::DriveIntegrationService( profile, NULL, fake_drive_service_, std::string(), test_cache_root_.path(), NULL); return integration_service_; } private: base::ScopedTempDir test_cache_root_; drive::FakeDriveService* fake_drive_service_; drive::DriveIntegrationService* integration_service_; DriveIntegrationServiceFactory::FactoryCallback create_drive_integration_service_; scoped_ptr service_factory_for_test_; }; // Listener to obtain the test relative messages synchronously. class FileManagerTestListener : public content::NotificationObserver { public: struct Message { int type; std::string message; scoped_refptr function; }; FileManagerTestListener() { registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_TEST_PASSED, content::NotificationService::AllSources()); registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_TEST_FAILED, content::NotificationService::AllSources()); registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_TEST_MESSAGE, content::NotificationService::AllSources()); } Message GetNextMessage() { if (messages_.empty()) content::RunMessageLoop(); const Message entry = messages_.front(); messages_.pop_front(); return entry; } virtual void Observe(int type, const content::NotificationSource& source, const content::NotificationDetails& details) OVERRIDE { Message entry; entry.type = type; entry.message = type != chrome::NOTIFICATION_EXTENSION_TEST_PASSED ? *content::Details(details).ptr() : std::string(); entry.function = type == chrome::NOTIFICATION_EXTENSION_TEST_MESSAGE ? content::Source(source).ptr() : NULL; messages_.push_back(entry); base::MessageLoopForUI::current()->Quit(); } private: std::deque messages_; content::NotificationRegistrar registrar_; }; // Parameter of FileManagerBrowserTest. // The second value is the case name of JavaScript. typedef std::tr1::tuple TestParameter; // The base test class. class FileManagerBrowserTest : public ExtensionApiTest, public ::testing::WithParamInterface { protected: FileManagerBrowserTest() : local_volume_(new LocalTestVolume), drive_volume_(std::tr1::get<0>(GetParam()) != IN_GUEST_MODE ? new DriveTestVolume() : NULL) {} virtual void SetUpInProcessBrowserTestFixture() OVERRIDE; virtual void SetUpOnMainThread() OVERRIDE; // Adds an incognito and guest-mode flags for tests in the guest mode. virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE; // Loads our testing extension and sends it a string identifying the current // test. void StartTest(); const scoped_ptr local_volume_; const scoped_ptr drive_volume_; }; void FileManagerBrowserTest::SetUpInProcessBrowserTestFixture() { ExtensionApiTest::SetUpInProcessBrowserTestFixture(); extensions::ComponentLoader::EnableBackgroundExtensionsForTesting(); if (drive_volume_) ASSERT_TRUE(drive_volume_->SetUp()); } void FileManagerBrowserTest::SetUpOnMainThread() { ExtensionApiTest::SetUpOnMainThread(); ASSERT_TRUE(local_volume_->Mount(browser()->profile())); if (drive_volume_) { // Install the web server to serve the mocked share dialog. ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); const GURL share_url_base(embedded_test_server()->GetURL( "/chromeos/file_manager/share_dialog_mock/index.html")); drive_volume_->ConfigureShareUrlBase(share_url_base); test_util::WaitUntilDriveMountPointIsAdded(browser()->profile()); } } void FileManagerBrowserTest::SetUpCommandLine(CommandLine* command_line) { if (std::tr1::get<0>(GetParam()) == IN_GUEST_MODE) { command_line->AppendSwitch(chromeos::switches::kGuestSession); command_line->AppendSwitchNative(chromeos::switches::kLoginUser, ""); command_line->AppendSwitch(switches::kIncognito); } // TODO(yoshiki): Remove the flag when the feature is launched. if (std::tr1::get<1>(GetParam()) == std::string("suggestAppDialog")) { command_line->AppendSwitch( chromeos::switches::kFileManagerEnableWebstoreIntegration); } ExtensionApiTest::SetUpCommandLine(command_line); } IN_PROC_BROWSER_TEST_P(FileManagerBrowserTest, Test) { // Launch the extension. base::FilePath path = test_data_dir_.AppendASCII("file_manager_browsertest"); const extensions::Extension* extension = LoadExtensionAsComponent(path); ASSERT_TRUE(extension); // Handle the messages from JavaScript. // The while loop is break when the test is passed or failed. FileManagerTestListener listener; base::JSONValueConverter add_entries_message_converter; while (true) { FileManagerTestListener::Message entry = listener.GetNextMessage(); if (entry.type == chrome::NOTIFICATION_EXTENSION_TEST_PASSED) { // Test succeed. break; } else if (entry.type == chrome::NOTIFICATION_EXTENSION_TEST_FAILED) { // Test failed. ADD_FAILURE() << entry.message; break; } // Parse the message value as JSON. const scoped_ptr value( base::JSONReader::Read(entry.message)); // If the message is not the expected format, just ignore it. const base::DictionaryValue* message_dictionary = NULL; std::string name; if (!value || !value->GetAsDictionary(&message_dictionary) || !message_dictionary->GetString("name", &name)) continue; if (name == "getTestName") { // Pass the test case name. entry.function->Reply(std::tr1::get<1>(GetParam())); } else if (name == "getRootPaths") { // Pass the root paths. const scoped_ptr res(new base::DictionaryValue()); res->SetString("downloads", "/" + util::GetDownloadsMountPointName(browser()->profile())); res->SetString("drive", "/" + drive::util::GetDriveMountPointPath(browser()->profile() ).BaseName().AsUTF8Unsafe() + "/root"); std::string jsonString; base::JSONWriter::Write(res.get(), &jsonString); entry.function->Reply(jsonString); } else if (name == "isInGuestMode") { // Obtain whether the test is in guest mode or not. entry.function->Reply(std::tr1::get<0>(GetParam()) ? "true" : "false"); } else if (name == "getCwsWidgetContainerMockUrl") { // Obtain whether the test is in guest mode or not. const GURL url = embedded_test_server()->GetURL( "/chromeos/file_manager/cws_container_mock/index.html"); std::string origin = url.GetOrigin().spec(); // Removes trailing a slash. if (*origin.rbegin() == '/') origin.resize(origin.length() - 1); const scoped_ptr res(new base::DictionaryValue()); res->SetString("url", url.spec()); res->SetString("origin", origin); std::string jsonString; base::JSONWriter::Write(res.get(), &jsonString); entry.function->Reply(jsonString); } else if (name == "addEntries") { // Add entries to the specified volume. AddEntriesMessage message; if (!add_entries_message_converter.Convert(*value.get(), &message)) { entry.function->Reply("onError"); continue; } for (size_t i = 0; i < message.entries.size(); ++i) { switch (message.volume) { case LOCAL_VOLUME: local_volume_->CreateEntry(*message.entries[i]); break; case DRIVE_VOLUME: if (drive_volume_) drive_volume_->CreateEntry(*message.entries[i]); break; default: NOTREACHED(); break; } } entry.function->Reply("onEntryAdded"); } } } INSTANTIATE_TEST_CASE_P( FileDisplay, FileManagerBrowserTest, ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, "fileDisplayDownloads"), TestParameter(IN_GUEST_MODE, "fileDisplayDownloads"), TestParameter(NOT_IN_GUEST_MODE, "fileDisplayDrive"))); INSTANTIATE_TEST_CASE_P( OpenSpecialTypes, FileManagerBrowserTest, ::testing::Values(TestParameter(IN_GUEST_MODE, "videoOpenDownloads"), TestParameter(NOT_IN_GUEST_MODE, "videoOpenDownloads"), TestParameter(NOT_IN_GUEST_MODE, "videoOpenDrive"), // Audio player tests are temporary disabled. // TODO(yoshiki): Re-enable them: crbug.com/340955. // TestParameter(IN_GUEST_MODE, "audioOpenDownloads"), // TestParameter(NOT_IN_GUEST_MODE, "audioOpenDownloads"), // TestParameter(NOT_IN_GUEST_MODE, "audioOpenDrive"), TestParameter(IN_GUEST_MODE, "galleryOpenDownloads"), TestParameter(NOT_IN_GUEST_MODE, "galleryOpenDownloads"), TestParameter(NOT_IN_GUEST_MODE, "galleryOpenDrive"))); INSTANTIATE_TEST_CASE_P( KeyboardOperations, FileManagerBrowserTest, ::testing::Values(TestParameter(IN_GUEST_MODE, "keyboardDeleteDownloads"), TestParameter(NOT_IN_GUEST_MODE, "keyboardDeleteDownloads"), TestParameter(NOT_IN_GUEST_MODE, "keyboardDeleteDrive"), TestParameter(IN_GUEST_MODE, "keyboardCopyDownloads"), TestParameter(NOT_IN_GUEST_MODE, "keyboardCopyDownloads"), TestParameter(NOT_IN_GUEST_MODE, "keyboardCopyDrive"))); INSTANTIATE_TEST_CASE_P( DriveSpecific, FileManagerBrowserTest, ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, "openSidebarRecent"), TestParameter(NOT_IN_GUEST_MODE, "openSidebarOffline"), TestParameter(NOT_IN_GUEST_MODE, "openSidebarSharedWithMe"), TestParameter(NOT_IN_GUEST_MODE, "autocomplete"))); INSTANTIATE_TEST_CASE_P( Transfer, FileManagerBrowserTest, ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, "transferFromDriveToDownloads"), TestParameter(NOT_IN_GUEST_MODE, "transferFromDownloadsToDrive"), TestParameter(NOT_IN_GUEST_MODE, "transferFromSharedToDownloads"), TestParameter(NOT_IN_GUEST_MODE, "transferFromSharedToDrive"), TestParameter(NOT_IN_GUEST_MODE, "transferFromRecentToDownloads"), TestParameter(NOT_IN_GUEST_MODE, "transferFromRecentToDrive"), TestParameter(NOT_IN_GUEST_MODE, "transferFromOfflineToDownloads"), TestParameter(NOT_IN_GUEST_MODE, "transferFromOfflineToDrive"))); INSTANTIATE_TEST_CASE_P( HideSearchBox, FileManagerBrowserTest, ::testing::Values(TestParameter(IN_GUEST_MODE, "hideSearchBox"), TestParameter(NOT_IN_GUEST_MODE, "hideSearchBox"))); INSTANTIATE_TEST_CASE_P( RestorePrefs, FileManagerBrowserTest, ::testing::Values(TestParameter(IN_GUEST_MODE, "restoreSortColumn"), TestParameter(NOT_IN_GUEST_MODE, "restoreSortColumn"), TestParameter(IN_GUEST_MODE, "restoreCurrentView"), TestParameter(NOT_IN_GUEST_MODE, "restoreCurrentView"))); INSTANTIATE_TEST_CASE_P( ShareDialog, FileManagerBrowserTest, ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, "shareFile"), TestParameter(NOT_IN_GUEST_MODE, "shareDirectory"))); INSTANTIATE_TEST_CASE_P( RestoreGeometry, FileManagerBrowserTest, ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, "restoreGeometry"), TestParameter(IN_GUEST_MODE, "restoreGeometry"))); INSTANTIATE_TEST_CASE_P( Traverse, FileManagerBrowserTest, ::testing::Values(TestParameter(IN_GUEST_MODE, "traverseDownloads"), TestParameter(NOT_IN_GUEST_MODE, "traverseDownloads"), TestParameter(NOT_IN_GUEST_MODE, "traverseDrive"))); INSTANTIATE_TEST_CASE_P( SuggestAppDialog, FileManagerBrowserTest, ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, "suggestAppDialog"))); INSTANTIATE_TEST_CASE_P( ExecuteDefaultTaskOnDownloads, FileManagerBrowserTest, ::testing::Values( TestParameter(NOT_IN_GUEST_MODE, "executeDefaultTaskOnDownloads"), TestParameter(IN_GUEST_MODE, "executeDefaultTaskOnDownloads"))); INSTANTIATE_TEST_CASE_P( ExecuteDefaultTaskOnDrive, FileManagerBrowserTest, ::testing::Values( TestParameter(NOT_IN_GUEST_MODE, "executeDefaultTaskOnDrive"))); INSTANTIATE_TEST_CASE_P( NavigationList, FileManagerBrowserTest, ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, "traverseNavigationList"))); INSTANTIATE_TEST_CASE_P( TabIndex, FileManagerBrowserTest, ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, "searchBoxFocus"))); INSTANTIATE_TEST_CASE_P( Thumbnails, FileManagerBrowserTest, ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, "thumbnailsDownloads"), TestParameter(IN_GUEST_MODE, "thumbnailsDownloads"))); } // namespace } // namespace file_manager