Home | History | Annotate | Download | only in renderer
      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     WebKit::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(WebKit::WebSize(500, 500));
     56     view()->webwidget()->setFocus(true);
     57   }
     58 
     59   int GetSelectedIndex() {
     60     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, &param);
     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, &param);
    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