1 # Copyright 2014 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 # -*- coding: utf-8 -*- 6 """Automated tests for many websites""" 7 8 import argparse 9 import logging 10 11 from environment import Environment 12 from websitetest import WebsiteTest 13 14 15 class Facebook(WebsiteTest): 16 17 def Login(self): 18 self.GoTo("https://www.facebook.com") 19 self.FillUsernameInto("[name='email']") 20 self.FillPasswordInto("[name='pass']") 21 self.Submit("[name='pass']") 22 23 def Logout(self): 24 self.WaitUntilDisplayed("#userNavigationLabel") 25 self.Click("#userNavigationLabel") 26 self.WaitUntilDisplayed("#logout_form [type='submit']") 27 self.Click("#logout_form [type='submit']") 28 29 30 class Google(WebsiteTest): 31 32 def Login(self): 33 self.GoTo("https://accounts.google.com/ServiceLogin?sacu=1&continue=") 34 self.FillUsernameInto("#Email") 35 self.FillPasswordInto("#Passwd") 36 self.Submit("#Passwd") 37 38 def Logout(self): 39 self.GoTo("https://accounts.google.com/Logout") 40 41 42 class Linkedin(WebsiteTest): 43 44 def Login(self): 45 self.GoTo("https://www.linkedin.com") 46 self.FillUsernameInto("#session_key-login") 47 self.FillPasswordInto("#session_password-login") 48 self.Submit("#session_password-login") 49 50 def Logout(self): 51 self.WaitUntilDisplayed(".account-toggle") 52 self.HoverOver(".account-toggle") 53 self.WaitUntilDisplayed(".account-settings .act-set-action") 54 self.Click(".account-settings .act-set-action") 55 56 57 class Mailru(WebsiteTest): 58 59 def Login(self): 60 self.GoTo("https://mail.ru") 61 self.FillUsernameInto("#mailbox__login") 62 self.FillPasswordInto("#mailbox__password") 63 self.Submit("#mailbox__password") 64 65 def Logout(self): 66 self.Click("#PH_logoutLink") 67 68 69 class Nytimes(WebsiteTest): 70 71 def Login(self): 72 self.GoTo("https://myaccount.nytimes.com/auth/login") 73 self.FillUsernameInto("#userid") 74 self.FillPasswordInto("#password") 75 self.Submit("#password") 76 77 def Logout(self): 78 self.GoTo("https://myaccount.nytimes.com/gst/signout") 79 80 81 class Pinterest(WebsiteTest): 82 83 def Login(self): 84 self.GoTo("https://www.pinterest.com/login/") 85 self.FillUsernameInto("[name='username_or_email']") 86 self.FillPasswordInto("[name='password']") 87 self.Submit("[name='password']") 88 89 def Logout(self): 90 self.GoTo("https://www.pinterest.com/logout/") 91 92 93 class Reddit(WebsiteTest): 94 95 def Login(self): 96 self.GoTo("http://www.reddit.com") 97 self.Click(".user .login-required") 98 self.FillUsernameInto("#user_login") 99 self.FillPasswordInto("#passwd_login") 100 self.Wait(2) 101 self.Submit("#passwd_login") 102 103 def Logout(self): 104 self.Click("form[action='http://www.reddit.com/logout'] a") 105 106 107 class Tumblr(WebsiteTest): 108 109 def Login(self): 110 self.GoTo("https://www.tumblr.com/login") 111 self.FillUsernameInto("#signup_email") 112 self.FillPasswordInto("#signup_password") 113 self.Submit("#signup_password") 114 115 def Logout(self): 116 self.GoTo("https://www.tumblr.com/logout") 117 118 119 class Wikipedia(WebsiteTest): 120 121 def Login(self): 122 self.GoTo("https://en.wikipedia.org/w/index.php?title=Special:UserLogin") 123 self.FillUsernameInto("#wpName1") 124 self.FillPasswordInto("#wpPassword1") 125 self.Submit("#wpPassword1") 126 127 def Logout(self): 128 self.GoTo("https://en.wikipedia.org/w/index.php?title=Special:UserLogout") 129 130 131 class Yandex(WebsiteTest): 132 133 def Login(self): 134 self.GoTo("https://mail.yandex.com") 135 self.FillUsernameInto("#b-mail-domik-username11") 136 self.FillPasswordInto("#b-mail-domik-password11") 137 self.Click(".b-mail-button__button") 138 139 def Logout(self): 140 while not self.IsDisplayed(".b-mail-dropdown__item__content" 141 u"..daria-action"): 142 self.ClickIfClickable(".header-user-pic.b-mail-dropdown__handle") 143 self.Wait(1) 144 self.Click(u".b-mail-dropdown__item__content..daria-action") 145 146 147 # Disabled tests. 148 149 150 # Bug not reproducible without test. 151 class Amazon(WebsiteTest): 152 153 def Login(self): 154 self.GoTo( 155 "https://www.amazon.com/ap/signin?openid.assoc_handle=usflex" 156 "&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net" 157 "%2Fauth%2F2.0") 158 self.FillUsernameInto("[name='email']") 159 self.FillPasswordInto("[name='password']") 160 self.Submit("[name='password']") 161 162 def Logout(self): 163 while not self.IsDisplayed("#nav-item-signout"): 164 self.Wait(1) 165 self.HoverOver("#nav-signin-title") 166 self.Click("#nav-item-signout") 167 168 169 # Password not saved. 170 class Ask(WebsiteTest): 171 172 def Login(self): 173 self.GoTo("http://www.ask.com/answers/browse?qsrc=321&q=&o=0&l=dir#") 174 while not self.IsDisplayed("[name='username']"): 175 self.Click("#a16CnbSignInText") 176 self.Wait(1) 177 self.FillUsernameInto("[name='username']") 178 self.FillPasswordInto("[name='password']") 179 self.Click(".signin_show.signin_submit") 180 181 def Logout(self): 182 self.WaitUntilDisplayed("#a16CnbSignInText") 183 self.Click("#a16CnbSignInText") 184 185 186 # Password not saved. 187 class Baidu(WebsiteTest): 188 189 def Login(self): 190 self.GoTo("http://www.baidu.com/") 191 self.Click("[name='tj_login']") 192 self.WaitUntilDisplayed("[name='userName']") 193 self.FillUsernameInto("[name='userName']") 194 self.FillPasswordInto("[name='password']") 195 self.Submit("[name='password']") 196 197 def Logout(self): 198 self.Wait(1) 199 self.GoTo("https://passport.baidu.com/?logout&u=http://www.baidu.com") 200 201 202 # http://crbug.com/368690 203 class Cnn(WebsiteTest): 204 205 def Login(self): 206 self.GoTo("http://www.cnn.com") 207 self.Wait(5) 208 while not self.IsDisplayed(".cnnOvrlyBtn.cnnBtnLogIn"): 209 self.ClickIfClickable("#hdr-auth .no-border.no-pad-right a") 210 self.Wait(1) 211 212 self.Click(".cnnOvrlyBtn.cnnBtnLogIn") 213 self.FillUsernameInto("#cnnOverlayEmail1l") 214 self.FillPasswordInto("#cnnOverlayPwd") 215 self.Click(".cnnOvrlyBtn.cnnBtnLogIn") 216 self.Click(".cnnOvrlyBtn.cnnBtnLogIn") 217 self.Wait(5) 218 219 def Logout(self): 220 self.Wait(4) 221 self.Click("#hdr-auth .no-border.no-pad-right") 222 223 224 # http://crbug.com/368690 225 class Ebay(WebsiteTest): 226 227 def Login(self): 228 self.GoTo("https://signin.ebay.com/") 229 self.FillUsernameInto("[name='userid']") 230 self.FillPasswordInto("[name='pass']") 231 self.Submit("[name='pass']") 232 233 def Logout(self): 234 self.WaitUntilDisplayed("#gh-ug") 235 self.Click("#gh-ug") 236 self.WaitUntilDisplayed("#gh-uo") 237 self.Click("#gh-uo") 238 239 240 # Iframe, password saved but not autofileld. 241 class Espn(WebsiteTest): 242 243 def Login(self): 244 self.GoTo("http://espn.go.com/") 245 while not self.IsDisplayed("#cboxLoadedContent iframe"): 246 self.Click("#signin .cbOverlay") 247 self.Wait(1) 248 frame = self.driver.find_element_by_css_selector("#cboxLoadedContent " 249 "iframe") 250 self.driver.switch_to_frame(frame) 251 self.WaitUntilDisplayed("#username") 252 self.FillUsernameInto("#username") 253 self.FillPasswordInto("#password") 254 while self.IsDisplayed("#password"): 255 self.ClickIfClickable("#submitBtn") 256 self.Wait(1) 257 258 def Logout(self): 259 self.WaitUntilDisplayed("#signin .small") 260 self.Click("#signin .small") 261 262 263 # http://crbug.com/367768 264 class Live(WebsiteTest): 265 266 def Login(self): 267 self.GoTo("https://www.live.com") 268 self.FillUsernameInto("[name='login']") 269 self.FillPasswordInto("[name='passwd']") 270 self.Submit("[name='passwd']") 271 272 def Logout(self): 273 self.WaitUntilDisplayed("#c_meun") 274 self.Click("#c_meun") 275 self.WaitUntilDisplayed("#c_signout") 276 self.Click("#c_signout") 277 278 279 # http://crbug.com/368690 280 class One63(WebsiteTest): 281 282 def Login(self): 283 self.GoTo("http://www.163.com") 284 self.HoverOver("#js_N_navHighlight") 285 self.WaitUntilDisplayed("#js_loginframe_username") 286 self.FillUsernameInto("#js_loginframe_username") 287 self.FillPasswordInto(".ntes-loginframe-label-ipt[type='password']") 288 self.Click(".ntes-loginframe-btn") 289 290 def Logout(self): 291 self.WaitUntilDisplayed("#js_N_navLogout") 292 self.Click("#js_N_navLogout") 293 294 295 # http://crbug.com/368690 296 class Vube(WebsiteTest): 297 298 def Login(self): 299 self.GoTo("https://vube.com") 300 self.Click("[vube-login='']") 301 self.WaitUntilDisplayed("[ng-model='login.user']") 302 self.FillUsernameInto("[ng-model='login.user']") 303 self.FillPasswordInto("[ng-model='login.pass']") 304 while (self.IsDisplayed("[ng-model='login.pass']") 305 and not self.IsDisplayed(".prompt.alert")): 306 self.ClickIfClickable("[ng-click='login()']") 307 self.Wait(1) 308 309 def Logout(self): 310 self.WaitUntilDisplayed("[ng-click='user.logout()']") 311 self.Click("[ng-click='user.logout()']") 312 313 314 # Tests that can cause a crash. 315 316 317 class Yahoo(WebsiteTest): 318 319 def Login(self): 320 self.GoTo("https://login.yahoo.com") 321 self.FillUsernameInto("#username") 322 self.FillPasswordInto("#passwd") 323 self.Submit("#passwd") 324 325 def Logout(self): 326 self.WaitUntilDisplayed(".tab.tab-user>.mod.view_default") 327 self.HoverOver(".tab.tab-user>.mod.view_default") 328 self.WaitUntilDisplayed("[data-pos='4'] .lbl.y-link-1") 329 self.Click("[data-pos='4'] .lbl.y-link-1") 330 331 332 def Tests(environment): 333 334 335 # Working tests. 336 337 338 environment.AddWebsiteTest(Facebook("facebook")) 339 340 environment.AddWebsiteTest(Google("google")) 341 342 environment.AddWebsiteTest(Linkedin("linkedin")) 343 344 environment.AddWebsiteTest(Mailru("mailru")) 345 346 environment.AddWebsiteTest(Nytimes("nytimes")) 347 348 environment.AddWebsiteTest(Pinterest("pinterest")) 349 350 environment.AddWebsiteTest(Reddit("reddit", username_not_auto=True)) 351 352 environment.AddWebsiteTest(Tumblr("tumblr", username_not_auto=True)) 353 354 environment.AddWebsiteTest(Wikipedia("wikipedia", username_not_auto=True)) 355 356 environment.AddWebsiteTest(Yandex("yandex")) 357 358 359 # Disabled tests. 360 361 362 # Bug not reproducible without test. 363 environment.AddWebsiteTest(Amazon("amazon"), disabled=True) 364 365 # Password not saved. 366 environment.AddWebsiteTest(Ask("ask"), disabled=True) 367 368 # Password not saved. 369 environment.AddWebsiteTest(Baidu("baidu"), disabled=True) 370 371 # http://crbug.com/368690 372 environment.AddWebsiteTest(Cnn("cnn"), disabled=True) 373 374 # http://crbug.com/368690 375 environment.AddWebsiteTest(Ebay("ebay"), disabled=True) 376 377 # Iframe, password saved but not autofileld. 378 environment.AddWebsiteTest(Espn("espn"), disabled=True) 379 380 # http://crbug.com/367768 381 environment.AddWebsiteTest(Live("live", username_not_auto=True), 382 disabled=True) 383 384 # http://crbug.com/368690 385 environment.AddWebsiteTest(One63("163"), disabled=True) 386 387 # http://crbug.com/368690 388 environment.AddWebsiteTest(Vube("vube"), disabled=True) 389 390 # Tests that can cause a crash (the cause of the crash is not related to the 391 # password manager). 392 environment.AddWebsiteTest(Yahoo("yahoo", username_not_auto=True), 393 disabled=True) 394 395 396 def RunTests(chrome_path, chromedriver_path, profile_path, 397 environment_passwords_path, enable_automatic_password_saving, 398 environment_numeric_level, log_to_console, environment_log_file, 399 all_tests, tests): 400 401 """Runs the the tests 402 403 Args: 404 chrome_path: The chrome binary file. 405 chromedriver_path: The chromedriver binary file. 406 profile_path: The chrome testing profile folder. 407 environment_passwords_path: The usernames and passwords file. 408 enable_automatic_password_saving: If True, the passwords are going to be 409 saved without showing the prompt. 410 environment_numeric_level: The log verbosity. 411 log_to_console: If True, the debug logs will be shown on the console. 412 environment_log_file: The file where to store the log. If it's empty, the 413 log is not stored. 414 all_tests: If True, all the tests are going to be ran. 415 tests: A list of the names of the WebsiteTests that are going to be tested. 416 417 Raises: 418 Exception: An exception is raised if the one of the tests fails. 419 """ 420 421 environment = Environment(chrome_path, chromedriver_path, profile_path, 422 environment_passwords_path, 423 enable_automatic_password_saving, 424 environment_numeric_level, 425 log_to_console, 426 environment_log_file) 427 428 # Test which care about the save-password prompt need the prompt 429 # to be shown. Automatic password saving results in no prompt. 430 run_prompt_tests = not enable_automatic_password_saving 431 432 Tests(environment) 433 434 if all_tests: 435 environment.AllTests(run_prompt_tests) 436 elif tests: 437 environment.Test(tests, run_prompt_tests) 438 else: 439 environment.WorkingTests(run_prompt_tests) 440 441 environment.Quit() 442 443 444 # Tests setup. 445 if __name__ == "__main__": 446 parser = argparse.ArgumentParser( 447 description="Password Manager automated tests help.") 448 449 parser.add_argument( 450 "--chrome-path", action="store", dest="chrome_path", 451 help="Set the chrome path (required).", nargs=1, required=True) 452 parser.add_argument( 453 "--chromedriver-path", action="store", dest="chromedriver_path", 454 help="Set the chromedriver path (required).", nargs=1, required=True) 455 parser.add_argument( 456 "--profile-path", action="store", dest="profile_path", 457 help="Set the profile path (required). You just need to choose a " 458 "temporary empty folder. If the folder is not empty all its content " 459 "is going to be removed.", 460 nargs=1, required=True) 461 462 parser.add_argument( 463 "--passwords-path", action="store", dest="passwords_path", 464 help="Set the usernames/passwords path (required).", nargs=1, 465 required=True) 466 parser.add_argument("--all", action="store_true", dest="all", 467 help="Run all tests.") 468 parser.add_argument("--log", action="store", nargs=1, dest="log_level", 469 help="Set log level.") 470 471 parser.add_argument("--log-screen", action="store_true", dest="log_screen", 472 help="Show log on the screen.") 473 parser.add_argument("--log-file", action="store", dest="log_file", 474 help="Write the log in a file.", nargs=1) 475 parser.add_argument("tests", help="Tests to be run.", nargs="*") 476 477 args = parser.parse_args() 478 479 passwords_path = args.passwords_path[0] 480 481 numeric_level = None 482 if args.log_level: 483 numeric_level = getattr(logging, args.log_level[0].upper(), None) 484 if not isinstance(numeric_level, int): 485 raise ValueError("Invalid log level: %s" % args.log_level[0]) 486 487 log_file = None 488 if args.log_file: 489 log_file = args.log_file[0] 490 491 # Run the test without enable-automatic-password-saving to check whether or 492 # not the prompt is shown in the way we expected. 493 RunTests(args.chrome_path[0], 494 args.chromedriver_path[0], 495 args.profile_path[0], 496 passwords_path, 497 False, 498 numeric_level, 499 args.log_screen, 500 log_file, 501 args.all, 502 args.tests) 503 504 # Run the test with enable-automatic-password-saving to check whether or not 505 # the passwords is stored in the the way we expected. 506 RunTests(args.chrome_path[0], 507 args.chromedriver_path[0], 508 args.profile_path[0], 509 passwords_path, 510 True, 511 numeric_level, 512 args.log_screen, 513 log_file, 514 args.all, 515 args.tests) 516