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. 4 5 #include "base/strings/utf_string_conversions.h" 6 #include "content/common/view_messages.h" 7 #include "content/public/test/render_view_test.h" 8 #include "content/renderer/render_view_impl.h" 9 #include "testing/gtest/include/gtest/gtest.h" 10 #include "third_party/WebKit/public/web/WebView.h" 11 #include "third_party/WebKit/public/platform/WebSize.h" 12 13 // Tests for the external select popup menu (Mac specific). 14 15 namespace content { 16 namespace { 17 18 const char* const kSelectID = "mySelect"; 19 const char* const kEmptySelectID = "myEmptySelect"; 20 21 } // namespace 22 23 class ExternalPopupMenuTest : public RenderViewTest { 24 public: 25 ExternalPopupMenuTest() {} 26 27 RenderViewImpl* view() { 28 return static_cast<RenderViewImpl*>(view_); 29 } 30 31 virtual void SetUp() { 32 RenderViewTest::SetUp(); 33 // We need to set this explictly as RenderMain is not run. 34 blink::WebView::setUseExternalPopupMenus(true); 35 36 std::string html = "<select id='mySelect' onchange='selectChanged(this)'>" 37 " <option>zero</option>" 38 " <option selected='1'>one</option>" 39 " <option>two</option>" 40 "</select>" 41 "<select id='myEmptySelect'>" 42 "</select>"; 43 if (ShouldRemoveSelectOnChange()) { 44 html += "<script>" 45 " function selectChanged(select) {" 46 " select.parentNode.removeChild(select);" 47 " }" 48 "</script>"; 49 } 50 51 // Load the test page. 52 LoadHTML(html.c_str()); 53 54 // Set a minimum size and give focus so simulated events work. 55 view()->webwidget()->resize(blink::WebSize(500, 500)); 56 view()->webwidget()->setFocus(true); 57 } 58 59 int GetSelectedIndex() { 60 base::string16 script(ASCIIToUTF16(kSelectID)); 61 script.append(ASCIIToUTF16(".selectedIndex")); 62 int selected_index = -1; 63 ExecuteJavaScriptAndReturnIntValue(script, &selected_index); 64 return selected_index; 65 } 66 67 protected: 68 virtual bool ShouldRemoveSelectOnChange() const { return false; } 69 70 DISALLOW_COPY_AND_ASSIGN(ExternalPopupMenuTest); 71 }; 72 73 // Normal case: test showing a select popup, canceling/selecting an item. 74 TEST_F(ExternalPopupMenuTest, NormalCase) { 75 IPC::TestSink& sink = render_thread_->sink(); 76 77 // Click the text field once. 78 EXPECT_TRUE(SimulateElementClick(kSelectID)); 79 80 // We should have sent a message to the browser to show the popup menu. 81 const IPC::Message* message = 82 sink.GetUniqueMessageMatching(ViewHostMsg_ShowPopup::ID); 83 ASSERT_TRUE(message != NULL); 84 Tuple1<ViewHostMsg_ShowPopup_Params> param; 85 ViewHostMsg_ShowPopup::Read(message, ¶m); 86 ASSERT_EQ(3U, param.a.popup_items.size()); 87 EXPECT_EQ(1, param.a.selected_item); 88 89 // Simulate the user canceling the popup, the index should not have changed. 90 view()->OnSelectPopupMenuItem(-1); 91 EXPECT_EQ(1, GetSelectedIndex()); 92 93 // Show the pop-up again and this time make a selection. 94 EXPECT_TRUE(SimulateElementClick(kSelectID)); 95 view()->OnSelectPopupMenuItem(0); 96 EXPECT_EQ(0, GetSelectedIndex()); 97 98 // Show the pop-up again and make another selection. 99 sink.ClearMessages(); 100 EXPECT_TRUE(SimulateElementClick(kSelectID)); 101 message = sink.GetUniqueMessageMatching(ViewHostMsg_ShowPopup::ID); 102 ASSERT_TRUE(message != NULL); 103 ViewHostMsg_ShowPopup::Read(message, ¶m); 104 ASSERT_EQ(3U, param.a.popup_items.size()); 105 EXPECT_EQ(0, param.a.selected_item); 106 } 107 108 // Page shows popup, then navigates away while popup showing, then select. 109 TEST_F(ExternalPopupMenuTest, ShowPopupThenNavigate) { 110 // Click the text field once. 111 EXPECT_TRUE(SimulateElementClick(kSelectID)); 112 113 // Now we navigate to another pager. 114 LoadHTML("<blink>Awesome page!</blink>"); 115 116 // Now the user selects something, we should not crash. 117 view()->OnSelectPopupMenuItem(-1); 118 } 119 120 // An empty select should not cause a crash when clicked. 121 // http://crbug.com/63774 122 TEST_F(ExternalPopupMenuTest, EmptySelect) { 123 EXPECT_TRUE(SimulateElementClick(kEmptySelectID)); 124 } 125 126 class ExternalPopupMenuRemoveTest : public ExternalPopupMenuTest { 127 public: 128 ExternalPopupMenuRemoveTest() {} 129 130 protected: 131 virtual bool ShouldRemoveSelectOnChange() const OVERRIDE { return true; } 132 }; 133 134 // Tests that nothing bad happen when the page removes the select when it 135 // changes. (http://crbug.com/61997) 136 TEST_F(ExternalPopupMenuRemoveTest, RemoveOnChange) { 137 // Click the text field once to show the popup. 138 EXPECT_TRUE(SimulateElementClick(kSelectID)); 139 140 // Select something, it causes the select to be removed from the page. 141 view()->OnSelectPopupMenuItem(0); 142 143 // Just to check the soundness of the test, call SimulateElementClick again. 144 // It should return false as the select has been removed. 145 EXPECT_FALSE(SimulateElementClick(kSelectID)); 146 } 147 148 } // namespace content 149