Home | History | Annotate | Download | only in password_manager
      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