| Index: third_party/WebKit/Source/web/tests/LinkSelectionTest.cpp
|
| diff --git a/third_party/WebKit/Source/web/tests/LinkSelectionTest.cpp b/third_party/WebKit/Source/web/tests/LinkSelectionTest.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..28a8b4bc96b18cbe894883de24b931342e59cd29
|
| --- /dev/null
|
| +++ b/third_party/WebKit/Source/web/tests/LinkSelectionTest.cpp
|
| @@ -0,0 +1,314 @@
|
| +// Copyright (c) 2016 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 "core/dom/Range.h"
|
| +#include "core/frame/FrameView.h"
|
| +#include "core/input/EventHandler.h"
|
| +#include "core/page/ChromeClient.h"
|
| +#include "core/page/ContextMenuController.h"
|
| +#include "core/page/FocusController.h"
|
| +#include "core/page/Page.h"
|
| +#include "platform/Cursor.h"
|
| +#include "platform/testing/URLTestHelpers.h"
|
| +#include "platform/testing/UnitTestHelpers.h"
|
| +#include "public/web/WebSettings.h"
|
| +#include "testing/gmock/include/gmock/gmock.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +#include "web/WebLocalFrameImpl.h"
|
| +#include "web/tests/FrameTestHelpers.h"
|
| +
|
| +using ::testing::_;
|
| +
|
| +namespace blink {
|
| +
|
| +IntSize scaled(IntSize p, float scale)
|
| +{
|
| + p.scale(scale, scale);
|
| + return p;
|
| +}
|
| +
|
| +class LinkSelectionTestBase : public ::testing::Test {
|
| +protected:
|
| + enum DragFlag {
|
| + SendDownEvent = 1,
|
| + SendUpEvent = 1 << 1
|
| + };
|
| + using DragFlags = unsigned;
|
| +
|
| + void emulateMouseDrag(const IntPoint& downPoint, const IntPoint& upPoint, int modifiers,
|
| + DragFlags = SendDownEvent | SendUpEvent);
|
| +
|
| + void emulateMouseClick(const IntPoint& clickPoint, WebMouseEvent::Button, int modifiers, int count = 1);
|
| + void emulateMouseDown(const IntPoint& clickPoint, WebMouseEvent::Button, int modifiers, int count = 1);
|
| +
|
| + String getSelectionText();
|
| +
|
| + FrameTestHelpers::WebViewHelper m_helper;
|
| + WebViewImpl* m_webView = nullptr;
|
| + RawPtrWillBePersistent<WebLocalFrameImpl> m_mainFrame = nullptr;
|
| +};
|
| +
|
| +void LinkSelectionTestBase::emulateMouseDrag(const IntPoint& downPoint, const IntPoint& upPoint, int modifiers, DragFlags dragFlags)
|
| +{
|
| + if (dragFlags & SendDownEvent) {
|
| + const auto& downEvent = FrameTestHelpers::createMouseEvent(WebMouseEvent::MouseDown, WebMouseEvent::ButtonLeft, downPoint, modifiers);
|
| + m_webView->handleInputEvent(downEvent);
|
| + }
|
| +
|
| + const int kMoveEventsNumber = 10;
|
| + const float kMoveIncrementFraction = 1. / kMoveEventsNumber;
|
| + const auto& upDownVector = upPoint - downPoint;
|
| + for (int i = 0; i < kMoveEventsNumber; ++i) {
|
| + const auto& movePoint = downPoint + scaled(upDownVector, i * kMoveIncrementFraction);
|
| + const auto& moveEvent = FrameTestHelpers::createMouseEvent(WebMouseEvent::MouseMove, WebMouseEvent::ButtonLeft, movePoint, modifiers);
|
| + m_webView->handleInputEvent(moveEvent);
|
| + }
|
| +
|
| + if (dragFlags & SendUpEvent) {
|
| + const auto& upEvent = FrameTestHelpers::createMouseEvent(WebMouseEvent::MouseUp, WebMouseEvent::ButtonLeft, upPoint, modifiers);
|
| + m_webView->handleInputEvent(upEvent);
|
| + }
|
| +}
|
| +
|
| +void LinkSelectionTestBase::emulateMouseClick(const IntPoint& clickPoint, WebMouseEvent::Button button, int modifiers, int count)
|
| +{
|
| + auto event = FrameTestHelpers::createMouseEvent(WebMouseEvent::MouseDown, button, clickPoint, modifiers);
|
| + event.clickCount = count;
|
| + m_webView->handleInputEvent(event);
|
| + event.type = WebMouseEvent::MouseUp;
|
| + m_webView->handleInputEvent(event);
|
| +}
|
| +
|
| +void LinkSelectionTestBase::emulateMouseDown(const IntPoint& clickPoint, WebMouseEvent::Button button, int modifiers, int count)
|
| +{
|
| + auto event = FrameTestHelpers::createMouseEvent(WebMouseEvent::MouseDown, button, clickPoint, modifiers);
|
| + event.clickCount = count;
|
| + m_webView->handleInputEvent(event);
|
| +}
|
| +
|
| +String LinkSelectionTestBase::getSelectionText()
|
| +{
|
| + return m_mainFrame->selectionAsText();
|
| +}
|
| +
|
| +class TestFrameClient : public FrameTestHelpers::TestWebFrameClient {
|
| +public:
|
| + MOCK_METHOD4(loadURLExternally,
|
| + void(const WebURLRequest&, WebNavigationPolicy, const WebString& downloadName, bool shouldReplaceCurrentEntry));
|
| +};
|
| +
|
| +class LinkSelectionTest : public LinkSelectionTestBase {
|
| +protected:
|
| + void SetUp() override
|
| + {
|
| + const char* const kHTMLString =
|
| + "<a id='link' href='foo.com' style='font-size:20pt'>Text to select foobar</a>"
|
| + "<div id='page_text'>Lorem ipsum dolor sit amet</div>";
|
| +
|
| + // We need to set deviceSupportsMouse setting to true and page's focus controller to active
|
| + // so that FrameView can set the mouse cursor.
|
| + m_webView = m_helper.initialize(false, &m_testFrameClient, nullptr,
|
| + [](WebSettings* settings) { settings->setDeviceSupportsMouse(true); });
|
| + m_mainFrame = m_webView->mainFrameImpl();
|
| + FrameTestHelpers::loadHTMLString(m_mainFrame, kHTMLString, URLTestHelpers::toKURL("http://foobar.com"));
|
| + m_webView->resize(WebSize(800, 600));
|
| + m_webView->page()->focusController().setActive(true);
|
| +
|
| + auto* document = m_mainFrame->frame()->document();
|
| + ASSERT_NE(nullptr, document);
|
| + auto* linkToSelect = document->getElementById("link")->firstChild();
|
| + ASSERT_NE(nullptr, linkToSelect);
|
| + // We get larger range that we actually want to select, because we need a slightly larger
|
| + // rect to include the last character to the selection.
|
| + const auto rangeToSelect = Range::create(*document, linkToSelect, 5, linkToSelect, 16);
|
| +
|
| + const auto& selectionRect = rangeToSelect->boundingBox();
|
| + const auto& selectionRectCenterY = selectionRect.center().y();
|
| + m_leftPointInLink = selectionRect.minXMinYCorner();
|
| + m_leftPointInLink.setY(selectionRectCenterY);
|
| +
|
| + m_rightPointInLink = selectionRect.maxXMinYCorner();
|
| + m_rightPointInLink.setY(selectionRectCenterY);
|
| + m_rightPointInLink.move(-2, 0);
|
| + }
|
| +
|
| + TestFrameClient m_testFrameClient;
|
| + IntPoint m_leftPointInLink;
|
| + IntPoint m_rightPointInLink;
|
| +};
|
| +
|
| +TEST_F(LinkSelectionTest, MouseDragWithoutAltAllowNoLinkSelection)
|
| +{
|
| + emulateMouseDrag(m_leftPointInLink, m_rightPointInLink, 0);
|
| + EXPECT_TRUE(getSelectionText().isEmpty());
|
| +}
|
| +
|
| +TEST_F(LinkSelectionTest, MouseDragWithAltAllowSelection)
|
| +{
|
| + emulateMouseDrag(m_leftPointInLink, m_rightPointInLink, WebInputEvent::AltKey);
|
| + EXPECT_EQ("to select", getSelectionText());
|
| +}
|
| +
|
| +TEST_F(LinkSelectionTest, HandCursorDuringLinkDrag)
|
| +{
|
| + emulateMouseDrag(m_rightPointInLink, m_leftPointInLink, 0, SendDownEvent);
|
| + m_mainFrame->frame()->localFrameRoot()->eventHandler().scheduleCursorUpdate();
|
| + testing::runDelayedTasks(50);
|
| + const auto& cursor = m_mainFrame->frame()->chromeClient().lastSetCursorForTesting();
|
| + EXPECT_EQ(Cursor::Hand, cursor.getType());
|
| +}
|
| +
|
| +TEST_F(LinkSelectionTest, CaretCursorOverLinkDuringSelection)
|
| +{
|
| + emulateMouseDrag(m_rightPointInLink, m_leftPointInLink, WebInputEvent::AltKey, SendDownEvent);
|
| + m_mainFrame->frame()->localFrameRoot()->eventHandler().scheduleCursorUpdate();
|
| + testing::runDelayedTasks(50);
|
| + const auto& cursor = m_mainFrame->frame()->chromeClient().lastSetCursorForTesting();
|
| + EXPECT_EQ(Cursor::IBeam, cursor.getType());
|
| +}
|
| +
|
| +TEST_F(LinkSelectionTest, HandCursorOverLinkAfterContextMenu)
|
| +{
|
| + // Move mouse.
|
| + emulateMouseDrag(m_rightPointInLink, m_leftPointInLink, 0, 0);
|
| +
|
| + // Show context menu. We don't send mouseup event here since in browser it doesn't reach
|
| + // blink because of shown context menu.
|
| + emulateMouseDown(m_leftPointInLink, WebMouseEvent::ButtonRight, 0, 1);
|
| +
|
| + LocalFrame* frame = m_mainFrame->frame();
|
| + // Hide context menu.
|
| + frame->page()->contextMenuController().clearContextMenu();
|
| +
|
| + frame->localFrameRoot()->eventHandler().scheduleCursorUpdate();
|
| + testing::runDelayedTasks(50);
|
| + const auto& cursor = m_mainFrame->frame()->chromeClient().lastSetCursorForTesting();
|
| + EXPECT_EQ(Cursor::Hand, cursor.getType());
|
| +}
|
| +
|
| +TEST_F(LinkSelectionTest, SingleClickWithAltStartsDownload)
|
| +{
|
| + EXPECT_CALL(m_testFrameClient, loadURLExternally(_, WebNavigationPolicy::WebNavigationPolicyDownload, WebString(), _));
|
| + emulateMouseClick(m_leftPointInLink, WebMouseEvent::ButtonLeft, WebInputEvent::AltKey);
|
| +}
|
| +
|
| +TEST_F(LinkSelectionTest, SingleClickWithAltStartsDownloadWhenTextSelected)
|
| +{
|
| + auto* document = m_mainFrame->frame()->document();
|
| + auto* textToSelect = document->getElementById("page_text")->firstChild();
|
| + ASSERT_NE(nullptr, textToSelect);
|
| +
|
| + // Select some page text outside the link element.
|
| + const RefPtrWillBeRawPtr<Range> rangeToSelect = Range::create(*document, textToSelect, 1, textToSelect, 20);
|
| + const auto& selectionRect = rangeToSelect->boundingBox();
|
| + m_mainFrame->moveRangeSelection(selectionRect.minXMinYCorner(), selectionRect.maxXMaxYCorner());
|
| + EXPECT_FALSE(getSelectionText().isEmpty());
|
| +
|
| + EXPECT_CALL(m_testFrameClient, loadURLExternally(_, WebNavigationPolicy::WebNavigationPolicyDownload, WebString(), _));
|
| + emulateMouseClick(m_leftPointInLink, WebMouseEvent::ButtonLeft, WebInputEvent::AltKey);
|
| +}
|
| +
|
| +class LinkSelectionClickEventsTest : public LinkSelectionTestBase {
|
| +protected:
|
| + class MockEventListener final : public EventListener {
|
| + public:
|
| + static PassRefPtrWillBeRawPtr<MockEventListener> create()
|
| + {
|
| + return adoptRefWillBeNoop(new MockEventListener());
|
| + }
|
| +
|
| + bool operator==(const EventListener& other) const final
|
| + {
|
| + return this == &other;
|
| + }
|
| +
|
| + MOCK_METHOD2(handleEvent, void(ExecutionContext* executionContext, Event*));
|
| +
|
| + private:
|
| + MockEventListener() : EventListener(CPPEventListenerType)
|
| + {
|
| + }
|
| + };
|
| +
|
| + void SetUp() override
|
| + {
|
| + const char* const kHTMLString =
|
| + "<div id='empty_div' style='width: 100px; height: 100px;'></div>"
|
| + "<span id='text_div'>Sometexttoshow</span>";
|
| +
|
| + m_webView = m_helper.initialize(false);
|
| + m_mainFrame = m_webView->mainFrameImpl();
|
| + FrameTestHelpers::loadHTMLString(m_mainFrame, kHTMLString, URLTestHelpers::toKURL("http://foobar.com"));
|
| + m_webView->resize(WebSize(800, 600));
|
| + m_webView->page()->focusController().setActive(true);
|
| +
|
| + auto* document = m_mainFrame->frame()->document();
|
| + ASSERT_NE(nullptr, document);
|
| +
|
| + auto* emptyDiv = document->getElementById("empty_div");
|
| + auto* textDiv = document->getElementById("text_div");
|
| + ASSERT_NE(nullptr, emptyDiv);
|
| + ASSERT_NE(nullptr, textDiv);
|
| + }
|
| +
|
| + void checkMouseClicks(Element& element, bool doubleClickEvent)
|
| + {
|
| + struct ScopedListenersCleaner {
|
| + ScopedListenersCleaner(Element* element) : m_element(element) {}
|
| +
|
| + ~ScopedListenersCleaner()
|
| + {
|
| + m_element->removeAllEventListeners();
|
| + }
|
| +
|
| + RawPtrWillBePersistent<Element> m_element;
|
| + } const listenersCleaner(&element);
|
| +
|
| + RefPtrWillBeRawPtr<MockEventListener> eventHandler = MockEventListener::create();
|
| + element.addEventListener(
|
| + doubleClickEvent ? EventTypeNames::dblclick : EventTypeNames::click,
|
| + eventHandler);
|
| +
|
| + ::testing::InSequence s;
|
| + EXPECT_CALL(*eventHandler, handleEvent(_, _)).Times(1);
|
| +
|
| + const auto& elemBounds = element.boundsInViewport();
|
| + const int clickCount = doubleClickEvent ? 2 : 1;
|
| + emulateMouseClick(elemBounds.center(), WebMouseEvent::ButtonLeft, 0, clickCount);
|
| +
|
| + if (doubleClickEvent) {
|
| + EXPECT_EQ(element.innerText().isEmpty(), getSelectionText().isEmpty());
|
| + }
|
| + }
|
| +};
|
| +
|
| +TEST_F(LinkSelectionClickEventsTest, SingleAndDoubleClickWillBeHandled)
|
| +{
|
| + auto* document = m_mainFrame->frame()->document();
|
| + auto* element = document->getElementById("empty_div");
|
| +
|
| + {
|
| + SCOPED_TRACE("Empty div, single click");
|
| + checkMouseClicks(*element, false);
|
| + }
|
| +
|
| + {
|
| + SCOPED_TRACE("Empty div, double click");
|
| + checkMouseClicks(*element, true);
|
| + }
|
| +
|
| + element = document->getElementById("text_div");
|
| +
|
| + {
|
| + SCOPED_TRACE("Text div, single click");
|
| + checkMouseClicks(*element, false);
|
| + }
|
| +
|
| + {
|
| + SCOPED_TRACE("Text div, double click");
|
| + checkMouseClicks(*element, true);
|
| + }
|
| +}
|
| +
|
| +} // namespace blink
|
|
|