1 // Copyright 2013 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 "chrome/browser/ui/views/autofill/autofill_dialog_views.h" 6 7 #include "base/basictypes.h" 8 #include "base/compiler_specific.h" 9 #include "base/memory/scoped_ptr.h" 10 #include "chrome/browser/ui/autofill/mock_autofill_dialog_view_delegate.h" 11 #include "chrome/browser/ui/tabs/tab_strip_model.h" 12 #include "chrome/browser/ui/views/autofill/decorated_textfield.h" 13 #include "chrome/browser/ui/views/frame/browser_view.h" 14 #include "chrome/browser/ui/views/frame/test_with_browser_view.h" 15 #include "components/web_modal/test_web_contents_modal_dialog_host.h" 16 #include "components/web_modal/test_web_contents_modal_dialog_manager_delegate.h" 17 #include "components/web_modal/web_contents_modal_dialog_manager.h" 18 #include "content/public/common/url_constants.h" 19 #include "testing/gmock/include/gmock/gmock.h" 20 #include "testing/gtest/include/gtest/gtest.h" 21 #include "ui/views/controls/webview/webview.h" 22 #include "ui/views/widget/widget.h" 23 24 namespace autofill { 25 26 namespace { 27 28 using testing::Return; 29 using web_modal::WebContentsModalDialogManager; 30 31 // A views implementation of the Autofill dialog with slightly more testability. 32 class TestAutofillDialogViews : public AutofillDialogViews { 33 public: 34 explicit TestAutofillDialogViews(AutofillDialogViewDelegate* delegate) 35 : AutofillDialogViews(delegate) {} 36 virtual ~TestAutofillDialogViews() {} 37 38 using AutofillDialogViews::GetLoadingShieldForTesting; 39 using AutofillDialogViews::GetSignInWebViewForTesting; 40 using AutofillDialogViews::GetNotificationAreaForTesting; 41 using AutofillDialogViews::GetScrollableAreaForTesting; 42 43 private: 44 DISALLOW_COPY_AND_ASSIGN(TestAutofillDialogViews); 45 }; 46 47 } // namespace 48 49 class AutofillDialogViewsTest : public TestWithBrowserView { 50 public: 51 AutofillDialogViewsTest() {} 52 virtual ~AutofillDialogViewsTest() {} 53 54 // TestWithBrowserView: 55 virtual void SetUp() OVERRIDE { 56 TestWithBrowserView::SetUp(); 57 58 view_delegate_.SetProfile(profile()); 59 60 AddTab(browser(), GURL(url::kAboutBlankURL)); 61 TabStripModel* tab_strip_model = browser()->tab_strip_model(); 62 content::WebContents* contents = tab_strip_model->GetWebContentsAt(0); 63 ASSERT_TRUE(contents); 64 view_delegate_.SetWebContents(contents); 65 66 BrowserView* browser_view = 67 BrowserView::GetBrowserViewForBrowser(browser()); 68 dialog_host_.reset(new web_modal::TestWebContentsModalDialogHost( 69 browser_view->GetWidget()->GetNativeView())); 70 dialog_delegate_.set_web_contents_modal_dialog_host(dialog_host_.get()); 71 72 WebContentsModalDialogManager* dialog_manager = 73 WebContentsModalDialogManager::FromWebContents(contents); 74 ASSERT_TRUE(dialog_manager); 75 dialog_manager->SetDelegate(&dialog_delegate_); 76 77 dialog_.reset(new TestAutofillDialogViews(&view_delegate_)); 78 dialog_->Show(); 79 } 80 81 virtual void TearDown() OVERRIDE { 82 dialog_->GetWidget()->CloseNow(); 83 dialog_.reset(); 84 85 TestWithBrowserView::TearDown(); 86 } 87 88 MockAutofillDialogViewDelegate* delegate() { return &view_delegate_; } 89 90 TestAutofillDialogViews* dialog() { return dialog_.get(); } 91 92 protected: 93 void SetSectionsFocusable() { 94 dialog()->GetLoadingShieldForTesting()->SetFocusable(true); 95 // The sign in web view is not focusable until a web contents is created. 96 // TODO(dbeam): figure out how to create a web contents on the right thread. 97 dialog()->GetNotificationAreaForTesting()->SetFocusable(true); 98 dialog()->GetScrollableAreaForTesting()->SetFocusable(true); 99 } 100 101 private: 102 // Fake dialog delegate and host to isolate test behavior. 103 web_modal::TestWebContentsModalDialogManagerDelegate dialog_delegate_; 104 scoped_ptr<web_modal::TestWebContentsModalDialogHost> dialog_host_; 105 106 // Mock view delegate as this file only tests the view. 107 testing::NiceMock<MockAutofillDialogViewDelegate> view_delegate_; 108 109 scoped_ptr<TestAutofillDialogViews> dialog_; 110 }; 111 112 TEST_F(AutofillDialogViewsTest, InitialFocus) { 113 views::FocusManager* focus_manager = dialog()->GetWidget()->GetFocusManager(); 114 views::View* focused_view = focus_manager->GetFocusedView(); 115 EXPECT_STREQ(DecoratedTextfield::kViewClassName, 116 focused_view->GetClassName()); 117 } 118 119 TEST_F(AutofillDialogViewsTest, SignInFocus) { 120 SetSectionsFocusable(); 121 122 views::View* loading_shield = dialog()->GetLoadingShieldForTesting(); 123 views::View* sign_in_web_view = dialog()->GetSignInWebViewForTesting(); 124 views::View* notification_area = dialog()->GetNotificationAreaForTesting(); 125 views::View* scrollable_area = dialog()->GetScrollableAreaForTesting(); 126 127 dialog()->ShowSignIn(); 128 129 // The sign in view should be the only showing and focusable view. 130 EXPECT_TRUE(sign_in_web_view->IsFocusable()); 131 EXPECT_FALSE(loading_shield->IsFocusable()); 132 EXPECT_FALSE(notification_area->IsFocusable()); 133 EXPECT_FALSE(scrollable_area->IsFocusable()); 134 135 EXPECT_CALL(*delegate(), ShouldShowSpinner()).WillRepeatedly(Return(false)); 136 dialog()->HideSignIn(); 137 138 // Hide sign in while not loading Wallet items as if the user clicked "Back". 139 EXPECT_TRUE(notification_area->IsFocusable()); 140 EXPECT_TRUE(scrollable_area->IsFocusable()); 141 EXPECT_FALSE(loading_shield->IsFocusable()); 142 EXPECT_FALSE(sign_in_web_view->IsFocusable()); 143 144 dialog()->ShowSignIn(); 145 146 EXPECT_TRUE(sign_in_web_view->IsFocusable()); 147 EXPECT_FALSE(loading_shield->IsFocusable()); 148 EXPECT_FALSE(notification_area->IsFocusable()); 149 EXPECT_FALSE(scrollable_area->IsFocusable()); 150 151 EXPECT_CALL(*delegate(), ShouldShowSpinner()).WillRepeatedly(Return(true)); 152 dialog()->HideSignIn(); 153 154 // Hide sign in while pretending to load Wallet data. 155 EXPECT_TRUE(loading_shield->IsFocusable()); 156 EXPECT_FALSE(notification_area->IsFocusable()); 157 EXPECT_FALSE(scrollable_area->IsFocusable()); 158 EXPECT_FALSE(sign_in_web_view->IsFocusable()); 159 } 160 161 TEST_F(AutofillDialogViewsTest, LoadingFocus) { 162 SetSectionsFocusable(); 163 164 views::View* loading_shield = dialog()->GetLoadingShieldForTesting(); 165 views::View* sign_in_web_view = dialog()->GetSignInWebViewForTesting(); 166 views::View* notification_area = dialog()->GetNotificationAreaForTesting(); 167 views::View* scrollable_area = dialog()->GetScrollableAreaForTesting(); 168 169 // Pretend as if loading Wallet data. 170 EXPECT_CALL(*delegate(), ShouldShowSpinner()).WillRepeatedly(Return(true)); 171 dialog()->UpdateAccountChooser(); 172 173 EXPECT_TRUE(loading_shield->IsFocusable()); 174 EXPECT_FALSE(notification_area->IsFocusable()); 175 EXPECT_FALSE(scrollable_area->IsFocusable()); 176 EXPECT_FALSE(sign_in_web_view->IsFocusable()); 177 178 // Pretend as if Wallet data has finished loading. 179 EXPECT_CALL(*delegate(), ShouldShowSpinner()).WillRepeatedly(Return(false)); 180 dialog()->UpdateAccountChooser(); 181 182 EXPECT_TRUE(notification_area->IsFocusable()); 183 EXPECT_TRUE(scrollable_area->IsFocusable()); 184 EXPECT_FALSE(loading_shield->IsFocusable()); 185 EXPECT_FALSE(sign_in_web_view->IsFocusable()); 186 } 187 188 TEST_F(AutofillDialogViewsTest, ImeEventDoesntCrash) { 189 // IMEs create synthetic events with no backing native event. 190 views::FocusManager* focus_manager = dialog()->GetWidget()->GetFocusManager(); 191 views::View* focused_view = focus_manager->GetFocusedView(); 192 ASSERT_STREQ(DecoratedTextfield::kViewClassName, 193 focused_view->GetClassName()); 194 EXPECT_FALSE(dialog()->HandleKeyEvent( 195 static_cast<views::Textfield*>(focused_view), 196 ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_A, 0, false))); 197 } 198 199 } // namespace autofill 200