Commit 2b7f29d7 authored by Alex Lau's avatar Alex Lau Committed by Commit Bot

Add mock ARC volume and initial tests.

This adds a fake local ARC volume for testing. Initial integration
tests added check that
1) the "Toggle Play Folders" button work in hiding and showing the
   non-default Android files and folders.
2) the "Toggle Play Folders" button is shown inside Play Files but
   hidden from the "Recents" pane.

Bug: 877371
Test: Tested on Chromium build.
Change-Id: Ic35de5ebb06f901ad229c9b35f1917ac9353a459
Reviewed-on: https://chromium-review.googlesource.com/1201637
Commit-Queue: Alex Lau <alexlau@chromium.org>
Reviewed-by: default avatarNaoki Fukino <fukino@chromium.org>
Cr-Commit-Position: refs/heads/master@{#589847}
parent f57f5f8e
...@@ -565,14 +565,17 @@ WRAPPED_INSTANTIATE_TEST_CASE_P( ...@@ -565,14 +565,17 @@ WRAPPED_INSTANTIATE_TEST_CASE_P(
WRAPPED_INSTANTIATE_TEST_CASE_P( WRAPPED_INSTANTIATE_TEST_CASE_P(
GearMenu, /* gear_menu.js */ GearMenu, /* gear_menu.js */
FilesAppBrowserTest, FilesAppBrowserTest,
::testing::Values(TestCase("showHiddenFilesDownloads"), ::testing::Values(
TestCase("showHiddenFilesDownloads").InGuestMode(), TestCase("showHiddenFilesDownloads"),
TestCase("showHiddenFilesDrive"), TestCase("showHiddenFilesDownloads").InGuestMode(),
TestCase("showHiddenFilesDrive").EnableDriveFs(), TestCase("showHiddenFilesDrive"),
TestCase("toogleGoogleDocsDrive"), TestCase("showHiddenFilesDrive").EnableDriveFs(),
TestCase("toogleGoogleDocsDrive").EnableDriveFs(), TestCase("toogleGoogleDocsDrive"),
TestCase("showPasteIntoCurrentFolder"), TestCase("toogleGoogleDocsDrive").EnableDriveFs(),
TestCase("showSelectAllInCurrentFolder"))); TestCase("showPasteIntoCurrentFolder"),
TestCase("showSelectAllInCurrentFolder"),
TestCase("showToggleHiddenAndroidFoldersGearMenuItemsInMyFiles"),
TestCase("enableToggleHiddenAndroidFoldersShowsHiddenFiles")));
WRAPPED_INSTANTIATE_TEST_CASE_P( WRAPPED_INSTANTIATE_TEST_CASE_P(
Crostini, /* crostini.js */ Crostini, /* crostini.js */
......
...@@ -100,7 +100,13 @@ struct AddEntriesMessage { ...@@ -100,7 +100,13 @@ struct AddEntriesMessage {
struct TestEntryInfo; struct TestEntryInfo;
// Represents the various volumes available for adding entries. // Represents the various volumes available for adding entries.
enum TargetVolume { LOCAL_VOLUME, DRIVE_VOLUME, CROSTINI_VOLUME, USB_VOLUME }; enum TargetVolume {
LOCAL_VOLUME,
DRIVE_VOLUME,
CROSTINI_VOLUME,
USB_VOLUME,
ANDROID_FILES_VOLUME
};
// Represents the different types of entries (e.g. file, folder). // Represents the different types of entries (e.g. file, folder).
enum EntryType { FILE, DIRECTORY, TEAM_DRIVE }; enum EntryType { FILE, DIRECTORY, TEAM_DRIVE };
...@@ -143,6 +149,8 @@ struct AddEntriesMessage { ...@@ -143,6 +149,8 @@ struct AddEntriesMessage {
*volume = CROSTINI_VOLUME; *volume = CROSTINI_VOLUME;
else if (value == "usb") else if (value == "usb")
*volume = USB_VOLUME; *volume = USB_VOLUME;
else if (value == "android_files")
*volume = ANDROID_FILES_VOLUME;
else else
return false; return false;
return true; return true;
...@@ -488,6 +496,30 @@ class DownloadsTestVolume : public LocalTestVolume { ...@@ -488,6 +496,30 @@ class DownloadsTestVolume : public LocalTestVolume {
DISALLOW_COPY_AND_ASSIGN(DownloadsTestVolume); DISALLOW_COPY_AND_ASSIGN(DownloadsTestVolume);
}; };
class AndroidFilesTestVolume : public LocalTestVolume {
public:
AndroidFilesTestVolume() : LocalTestVolume("AndroidFiles") {}
~AndroidFilesTestVolume() override = default;
bool Initialize(Profile* profile) { return CreateRootDirectory(profile); }
bool Mount(Profile* profile) override {
return CreateRootDirectory(profile) &&
VolumeManager::Get(profile)->RegisterAndroidFilesDirectoryForTesting(
root_path());
}
const base::FilePath& mount_path() const { return root_path(); }
void Unmount(Profile* profile) {
VolumeManager::Get(profile)->RemoveAndroidFilesDirectoryForTesting(
root_path());
}
private:
DISALLOW_COPY_AND_ASSIGN(AndroidFilesTestVolume);
};
// CrostiniTestVolume: local test volume for the "Linux files" directory. // CrostiniTestVolume: local test volume for the "Linux files" directory.
class CrostiniTestVolume : public LocalTestVolume { class CrostiniTestVolume : public LocalTestVolume {
public: public:
...@@ -1040,6 +1072,9 @@ void FileManagerBrowserTestBase::SetUpOnMainThread() { ...@@ -1040,6 +1072,9 @@ void FileManagerBrowserTestBase::SetUpOnMainThread() {
->AddCustomMountPointCallback( ->AddCustomMountPointCallback(
base::BindRepeating(&FileManagerBrowserTestBase::MaybeMountCrostini, base::BindRepeating(&FileManagerBrowserTestBase::MaybeMountCrostini,
base::Unretained(this))); base::Unretained(this)));
android_files_volume_ = std::make_unique<AndroidFilesTestVolume>();
android_files_volume_->Mount(profile());
} }
display_service_ = display_service_ =
...@@ -1173,6 +1208,10 @@ void FileManagerBrowserTestBase::OnCommand(const std::string& name, ...@@ -1173,6 +1208,10 @@ void FileManagerBrowserTestBase::OnCommand(const std::string& name,
dictionary.SetString( dictionary.SetString(
"drive", base::StrCat({"/", drive_mount_name.value(), "/root"})); "drive", base::StrCat({"/", drive_mount_name.value(), "/root"}));
} }
if (android_files_volume_) {
dictionary.SetString("android_files",
"/" + util::GetAndroidFilesMountPointName());
}
} }
base::JSONWriter::Write(dictionary, output); base::JSONWriter::Write(dictionary, output);
return; return;
...@@ -1229,6 +1268,11 @@ void FileManagerBrowserTestBase::OnCommand(const std::string& name, ...@@ -1229,6 +1268,11 @@ void FileManagerBrowserTestBase::OnCommand(const std::string& name,
LOG(FATAL) << "Add entry: but no USB volume."; LOG(FATAL) << "Add entry: but no USB volume.";
} }
break; break;
case AddEntriesMessage::ANDROID_FILES_VOLUME:
CHECK(android_files_volume_);
ASSERT_TRUE(android_files_volume_->Initialize(profile()));
android_files_volume_->CreateEntry(*message.entries[i]);
break;
} }
} }
......
...@@ -25,6 +25,7 @@ class DriveTestVolume; ...@@ -25,6 +25,7 @@ class DriveTestVolume;
class FakeTestVolume; class FakeTestVolume;
class LocalTestVolume; class LocalTestVolume;
class CrostiniTestVolume; class CrostiniTestVolume;
class AndroidFilesTestVolume;
class FileManagerBrowserTestBase : public extensions::ExtensionApiTest { class FileManagerBrowserTestBase : public extensions::ExtensionApiTest {
protected: protected:
...@@ -109,6 +110,7 @@ class FileManagerBrowserTestBase : public extensions::ExtensionApiTest { ...@@ -109,6 +110,7 @@ class FileManagerBrowserTestBase : public extensions::ExtensionApiTest {
std::unique_ptr<LocalTestVolume> local_volume_; std::unique_ptr<LocalTestVolume> local_volume_;
std::unique_ptr<CrostiniTestVolume> crostini_volume_; std::unique_ptr<CrostiniTestVolume> crostini_volume_;
std::unique_ptr<AndroidFilesTestVolume> android_files_volume_;
std::map<Profile*, std::unique_ptr<DriveTestVolume>> drive_volumes_; std::map<Profile*, std::unique_ptr<DriveTestVolume>> drive_volumes_;
DriveTestVolume* drive_volume_ = nullptr; DriveTestVolume* drive_volume_ = nullptr;
std::unique_ptr<FakeTestVolume> usb_volume_; std::unique_ptr<FakeTestVolume> usb_volume_;
......
...@@ -37,6 +37,7 @@ const char kDownloadsFolderName[] = "Downloads"; ...@@ -37,6 +37,7 @@ const char kDownloadsFolderName[] = "Downloads";
const char kGoogleDriveDisplayName[] = "Google Drive"; const char kGoogleDriveDisplayName[] = "Google Drive";
const char kRootRelativeToDriveMount[] = "root"; const char kRootRelativeToDriveMount[] = "root";
const char kTeamDrivesRelativeToDriveMount[] = "team_drives"; const char kTeamDrivesRelativeToDriveMount[] = "team_drives";
const char kAndroidFilesMountPointName[] = "android_files";
// Sync with the file provider in ARC++ side. // Sync with the file provider in ARC++ side.
constexpr char kArcFileProviderUrl[] = constexpr char kArcFileProviderUrl[] =
...@@ -128,6 +129,10 @@ std::string GetDownloadsMountPointName(Profile* profile) { ...@@ -128,6 +129,10 @@ std::string GetDownloadsMountPointName(Profile* profile) {
return net::EscapeQueryParamValue(kDownloadsFolderName + id, false); return net::EscapeQueryParamValue(kDownloadsFolderName + id, false);
} }
std::string GetAndroidFilesMountPointName() {
return kAndroidFilesMountPointName;
}
std::string GetCrostiniMountPointName(Profile* profile) { std::string GetCrostiniMountPointName(Profile* profile) {
// crostini_<hash>_termina_penguin // crostini_<hash>_termina_penguin
return base::JoinString( return base::JoinString(
......
...@@ -46,6 +46,9 @@ bool MigratePathFromOldFormat(Profile* profile, ...@@ -46,6 +46,9 @@ bool MigratePathFromOldFormat(Profile* profile,
// The canonical mount point name for "Downloads" folder. // The canonical mount point name for "Downloads" folder.
std::string GetDownloadsMountPointName(Profile* profile); std::string GetDownloadsMountPointName(Profile* profile);
// The canonical mount point name for ARC "Play files" folder.
std::string GetAndroidFilesMountPointName();
// The canonical mount point name for crostini "Linux files" folder. // The canonical mount point name for crostini "Linux files" folder.
std::string GetCrostiniMountPointName(Profile* profile); std::string GetCrostiniMountPointName(Profile* profile);
......
...@@ -54,7 +54,6 @@ const uint32_t kFilesystemTypeGenericHierarchical = 2; ...@@ -54,7 +54,6 @@ const uint32_t kFilesystemTypeGenericHierarchical = 2;
const char kFileManagerMTPMountNamePrefix[] = "fileman-mtp-"; const char kFileManagerMTPMountNamePrefix[] = "fileman-mtp-";
const char kMtpVolumeIdPrefix[] = "mtp:"; const char kMtpVolumeIdPrefix[] = "mtp:";
const char kRootPath[] = "/"; const char kRootPath[] = "/";
const char kAndroidFilesMountPointName[] = "android_files";
// Registers |path| as the "Downloads" folder to the FileSystem API backend. // Registers |path| as the "Downloads" folder to the FileSystem API backend.
// If another folder is already mounted. It revokes and overrides the old one. // If another folder is already mounted. It revokes and overrides the old one.
...@@ -89,8 +88,8 @@ bool RegisterAndroidFilesMountPoint() { ...@@ -89,8 +88,8 @@ bool RegisterAndroidFilesMountPoint() {
storage::ExternalMountPoints* const mount_points = storage::ExternalMountPoints* const mount_points =
storage::ExternalMountPoints::GetSystemInstance(); storage::ExternalMountPoints::GetSystemInstance();
return mount_points->RegisterFileSystem( return mount_points->RegisterFileSystem(
kAndroidFilesMountPointName, storage::kFileSystemTypeNativeLocal, file_manager::util::GetAndroidFilesMountPointName(),
storage::FileSystemMountOption(), storage::kFileSystemTypeNativeLocal, storage::FileSystemMountOption(),
base::FilePath(util::kAndroidFilesPath)); base::FilePath(util::kAndroidFilesPath));
} }
...@@ -342,13 +341,14 @@ std::unique_ptr<Volume> Volume::CreateForSshfsCrostini( ...@@ -342,13 +341,14 @@ std::unique_ptr<Volume> Volume::CreateForSshfsCrostini(
} }
// static // static
std::unique_ptr<Volume> Volume::CreateForAndroidFiles() { std::unique_ptr<Volume> Volume::CreateForAndroidFiles(
const base::FilePath& mount_path) {
std::unique_ptr<Volume> volume(new Volume()); std::unique_ptr<Volume> volume(new Volume());
volume->type_ = VOLUME_TYPE_ANDROID_FILES; volume->type_ = VOLUME_TYPE_ANDROID_FILES;
volume->device_type_ = chromeos::DEVICE_TYPE_UNKNOWN; volume->device_type_ = chromeos::DEVICE_TYPE_UNKNOWN;
// Keep source_path empty. // Keep source_path empty.
volume->source_ = SOURCE_SYSTEM; volume->source_ = SOURCE_SYSTEM;
volume->mount_path_ = base::FilePath(util::kAndroidFilesPath); volume->mount_path_ = mount_path;
volume->mount_condition_ = chromeos::disks::MOUNT_CONDITION_NONE; volume->mount_condition_ = chromeos::disks::MOUNT_CONDITION_NONE;
volume->volume_id_ = GenerateVolumeId(*volume); volume->volume_id_ = GenerateVolumeId(*volume);
volume->watchable_ = true; volume->watchable_ = true;
...@@ -570,6 +570,27 @@ void VolumeManager::RemoveSshfsCrostiniVolume( ...@@ -570,6 +570,27 @@ void VolumeManager::RemoveSshfsCrostiniVolume(
chromeos::disks::DiskMountManager::UnmountPathCallback()); chromeos::disks::DiskMountManager::UnmountPathCallback());
} }
bool VolumeManager::RegisterAndroidFilesDirectoryForTesting(
const base::FilePath& path) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
bool result =
storage::ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
file_manager::util::GetAndroidFilesMountPointName(),
storage::kFileSystemTypeNativeLocal, storage::FileSystemMountOption(),
path);
DCHECK(result);
DoMountEvent(chromeos::MOUNT_ERROR_NONE, Volume::CreateForAndroidFiles(path));
return true;
}
bool VolumeManager::RemoveAndroidFilesDirectoryForTesting(
const base::FilePath& path) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DoUnmountEvent(chromeos::MOUNT_ERROR_NONE,
*Volume::CreateForAndroidFiles(path));
return true;
}
bool VolumeManager::RegisterDownloadsDirectoryForTesting( bool VolumeManager::RegisterDownloadsDirectoryForTesting(
const base::FilePath& path) { const base::FilePath& path) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
...@@ -931,7 +952,9 @@ void VolumeManager::OnArcPlayStoreEnabledChanged(bool enabled) { ...@@ -931,7 +952,9 @@ void VolumeManager::OnArcPlayStoreEnabledChanged(bool enabled) {
DoMountEvent(chromeos::MOUNT_ERROR_NONE, DoMountEvent(chromeos::MOUNT_ERROR_NONE,
Volume::CreateForMediaView(arc::kAudioRootDocumentId)); Volume::CreateForMediaView(arc::kAudioRootDocumentId));
if (IsShowAndroidFilesEnabled()) if (IsShowAndroidFilesEnabled())
DoMountEvent(chromeos::MOUNT_ERROR_NONE, Volume::CreateForAndroidFiles()); DoMountEvent(chromeos::MOUNT_ERROR_NONE,
Volume::CreateForAndroidFiles(
base::FilePath(util::kAndroidFilesPath)));
} else { } else {
DoUnmountEvent(chromeos::MOUNT_ERROR_NONE, DoUnmountEvent(chromeos::MOUNT_ERROR_NONE,
*Volume::CreateForMediaView(arc::kImagesRootDocumentId)); *Volume::CreateForMediaView(arc::kImagesRootDocumentId));
...@@ -941,7 +964,8 @@ void VolumeManager::OnArcPlayStoreEnabledChanged(bool enabled) { ...@@ -941,7 +964,8 @@ void VolumeManager::OnArcPlayStoreEnabledChanged(bool enabled) {
*Volume::CreateForMediaView(arc::kAudioRootDocumentId)); *Volume::CreateForMediaView(arc::kAudioRootDocumentId));
if (IsShowAndroidFilesEnabled()) { if (IsShowAndroidFilesEnabled()) {
DoUnmountEvent(chromeos::MOUNT_ERROR_NONE, DoUnmountEvent(chromeos::MOUNT_ERROR_NONE,
*Volume::CreateForAndroidFiles()); *Volume::CreateForAndroidFiles(
base::FilePath(util::kAndroidFilesPath)));
} }
} }
......
...@@ -106,7 +106,8 @@ class Volume : public base::SupportsWeakPtr<Volume> { ...@@ -106,7 +106,8 @@ class Volume : public base::SupportsWeakPtr<Volume> {
const std::string& root_document_id); const std::string& root_document_id);
static std::unique_ptr<Volume> CreateForSshfsCrostini( static std::unique_ptr<Volume> CreateForSshfsCrostini(
const base::FilePath& crostini_path); const base::FilePath& crostini_path);
static std::unique_ptr<Volume> CreateForAndroidFiles(); static std::unique_ptr<Volume> CreateForAndroidFiles(
const base::FilePath& mount_path);
static std::unique_ptr<Volume> CreateForTesting( static std::unique_ptr<Volume> CreateForTesting(
const base::FilePath& path, const base::FilePath& path,
VolumeType volume_type, VolumeType volume_type,
...@@ -304,6 +305,14 @@ class VolumeManager : public KeyedService, ...@@ -304,6 +305,14 @@ class VolumeManager : public KeyedService,
// |path| with CROSTINI type, and adds its volume info. // |path| with CROSTINI type, and adds its volume info.
bool RegisterCrostiniDirectoryForTesting(const base::FilePath& path); bool RegisterCrostiniDirectoryForTesting(const base::FilePath& path);
// For testing purpose, registers a native local file system pointing to
// |path| with ANDROID_FILES type, and adds its volume info.
bool RegisterAndroidFilesDirectoryForTesting(const base::FilePath& path);
// For testing purpose, removes a registered native local file system
// pointing to |path| with ANDROID_FILES type, and removes its volume info.
bool RemoveAndroidFilesDirectoryForTesting(const base::FilePath& path);
// For testing purpose, adds a volume info pointing to |path|, with TESTING // For testing purpose, adds a volume info pointing to |path|, with TESTING
// type. Assumes that the mount point is already registered. // type. Assumes that the mount point is already registered.
void AddVolumeForTesting(const base::FilePath& path, void AddVolumeForTesting(const base::FilePath& path,
......
...@@ -457,6 +457,7 @@ window.addEventListener('load', function() { ...@@ -457,6 +457,7 @@ window.addEventListener('load', function() {
var roots = JSON.parse(paths); var roots = JSON.parse(paths);
RootPath.DOWNLOADS = roots.downloads; RootPath.DOWNLOADS = roots.downloads;
RootPath.DRIVE = roots.drive; RootPath.DRIVE = roots.drive;
RootPath.ANDROID_FILES = roots.android_files;
chrome.test.sendMessage( chrome.test.sendMessage(
JSON.stringify({name: 'getTestName'}), steps.shift()); JSON.stringify({name: 'getTestName'}), steps.shift());
}, },
......
...@@ -35,6 +35,16 @@ const BASIC_DRIVE_ENTRY_SET_WITH_HIDDEN = [ ...@@ -35,6 +35,16 @@ const BASIC_DRIVE_ENTRY_SET_WITH_HIDDEN = [
ENTRIES.hiddenFile ENTRIES.hiddenFile
]; ];
const BASIC_ANDROID_ENTRY_SET = [
ENTRIES.directoryDocuments, ENTRIES.directoryMovies, ENTRIES.directoryMusic,
ENTRIES.directoryPictures
];
const BASIC_ANDROID_ENTRY_SET_WITH_HIDDEN = [
ENTRIES.directoryDocuments, ENTRIES.directoryMovies, ENTRIES.directoryMusic,
ENTRIES.directoryPictures, ENTRIES.hello, ENTRIES.world, ENTRIES.directoryA
];
/** /**
* Expected files shown in Drive with Google Docs disabled * Expected files shown in Drive with Google Docs disabled
* *
...@@ -57,11 +67,39 @@ const BASIC_DRIVE_ENTRY_SET_WITHOUT_GDOCS = [ ...@@ -57,11 +67,39 @@ const BASIC_DRIVE_ENTRY_SET_WITHOUT_GDOCS = [
* @return {!Array} The test steps to toggle hidden files * @return {!Array} The test steps to toggle hidden files
*/ */
function getTestCaseStepsForHiddenFiles(basicSet, hiddenEntrySet) { function getTestCaseStepsForHiddenFiles(basicSet, hiddenEntrySet) {
return getTestCaseStepsForHiddenFilesWithMenuItem(
basicSet, hiddenEntrySet, '#gear-menu-toggle-hidden-files');
}
/**
* Gets the common steps to toggle Android hidden files in the Files app
* @param {!Array<!TestEntryInfo>} basicSet Files expected before showing hidden
* @param {!Array<!TestEntryInfo>} hiddenEntrySet Files expected after showing
* hidden
* @return {!Array} The test steps to toggle hidden files
*/
function getTestCaseStepsForAndroidHiddenFiles(basicSet, hiddenEntrySet) {
return getTestCaseStepsForHiddenFilesWithMenuItem(
basicSet, hiddenEntrySet, '#gear-menu-toggle-hidden-android-folders');
}
/**
* Gets the common steps to toggle hidden files in the Files app
* @param {!Array<!TestEntryInfo>} basicSet Files expected before showing hidden
* @param {!Array<!TestEntryInfo>} hiddenEntrySet Files expected after showing
* hidden
* @param {string} toggleMenuItemSelector Selector for the menu item that
* toggles hidden file visibility
* @return {!Array} The test steps to toggle hidden files
*/
function getTestCaseStepsForHiddenFilesWithMenuItem(
basicSet, hiddenEntrySet, toggleMenuItemSelector) {
var appId; var appId;
return [ return [
function(id) { function(id) {
appId = id; appId = id;
remoteCall.waitForElement(appId, '#gear-button').then(this.next); remoteCall.waitForElement(appId, '#gear-button:not([hidden])')
.then(this.next);
}, },
// Open the gear menu by clicking the gear button. // Open the gear menu by clicking the gear button.
function() { function() {
...@@ -76,25 +114,26 @@ function getTestCaseStepsForHiddenFiles(basicSet, hiddenEntrySet) { ...@@ -76,25 +114,26 @@ function getTestCaseStepsForHiddenFiles(basicSet, hiddenEntrySet) {
}, },
// Wait for menu item to appear. // Wait for menu item to appear.
function(result) { function(result) {
remoteCall.waitForElement(appId, remoteCall
'#gear-menu-toggle-hidden-files:not([disabled])').then(this.next); .waitForElement(appId, toggleMenuItemSelector + ':not([disabled])')
.then(this.next);
}, },
// Wait for menu item to appear. // Wait for menu item to appear.
function(result) { function(result) {
remoteCall.waitForElement(appId, remoteCall
'#gear-menu-toggle-hidden-files:not([checked])').then(this.next); .waitForElement(appId, toggleMenuItemSelector + ':not([checked])')
.then(this.next);
}, },
// Click the menu item. // Click the menu item.
function(results) { function(results) {
remoteCall.callRemoteTestUtil( remoteCall.callRemoteTestUtil(
'fakeMouseClick', appId, ['#gear-menu-toggle-hidden-files'], 'fakeMouseClick', appId, [toggleMenuItemSelector], this.next);
this.next);
}, },
// Wait for item to be checked. // Wait for item to be checked.
function(result) { function(result) {
chrome.test.assertTrue(result); chrome.test.assertTrue(result);
remoteCall.waitForElement(appId, remoteCall.waitForElement(appId, toggleMenuItemSelector + '[checked]')
'#gear-menu-toggle-hidden-files[checked]').then(this.next); .then(this.next);
}, },
// Check the hidden files are displayed. // Check the hidden files are displayed.
function(result) { function(result) {
...@@ -104,7 +143,8 @@ function getTestCaseStepsForHiddenFiles(basicSet, hiddenEntrySet) { ...@@ -104,7 +143,8 @@ function getTestCaseStepsForHiddenFiles(basicSet, hiddenEntrySet) {
}, },
// Repeat steps to toggle again. // Repeat steps to toggle again.
function(inAppId) { function(inAppId) {
remoteCall.waitForElement(appId, '#gear-button').then(this.next); remoteCall.waitForElement(appId, '#gear-button:not([hidden])')
.then(this.next);
}, },
function() { function() {
remoteCall.callRemoteTestUtil( remoteCall.callRemoteTestUtil(
...@@ -116,22 +156,23 @@ function getTestCaseStepsForHiddenFiles(basicSet, hiddenEntrySet) { ...@@ -116,22 +156,23 @@ function getTestCaseStepsForHiddenFiles(basicSet, hiddenEntrySet) {
this.next); this.next);
}, },
function(result) { function(result) {
remoteCall.waitForElement(appId, remoteCall
'#gear-menu-toggle-hidden-files:not([disabled])').then(this.next); .waitForElement(appId, toggleMenuItemSelector + ':not([disabled])')
.then(this.next);
}, },
function(result) { function(result) {
remoteCall.waitForElement(appId, remoteCall.waitForElement(appId, toggleMenuItemSelector + '[checked]')
'#gear-menu-toggle-hidden-files[checked]').then(this.next); .then(this.next);
}, },
function(results) { function(results) {
remoteCall.callRemoteTestUtil( remoteCall.callRemoteTestUtil(
'fakeMouseClick', appId, ['#gear-menu-toggle-hidden-files'], 'fakeMouseClick', appId, [toggleMenuItemSelector], this.next);
this.next);
}, },
function(result) { function(result) {
chrome.test.assertTrue(result); chrome.test.assertTrue(result);
remoteCall.waitForElement(appId, remoteCall
'#gear-menu-toggle-hidden-files:not([checked])').then(this.next); .waitForElement(appId, toggleMenuItemSelector + ':not([checked])')
.then(this.next);
}, },
function(result) { function(result) {
remoteCall.waitForFiles(appId, TestEntryInfo.getExpectedRows(basicSet), remoteCall.waitForFiles(appId, TestEntryInfo.getExpectedRows(basicSet),
...@@ -276,6 +317,126 @@ testcase.toogleGoogleDocsDrive = function() { ...@@ -276,6 +317,126 @@ testcase.toogleGoogleDocsDrive = function() {
]); ]);
}; };
/**
* Tests that toggle-hidden-android-folders menu item exists when "Play files"
* is selected, but hidden in Recents.
*/
testcase.showToggleHiddenAndroidFoldersGearMenuItemsInMyFiles = function() {
var appId;
StepsRunner.run([
// Open Files.App on Play Files.
function() {
openNewWindow(null, RootPath.ANDROID_FILES).then(this.next);
},
function(inAppId) {
appId = inAppId;
addEntries(['android_files'], BASIC_ANDROID_ENTRY_SET, this.next);
},
// Wait for the file list to appear.
function(result) {
chrome.test.assertTrue(result);
remoteCall.waitForElement(appId, '#file-list').then(this.next);
},
// Wait for the gear menu button to appear.
function() {
remoteCall.waitForElement(appId, '#gear-button:not([hidden])')
.then(this.next);
},
// Click the gear menu button.
function() {
remoteCall.callRemoteTestUtil(
'fakeMouseClick', appId, ['#gear-button'], this.next);
},
// Wait for the gear menu to appear.
function(result) {
chrome.test.assertTrue(result);
remoteCall.waitForElement(appId, '#gear-menu:not([hidden])')
.then(this.next);
},
// #toggle-hidden-android-folders command should be shown and disabled by
// default.
function() {
remoteCall
.waitForElement(
appId,
'#gear-menu-toggle-hidden-android-folders' +
':not([checked]):not([hidden])')
.then(this.next);
},
// Click the file list: the gear menu should hide.
function() {
remoteCall.callRemoteTestUtil(
'fakeMouseClick', appId, ['#file-list'], this.next);
},
// Wait for the gear menu to hide.
function() {
remoteCall.waitForElement(appId, '#gear-menu[hidden]').then(this.next);
},
// Navigate to Recent.
function() {
remoteCall.callRemoteTestUtil(
'fakeMouseClick', appId, ['span[root-type-icon=\'recent\']'],
this.next);
},
// Click the gear menu button.
function() {
remoteCall.callRemoteTestUtil(
'fakeMouseClick', appId, ['#gear-button'], this.next);
},
// Wait for the gear menu to appear.
function(result) {
chrome.test.assertTrue(result);
remoteCall.waitForElement(appId, '#gear-menu:not([hidden])')
.then(this.next);
},
// #toggle-hidden-android-folders command should be hidden.
function(result) {
remoteCall
.waitForElement(
appId, '#gear-menu-toggle-hidden-android-folders[hidden]')
.then(this.next);
},
function() {
checkIfNoErrorsOccured(this.next);
},
]);
};
/**
* Tests that "Play files" shows the full set of files after
* toggle-hidden-android-folders is enabled.
*/
testcase.enableToggleHiddenAndroidFoldersShowsHiddenFiles = function() {
var appId;
var steps = [
// Open Files.App on Play Files.
function() {
openNewWindow(null, RootPath.ANDROID_FILES).then(this.next);
},
function(inAppId) {
appId = inAppId;
addEntries(
['android_files'], BASIC_ANDROID_ENTRY_SET_WITH_HIDDEN, this.next);
},
// Wait for the file list to appear.
function(result) {
chrome.test.assertTrue(result);
remoteCall.waitForElement(appId, '#file-list').then(this.next);
},
// Wait for the gear menu button to appear.
function() {
remoteCall.waitForElement(appId, '#gear-button:not([hidden])')
.then(this.next);
},
function() {
this.next(appId);
}
];
steps = steps.concat(getTestCaseStepsForAndroidHiddenFiles(
BASIC_ANDROID_ENTRY_SET, BASIC_ANDROID_ENTRY_SET_WITH_HIDDEN));
StepsRunner.run(steps);
};
/** /**
* Tests the paste-into-current-folder menu item. * Tests the paste-into-current-folder menu item.
*/ */
......
...@@ -12,6 +12,7 @@ testcase.showMyFiles = function() { ...@@ -12,6 +12,7 @@ testcase.showMyFiles = function() {
'Recent: FakeItem', 'Recent: FakeItem',
'My files: EntryListItem', 'My files: EntryListItem',
'Downloads: SubDirectoryItem', 'Downloads: SubDirectoryItem',
'Play files: SubDirectoryItem',
'Linux files: FakeItem', 'Linux files: FakeItem',
'Google Drive: DriveVolumeItem', 'Google Drive: DriveVolumeItem',
'My Drive: SubDirectoryItem', 'My Drive: SubDirectoryItem',
...@@ -192,10 +193,11 @@ testcase.myFilesDisplaysAndOpensEntries = function() { ...@@ -192,10 +193,11 @@ testcase.myFilesDisplaysAndOpensEntries = function() {
function(result) { function(result) {
chrome.test.assertTrue(result); chrome.test.assertTrue(result);
const downloadsRow = ['Downloads', '--', 'Folder']; const downloadsRow = ['Downloads', '--', 'Folder'];
const playFilesRow = ['Play files', '--', 'Folder'];
const crostiniRow = ['Linux files', '--', 'Folder']; const crostiniRow = ['Linux files', '--', 'Folder'];
remoteCall remoteCall
.waitForFiles( .waitForFiles(
appId, [downloadsRow, crostiniRow], appId, [downloadsRow, playFilesRow, crostiniRow],
{ignoreFileSize: true, ignoreLastModifiedTime: true}) {ignoreFileSize: true, ignoreLastModifiedTime: true})
.then(this.next); .then(this.next);
}, },
......
...@@ -218,6 +218,7 @@ var SharedOption = Object.freeze({ ...@@ -218,6 +218,7 @@ var SharedOption = Object.freeze({
var RootPath = Object.seal({ var RootPath = Object.seal({
DOWNLOADS: '/must-be-filled-in-test-setup', DOWNLOADS: '/must-be-filled-in-test-setup',
DRIVE: '/must-be-filled-in-test-setup', DRIVE: '/must-be-filled-in-test-setup',
ANDROID_FILES: '/must-be-filled-in-test-setup',
}); });
...@@ -732,5 +733,67 @@ var ENTRIES = { ...@@ -732,5 +733,67 @@ var ENTRIES = {
canDelete: false, canDelete: false,
canShare: true canShare: true
}, },
}) }),
// Default Android directories.
directoryDocuments: new TestEntryInfo({
type: EntryType.DIRECTORY,
targetPath: 'Documents',
lastModifiedTime: 'Jan 1, 2000, 1:00 AM',
nameText: 'Documents',
sizeText: '--',
typeText: 'Folder',
capabilities: {
canCopy: false,
canAddChildren: true,
canRename: false,
canDelete: false,
canShare: true
},
}),
directoryMovies: new TestEntryInfo({
type: EntryType.DIRECTORY,
targetPath: 'Movies',
lastModifiedTime: 'Jan 1, 2000, 1:00 AM',
nameText: 'Movies',
sizeText: '--',
typeText: 'Folder',
capabilities: {
canCopy: false,
canAddChildren: true,
canRename: false,
canDelete: false,
canShare: true
},
}),
directoryMusic: new TestEntryInfo({
type: EntryType.DIRECTORY,
targetPath: 'Music',
lastModifiedTime: 'Jan 1, 2000, 1:00 AM',
nameText: 'Music',
sizeText: '--',
typeText: 'Folder',
capabilities: {
canCopy: false,
canAddChildren: true,
canRename: false,
canDelete: false,
canShare: true
},
}),
directoryPictures: new TestEntryInfo({
type: EntryType.DIRECTORY,
targetPath: 'Pictures',
lastModifiedTime: 'Jan 1, 2000, 1:00 AM',
nameText: 'Pictures',
sizeText: '--',
typeText: 'Folder',
capabilities: {
canCopy: false,
canAddChildren: true,
canRename: false,
canDelete: false,
canShare: true
},
}),
}; };
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment