blob: 26a5539e8c9b127df61238d51a951a4443bee1f4 [file] [log] [blame]
// Copyright 2019 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 <memory>
#include "components/ui_devtools/views/dom_agent_views.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "components/ui_devtools/css_agent.h"
#include "components/ui_devtools/ui_devtools_unittest_utils.h"
#include "components/ui_devtools/ui_element.h"
#include "components/ui_devtools/views/overlay_agent_views.h"
#include "components/ui_devtools/views/view_element.h"
#include "components/ui_devtools/views/widget_element.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/native_widget_private.h"
#include "ui/views/widget/widget.h"
#if defined(USE_AURA)
#include "components/ui_devtools/views/window_element.h"
#include "ui/aura/client/window_parenting_client.h"
#include "ui/aura/env.h"
#include "ui/aura/window_tree_host.h"
#endif // defined(USE_AURA)
namespace ui_devtools {
namespace DOM = protocol::DOM;
namespace {
class TestView : public views::View {
public:
TestView(const char* name) : name_(name) {}
const char* GetClassName() const override { return name_; }
private:
const char* name_;
DISALLOW_COPY_AND_ASSIGN(TestView);
};
std::string GetAttributeValue(const std::string& attribute, DOM::Node* node) {
EXPECT_TRUE(node->hasAttributes());
protocol::Array<std::string>* attributes = node->getAttributes(nullptr);
for (size_t i = 0; i < attributes->size() - 1; i += 2) {
if ((*attributes)[i] == attribute)
return (*attributes)[i + 1];
}
return std::string();
}
DOM::Node* FindNodeWithID(int id, DOM::Node* root) {
if (id == root->getNodeId()) {
return root;
}
protocol::Array<DOM::Node>* children = root->getChildren(nullptr);
for (size_t i = 0; i < children->size(); i++) {
if (DOM::Node* node = FindNodeWithID(id, (*children)[i].get()))
return node;
}
return nullptr;
}
} // namespace
class DOMAgentTest : public views::ViewsTestBase {
public:
DOMAgentTest() {}
~DOMAgentTest() override {}
views::internal::NativeWidgetPrivate* CreateTestNativeWidget() {
views::Widget* widget = new views::Widget;
views::Widget::InitParams params;
params.ownership = views::Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET;
#if defined(USE_AURA)
params.parent = GetContext();
#endif
widget->Init(std::move(params));
return widget->native_widget_private();
}
std::unique_ptr<views::Widget> CreateTestWidget(
const gfx::Rect& bounds,
const std::string* name = nullptr) {
auto widget = std::make_unique<views::Widget>();
views::Widget::InitParams params;
params.delegate = nullptr;
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.bounds = bounds;
#if defined(USE_AURA)
params.parent = GetContext();
#endif
if (name)
params.name = *name;
widget->Init(std::move(params));
widget->Show();
return widget;
}
#if defined(USE_AURA)
std::unique_ptr<aura::Window> CreateChildWindow(
aura::Window* parent,
aura::client::WindowType type = aura::client::WINDOW_TYPE_NORMAL) {
std::unique_ptr<aura::Window> window =
std::make_unique<aura::Window>(nullptr, type);
window->Init(ui::LAYER_NOT_DRAWN);
window->SetBounds(gfx::Rect());
parent->AddChild(window.get());
window->Show();
return window;
}
#endif
void SetUp() override {
fake_frontend_channel_ = std::make_unique<FakeFrontendChannel>();
uber_dispatcher_ = std::make_unique<protocol::UberDispatcher>(
fake_frontend_channel_.get());
dom_agent_ = DOMAgentViews::Create();
dom_agent_->Init(uber_dispatcher_.get());
css_agent_ = std::make_unique<CSSAgent>(dom_agent_.get());
css_agent_->Init(uber_dispatcher_.get());
css_agent_->enable();
overlay_agent_ = OverlayAgentViews::Create(dom_agent_.get());
overlay_agent_->Init(uber_dispatcher_.get());
overlay_agent_->enable();
// We need to create |dom_agent| first to observe creation of
// WindowTreeHosts in ViewTestBase::SetUp().
views::ViewsTestBase::SetUp();
#if defined(USE_AURA)
top_window = CreateChildWindow(GetContext());
#endif
}
void TearDown() override {
#if defined(USE_AURA)
top_window.reset();
#endif
css_agent_.reset();
overlay_agent_.reset();
dom_agent_.reset();
uber_dispatcher_.reset();
fake_frontend_channel_.reset();
views::ViewsTestBase::TearDown();
}
template <typename T>
bool WasChildNodeInserted(T* parent, int previous_sibling_id = 0) {
const int parent_id = GetIDForBackendElement(parent);
return frontend_channel()->CountProtocolNotificationMessageStartsWith(
base::StringPrintf("{\"method\":\"DOM.childNodeInserted\","
"\"params\":{\"parentNodeId\":%d,"
"\"previousNodeId\":%d",
parent_id, previous_sibling_id)) == 1;
}
template <typename T, typename U>
bool WasChildNodeInserted(T* parent, U* previous_sibling) {
const int previous_sibling_id =
previous_sibling ? GetIDForBackendElement(previous_sibling) : 0;
return WasChildNodeInserted(parent, previous_sibling_id);
}
template <typename T>
bool WasChildNodeRemoved(T* parent, int node_id) {
const int parent_id = GetIDForBackendElement(parent);
return frontend_channel()->CountProtocolNotificationMessage(
base::StringPrintf(
"{\"method\":\"DOM.childNodeRemoved\",\"params\":{"
"\"parentNodeId\":%d,\"nodeId\":%d}}",
parent_id, node_id)) == 1;
}
template <typename T>
int GetIDForBackendElement(T* element) {
return dom_agent()->element_root()->FindUIElementIdForBackendElement<T>(
element);
}
template <typename T>
DOM::Node* FindInRoot(T* element, DOM::Node* root) {
return FindNodeWithID(GetIDForBackendElement(element), root);
}
// The following three methods test that a tree of DOM::Node exactly
// corresponds 1:1 with a views/Aura hierarchy
#if defined(USE_AURA)
bool ElementTreeMatchesDOMTree(aura::Window* window, DOM::Node* root) {
if (GetIDForBackendElement(window) != root->getNodeId() ||
"Window" != root->getNodeName() ||
window->GetName() != GetAttributeValue("name", root)) {
return false;
}
protocol::Array<DOM::Node>* children = root->getChildren(nullptr);
size_t child_index = 0;
views::Widget* widget = views::Widget::GetWidgetForNativeView(window);
if (widget &&
!ElementTreeMatchesDOMTree(widget, (*children)[child_index++].get())) {
return false;
}
for (aura::Window* child_window : window->children()) {
if (!ElementTreeMatchesDOMTree(child_window,
(*children)[child_index++].get()))
return false;
}
// Make sure there are no stray children.
return child_index == children->size();
}
#endif
bool ElementTreeMatchesDOMTree(views::Widget* widget, DOM::Node* root) {
if (GetIDForBackendElement(widget) != root->getNodeId() ||
"Widget" != root->getNodeName() ||
widget->GetName() != GetAttributeValue("name", root)) {
return false;
}
protocol::Array<DOM::Node>* children = root->getChildren(nullptr);
views::View* root_view = widget->GetRootView();
return root_view
? ElementTreeMatchesDOMTree(root_view, (*children)[0].get())
: children->empty();
}
bool ElementTreeMatchesDOMTree(views::View* view, DOM::Node* root) {
if (GetIDForBackendElement(view) != root->getNodeId() ||
"View" != root->getNodeName() ||
view->GetClassName() != GetAttributeValue("name", root)) {
return false;
}
protocol::Array<DOM::Node>* children = root->getChildren(nullptr);
std::vector<views::View*> child_views = view->GetChildrenInZOrder();
const size_t child_count = child_views.size();
if (child_count != children->size())
return false;
for (size_t i = 0; i < child_count; i++) {
if (!ElementTreeMatchesDOMTree(child_views[i], (*children)[i].get()))
return false;
}
return true;
}
FakeFrontendChannel* frontend_channel() {
return fake_frontend_channel_.get();
}
DOMAgentViews* dom_agent() { return dom_agent_.get(); }
#if defined(USE_AURA)
std::unique_ptr<aura::Window> top_window;
#endif
private:
std::unique_ptr<protocol::UberDispatcher> uber_dispatcher_;
std::unique_ptr<FakeFrontendChannel> fake_frontend_channel_;
std::unique_ptr<DOMAgentViews> dom_agent_;
std::unique_ptr<CSSAgent> css_agent_;
std::unique_ptr<OverlayAgentViews> overlay_agent_;
DISALLOW_COPY_AND_ASSIGN(DOMAgentTest);
};
// Tests to ensure that the DOMAgent's hierarchy matches the real hierarchy.
#if defined(USE_AURA)
TEST_F(DOMAgentTest, GetDocumentWithWindowWidgetView) {
// parent_window
// widget
// (root/content views)
// child_view
// child_window
std::unique_ptr<views::Widget> widget(
CreateTestWidget(gfx::Rect(1, 1, 80, 80)));
aura::Window* parent_window = widget->GetNativeWindow();
parent_window->SetName("parent_window");
std::unique_ptr<aura::Window> child_window = CreateChildWindow(parent_window);
child_window->SetName("child_window");
widget->Show();
views::View* child_view = new TestView("child_view");
widget->GetRootView()->AddChildView(child_view);
std::unique_ptr<DOM::Node> root;
dom_agent()->getDocument(&root);
DOM::Node* parent_node = FindInRoot(parent_window, root.get());
DCHECK(parent_node);
EXPECT_TRUE(ElementTreeMatchesDOMTree(parent_window, parent_node));
}
TEST_F(DOMAgentTest, GetDocumentNativeWidgetOwnsWidget) {
views::internal::NativeWidgetPrivate* native_widget_private =
CreateTestNativeWidget();
views::Widget* widget = native_widget_private->GetWidget();
aura::Window* parent_window = widget->GetNativeWindow();
std::unique_ptr<DOM::Node> root;
dom_agent()->getDocument(&root);
DOM::Node* parent_node = FindInRoot(parent_window, root.get());
DCHECK(parent_node);
EXPECT_TRUE(ElementTreeMatchesDOMTree(parent_window, parent_node));
// Destroy NativeWidget followed by |widget|
widget->CloseNow();
}
#endif // defined(USE_AURA)
TEST_F(DOMAgentTest, GetDocumentMultipleWidgets) {
// widget_a
// (root/contents views)
// child_a1
// child_a2
// widget_b
// (root/contents views)
// child_b1
// child_b11
// child_b111
// child_b1111
// child_b112
// child_b113
// child_b12
// child_b121
// child_b122
std::unique_ptr<views::Widget> widget_a(
CreateTestWidget(gfx::Rect(1, 1, 80, 80)));
std::unique_ptr<views::Widget> widget_b(
CreateTestWidget(gfx::Rect(100, 100, 80, 80)));
widget_a->GetRootView()->AddChildView(new TestView("child_a1"));
widget_a->GetRootView()->AddChildView(new TestView("child_a2"));
auto child_b1 = std::make_unique<TestView>("child_b1");
child_b1->set_owned_by_client();
widget_b->GetRootView()->AddChildView(child_b1.get());
auto child_b11 = std::make_unique<TestView>("child_b11");
child_b11->set_owned_by_client();
child_b1->AddChildView(child_b11.get());
auto child_b111 = std::make_unique<TestView>("child_b111");
child_b111->set_owned_by_client();
child_b11->AddChildView(child_b111.get());
child_b111->AddChildView(new TestView("child_b1111"));
child_b11->AddChildView(new TestView("child_b112"));
child_b11->AddChildView(new TestView("child_b113"));
auto child_b12 = std::make_unique<TestView>("child_b12");
child_b12->set_owned_by_client();
child_b1->AddChildView(child_b12.get());
child_b12->AddChildView(new TestView("child_b121"));
child_b12->AddChildView(new TestView("child_b122"));
std::unique_ptr<DOM::Node> root;
dom_agent()->getDocument(&root);
DOM::Node* widget_node_a = FindInRoot(widget_a.get(), root.get());
DCHECK(widget_node_a);
EXPECT_TRUE(ElementTreeMatchesDOMTree(widget_a.get(), widget_node_a));
DOM::Node* widget_node_b = FindInRoot(widget_b.get(), root.get());
DCHECK(widget_node_b);
EXPECT_TRUE(ElementTreeMatchesDOMTree(widget_b.get(), widget_node_b));
}
// Tests to ensure correct messages are sent when elements are added,
// removed, and moved around.
#if defined(USE_AURA)
TEST_F(DOMAgentTest, WindowAddedChildNodeInserted) {
// Initialize DOMAgent
std::unique_ptr<aura::Window> first_child =
CreateChildWindow(top_window.get());
std::unique_ptr<DOM::Node> root;
dom_agent()->getDocument(&root);
std::unique_ptr<aura::Window> second_child(
CreateChildWindow(top_window.get()));
EXPECT_TRUE(WasChildNodeInserted(top_window.get(), first_child.get()));
}
TEST_F(DOMAgentTest, WindowDestroyedChildNodeRemoved) {
std::unique_ptr<aura::Window> child_1 = CreateChildWindow(top_window.get());
std::unique_ptr<aura::Window> child_2 = CreateChildWindow(child_1.get());
// Initialize DOMAgent
std::unique_ptr<DOM::Node> root;
dom_agent()->getDocument(&root);
int child_id = GetIDForBackendElement(child_2.get());
child_2.reset();
EXPECT_TRUE(WasChildNodeRemoved(child_1.get(), child_id));
}
TEST_F(DOMAgentTest, WindowReorganizedChildNodeRearranged) {
std::unique_ptr<aura::Window> child_1 = CreateChildWindow(top_window.get());
std::unique_ptr<aura::Window> child_2 = CreateChildWindow(top_window.get());
std::unique_ptr<aura::Window> child_11 = CreateChildWindow(child_1.get());
std::unique_ptr<aura::Window> child_21 = CreateChildWindow(child_2.get());
// Initialize DOMAgent
std::unique_ptr<DOM::Node> root;
dom_agent()->getDocument(&root);
int moving_child_id = GetIDForBackendElement(child_11.get());
child_2->AddChild(child_11.get());
EXPECT_TRUE(WasChildNodeRemoved(child_1.get(), moving_child_id));
EXPECT_TRUE(WasChildNodeInserted(child_2.get(), child_21.get()));
}
TEST_F(DOMAgentTest, WindowReorganizedChildNodeRemovedAndInserted) {
std::unique_ptr<aura::Window> child_1 = CreateChildWindow(top_window.get());
std::unique_ptr<aura::Window> child_2 = CreateChildWindow(top_window.get());
std::unique_ptr<aura::Window> child_21 = CreateChildWindow(child_2.get());
std::unique_ptr<aura::Window> child_22 = CreateChildWindow(child_2.get());
// Initialized at the end since it will be a child of |child_2| at
// tear down.
std::unique_ptr<aura::Window> child_11 = CreateChildWindow(child_1.get());
// Initialize DOMAgent
std::unique_ptr<DOM::Node> root;
dom_agent()->getDocument(&root);
int moving_child_id = GetIDForBackendElement(child_11.get());
child_1->RemoveChild(child_11.get());
EXPECT_TRUE(WasChildNodeRemoved(child_1.get(), moving_child_id));
child_2->AddChild(child_11.get());
EXPECT_TRUE(WasChildNodeInserted(child_2.get(), child_22.get()));
}
TEST_F(DOMAgentTest, WindowStackingChangedChildNodeRemovedAndInserted) {
std::unique_ptr<aura::Window> child_11 = CreateChildWindow(top_window.get());
std::unique_ptr<aura::Window> child_12 = CreateChildWindow(top_window.get());
std::unique_ptr<aura::Window> child_13 = CreateChildWindow(top_window.get());
// Initialize DOMAgent
std::unique_ptr<DOM::Node> root;
dom_agent()->getDocument(&root);
int moving_child_id = GetIDForBackendElement(child_11.get());
top_window->StackChildAbove(child_11.get(), child_12.get());
EXPECT_TRUE(WasChildNodeRemoved(top_window.get(), moving_child_id));
EXPECT_TRUE(WasChildNodeInserted(top_window.get(), child_12.get()));
}
#endif // defined(USE_AURA)
TEST_F(DOMAgentTest, ViewInserted) {
std::unique_ptr<views::Widget> widget(
CreateTestWidget(gfx::Rect(1, 1, 80, 80)));
widget->Show();
// Initialize DOMAgent
std::unique_ptr<DOM::Node> root;
dom_agent()->getDocument(&root);
views::View* root_view = widget->GetRootView();
ASSERT_FALSE(root_view->children().empty());
auto* last_child = root_view->children().back();
root_view->AddChildView(std::make_unique<views::View>());
EXPECT_TRUE(WasChildNodeInserted(root_view, last_child));
}
TEST_F(DOMAgentTest, ViewRemoved) {
std::unique_ptr<views::Widget> widget(
CreateTestWidget(gfx::Rect(1, 1, 80, 80)));
widget->Show();
views::View* root_view = widget->GetRootView();
// Need to store |child_view| in unique_ptr because it is removed from the
// widget and needs to be destroyed independently
std::unique_ptr<views::View> child_view = std::make_unique<views::View>();
root_view->AddChildView(child_view.get());
// Initialize DOMAgent
std::unique_ptr<DOM::Node> root;
dom_agent()->getDocument(&root);
int removed_node_id = GetIDForBackendElement(child_view.get());
root_view->RemoveChildView(child_view.get());
EXPECT_TRUE(WasChildNodeRemoved(root_view, removed_node_id));
}
TEST_F(DOMAgentTest, ViewRearranged) {
std::unique_ptr<views::Widget> widget(
CreateTestWidget(gfx::Rect(1, 1, 80, 80)));
widget->Show();
views::View* root_view = widget->GetRootView();
views::View* parent_view = new views::View;
views::View* target_view = new views::View;
views::View* child_view = new views::View;
views::View* child_view_1 = new views::View;
root_view->AddChildView(parent_view);
root_view->AddChildView(target_view);
parent_view->AddChildView(child_view);
parent_view->AddChildView(child_view_1);
// Initialize DOMAgent
std::unique_ptr<DOM::Node> root;
dom_agent()->getDocument(&root);
// Reorder child_view_1 from index 1 to 0 in view::Views tree. This makes
// DOM tree remove view node at position 1 and insert it at position 0.
int child_1_id = GetIDForBackendElement(child_view_1);
parent_view->ReorderChildView(child_view_1, 0);
EXPECT_TRUE(WasChildNodeRemoved(parent_view, child_1_id));
EXPECT_TRUE(WasChildNodeInserted(parent_view));
// Reorder child_view_1 to the same index 0 shouldn't perform reroder
// work, so we still expect 1 remove and 1 insert protocol notification
// messages.
parent_view->ReorderChildView(child_view_1, 0);
EXPECT_TRUE(WasChildNodeRemoved(parent_view, child_1_id));
EXPECT_TRUE(WasChildNodeInserted(parent_view));
int child_id = GetIDForBackendElement(child_view);
parent_view->RemoveChildView(child_view);
target_view->AddChildView(child_view);
EXPECT_TRUE(WasChildNodeRemoved(parent_view, child_id));
EXPECT_TRUE(WasChildNodeInserted(target_view));
}
TEST_F(DOMAgentTest, ViewRearrangedRemovedAndInserted) {
std::unique_ptr<views::Widget> widget(
CreateTestWidget(gfx::Rect(1, 1, 80, 80)));
widget->Show();
views::View* root_view = widget->GetRootView();
views::View* parent_view = new views::View;
views::View* target_view = new views::View;
views::View* child_view = new views::View;
root_view->AddChildView(parent_view);
root_view->AddChildView(target_view);
parent_view->AddChildView(child_view);
// Initialize DOMAgent
std::unique_ptr<DOM::Node> root;
dom_agent()->getDocument(&root);
int child_id = GetIDForBackendElement(child_view);
parent_view->RemoveChildView(child_view);
target_view->AddChildView(child_view);
EXPECT_TRUE(WasChildNodeRemoved(parent_view, child_id));
EXPECT_TRUE(WasChildNodeInserted(target_view));
}
TEST_F(DOMAgentTest, NodeIdToUIElementTest) {
// widget
// root_view
// child_a1
// child_a11
// child_a111
// child_a1111
// child_a112
std::unique_ptr<views::Widget> widget(
CreateTestWidget(gfx::Rect(1, 1, 80, 80)));
widget->Show();
views::View* root_view = widget->GetRootView();
views::View* child_a1 =
root_view->AddChildView(std::make_unique<views::View>());
views::View* child_a11 =
child_a1->AddChildView(std::make_unique<views::View>());
views::View* child_a111 =
child_a11->AddChildView(std::make_unique<views::View>());
views::View* child_a112 =
child_a11->AddChildView(std::make_unique<views::View>());
views::View* child_a1111 =
child_a111->AddChildView(std::make_unique<views::View>());
std::unique_ptr<DOM::Node> root;
dom_agent()->getDocument(&root);
int child_a1_id = GetIDForBackendElement(child_a1);
int child_a11_id = GetIDForBackendElement(child_a11);
int child_a111_id = GetIDForBackendElement(child_a111);
int child_a112_id = GetIDForBackendElement(child_a112);
int child_a1111_id = GetIDForBackendElement(child_a1111);
// Make sure all child nodes are in the |node_id_to_ui_element_| map.
EXPECT_NE(dom_agent()->GetElementFromNodeId(child_a1_id), nullptr);
EXPECT_NE(dom_agent()->GetElementFromNodeId(child_a11_id), nullptr);
EXPECT_NE(dom_agent()->GetElementFromNodeId(child_a111_id), nullptr);
EXPECT_NE(dom_agent()->GetElementFromNodeId(child_a112_id), nullptr);
EXPECT_NE(dom_agent()->GetElementFromNodeId(child_a1111_id), nullptr);
root_view->RemoveChildView(child_a1);
// Check that child_a1 and its children are all removed from the
// |node_id_to_ui_element_| map.
EXPECT_EQ(dom_agent()->GetElementFromNodeId(child_a1_id), nullptr);
EXPECT_EQ(dom_agent()->GetElementFromNodeId(child_a11_id), nullptr);
EXPECT_EQ(dom_agent()->GetElementFromNodeId(child_a111_id), nullptr);
EXPECT_EQ(dom_agent()->GetElementFromNodeId(child_a112_id), nullptr);
EXPECT_EQ(dom_agent()->GetElementFromNodeId(child_a1111_id), nullptr);
// Required since it was removed from its parent view.
delete child_a1;
}
// Tests to ensure dom search for native UI is working
TEST_F(DOMAgentTest, SimpleDomSearch) {
std::unique_ptr<views::Widget> widget_a(
CreateTestWidget(gfx::Rect(1, 1, 80, 80)));
widget_a->GetRootView()->AddChildView(new TestView("child_a1"));
widget_a->GetRootView()->AddChildView(new TestView("child_a2"));
std::unique_ptr<DOM::Node> root;
dom_agent()->getDocument(&root);
std::string search_id;
int result_count = 0;
std::unique_ptr<protocol::Array<int>> node_ids = nullptr;
// 1 match
dom_agent()->performSearch("child_a1", false, &search_id, &result_count);
EXPECT_EQ(result_count, 1);
dom_agent()->getSearchResults(search_id, 0, result_count, &node_ids);
EXPECT_EQ(node_ids->size(), 1u);
dom_agent()->discardSearchResults(search_id);
node_ids.reset();
// no match
dom_agent()->performSearch("child_a12", false, &search_id, &result_count);
EXPECT_EQ(result_count, 0);
dom_agent()->getSearchResults(search_id, 0, 1, &node_ids);
EXPECT_TRUE(!node_ids);
}
TEST_F(DOMAgentTest, ExactDomSearch) {
std::unique_ptr<views::Widget> widget_a(
CreateTestWidget(gfx::Rect(1, 1, 80, 80)));
widget_a->GetRootView()->AddChildView(new TestView("child_a"));
widget_a->GetRootView()->AddChildView(new TestView("child_aa"));
std::unique_ptr<DOM::Node> root;
dom_agent()->getDocument(&root);
std::string search_id;
int result_count = 0;
std::unique_ptr<protocol::Array<int>> node_ids = nullptr;
// substring matches
dom_agent()->performSearch("child_a", false, &search_id, &result_count);
EXPECT_EQ(result_count, 2);
dom_agent()->getSearchResults(search_id, 0, result_count, &node_ids);
EXPECT_EQ(node_ids->size(), 2u);
dom_agent()->discardSearchResults(search_id);
node_ids.reset();
// exact string matches
dom_agent()->performSearch("\"child_a\"", false, &search_id, &result_count);
EXPECT_EQ(result_count, 1);
dom_agent()->getSearchResults(search_id, 0, result_count, &node_ids);
EXPECT_EQ(node_ids->size(), 1u);
dom_agent()->discardSearchResults(search_id);
node_ids.reset();
dom_agent()->performSearch("\"child\"", false, &search_id, &result_count);
EXPECT_EQ(result_count, 0);
dom_agent()->getSearchResults(search_id, 0, 1, &node_ids);
EXPECT_TRUE(!node_ids);
}
TEST_F(DOMAgentTest, TagDomSearch) {
std::string widget_name = "TestElement";
std::unique_ptr<views::Widget> widget_a(
CreateTestWidget(gfx::Rect(1, 1, 80, 80), &widget_name));
std::unique_ptr<views::Widget> widget_b(
CreateTestWidget(gfx::Rect(1, 1, 80, 80), &widget_name));
std::unique_ptr<views::Widget> widget_c(
CreateTestWidget(gfx::Rect(1, 1, 80, 80), &widget_name));
widget_a->GetRootView()->AddChildView(new TestView("WidgetView"));
std::unique_ptr<DOM::Node> root;
dom_agent()->getDocument(&root);
std::string search_id;
int result_count = 0;
std::unique_ptr<protocol::Array<int>> node_ids = nullptr;
// normal search looks for any "widget" substrings
dom_agent()->performSearch("widget", false, &search_id, &result_count);
EXPECT_EQ(result_count, 4);
dom_agent()->getSearchResults(search_id, 0, result_count, &node_ids);
EXPECT_EQ(node_ids->size(), 4u);
dom_agent()->discardSearchResults(search_id);
node_ids.reset();
// tag search only looks for <widget...>
dom_agent()->performSearch("<widget>", false, &search_id, &result_count);
EXPECT_EQ(result_count, 3);
dom_agent()->getSearchResults(search_id, 0, result_count, &node_ids);
EXPECT_EQ(node_ids->size(), 3u);
}
TEST_F(DOMAgentTest, DomSearchForStylesPanel) {
std::unique_ptr<views::Widget> widget_a(
CreateTestWidget(gfx::Rect(1, 1, 80, 80)));
widget_a->GetRootView()->AddChildView(new TestView("child_a1"));
std::unique_ptr<DOM::Node> root;
dom_agent()->getDocument(&root);
std::string search_id;
int result_count = 0;
std::unique_ptr<protocol::Array<int>> node_ids = nullptr;
// Search for something that is in style properties but not in dom name or
// attributes.
dom_agent()->performSearch("style: classname: child_a1", false, &search_id,
&result_count);
EXPECT_EQ(result_count, 1);
dom_agent()->getSearchResults(search_id, 0, result_count, &node_ids);
EXPECT_EQ(node_ids->size(), 1u);
node_ids.reset();
dom_agent()->performSearch("classname: child_a1", false, &search_id,
&result_count);
EXPECT_EQ(result_count, 0);
dom_agent()->getSearchResults(search_id, 0, 1, &node_ids);
EXPECT_TRUE(!node_ids);
}
} // namespace ui_devtools