1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/strings/utf_string_conversions.h"
6 #include "content/common/frame_messages.h"
7 #include "content/public/test/render_view_test.h"
8 #include "content/renderer/render_frame_impl.h"
9 #include "content/renderer/render_view_impl.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11 #include "third_party/WebKit/public/web/WebView.h"
12 #include "third_party/WebKit/public/platform/WebSize.h"
14 // Tests for the external select popup menu (Mac specific).
19 const char* const kSelectID
= "mySelect";
20 const char* const kEmptySelectID
= "myEmptySelect";
24 class ExternalPopupMenuTest
: public RenderViewTest
{
26 ExternalPopupMenuTest() {}
28 RenderViewImpl
* view() {
29 return static_cast<RenderViewImpl
*>(view_
);
32 RenderFrameImpl
* frame() {
33 return view()->GetMainRenderFrame();
36 void SetUp() override
{
37 RenderViewTest::SetUp();
38 // We need to set this explictly as RenderMain is not run.
39 blink::WebView::setUseExternalPopupMenus(true);
41 std::string html
= "<select id='mySelect' onchange='selectChanged(this)'>"
42 " <option>zero</option>"
43 " <option selected='1'>one</option>"
44 " <option>two</option>"
46 "<select id='myEmptySelect'>"
48 if (ShouldRemoveSelectOnChange()) {
50 " function selectChanged(select) {"
51 " select.parentNode.removeChild(select);"
56 // Load the test page.
57 LoadHTML(html
.c_str());
59 // Set a minimum size and give focus so simulated events work.
60 view()->webwidget()->resize(blink::WebSize(500, 500));
61 view()->webwidget()->setFocus(true);
64 int GetSelectedIndex() {
65 base::string16
script(base::ASCIIToUTF16(kSelectID
));
66 script
.append(base::ASCIIToUTF16(".selectedIndex"));
67 int selected_index
= -1;
68 ExecuteJavaScriptAndReturnIntValue(script
, &selected_index
);
69 return selected_index
;
73 virtual bool ShouldRemoveSelectOnChange() const { return false; }
75 DISALLOW_COPY_AND_ASSIGN(ExternalPopupMenuTest
);
78 // Normal case: test showing a select popup, canceling/selecting an item.
79 TEST_F(ExternalPopupMenuTest
, NormalCase
) {
80 IPC::TestSink
& sink
= render_thread_
->sink();
82 // Click the text field once.
83 EXPECT_TRUE(SimulateElementClick(kSelectID
));
85 // We should have sent a message to the browser to show the popup menu.
86 const IPC::Message
* message
=
87 sink
.GetUniqueMessageMatching(FrameHostMsg_ShowPopup::ID
);
88 ASSERT_TRUE(message
!= NULL
);
89 base::Tuple
<FrameHostMsg_ShowPopup_Params
> param
;
90 FrameHostMsg_ShowPopup::Read(message
, ¶m
);
91 ASSERT_EQ(3U, base::get
<0>(param
).popup_items
.size());
92 EXPECT_EQ(1, base::get
<0>(param
).selected_item
);
94 // Simulate the user canceling the popup; the index should not have changed.
95 frame()->OnSelectPopupMenuItem(-1);
96 EXPECT_EQ(1, GetSelectedIndex());
98 // Show the pop-up again and this time make a selection.
99 EXPECT_TRUE(SimulateElementClick(kSelectID
));
100 frame()->OnSelectPopupMenuItem(0);
101 EXPECT_EQ(0, GetSelectedIndex());
103 // Show the pop-up again and make another selection.
104 sink
.ClearMessages();
105 EXPECT_TRUE(SimulateElementClick(kSelectID
));
106 message
= sink
.GetUniqueMessageMatching(FrameHostMsg_ShowPopup::ID
);
107 ASSERT_TRUE(message
!= NULL
);
108 FrameHostMsg_ShowPopup::Read(message
, ¶m
);
109 ASSERT_EQ(3U, base::get
<0>(param
).popup_items
.size());
110 EXPECT_EQ(0, base::get
<0>(param
).selected_item
);
113 // Page shows popup, then navigates away while popup showing, then select.
114 TEST_F(ExternalPopupMenuTest
, ShowPopupThenNavigate
) {
115 // Click the text field once.
116 EXPECT_TRUE(SimulateElementClick(kSelectID
));
118 // Now we navigate to another pager.
119 LoadHTML("<blink>Awesome page!</blink>");
121 // Now the user selects something, we should not crash.
122 frame()->OnSelectPopupMenuItem(-1);
125 // An empty select should not cause a crash when clicked.
126 // http://crbug.com/63774
127 TEST_F(ExternalPopupMenuTest
, EmptySelect
) {
128 EXPECT_TRUE(SimulateElementClick(kEmptySelectID
));
131 class ExternalPopupMenuRemoveTest
: public ExternalPopupMenuTest
{
133 ExternalPopupMenuRemoveTest() {}
136 bool ShouldRemoveSelectOnChange() const override
{ return true; }
139 // Tests that nothing bad happen when the page removes the select when it
140 // changes. (http://crbug.com/61997)
141 TEST_F(ExternalPopupMenuRemoveTest
, RemoveOnChange
) {
142 // Click the text field once to show the popup.
143 EXPECT_TRUE(SimulateElementClick(kSelectID
));
145 // Select something, it causes the select to be removed from the page.
146 frame()->OnSelectPopupMenuItem(0);
148 // Just to check the soundness of the test, call SimulateElementClick again.
149 // It should return false as the select has been removed.
150 EXPECT_FALSE(SimulateElementClick(kSelectID
));
153 class ExternalPopupMenuDisplayNoneTest
: public ExternalPopupMenuTest
{
155 ExternalPopupMenuDisplayNoneTest() {}
157 void SetUp() override
{
158 RenderViewTest::SetUp();
159 // We need to set this explictly as RenderMain is not run.
160 blink::WebView::setUseExternalPopupMenus(true);
162 std::string html
= "<select id='mySelect'>"
163 " <option value='zero'>zero</option>"
164 " <optgroup label='hide' style='display: none'>"
165 " <option value='one'>one</option>"
167 " <option value='two'>two</option>"
168 " <option value='three'>three</option>"
169 " <option value='four'>four</option>"
170 " <option value='five'>five</option>"
172 // Load the test page.
173 LoadHTML(html
.c_str());
175 // Set a minimum size and give focus so simulated events work.
176 view()->webwidget()->resize(blink::WebSize(500, 500));
177 view()->webwidget()->setFocus(true);
182 TEST_F(ExternalPopupMenuDisplayNoneTest
, SelectItem
) {
183 IPC::TestSink
& sink
= render_thread_
->sink();
185 // Click the text field once to show the popup.
186 EXPECT_TRUE(SimulateElementClick(kSelectID
));
188 // Read the message sent to browser to show the popup menu.
189 const IPC::Message
* message
=
190 sink
.GetUniqueMessageMatching(FrameHostMsg_ShowPopup::ID
);
191 ASSERT_TRUE(message
!= NULL
);
192 base::Tuple
<FrameHostMsg_ShowPopup_Params
> param
;
193 FrameHostMsg_ShowPopup::Read(message
, ¶m
);
194 // Number of items should match item count minus the number
195 // of "display: none" items.
196 ASSERT_EQ(5U, base::get
<0>(param
).popup_items
.size());
198 // Select index 1 item. This should select item with index 2,
199 // skipping the item with 'display: none'
200 frame()->OnSelectPopupMenuItem(1);
202 EXPECT_EQ(2, GetSelectedIndex());
205 } // namespace content