blob: 0ea34d8809f1b191504d2cc833f74fef694230d3 [file] [log] [blame]
[email protected]c6d068ff2011-10-14 17:28:231// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]caf706f2010-10-26 17:54:082// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
tzik1068f1be2016-06-03 07:25:205#include <tuple>
6
avi1023d012015-12-25 02:39:147#include "base/macros.h"
[email protected]74ebfb12013-06-07 20:48:008#include "base/strings/utf_string_conversions.h"
avi485e5fd62014-08-25 23:26:149#include "content/common/frame_messages.h"
[email protected]899617f2012-06-04 02:27:1410#include "content/public/test/render_view_test.h"
avi485e5fd62014-08-25 23:26:1411#include "content/renderer/render_frame_impl.h"
[email protected]068970d2011-10-11 00:05:1612#include "content/renderer/render_view_impl.h"
[email protected]caf706f2010-10-26 17:54:0813#include "testing/gtest/include/gtest/gtest.h"
Blink Reformata30d4232018-04-07 15:31:0614#include "third_party/blink/public/platform/web_size.h"
Kent Tamura5405341d52018-12-20 00:22:0715#include "third_party/blink/public/web/web_local_frame.h"
Blink Reformata30d4232018-04-07 15:31:0616#include "third_party/blink/public/web/web_view.h"
[email protected]caf706f2010-10-26 17:54:0817
18// Tests for the external select popup menu (Mac specific).
19
[email protected]e9ff79c2012-10-19 21:31:2620namespace content {
[email protected]caf706f2010-10-26 17:54:0821namespace {
22
23const char* const kSelectID = "mySelect";
[email protected]92ccbdd2010-12-01 19:30:4424const char* const kEmptySelectID = "myEmptySelect";
[email protected]caf706f2010-10-26 17:54:0825
26} // namespace
27
[email protected]e9ff79c2012-10-19 21:31:2628class ExternalPopupMenuTest : public RenderViewTest {
[email protected]caf706f2010-10-26 17:54:0829 public:
30 ExternalPopupMenuTest() {}
31
[email protected]068970d2011-10-11 00:05:1632 RenderViewImpl* view() {
33 return static_cast<RenderViewImpl*>(view_);
34 }
35
avi485e5fd62014-08-25 23:26:1436 RenderFrameImpl* frame() {
mostynbc33353232014-09-12 09:38:3137 return view()->GetMainRenderFrame();
avi485e5fd62014-08-25 23:26:1438 }
39
dcheng60135332015-01-09 02:05:3440 void SetUp() override {
[email protected]e9ff79c2012-10-19 21:31:2641 RenderViewTest::SetUp();
[email protected]caf706f2010-10-26 17:54:0842 // We need to set this explictly as RenderMain is not run.
Blink Reformat1c4d759e2017-04-09 16:34:5443 blink::WebView::SetUseExternalPopupMenus(true);
[email protected]caf706f2010-10-26 17:54:0844
[email protected]360bc0b12010-11-11 19:21:2645 std::string html = "<select id='mySelect' onchange='selectChanged(this)'>"
46 " <option>zero</option>"
47 " <option selected='1'>one</option>"
48 " <option>two</option>"
[email protected]92ccbdd2010-12-01 19:30:4449 "</select>"
50 "<select id='myEmptySelect'>"
[email protected]360bc0b12010-11-11 19:21:2651 "</select>";
52 if (ShouldRemoveSelectOnChange()) {
53 html += "<script>"
54 " function selectChanged(select) {"
55 " select.parentNode.removeChild(select);"
56 " }"
57 "</script>";
58 }
59
[email protected]caf706f2010-10-26 17:54:0860 // Load the test page.
[email protected]360bc0b12010-11-11 19:21:2661 LoadHTML(html.c_str());
[email protected]caf706f2010-10-26 17:54:0862
63 // Set a minimum size and give focus so simulated events work.
Blink Reformat1c4d759e2017-04-09 16:34:5464 view()->GetWidget()->GetWebWidget()->Resize(blink::WebSize(500, 500));
65 view()->GetWidget()->GetWebWidget()->SetFocus(true);
[email protected]caf706f2010-10-26 17:54:0866 }
67
68 int GetSelectedIndex() {
[email protected]32956122013-12-25 07:29:2469 base::string16 script(base::ASCIIToUTF16(kSelectID));
70 script.append(base::ASCIIToUTF16(".selectedIndex"));
[email protected]caf706f2010-10-26 17:54:0871 int selected_index = -1;
72 ExecuteJavaScriptAndReturnIntValue(script, &selected_index);
73 return selected_index;
74 }
75
[email protected]360bc0b12010-11-11 19:21:2676 protected:
77 virtual bool ShouldRemoveSelectOnChange() const { return false; }
78
[email protected]caf706f2010-10-26 17:54:0879 DISALLOW_COPY_AND_ASSIGN(ExternalPopupMenuTest);
80};
81
82// Normal case: test showing a select popup, canceling/selecting an item.
83TEST_F(ExternalPopupMenuTest, NormalCase) {
[email protected]c6d068ff2011-10-14 17:28:2384 IPC::TestSink& sink = render_thread_->sink();
[email protected]caf706f2010-10-26 17:54:0885
86 // Click the text field once.
87 EXPECT_TRUE(SimulateElementClick(kSelectID));
88
89 // We should have sent a message to the browser to show the popup menu.
90 const IPC::Message* message =
avi485e5fd62014-08-25 23:26:1491 sink.GetUniqueMessageMatching(FrameHostMsg_ShowPopup::ID);
[email protected]caf706f2010-10-26 17:54:0892 ASSERT_TRUE(message != NULL);
tzik1068f1be2016-06-03 07:25:2093 std::tuple<FrameHostMsg_ShowPopup_Params> param;
avi485e5fd62014-08-25 23:26:1494 FrameHostMsg_ShowPopup::Read(message, &param);
tzik1068f1be2016-06-03 07:25:2095 ASSERT_EQ(3U, std::get<0>(param).popup_items.size());
96 EXPECT_EQ(1, std::get<0>(param).selected_item);
[email protected]caf706f2010-10-26 17:54:0897
avi485e5fd62014-08-25 23:26:1498 // Simulate the user canceling the popup; the index should not have changed.
99 frame()->OnSelectPopupMenuItem(-1);
[email protected]caf706f2010-10-26 17:54:08100 EXPECT_EQ(1, GetSelectedIndex());
101
102 // Show the pop-up again and this time make a selection.
103 EXPECT_TRUE(SimulateElementClick(kSelectID));
avi485e5fd62014-08-25 23:26:14104 frame()->OnSelectPopupMenuItem(0);
[email protected]caf706f2010-10-26 17:54:08105 EXPECT_EQ(0, GetSelectedIndex());
106
107 // Show the pop-up again and make another selection.
108 sink.ClearMessages();
109 EXPECT_TRUE(SimulateElementClick(kSelectID));
avi485e5fd62014-08-25 23:26:14110 message = sink.GetUniqueMessageMatching(FrameHostMsg_ShowPopup::ID);
[email protected]caf706f2010-10-26 17:54:08111 ASSERT_TRUE(message != NULL);
avi485e5fd62014-08-25 23:26:14112 FrameHostMsg_ShowPopup::Read(message, &param);
tzik1068f1be2016-06-03 07:25:20113 ASSERT_EQ(3U, std::get<0>(param).popup_items.size());
114 EXPECT_EQ(0, std::get<0>(param).selected_item);
[email protected]caf706f2010-10-26 17:54:08115}
116
117// Page shows popup, then navigates away while popup showing, then select.
118TEST_F(ExternalPopupMenuTest, ShowPopupThenNavigate) {
119 // Click the text field once.
120 EXPECT_TRUE(SimulateElementClick(kSelectID));
121
122 // Now we navigate to another pager.
123 LoadHTML("<blink>Awesome page!</blink>");
124
125 // Now the user selects something, we should not crash.
avi485e5fd62014-08-25 23:26:14126 frame()->OnSelectPopupMenuItem(-1);
[email protected]caf706f2010-10-26 17:54:08127}
[email protected]360bc0b12010-11-11 19:21:26128
[email protected]92ccbdd2010-12-01 19:30:44129// An empty select should not cause a crash when clicked.
130// http://crbug.com/63774
131TEST_F(ExternalPopupMenuTest, EmptySelect) {
132 EXPECT_TRUE(SimulateElementClick(kEmptySelectID));
133}
134
[email protected]360bc0b12010-11-11 19:21:26135class ExternalPopupMenuRemoveTest : public ExternalPopupMenuTest {
136 public:
137 ExternalPopupMenuRemoveTest() {}
138
139 protected:
dcheng6d18e402014-10-21 12:32:52140 bool ShouldRemoveSelectOnChange() const override { return true; }
[email protected]360bc0b12010-11-11 19:21:26141};
142
143// Tests that nothing bad happen when the page removes the select when it
144// changes. (http://crbug.com/61997)
tkent4e91ab82015-08-05 22:36:46145TEST_F(ExternalPopupMenuRemoveTest, RemoveOnChange) {
[email protected]360bc0b12010-11-11 19:21:26146 // Click the text field once to show the popup.
147 EXPECT_TRUE(SimulateElementClick(kSelectID));
148
149 // Select something, it causes the select to be removed from the page.
avi485e5fd62014-08-25 23:26:14150 frame()->OnSelectPopupMenuItem(0);
[email protected]360bc0b12010-11-11 19:21:26151
152 // Just to check the soundness of the test, call SimulateElementClick again.
153 // It should return false as the select has been removed.
154 EXPECT_FALSE(SimulateElementClick(kSelectID));
155}
[email protected]e9ff79c2012-10-19 21:31:26156
Kent Tamura5405341d52018-12-20 00:22:07157// crbug.com/912211
158TEST_F(ExternalPopupMenuRemoveTest, RemoveFrameOnChange) {
159 LoadHTML(
160 "<style>* { margin: 0; } iframe { border: 0; }</style>"
161 "<body><iframe srcdoc=\""
162 "<style>* { margin: 0; }</style><select><option>opt1<option>opt2"
163 "\"></iframe>"
164 "<script>"
165 "onload = function() {"
166 " const frame = document.querySelector('iframe');"
167 " frame.contentDocument.querySelector('select').onchange = "
168 " () => { frame.remove(); };"
169 "};"
170 "</script>");
171 // Open a popup.
172 SimulatePointClick(gfx::Point(8, 8));
173 // Select something on the sub-frame, it causes the frame to be removed from
174 // the page.
175 auto* child_web_frame =
176 static_cast<blink::WebLocalFrame*>(frame()->GetWebFrame()->FirstChild());
177 static_cast<RenderFrameImpl*>(RenderFrame::FromWebFrame(child_web_frame))
178 ->OnSelectPopupMenuItem(1);
179 // The test passes if the test didn't crash and ASAN didn't complain.
180}
181
[email protected]d0cd67482014-08-12 19:17:12182class ExternalPopupMenuDisplayNoneTest : public ExternalPopupMenuTest {
183 public:
184 ExternalPopupMenuDisplayNoneTest() {}
185
dcheng60135332015-01-09 02:05:34186 void SetUp() override {
[email protected]d0cd67482014-08-12 19:17:12187 RenderViewTest::SetUp();
188 // We need to set this explictly as RenderMain is not run.
Blink Reformat1c4d759e2017-04-09 16:34:54189 blink::WebView::SetUseExternalPopupMenus(true);
[email protected]d0cd67482014-08-12 19:17:12190
191 std::string html = "<select id='mySelect'>"
192 " <option value='zero'>zero</option>"
193 " <optgroup label='hide' style='display: none'>"
194 " <option value='one'>one</option>"
195 " </optgroup>"
196 " <option value='two'>two</option>"
197 " <option value='three'>three</option>"
198 " <option value='four'>four</option>"
199 " <option value='five'>five</option>"
200 "</select>";
201 // Load the test page.
202 LoadHTML(html.c_str());
203
204 // Set a minimum size and give focus so simulated events work.
Blink Reformat1c4d759e2017-04-09 16:34:54205 view()->GetWidget()->GetWebWidget()->Resize(blink::WebSize(500, 500));
206 view()->GetWidget()->GetWebWidget()->SetFocus(true);
[email protected]d0cd67482014-08-12 19:17:12207 }
208
209};
210
211TEST_F(ExternalPopupMenuDisplayNoneTest, SelectItem) {
sudarshan.p9ff8ce32014-09-03 11:20:37212 IPC::TestSink& sink = render_thread_->sink();
213
[email protected]d0cd67482014-08-12 19:17:12214 // Click the text field once to show the popup.
215 EXPECT_TRUE(SimulateElementClick(kSelectID));
216
sudarshan.p9ff8ce32014-09-03 11:20:37217 // Read the message sent to browser to show the popup menu.
218 const IPC::Message* message =
219 sink.GetUniqueMessageMatching(FrameHostMsg_ShowPopup::ID);
220 ASSERT_TRUE(message != NULL);
tzik1068f1be2016-06-03 07:25:20221 std::tuple<FrameHostMsg_ShowPopup_Params> param;
sudarshan.p9ff8ce32014-09-03 11:20:37222 FrameHostMsg_ShowPopup::Read(message, &param);
223 // Number of items should match item count minus the number
224 // of "display: none" items.
tzik1068f1be2016-06-03 07:25:20225 ASSERT_EQ(5U, std::get<0>(param).popup_items.size());
sudarshan.p9ff8ce32014-09-03 11:20:37226
[email protected]d0cd67482014-08-12 19:17:12227 // Select index 1 item. This should select item with index 2,
228 // skipping the item with 'display: none'
avi485e5fd62014-08-25 23:26:14229 frame()->OnSelectPopupMenuItem(1);
[email protected]d0cd67482014-08-12 19:17:12230
avi485e5fd62014-08-25 23:26:14231 EXPECT_EQ(2, GetSelectedIndex());
[email protected]d0cd67482014-08-12 19:17:12232}
233
[email protected]e9ff79c2012-10-19 21:31:26234} // namespace content