sync_setup_wizard_unittest.cc revision c407dc5cd9bdc5668497f21b26b09d988ab439de
1// Copyright (c) 2010 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/sync/sync_setup_wizard.h" 6 7#include "base/json/json_writer.h" 8#include "base/scoped_ptr.h" 9#include "base/stl_util-inl.h" 10#include "chrome/browser/browser.h" 11#include "chrome/browser/browser_list.h" 12#include "chrome/browser/google_service_auth_error.h" 13#include "chrome/browser/pref_service.h" 14#include "chrome/browser/sync/profile_sync_factory_mock.h" 15#include "chrome/browser/sync/profile_sync_service.h" 16#include "chrome/browser/sync/sync_setup_flow.h" 17#include "chrome/common/pref_names.h" 18#include "chrome/test/browser_with_test_window_test.h" 19#include "chrome/test/testing_profile.h" 20#include "chrome/test/test_browser_window.h" 21#include "testing/gtest/include/gtest/gtest.h" 22 23static const char kTestUser[] = "chrome.p13n.test@gmail.com"; 24static const char kTestPassword[] = "passwd"; 25static const char kTestCaptcha[] = "pizzamyheart"; 26static const char kTestCaptchaUrl[] = "http://pizzamyheart/"; 27 28typedef GoogleServiceAuthError AuthError; 29 30// A PSS subtype to inject. 31class ProfileSyncServiceForWizardTest : public ProfileSyncService { 32 public: 33 ProfileSyncServiceForWizardTest(ProfileSyncFactory* factory, Profile* profile) 34 : ProfileSyncService(factory, profile, false), 35 user_cancelled_dialog_(false) { 36 RegisterPreferences(); 37 ResetTestStats(); 38 } 39 40 virtual ~ProfileSyncServiceForWizardTest() { } 41 42 virtual void OnUserSubmittedAuth(const std::string& username, 43 const std::string& password, 44 const std::string& captcha) { 45 username_ = username; 46 password_ = password; 47 captcha_ = captcha; 48 } 49 50 virtual void OnUserChoseDatatypes(bool sync_everything, 51 const syncable::ModelTypeSet& chosen_types) { 52 user_chose_data_types_ = true; 53 chosen_data_types_ = chosen_types; 54 } 55 56 virtual void OnUserCancelledDialog() { 57 user_cancelled_dialog_ = true; 58 } 59 60 virtual string16 GetAuthenticatedUsername() const { 61 return UTF8ToUTF16(username_); 62 } 63 64 void set_auth_state(const std::string& last_email, 65 const AuthError& error) { 66 last_attempted_user_email_ = last_email; 67 last_auth_error_ = error; 68 } 69 70 void ResetTestStats() { 71 username_.clear(); 72 password_.clear(); 73 captcha_.clear(); 74 user_cancelled_dialog_ = false; 75 user_chose_data_types_ = false; 76 keep_everything_synced_ = false; 77 chosen_data_types_.clear(); 78 } 79 80 std::string username_; 81 std::string password_; 82 std::string captcha_; 83 bool user_cancelled_dialog_; 84 bool user_chose_data_types_; 85 bool keep_everything_synced_; 86 syncable::ModelTypeSet chosen_data_types_; 87 88 private: 89 DISALLOW_COPY_AND_ASSIGN(ProfileSyncServiceForWizardTest); 90}; 91 92class TestingProfileWithSyncService : public TestingProfile { 93 public: 94 TestingProfileWithSyncService() { 95 sync_service_.reset(new ProfileSyncServiceForWizardTest(&factory_, this)); 96 } 97 98 virtual ProfileSyncService* GetProfileSyncService() { 99 return sync_service_.get(); 100 } 101 private: 102 ProfileSyncFactoryMock factory_; 103 scoped_ptr<ProfileSyncService> sync_service_; 104}; 105 106class TestBrowserWindowForWizardTest : public TestBrowserWindow { 107 public: 108 explicit TestBrowserWindowForWizardTest(Browser* browser) 109 : TestBrowserWindow(browser), flow_(NULL), 110 was_show_html_dialog_called_(false) { 111 } 112 113 virtual ~TestBrowserWindowForWizardTest() { 114 if (flow_.get()) { 115 // In real life, the handlers are destroyed by the DOMUI infrastructure, 116 // which calls GetDOMMessageHandlers to take ownership. This does not 117 // exist in our test, so we perform cleanup manually. 118 std::vector<DOMMessageHandler*> handlers; 119 flow_->GetDOMMessageHandlers(&handlers); 120 // The handler contract is that they are valid for the lifetime of the 121 // HTMLDialogUIDelegate, but are cleaned up after the dialog is closed 122 // and/or deleted. 123 flow_.reset(); 124 STLDeleteElements(&handlers); 125 } 126 } 127 128 // We intercept this call to hijack the flow created and then use it to 129 // drive the wizard as if we were the HTML page. 130 virtual void ShowHTMLDialog(HtmlDialogUIDelegate* delegate, 131 gfx::NativeWindow parent_window) { 132 flow_.reset(static_cast<SyncSetupFlow*>(delegate)); 133 was_show_html_dialog_called_ = true; 134 } 135 136 bool TestAndResetWasShowHTMLDialogCalled() { 137 bool ret = was_show_html_dialog_called_; 138 was_show_html_dialog_called_ = false; 139 return ret; 140 } 141 142 // Simulates the user (or browser view hierarchy) closing the html dialog. 143 // Handles cleaning up the delegate and associated handlers. 144 void CloseDialog() { 145 if (flow_.get()) { 146 std::vector<DOMMessageHandler*> handlers; 147 flow_->GetDOMMessageHandlers(&handlers); 148 // The flow deletes itself here. Don't use reset(). 149 flow_.release()->OnDialogClosed(""); 150 STLDeleteElements(&handlers); 151 } 152 } 153 154 SyncSetupFlow* flow() { return flow_.get(); } 155 156 private: 157 // In real life, this is owned by the view that is opened by the browser. We 158 // mock all that out, so we need to take ownership so the flow doesn't leak. 159 scoped_ptr<SyncSetupFlow> flow_; 160 161 bool was_show_html_dialog_called_; 162}; 163 164class SyncSetupWizardTest : public BrowserWithTestWindowTest { 165 public: 166 SyncSetupWizardTest() 167 : ui_thread_(ChromeThread::UI, MessageLoop::current()), 168 file_thread_(ChromeThread::FILE, MessageLoop::current()), 169 test_window_(NULL), 170 wizard_(NULL) { } 171 virtual ~SyncSetupWizardTest() { } 172 virtual void SetUp() { 173 set_profile(new TestingProfileWithSyncService()); 174 profile()->CreateBookmarkModel(false); 175 // Wait for the bookmarks model to load. 176 profile()->BlockUntilBookmarkModelLoaded(); 177 set_browser(new Browser(Browser::TYPE_NORMAL, profile())); 178 test_window_ = new TestBrowserWindowForWizardTest(browser()); 179 set_window(test_window_); 180 browser()->set_window(window()); 181 BrowserList::SetLastActive(browser()); 182 service_ = static_cast<ProfileSyncServiceForWizardTest*>( 183 profile()->GetProfileSyncService()); 184 wizard_.reset(new SyncSetupWizard(service_)); 185 } 186 187 virtual void TearDown() { 188 test_window_ = NULL; 189 service_ = NULL; 190 wizard_.reset(); 191 } 192 193 ChromeThread ui_thread_; 194 ChromeThread file_thread_; 195 TestBrowserWindowForWizardTest* test_window_; 196 scoped_ptr<SyncSetupWizard> wizard_; 197 ProfileSyncServiceForWizardTest* service_; 198}; 199 200// See http://code.google.com/p/chromium/issues/detail?id=40715 for 201// why we skip the below tests on OS X. We don't use DISABLED_ as we 202// would have to change the corresponding FRIEND_TEST() declarations. 203 204#if defined(OS_MACOSX) 205#define SKIP_TEST_ON_MACOSX() \ 206 do { LOG(WARNING) << "Test skipped on OS X"; return; } while (0) 207#else 208#define SKIP_TEST_ON_MACOSX() do {} while (0) 209#endif 210 211TEST_F(SyncSetupWizardTest, InitialStepLogin) { 212 SKIP_TEST_ON_MACOSX(); 213 DictionaryValue dialog_args; 214 SyncSetupFlow::GetArgsForGaiaLogin(service_, &dialog_args); 215 std::string json_start_args; 216 base::JSONWriter::Write(&dialog_args, false, &json_start_args); 217 ListValue credentials; 218 std::string auth = "{\"user\":\""; 219 auth += std::string(kTestUser) + "\",\"pass\":\""; 220 auth += std::string(kTestPassword) + "\",\"captcha\":\""; 221 auth += std::string(kTestCaptcha) + "\"}"; 222 credentials.Append(new StringValue(auth)); 223 224 EXPECT_FALSE(wizard_->IsVisible()); 225 EXPECT_FALSE(test_window_->flow()); 226 wizard_->Step(SyncSetupWizard::GAIA_LOGIN); 227 228 EXPECT_TRUE(wizard_->IsVisible()); 229 EXPECT_TRUE(test_window_->TestAndResetWasShowHTMLDialogCalled()); 230 EXPECT_EQ(SyncSetupWizard::GAIA_LOGIN, test_window_->flow()->current_state_); 231 EXPECT_EQ(SyncSetupWizard::DONE, test_window_->flow()->end_state_); 232 EXPECT_EQ(json_start_args, test_window_->flow()->dialog_start_args_); 233 234 // Simulate the user submitting credentials. 235 test_window_->flow()->flow_handler_->HandleSubmitAuth(&credentials); 236 EXPECT_TRUE(wizard_->IsVisible()); 237 EXPECT_EQ(SyncSetupWizard::GAIA_LOGIN, test_window_->flow()->current_state_); 238 EXPECT_EQ(kTestUser, service_->username_); 239 EXPECT_EQ(kTestPassword, service_->password_); 240 EXPECT_EQ(kTestCaptcha, service_->captcha_); 241 EXPECT_FALSE(service_->user_cancelled_dialog_); 242 service_->ResetTestStats(); 243 244 // Simulate failed credentials. 245 AuthError invalid_gaia(AuthError::INVALID_GAIA_CREDENTIALS); 246 service_->set_auth_state(kTestUser, invalid_gaia); 247 wizard_->Step(SyncSetupWizard::GAIA_LOGIN); 248 EXPECT_TRUE(wizard_->IsVisible()); 249 EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); 250 EXPECT_EQ(SyncSetupWizard::GAIA_LOGIN, test_window_->flow()->current_state_); 251 dialog_args.Clear(); 252 SyncSetupFlow::GetArgsForGaiaLogin(service_, &dialog_args); 253 EXPECT_EQ(4U, dialog_args.size()); 254 std::string iframe_to_show; 255 dialog_args.GetString(L"iframeToShow", &iframe_to_show); 256 EXPECT_EQ("login", iframe_to_show); 257 std::string actual_user; 258 dialog_args.GetString(L"user", &actual_user); 259 EXPECT_EQ(kTestUser, actual_user); 260 int error = -1; 261 dialog_args.GetInteger(L"error", &error); 262 EXPECT_EQ(static_cast<int>(AuthError::INVALID_GAIA_CREDENTIALS), error); 263 service_->set_auth_state(kTestUser, AuthError::None()); 264 265 // Simulate captcha. 266 AuthError captcha_error(AuthError::FromCaptchaChallenge( 267 std::string(), GURL(kTestCaptchaUrl), GURL())); 268 service_->set_auth_state(kTestUser, captcha_error); 269 wizard_->Step(SyncSetupWizard::GAIA_LOGIN); 270 SyncSetupFlow::GetArgsForGaiaLogin(service_, &dialog_args); 271 EXPECT_EQ(4U, dialog_args.size()); 272 dialog_args.GetString(L"iframeToShow", &iframe_to_show); 273 EXPECT_EQ("login", iframe_to_show); 274 std::string captcha_url; 275 dialog_args.GetString(L"captchaUrl", &captcha_url); 276 EXPECT_EQ(kTestCaptchaUrl, GURL(captcha_url).spec()); 277 error = -1; 278 dialog_args.GetInteger(L"error", &error); 279 EXPECT_EQ(static_cast<int>(AuthError::CAPTCHA_REQUIRED), error); 280 service_->set_auth_state(kTestUser, AuthError::None()); 281 282 // Simulate success. 283 wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); 284 EXPECT_TRUE(wizard_->IsVisible()); 285 EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); 286 // In a non-discrete run, GAIA_SUCCESS immediately transitions you to 287 // CHOOSE_DATA_TYPES. 288 EXPECT_EQ(SyncSetupWizard::CHOOSE_DATA_TYPES, 289 test_window_->flow()->current_state_); 290 291 // That's all we're testing here, just move on to DONE. We'll test the 292 // "choose data types" scenarios elsewhere. 293 wizard_->Step(SyncSetupWizard::DONE); // No merge and sync. 294 EXPECT_TRUE(wizard_->IsVisible()); 295 EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); 296 EXPECT_EQ(SyncSetupWizard::DONE, test_window_->flow()->current_state_); 297} 298 299TEST_F(SyncSetupWizardTest, ChooseDataTypesSetsPrefs) { 300 SKIP_TEST_ON_MACOSX(); 301 wizard_->Step(SyncSetupWizard::GAIA_LOGIN); 302 wizard_->Step(SyncSetupWizard::CHOOSE_DATA_TYPES); 303 304 ListValue data_type_choices_value; 305 std::string data_type_choices = "{\"keepEverythingSynced\":false,"; 306 data_type_choices += "\"syncBookmarks\":true,\"syncPreferences\":true,"; 307 data_type_choices += "\"syncThemes\":false,\"syncPasswords\":false,"; 308 data_type_choices += "\"syncAutofill\":false,\"syncExtensions\":false,"; 309 data_type_choices += "\"syncTypedUrls\":true}"; 310 data_type_choices_value.Append(new StringValue(data_type_choices)); 311 312 // Simulate the user choosing data types; bookmarks and prefs are on, the rest 313 // are off. 314 test_window_->flow()->flow_handler_->HandleChooseDataTypes( 315 &data_type_choices_value); 316 EXPECT_TRUE(wizard_->IsVisible()); 317 EXPECT_TRUE(test_window_->TestAndResetWasShowHTMLDialogCalled()); 318 EXPECT_FALSE(service_->keep_everything_synced_); 319 EXPECT_EQ(service_->chosen_data_types_.count(syncable::BOOKMARKS), 1U); 320 EXPECT_EQ(service_->chosen_data_types_.count(syncable::PREFERENCES), 1U); 321 EXPECT_EQ(service_->chosen_data_types_.count(syncable::THEMES), 0U); 322 EXPECT_EQ(service_->chosen_data_types_.count(syncable::PASSWORDS), 0U); 323 EXPECT_EQ(service_->chosen_data_types_.count(syncable::AUTOFILL), 0U); 324 EXPECT_EQ(service_->chosen_data_types_.count(syncable::EXTENSIONS), 0U); 325 EXPECT_EQ(service_->chosen_data_types_.count(syncable::TYPED_URLS), 1U); 326 327 test_window_->CloseDialog(); 328} 329 330TEST_F(SyncSetupWizardTest, DialogCancelled) { 331 SKIP_TEST_ON_MACOSX(); 332 wizard_->Step(SyncSetupWizard::GAIA_LOGIN); 333 // Simulate the user closing the dialog. 334 test_window_->CloseDialog(); 335 EXPECT_FALSE(wizard_->IsVisible()); 336 EXPECT_TRUE(service_->user_cancelled_dialog_); 337 EXPECT_EQ(std::string(), service_->username_); 338 EXPECT_EQ(std::string(), service_->password_); 339 340 wizard_->Step(SyncSetupWizard::GAIA_LOGIN); 341 EXPECT_TRUE(wizard_->IsVisible()); 342 EXPECT_TRUE(test_window_->TestAndResetWasShowHTMLDialogCalled()); 343 wizard_->Step(SyncSetupWizard::GAIA_LOGIN); 344 EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); 345 346 test_window_->CloseDialog(); 347 EXPECT_FALSE(wizard_->IsVisible()); 348 EXPECT_TRUE(service_->user_cancelled_dialog_); 349 EXPECT_EQ(std::string(), service_->username_); 350 EXPECT_EQ(std::string(), service_->password_); 351} 352 353TEST_F(SyncSetupWizardTest, InvalidTransitions) { 354 SKIP_TEST_ON_MACOSX(); 355 wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); 356 EXPECT_FALSE(wizard_->IsVisible()); 357 EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); 358 359 wizard_->Step(SyncSetupWizard::DONE); 360 EXPECT_FALSE(wizard_->IsVisible()); 361 EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); 362 363 wizard_->Step(SyncSetupWizard::DONE_FIRST_TIME); 364 EXPECT_FALSE(wizard_->IsVisible()); 365 EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); 366 367 wizard_->Step(SyncSetupWizard::GAIA_LOGIN); 368 369 wizard_->Step(SyncSetupWizard::DONE); 370 EXPECT_EQ(SyncSetupWizard::GAIA_LOGIN, test_window_->flow()->current_state_); 371 wizard_->Step(SyncSetupWizard::DONE_FIRST_TIME); 372 EXPECT_EQ(SyncSetupWizard::GAIA_LOGIN, test_window_->flow()->current_state_); 373 374 wizard_->Step(SyncSetupWizard::SETUP_ABORTED_BY_PENDING_CLEAR); 375 EXPECT_EQ(SyncSetupWizard::GAIA_LOGIN, 376 test_window_->flow()->current_state_); 377 378 wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); 379 EXPECT_EQ(SyncSetupWizard::CHOOSE_DATA_TYPES, 380 test_window_->flow()->current_state_); 381 382 wizard_->Step(SyncSetupWizard::FATAL_ERROR); 383 EXPECT_EQ(SyncSetupWizard::FATAL_ERROR, test_window_->flow()->current_state_); 384} 385 386TEST_F(SyncSetupWizardTest, FullSuccessfulRunSetsPref) { 387 SKIP_TEST_ON_MACOSX(); 388 wizard_->Step(SyncSetupWizard::GAIA_LOGIN); 389 wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); 390 wizard_->Step(SyncSetupWizard::DONE); 391 test_window_->CloseDialog(); 392 EXPECT_FALSE(wizard_->IsVisible()); 393 EXPECT_TRUE(service_->profile()->GetPrefs()->GetBoolean( 394 prefs::kSyncHasSetupCompleted)); 395} 396 397TEST_F(SyncSetupWizardTest, FirstFullSuccessfulRunSetsPref) { 398 SKIP_TEST_ON_MACOSX(); 399 wizard_->Step(SyncSetupWizard::GAIA_LOGIN); 400 wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); 401 wizard_->Step(SyncSetupWizard::DONE_FIRST_TIME); 402 test_window_->CloseDialog(); 403 EXPECT_FALSE(wizard_->IsVisible()); 404 EXPECT_TRUE(service_->profile()->GetPrefs()->GetBoolean( 405 prefs::kSyncHasSetupCompleted)); 406} 407 408TEST_F(SyncSetupWizardTest, AbortedByPendingClear) { 409 SKIP_TEST_ON_MACOSX(); 410 wizard_->Step(SyncSetupWizard::GAIA_LOGIN); 411 wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); 412 wizard_->Step(SyncSetupWizard::SETUP_ABORTED_BY_PENDING_CLEAR); 413 EXPECT_EQ(SyncSetupWizard::SETUP_ABORTED_BY_PENDING_CLEAR, 414 test_window_->flow()->current_state_); 415 test_window_->CloseDialog(); 416 EXPECT_FALSE(wizard_->IsVisible()); 417} 418 419TEST_F(SyncSetupWizardTest, DiscreteRunChooseDataTypes) { 420 SKIP_TEST_ON_MACOSX(); 421 // For a discrete run, we need to have ran through setup once. 422 wizard_->Step(SyncSetupWizard::GAIA_LOGIN); 423 wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); 424 wizard_->Step(SyncSetupWizard::DONE); 425 test_window_->CloseDialog(); 426 EXPECT_TRUE(test_window_->TestAndResetWasShowHTMLDialogCalled()); 427 428 wizard_->Step(SyncSetupWizard::CHOOSE_DATA_TYPES); 429 EXPECT_TRUE(test_window_->TestAndResetWasShowHTMLDialogCalled()); 430 EXPECT_EQ(SyncSetupWizard::DONE, test_window_->flow()->end_state_); 431 432 wizard_->Step(SyncSetupWizard::DONE); 433 test_window_->CloseDialog(); 434 EXPECT_FALSE(wizard_->IsVisible()); 435} 436 437TEST_F(SyncSetupWizardTest, DiscreteRunChooseDataTypesAbortedByPendingClear) { 438 SKIP_TEST_ON_MACOSX(); 439 // For a discrete run, we need to have ran through setup once. 440 wizard_->Step(SyncSetupWizard::GAIA_LOGIN); 441 wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); 442 wizard_->Step(SyncSetupWizard::DONE); 443 test_window_->CloseDialog(); 444 EXPECT_TRUE(test_window_->TestAndResetWasShowHTMLDialogCalled()); 445 446 wizard_->Step(SyncSetupWizard::CHOOSE_DATA_TYPES); 447 EXPECT_TRUE(test_window_->TestAndResetWasShowHTMLDialogCalled()); 448 EXPECT_EQ(SyncSetupWizard::DONE, test_window_->flow()->end_state_); 449 wizard_->Step(SyncSetupWizard::SETUP_ABORTED_BY_PENDING_CLEAR); 450 EXPECT_EQ(SyncSetupWizard::SETUP_ABORTED_BY_PENDING_CLEAR, 451 test_window_->flow()->current_state_); 452 453 test_window_->CloseDialog(); 454 EXPECT_FALSE(wizard_->IsVisible()); 455} 456 457TEST_F(SyncSetupWizardTest, DiscreteRunGaiaLogin) { 458 SKIP_TEST_ON_MACOSX(); 459 DictionaryValue dialog_args; 460 // For a discrete run, we need to have ran through setup once. 461 wizard_->Step(SyncSetupWizard::GAIA_LOGIN); 462 wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); 463 wizard_->Step(SyncSetupWizard::DONE); 464 test_window_->CloseDialog(); 465 EXPECT_TRUE(test_window_->TestAndResetWasShowHTMLDialogCalled()); 466 467 wizard_->Step(SyncSetupWizard::GAIA_LOGIN); 468 EXPECT_EQ(SyncSetupWizard::GAIA_SUCCESS, test_window_->flow()->end_state_); 469 470 AuthError invalid_gaia(AuthError::INVALID_GAIA_CREDENTIALS); 471 service_->set_auth_state(kTestUser, invalid_gaia); 472 wizard_->Step(SyncSetupWizard::GAIA_LOGIN); 473 EXPECT_TRUE(wizard_->IsVisible()); 474 SyncSetupFlow::GetArgsForGaiaLogin(service_, &dialog_args); 475 EXPECT_EQ(4U, dialog_args.size()); 476 std::string iframe_to_show; 477 dialog_args.GetString(L"iframeToShow", &iframe_to_show); 478 EXPECT_EQ("login", iframe_to_show); 479 std::string actual_user; 480 dialog_args.GetString(L"user", &actual_user); 481 EXPECT_EQ(kTestUser, actual_user); 482 int error = -1; 483 dialog_args.GetInteger(L"error", &error); 484 EXPECT_EQ(static_cast<int>(AuthError::INVALID_GAIA_CREDENTIALS), error); 485 service_->set_auth_state(kTestUser, AuthError::None()); 486 487 wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); 488 EXPECT_TRUE(test_window_->TestAndResetWasShowHTMLDialogCalled()); 489} 490 491#undef SKIP_TEST_ON_MACOSX 492