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