Commit 81eefa40 authored by Hazim Mohamed's avatar Hazim Mohamed Committed by Commit Bot

[NativeFS] Introduce a browser test for native file system drag and drop

Introduces a browser test that implements end-to-end testing of
the DataTransferItem.getAsFileSystemHandle() method. It contains two
tests: one for dropped files and one for dropped directories.

Bug: 1080811
Change-Id: Ie64096539a732c0a2d101ca98bf9e86fcc9190ee
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2339945
Commit-Queue: Hazim Mohamed <hazimmohamed@google.com>
Reviewed-by: default avatarMarijn Kruisselbrink <mek@chromium.org>
Reviewed-by: default avatarDarwin Huang <huangdarwin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#797986}
parent fc6035ff
// Copyright 2020 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.
#include <string>
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/test/scoped_feature_list.h"
#include "content/browser/native_file_system/native_file_system_manager_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/common/drop_data.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/shell/browser/shell.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "ui/base/dragdrop/file_info/file_info.h"
#include "ui/gfx/geometry/point_f.h"
namespace content {
// End-to-end tests for Native File System drag and drop, or more specifically,
// DataTransferItem's getAsFileSystemHandle method.
class NativeFileSystemDragDropBrowserTest : public ContentBrowserTest {
public:
void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
scoped_feature_list_.InitAndEnableFeature(
blink::features::kNativeFileSystemAPI);
ASSERT_TRUE(embedded_test_server()->Start());
ContentBrowserTest::SetUp();
}
void SetUpCommandLine(base::CommandLine* command_line) override {
// Enable experimental web platform features to enable write access.
command_line->AppendSwitch(
switches::kEnableExperimentalWebPlatformFeatures);
// TODO(hazimmohamed): Remove this switch when NativeFileSystemDragAndDrop
// becomes part of kEnableExperimentalWebPlatformFeatures.
command_line->AppendSwitchASCII(switches::kEnableBlinkFeatures,
"NativeFileSystemDragAndDrop");
}
void TearDown() override {
ContentBrowserTest::TearDown();
ASSERT_TRUE(temp_dir_.Delete());
}
base::FilePath CreateTestFileInDirectory(const base::FilePath& directory_path,
const std::string& contents) {
base::ScopedAllowBlockingForTesting allow_blocking;
base::FilePath result;
EXPECT_TRUE(base::CreateTemporaryFileInDir(directory_path, &result));
EXPECT_TRUE(base::WriteFile(result, contents));
return result;
}
base::FilePath CreateTestDir() {
base::ScopedAllowBlockingForTesting allow_blocking;
base::FilePath result;
EXPECT_TRUE(base::CreateTemporaryDirInDir(
temp_dir_.GetPath(), FILE_PATH_LITERAL("test"), &result));
return result;
}
RenderWidgetHostImpl* GetRenderWidgetHostImplForMainFrame() {
WebContentsImpl* web_contents_impl =
static_cast<WebContentsImpl*>(shell()->web_contents());
return web_contents_impl->GetMainFrame()->GetRenderWidgetHost();
}
protected:
base::test::ScopedFeatureList scoped_feature_list_;
base::ScopedTempDir temp_dir_;
};
IN_PROC_BROWSER_TEST_F(NativeFileSystemDragDropBrowserTest, DropFile) {
// Get the RenderWidgetHostImpl for the main (and only) frame.
RenderWidgetHostImpl* render_widget_host_impl =
GetRenderWidgetHostImplForMainFrame();
DCHECK(render_widget_host_impl);
// Prepare the window for dragging and dropping.
ASSERT_TRUE(
NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
// Prevent defaults of drag operations and create a promise that will resolve
// on call to window.ondrop with the text from a dropped file. This text is
// retrieved using the NativeFileSystem getAsFileSystemHandle function. The
// promise will reject if zero/multiples items are dropped or if the item is
// not a file.
ASSERT_TRUE(
ExecJs(shell(),
"window.ondragenter = (e) => { e.preventDefault() };"
"window.ondragover = (e) => { e.preventDefault() };"
"var p = new Promise((resolve, reject) => {"
" window.ondrop = async (event) => {"
" event.preventDefault();"
" if (event.dataTransfer.items.length !== 1) {"
" reject('There were ' + event.dataTransfer.items.length"
" + ' dropped items. Expected 1.');"
" }"
" if (event.dataTransfer.items[0].kind != 'file') {"
" reject('The drag item was of kind: ' +"
" event.dataTransfer.items[0].kind + '. Expected"
" file.');"
" }"
" const fileItem = event.dataTransfer.items[0];"
" const fileHandle = await fileItem.getAsFileSystemHandle();"
" if (fileHandle.kind !== 'file') {"
" reject('The dragged item was a directory, expected it to"
" be a file.');"
" }"
" const file = await fileHandle.getFile();"
" const text = await file.text();"
" resolve(text);"
" }"
"});"));
// Create a test file with contents `test_contents` to drop on the webpage.
std::string test_contents = "Deleted code is debugged code.";
base::FilePath test_file_path =
CreateTestFileInDirectory(temp_dir_.GetPath(), test_contents);
// Get the points corresponding to the center of the browser window in both
// screen coordinates and window coordinates.
const gfx::Rect window_in_screen_coords =
render_widget_host_impl->GetView()->GetBoundsInRootWindow();
const gfx::PointF screen_point =
gfx::PointF(window_in_screen_coords.CenterPoint());
const gfx::PointF client_point =
gfx::PointF(window_in_screen_coords.width() / 2,
window_in_screen_coords.height() / 2);
// Drop the test file.
DropData drop_data;
drop_data.filenames.emplace_back(
ui::FileInfo(test_file_path, test_file_path.BaseName()));
render_widget_host_impl->FilterDropData(&drop_data);
render_widget_host_impl->DragTargetDragEnter(
drop_data, client_point, screen_point,
blink::WebDragOperationsMask::kWebDragOperationEvery,
/*key_modifiers=*/0);
render_widget_host_impl->DragTargetDragOver(
client_point, screen_point,
blink::WebDragOperationsMask::kWebDragOperationEvery,
/*key_modifiers=*/0);
render_widget_host_impl->DragTargetDrop(drop_data, client_point, screen_point,
/*key_modifiers=*/0);
// Expect the promise to resolve with `test_contents`.
EXPECT_EQ(test_contents, EvalJs(shell(), "p"));
}
IN_PROC_BROWSER_TEST_F(NativeFileSystemDragDropBrowserTest, DropDirectory) {
// Get the RenderWidgetHostImpl for the main (and only) frame.
RenderWidgetHostImpl* render_widget_host_impl =
GetRenderWidgetHostImplForMainFrame();
DCHECK(render_widget_host_impl);
// Prepare the window for dragging and dropping.
ASSERT_TRUE(
NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
// Prevent defaults of drag operations and create a promise that will resolve
// with the name of the child directory of the dropped directory. The promise
// rejects if there are zero/multiple items dropped or if the dropped item is
// directory. The promise will also reject if there are zero/multiple items
// inside the dropped directory.
ASSERT_TRUE(
ExecJs(shell(),
"window.ondragenter = (e) => { e.preventDefault() };"
"window.ondragover = (e) => { e.preventDefault() };"
"var p = new Promise((resolve, reject) => {"
" window.ondrop = async (dragEvent) => {"
" dragEvent.preventDefault();"
" if (dragEvent.dataTransfer.items.length !== 1) {"
" reject('There were ' + dragEvent.dataTransfer.items.length"
" + ' dropped items. Expected 1.');"
" }"
" if (dragEvent.dataTransfer.items[0].kind != 'file') {"
" reject('The drag item was of kind: ' +"
" dragEvent.dataTransfer.items[0].kind + '. Expected"
" file.');"
" }"
" const fileItem = dragEvent.dataTransfer.items[0];"
" directoryHandle = await fileItem.getAsFileSystemHandle();"
" if (directoryHandle.kind !== 'directory') {"
" reject('The dragged item was a file, expected it to be a "
" directory.');"
" }"
" let directoryContents = [];"
" for await (let fileName of directoryHandle.keys()) {"
" directoryContents.push(fileName);"
" };"
" if (directoryContents.length !== 1) {"
" reject('There were ', directoryContents.length, ' files "
" in the dropped directory. Expected 1.');"
" }"
" resolve(directoryContents.pop());"
" }"
"});"));
// Create a directory and create a file inside the directory.
const base::FilePath test_dir_path = CreateTestDir();
std::string contents = "Irrelevant contents.";
const base::FilePath file_inside_dir =
CreateTestFileInDirectory(test_dir_path, contents);
// Get the points corresponding to the center of the browser window in both
// screen coordinates and window coordinates.
const gfx::Rect window_in_screen_coords =
render_widget_host_impl->GetView()->GetBoundsInRootWindow();
const gfx::PointF screen_point =
gfx::PointF(window_in_screen_coords.CenterPoint());
const gfx::PointF client_point =
gfx::PointF(window_in_screen_coords.width() / 2,
window_in_screen_coords.height() / 2);
// Drop the test file.
DropData drop_data;
drop_data.filenames.emplace_back(
ui::FileInfo(test_dir_path, test_dir_path.BaseName()));
render_widget_host_impl->FilterDropData(&drop_data);
render_widget_host_impl->DragTargetDragEnter(
drop_data, client_point, screen_point,
blink::WebDragOperationsMask::kWebDragOperationEvery,
/*key_modifiers=*/0);
render_widget_host_impl->DragTargetDragOver(
client_point, screen_point,
blink::WebDragOperationsMask::kWebDragOperationEvery,
/*key_modifiers=*/0);
render_widget_host_impl->DragTargetDrop(drop_data, client_point, screen_point,
/*key_modifiers=*/0);
// Wait promise to resolve and expect the directory to have child with name
// matching the base name of `file_inside_dir`.
EXPECT_EQ(file_inside_dir.BaseName().AsUTF8Unsafe(), EvalJs(shell(), "p"));
}
} // namespace content
\ No newline at end of file
...@@ -1010,6 +1010,7 @@ test("content_browsertests") { ...@@ -1010,6 +1010,7 @@ test("content_browsertests") {
"../browser/message_port_provider_browsertest.cc", "../browser/message_port_provider_browsertest.cc",
"../browser/mojo_sandbox_browsertest.cc", "../browser/mojo_sandbox_browsertest.cc",
"../browser/native_file_system/file_system_chooser_browsertest.cc", "../browser/native_file_system/file_system_chooser_browsertest.cc",
"../browser/native_file_system/native_file_system_drag_drop_browsertest.cc",
"../browser/native_file_system/native_file_system_file_writer_impl_browsertest.cc", "../browser/native_file_system/native_file_system_file_writer_impl_browsertest.cc",
"../browser/navigation_browsertest.cc", "../browser/navigation_browsertest.cc",
"../browser/navigation_mhtml_browsertest.cc", "../browser/navigation_mhtml_browsertest.cc",
......
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