Commit 3f13d96b authored by Sasha Morrissey's avatar Sasha Morrissey Committed by Commit Bot

Fix context menu for Team Drive roots

Fixed a regression where context menus for Team Drive roots were no
longer displaying. Also added test support for Team Drives and a test
for a Team Drive root with default capabilities.

Bug: 996832
Cq-Include-Trybots: luci.chromium.try:closure_compilation
Change-Id: I70b384c79572803555626fd8af035ec883a00a5c
Reviewed-on: https://chromium-review.googlesource.com/1117719
Commit-Queue: Sasha Morrissey <sashab@chromium.org>
Reviewed-by: default avatarNoel Gordon <noel@chromium.org>
Cr-Commit-Position: refs/heads/master@{#571810}
parent fb90f578
......@@ -235,7 +235,12 @@ WRAPPED_INSTANTIATE_TEST_CASE_P(
TestCase("checkCutEnabledForReadWriteFolderInTree"),
TestCase("checkCutDisabledForReadOnlyFolderInTree"),
TestCase("checkPasteEnabledForReadWriteFolderInTree"),
TestCase("checkPasteDisabledForReadOnlyFolderInTree")));
TestCase("checkPasteDisabledForReadOnlyFolderInTree"),
TestCase("checkCutDisabledForTeamDriveRoot"),
TestCase("checkCopyEnabledForTeamDriveRoot"),
TestCase("checkRenameDisabledForTeamDriveRoot"),
TestCase("checkDeleteDisabledForTeamDriveRoot"),
TestCase("checkNewFolderEnabledForTeamDriveRoot")));
WRAPPED_INSTANTIATE_TEST_CASE_P(
Delete, /* delete.js */
......
......@@ -97,7 +97,7 @@ struct AddEntriesMessage {
enum TargetVolume { LOCAL_VOLUME, DRIVE_VOLUME, CROSTINI_VOLUME, USB_VOLUME };
// Represents the different types of entries (e.g. file, folder).
enum EntryType { FILE, DIRECTORY };
enum EntryType { FILE, DIRECTORY, TEAM_DRIVE };
// Represents whether an entry appears in 'Share with Me' or not.
enum SharedOption { NONE, SHARED };
......@@ -193,6 +193,7 @@ struct AddEntriesMessage {
const std::string& source_file_name,
const std::string& target_path,
const std::string& mime_type,
const std::string& team_drive_name,
SharedOption shared_option,
const base::Time& last_modified_time,
const EntryCapabilities& capabilities)
......@@ -200,6 +201,7 @@ struct AddEntriesMessage {
shared_option(shared_option),
source_file_name(source_file_name),
target_path(target_path),
team_drive_name(team_drive_name),
mime_type(mime_type),
last_modified_time(last_modified_time),
capabilities(capabilities) {}
......@@ -209,6 +211,7 @@ struct AddEntriesMessage {
std::string source_file_name; // Source file name prototype.
std::string target_path; // Target file or directory path.
std::string name_text; // Display file name.
std::string team_drive_name; // Name of team drive this entry is in.
std::string mime_type; // File entry content mime type.
base::Time last_modified_time; // Entry last modified time.
EntryCapabilities capabilities; // Entry permissions.
......@@ -222,6 +225,8 @@ struct AddEntriesMessage {
&TestEntryInfo::source_file_name);
converter->RegisterStringField("targetPath", &TestEntryInfo::target_path);
converter->RegisterStringField("nameText", &TestEntryInfo::name_text);
converter->RegisterStringField("teamDriveName",
&TestEntryInfo::team_drive_name);
converter->RegisterStringField("mimeType", &TestEntryInfo::mime_type);
converter->RegisterCustomField("sharedOption",
&TestEntryInfo::shared_option,
......@@ -239,6 +244,8 @@ struct AddEntriesMessage {
*type = FILE;
else if (value == "directory")
*type = DIRECTORY;
else if (value == "team_drive")
*type = TEAM_DRIVE;
else
return false;
return true;
......@@ -397,6 +404,10 @@ class LocalTestVolume : public TestVolume {
ASSERT_TRUE(base::CreateDirectory(target_path))
<< "Failed to create a directory: " << target_path.value();
break;
case AddEntriesMessage::TEAM_DRIVE:
NOTREACHED() << "Can't create a team drive in a local volume: "
<< target_path.value();
break;
}
ASSERT_TRUE(UpdateModifiedTime(entry));
......@@ -490,12 +501,12 @@ class FakeTestVolume : public LocalTestVolume {
// Note: must be kept in sync with BASIC_FAKE_ENTRY_SET defined in the
// integration_tests/file_manager JS code.
CreateEntry(AddEntriesMessage::TestEntryInfo(
AddEntriesMessage::FILE, "text.txt", "hello.txt", "text/plain",
AddEntriesMessage::SharedOption::NONE, base::Time::Now(),
AddEntriesMessage::FILE, "text.txt", "hello.txt", std::string(),
"text/plain", AddEntriesMessage::SharedOption::NONE, base::Time::Now(),
AddEntriesMessage::EntryCapabilities()));
CreateEntry(AddEntriesMessage::TestEntryInfo(
AddEntriesMessage::DIRECTORY, std::string(), "A", std::string(),
AddEntriesMessage::SharedOption::NONE, base::Time::Now(),
std::string(), AddEntriesMessage::SharedOption::NONE, base::Time::Now(),
AddEntriesMessage::EntryCapabilities()));
base::RunLoop().RunUntilIdle();
return true;
......@@ -547,10 +558,21 @@ class DriveTestVolume : public TestVolume {
drive::FileError error = drive::FILE_ERROR_OK;
std::unique_ptr<drive::ResourceEntry> parent_entry(
new drive::ResourceEntry);
integration_service_->file_system()->GetResourceEntry(
drive::util::GetDriveMyDriveRootPath().Append(path).DirName(),
google_apis::test_util::CreateCopyResultCallback(&error,
&parent_entry));
if (!entry.team_drive_name.empty()) {
integration_service_->file_system()->GetResourceEntry(
drive::util::GetDriveTeamDrivesRootPath()
.Append(entry.team_drive_name)
.Append(path)
.DirName(),
google_apis::test_util::CreateCopyResultCallback(&error,
&parent_entry));
} else {
integration_service_->file_system()->GetResourceEntry(
drive::util::GetDriveMyDriveRootPath().Append(path).DirName(),
google_apis::test_util::CreateCopyResultCallback(&error,
&parent_entry));
}
content::RunAllTasksUntilIdle();
ASSERT_EQ(drive::FILE_ERROR_OK, error);
ASSERT_TRUE(parent_entry);
......@@ -575,6 +597,9 @@ class DriveTestVolume : public TestVolume {
CreateDirectory(parent_entry->resource_id(), target_name,
entry.last_modified_time, capabilities);
break;
case AddEntriesMessage::TEAM_DRIVE:
CreateTeamDrive(entry.team_drive_name);
break;
}
// Any file or directory created above, will only appear in Drive after
......@@ -583,6 +608,11 @@ class DriveTestVolume : public TestVolume {
content::RunAllTasksUntilIdle();
}
// Creates a new Team Drive with ID |name| and name |name|.
void CreateTeamDrive(const std::string& name) {
fake_drive_service_->AddTeamDrive(name, name);
}
// Creates an empty directory with the given |name| and |modification_time|.
void CreateDirectory(
const std::string& parent_id,
......@@ -737,6 +767,10 @@ class DriveFsTestVolume : public DriveTestVolume {
ASSERT_TRUE(base::CreateDirectory(target_path))
<< "Failed to create a directory: " << target_path.value();
break;
case AddEntriesMessage::TEAM_DRIVE:
// TODO(sashab): Add support for Team Drives in DriveFS tests.
NOTREACHED();
break;
}
ASSERT_TRUE(UpdateModifiedTime(entry));
......
......@@ -275,11 +275,13 @@ CommandUtil.shouldShowMenuItemsForEntry = function(volumeManager, entry) {
if (!volumeManager || !volumeManager.getVolumeInfo(entry))
return false;
// If the entry is root entry of its volume, hide context menu entries.
if (CommandUtil.isRootEntry(volumeManager, entry))
// If the entry is root entry of its volume (but not a team drive root), hide
// context menu entries.
if (CommandUtil.isRootEntry(volumeManager, entry) &&
!util.isTeamDriveRoot(entry))
return false;
if (util.isTeamDrivesGrandRoot(entry) || util.isTeamDriveRoot(entry))
if (util.isTeamDrivesGrandRoot(entry))
return false;
return true;
......
......@@ -556,7 +556,7 @@ function SubDirectoryItem(label, dirEntry, parentDirItem, tree) {
}
// Sets up context menu of the item.
if (tree.contextMenuForSubitems && !util.isTeamDriveRoot(dirEntry))
if (tree.contextMenuForSubitems)
cr.ui.contextMenuHandler.setContextMenu(item, tree.contextMenuForSubitems);
// Populates children now if needed.
......
......@@ -238,6 +238,23 @@ var SHARED_WITH_ME_ENTRY_SET = [
ENTRIES.testSharedDocument
];
/**
* Entry set for Drive that includes team drives of various permissions and
* nested files with various permissions.
*
* TODO(sashab): Add support for capabilities of Team Drive roots.
*
* @type {Array<TestEntryInfo>}
* @const
*/
var TEAM_DRIVE_ENTRY_SET = [
ENTRIES.hello,
ENTRIES.teamDriveA,
ENTRIES.teamDriveAFile,
ENTRIES.teamDriveB,
ENTRIES.teamDriveBFile,
];
/**
* Opens a Files app's main window.
*
......
......@@ -608,3 +608,123 @@ testcase.checkPasteDisabledForReadOnlyFolderInTree = function() {
false);
});
};
/**
* Tests that the specified menu item is in |expectedEnabledState| when the
* context menu for the Team Drive root with name |teamDriveName| is opened in
* the directory tree.
*
* TODO(sashab): Make this take a map of {commandId: expectedEnabledState}, and
* flatten all tests into 1.
*
* @param {string} commandId ID of the command in the context menu to check.
* @param {string} teamDriveName Team drive name to open the context menu for.
* @param {boolean} expectedEnabledState True if the command should be enabled
* in the context menu, false if not.
*/
function checkTeamDriveContextMenuInTree(
commandId, teamDriveName, expectedEnabledState) {
let navItemSelector = `#directory-tree ` +
`.tree-item[full-path-for-testing="/team_drives/${teamDriveName}"]`;
let appId;
StepsRunner.run([
// Set up Files App.
function() {
setupAndWaitUntilReady(
null, RootPath.DRIVE, this.next, BASIC_LOCAL_ENTRY_SET,
TEAM_DRIVE_ENTRY_SET);
},
// Set focus on the file list.
function(results) {
appId = results.windowId;
remoteCall.callRemoteTestUtil(
'focus', appId, ['#file-list:not([hidden])'], this.next);
},
// Select 'Team Drives'.
function(result) {
chrome.test.assertTrue(!!result);
remoteCall.callRemoteTestUtil(
'selectFolderInTree', appId, ['Team Drives'], this.next);
},
// Expand 'Team Drives'.
function(result) {
chrome.test.assertTrue(!!result);
remoteCall.callRemoteTestUtil(
'expandSelectedFolderInTree', appId, [], this.next);
},
// Wait for the team drive to be visible.
function(result) {
chrome.test.assertTrue(result);
remoteCall.waitForElement(appId, `${navItemSelector}:not([hidden])`)
.then(this.next);
},
// Focus the selected team drive.
function() {
remoteCall.callRemoteTestUtil(
'focus', appId, ['#directory-tree'], this.next);
},
// Right-click the selected team drive.
function() {
remoteCall.callRemoteTestUtil(
'fakeMouseRightClick', appId,
[`${navItemSelector}:not([hidden]) .label`], this.next);
},
// Wait for the context menu to appear.
function(result) {
chrome.test.assertTrue(!!result);
remoteCall
.waitForElement(appId, '#directory-tree-context-menu:not([hidden])')
.then(this.next);
},
// Wait for the command option to appear.
function() {
let query;
if (expectedEnabledState) {
query = `[command="#${commandId}"]:not([hidden]):not([disabled])`;
} else {
query = `[command="#${commandId}"][disabled]:not([hidden])`;
}
remoteCall.waitForElement(appId, query).then(this.next);
},
// Check for Javascript errors.
function() {
checkIfNoErrorsOccured(this.next);
}
]);
}
/**
* Tests that the Cut menu item is disabled if a Team Drive Root is selected.
*/
testcase.checkCutDisabledForTeamDriveRoot = function() {
checkTeamDriveContextMenuInTree('cut', 'Team Drive A', false);
};
/**
* Tests that the Copy menu item is enabled if a Team Drive Root is selected.
*/
testcase.checkCopyEnabledForTeamDriveRoot = function() {
checkTeamDriveContextMenuInTree('copy', 'Team Drive A', true);
};
/**
* Tests that the Rename menu item is disabled if a Team Drive Root is selected.
*/
testcase.checkRenameDisabledForTeamDriveRoot = function() {
checkTeamDriveContextMenuInTree('rename', 'Team Drive A', false);
};
/**
* Tests that the Delete menu item is disabled if a Team Drive Root is selected.
*/
testcase.checkDeleteDisabledForTeamDriveRoot = function() {
checkTeamDriveContextMenuInTree('delete', 'Team Drive A', false);
};
/**
* Tests that the New Folder menu item is enabled if a Team Drive Root is
* selected.
*/
testcase.checkNewFolderEnabledForTeamDriveRoot = function() {
checkTeamDriveContextMenuInTree('new-folder', 'Team Drive A', true);
};
......@@ -199,7 +199,8 @@ function addEntries(volumeNames, entries, opt_callback) {
*/
var EntryType = Object.freeze({
FILE: 'file',
DIRECTORY: 'directory'
DIRECTORY: 'directory',
TEAM_DRIVE: 'team_drive',
});
/**
......@@ -268,7 +269,6 @@ function TestEntryInfoOptions() {}
* @type {EntryType} Entry type.
*/
TestEntryInfoOptions.prototype.type;
/**
* @type {string|undefined} Source file name that provides file contents
* (file location relative to /chrome/test/data/chromeos/file_manager/).
......@@ -279,6 +279,11 @@ TestEntryInfoOptions.prototype.sourceFileName;
* actual name of the file.
*/
TestEntryInfoOptions.prototype.targetPath;
/**
* @type {string} Name of the team drive this entry is in. Defaults to a blank
* string (no team drive). Team Drive names must be unique.
*/
TestEntryInfoOptions.prototype.teamDriveName;
/**
* @type {string|undefined} Mime type.
*/
......@@ -304,7 +309,6 @@ TestEntryInfoOptions.prototype.sizeText;
* @type {string} Type name to be shown in the type column.
*/
TestEntryInfoOptions.prototype.typeText;
/**
* @type {TestEntryCapabilities|undefined} Capabilities of this file. Defaults
* to all capabilities available (read-write access).
......@@ -314,6 +318,8 @@ TestEntryInfoOptions.prototype.capabilities;
/**
* File system entry information for tests. Structure should match TestEntryInfo
* in file_manager_browsertest_base.cc
* TODO(sashab): Remove this, rename TestEntryInfoOptions to TestEntryInfo and
* set the defaults in the record definition above.
*
* @param {TestEntryInfoOptions} options Parameters to create the TestEntryInfo.
*/
......@@ -321,6 +327,7 @@ function TestEntryInfo(options) {
this.type = options.type;
this.sourceFileName = options.sourceFileName || '';
this.targetPath = options.targetPath;
this.teamDriveName = options.teamDriveName || '';
this.mimeType = options.mimeType || '';
this.sharedOption = options.sharedOption || SharedOption.NONE;
this.lastModifiedTime = options.lastModifiedTime;
......@@ -549,6 +556,55 @@ var ENTRIES = {
typeText: 'Plain text'
}),
// Team-drive entries.
teamDriveA: new TestEntryInfo({
type: EntryType.TEAM_DRIVE,
teamDriveName: 'Team Drive A',
}),
teamDriveAFile: new TestEntryInfo({
type: EntryType.FILE,
sourceFileName: 'text.txt',
targetPath: 'teamDriveAFile.txt',
mimeType: 'text/plain',
lastModifiedTime: 'Sep 4, 1998, 12:34 PM',
nameText: 'teamDriveAFile.txt',
sizeText: '51 bytes',
typeText: 'Plain text',
teamDriveName: 'Team Drive A',
capabilities: {
canCopy: true,
canDelete: true,
canRename: true,
canAddChildren: false,
canShare: true,
},
}),
teamDriveB: new TestEntryInfo({
type: EntryType.TEAM_DRIVE,
teamDriveName: 'Team Drive B',
}),
teamDriveBFile: new TestEntryInfo({
type: EntryType.FILE,
sourceFileName: 'text.txt',
targetPath: 'teamDriveBFile.txt',
mimeType: 'text/plain',
lastModifiedTime: 'Sep 4, 1998, 12:34 PM',
nameText: 'teamDriveBFile.txt',
sizeText: '51 bytes',
typeText: 'Plain text',
teamDriveName: 'Team Drive B',
capabilities: {
canCopy: true,
canDelete: false,
canRename: false,
canAddChildren: false,
canShare: true,
},
}),
// Read-only and write-restricted entries.
// TODO(sashab): Generate all combinations of capabilities inside the test, to
......
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