summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrchtara@chromium.org <rchtara@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-23 16:07:43 +0000
committerrchtara@chromium.org <rchtara@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-23 16:07:43 +0000
commit2cfc162ce41dc4c92676634946b51ce04e4d8085 (patch)
treed27edda7fb1d184d6ac2dec4828967a926a906ae
parent057aac0ac4eaf7352846b3d2f88b4e913d8901c8 (diff)
downloadchromium_src-2cfc162ce41dc4c92676634946b51ce04e4d8085.zip
chromium_src-2cfc162ce41dc4c92676634946b51ce04e4d8085.tar.gz
chromium_src-2cfc162ce41dc4c92676634946b51ce04e4d8085.tar.bz2
Password Manager testing automation
Adding automatic tests to the password manager to simulate user interaction with websites. BUG=369521 Review URL: https://codereview.chromium.org/273523004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@272545 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--components/test/data/password_manager/README177
-rw-r--r--components/test/data/password_manager/environment.py328
-rw-r--r--components/test/data/password_manager/tests.py515
-rw-r--r--components/test/data/password_manager/websitetest.py406
4 files changed, 1426 insertions, 0 deletions
diff --git a/components/test/data/password_manager/README b/components/test/data/password_manager/README
new file mode 100644
index 0000000..3bc561c
--- /dev/null
+++ b/components/test/data/password_manager/README
@@ -0,0 +1,177 @@
+This file contains high-level info about how to use password manager tests and
+how to create new ones.
+
+The password manager tests purpose is to allow automatic password manager
+checking and avoiding to do so manually.
+The tests are written in python using selenium Webdriver library.
+
+
+=====Getting started=====
+
+Build ChromeDriver by building the 'chromedriver' target. This will
+create an executable binary in the build folder named 'chromedriver[.exe]'.
+
+Build chrome too by building the 'chrome' target. This will
+create an executable binary in the build folder named 'chrome[.exe]'.
+
+Install Selenium (the version tested was 2.41.0):
+pip install -U selenium
+
+
+For security reasons, we didn't publish the passwords and the usernames we
+used to test. So we put them to an xml file (websites.xml). The structure of
+the file is the following:
+<websites>
+ <website name = "website name">
+ <username>username</username>
+ <password>password</password>
+ </website>
+<websites>
+You can ask someone to give you the websites.xml file and put it in the same
+folder as the tests. You can also create your own websites.xml with your
+personal accounts.
+WARNING: All the content of the PROFILEPATH is going to be deleted.
+Show the help:
+python tests.py --help
+Run all the working tests tests by executing:
+python tests.py --chrome-path CHROMEPATH --chromedriver-path CHROMEDRIVERPATH
+--profile-path PROFILEPATH [--passwords_path PASSWORDSPATH]
+
+Run all the tests by executing:
+python tests.py --all --chrome-path CHROMEPATH --chromedriver-path
+CHROMEDRIVERPATH --profile-path PROFILEPATH [--passwords_path PASSWORDSPATH]
+
+Run one or many tests by executing:
+python tests.py google --chrome-path CHROMEPATH --chromedriver-path
+CHROMEDRIVERPATH profile-path PROFILEPATH [--passwords_path PASSWORDSPATH]
+
+python tests.py google facebook --chrome-path CHROMEPATH --chromedriver-path
+CHROMEDRIVERPATH --profile-path PROFILEPATH [--passwords_path PASSWORDSPATH]
+
+python tests.py google facebook amazon --chrome-path CHROMEPATH
+--chromedriver-path CHROMEDRIVERPATH --profile-path PROFILEPATH
+[--passwords_path PASSWORDSPATH]
+
+To display the debugging messages on the screen, use:
+python tests.py --log DEBUG|INFO|WARNING|ERROR|CRITICAL --log-screen
+To save debugging messages into a file, use:
+python tests.py --log DEBUG|INFO|WARNING|ERROR|CRITICAL --log-file LOG_FILE
+
+
+=====Creating new test=====
+
+1) Open tests.py.
+
+2) Add tests like this:
+
+class NewWebsiteTest(WebsiteTest):
+
+ def Login(self):
+ # Add login steps for the website, for example:
+ self.GoTo("http://url")
+ self.FillUsernameInto("Username CSS selector")
+ self.FillPasswordInto("Password CSS selector")
+ self.Submit("Password CSS selector")
+
+ def Logout(self):
+ # Add logout steps for the website, for example:
+ self.Click("Logout button CSS selector")
+
+Then, to create the new test, you need just to add:
+
+environment.AddWebsiteTest(NewWebsiteTest("website name"))
+
+* For security reasons, passwords and usernames need to be supplied in a
+separate XML file and never checked in to the repository. The XML file should
+contain data structured like this:
+
+<website name = "website name">
+ <username>username</username>
+ <password>password</password>
+</website>
+
+The "website name" is only used to find the username and password in the xml
+file.
+
+
+Use the flowing methods to perform the login and logout:
+The methods that you can use are:
+
+* Click: find an element using CSS Selector and click on it. Throw an
+exception if the element is not visible.
+self.Click("css_selector")
+* ClickIfClickable: find an element using CSS Selector and click on it if it's
+possible to do that.
+self.ClickIfClickable("css_selector")
+* GoTo: navigate the main frame to a url.
+self.GoTo("url")
+* HoverOver: find an element using CSS Selector and hover over it.
+self.HoverOver("css_selector")
+* SendEnterTo: find an element using CSS Selector and send enter to it.
+self.SendEnterTo("css_selector")
+
+* IsDisplayed: check if an element is displayed.
+self.IsDisplayed("css_selector")
+* Wait: wait for some amount of time in seconds.
+self.Wait(10)
+* WaitUntilDisplayed: wait for an element defined using CSS Selector to be
+displayed.
+self.WaitUntilDisplayed("css_selector")
+
+* FillPasswordInto: find an input element using CSS Selector and fill it with
+the password.
+self.FillPasswordInto("css_selector")
+* FillUsernameInto: find an input element using CSS Selector and fill it with
+the username.
+self.FillUsernameInto("css_selector")
+* Submit: find an element using CSS Selector and call its submit() handler.
+self.Submit("css_selector")
+
+
+=====Files structure=====
+
+Classes:
+* environment.py: the definition the tests Environment.
+* websitetest.py: WebsiteTest is defined here. You need to create an instance
+of this class for each website you want to test.
+
+Tests:
+* tests.py: the tests setup and the configuration for each website happens
+here. This file contain 3 separate kinds of tests:
+
+1) working tests: tests that are supposed to work. If you have a problem with
+one of them, rerun it again. Or try using the Known Issues section to fix it.
+2) tests that can cause a crash (the cause of the crash is not related to the
+password manager): This means that this set is expected to become a working
+test or failing test when the issue that causes the crash now is solved.
+3) failing tests: tests that fail for known bug related to the password
+manager. When this bug is solved, all the tests that were failing because of
+it are going to be moved to working tests.
+
+Other files:
+* websites.xml : a private file where you can find all the passwords. You can
+ask someone to give it to you or just create your own with your personal
+accounts.
+<websites>
+ <website name = "website name">
+ <username>username</username>
+ <password>password</password>
+ </website>
+</websites>
+
+
+=====Known Issues=====
+
+The tests are very fragile. Here are some suggestions for solving most of the
+problems:
+* Restart the tests.
+* Remove the profile if the tests fail at the beginning for unknown reason.
+* If tests fail, isolate the one that causes problem, read debugging messages
+and keep your eyes on the browser window to understand its causes:
+a) In the tests, we often need to wait for a menu to appear ... If the
+menu takes more time to appear than expected, the tests are going to fail.
+b) The websites change very often. And even if they are not changed, they some
+time show a popup that broke the tests. In the case you need to login manually
+to the website, close all popup and logout.
+* If you are logged in when the tests crashes, don't forget to log out before
+running the tests a second time.
diff --git a/components/test/data/password_manager/environment.py b/components/test/data/password_manager/environment.py
new file mode 100644
index 0000000..c0303de
--- /dev/null
+++ b/components/test/data/password_manager/environment.py
@@ -0,0 +1,328 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""The testing Environment class."""
+
+import logging
+import shutil
+import time
+
+from selenium import webdriver
+from selenium.common.exceptions import NoSuchElementException
+from selenium.common.exceptions import WebDriverException
+from selenium.webdriver.chrome.options import Options
+from xml.etree import ElementTree
+
+# Message strings to look for in chrome://password-manager-internals
+MESSAGE_ASK = "Message: Decision: ASK the user"
+MESSAGE_SAVE = "Message: Decision: SAVE the password"
+
+
+class Environment:
+ """Sets up the testing Environment. """
+
+ def __init__(self, chrome_path, chromedriver_path, profile_path,
+ passwords_path, enable_automatic_password_saving,
+ numeric_level=None, log_to_console=False, log_file=""):
+ """Creates a new testing Environment.
+
+ Args:
+ chrome_path: The chrome binary file.
+ chromedriver_path: The chromedriver binary file.
+ profile_path: The chrome testing profile folder.
+ passwords_path: The usernames and passwords file.
+ enable_automatic_password_saving: If True, the passwords are going to be
+ saved without showing the prompt.
+ numeric_level: The log verbosity.
+ log_to_console: If True, the debug logs will be shown on the console.
+ log_file: The file where to store the log. If it's empty, the log will
+ not be stored.
+
+ Raises:
+ Exception: An exception is raised if |profile_path| folder could not be
+ removed.
+ """
+ # Setting up the login.
+ if numeric_level is not None:
+ if log_file:
+ # Set up logging to file.
+ logging.basicConfig(level=numeric_level,
+ filename=log_file,
+ filemode='w')
+
+ if log_to_console:
+ console = logging.StreamHandler()
+ console.setLevel(numeric_level)
+ # Add the handler to the root logger.
+ logging.getLogger('').addHandler(console)
+
+ elif log_to_console:
+ logging.basicConfig(level=numeric_level)
+
+ # Cleaning the chrome testing profile folder.
+ try:
+ shutil.rmtree(profile_path)
+ except Exception, e:
+ # The tests execution can continue, but this make them less stable.
+ logging.error("Error: Could not wipe the chrome profile directory (%s). \
+ This affects the stability of the tests. Continuing to run tests."
+ % e)
+ options = Options()
+ if enable_automatic_password_saving:
+ options.add_argument("enable-automatic-password-saving")
+ # Chrome path.
+ options.binary_location = chrome_path
+ # Chrome testing profile path.
+ options.add_argument("user-data-dir=%s" % profile_path)
+
+ # The webdriver. It's possible to choose the port the service is going to
+ # run on. If it's left to 0, a free port will be found.
+ self.driver = webdriver.Chrome(chromedriver_path, 0, options)
+ # The password internals window.
+ self.internals_window = self.driver.current_window_handle
+ # Password internals page.
+ self.internals_page = "chrome://password-manager-internals/"
+ # The Website window.
+ self.website_window = None
+ # The WebsiteTests list.
+ self.websitetests = []
+ # An xml tree filled with logins and passwords.
+ self.passwords_tree = ElementTree.parse(passwords_path).getroot()
+ # The enabled WebsiteTests list.
+ self.working_tests = []
+ # Map messages to the number of their appearance in the log.
+ self.message_count = dict()
+ self.message_count[MESSAGE_ASK] = 0
+ self.message_count[MESSAGE_SAVE] = 0
+ # The tests needs two tabs to work. A new tab is opened with the first
+ # GoTo. This is why we store here whether or not it's the first time to
+ # execute GoTo.
+ self.first_go_to = True
+
+ def AddWebsiteTest(self, websitetest, disabled=False):
+ """Adds a WebsiteTest to the testing Environment.
+
+ Args:
+ websitetest: The WebsiteTest instance to be added.
+ disabled: Whether test is disabled.
+ """
+ websitetest.environment = self
+ websitetest.driver = self.driver
+ if self.passwords_tree is not None:
+ if not websitetest.username:
+ username_tag = (
+ self.passwords_tree.find(
+ ".//*[@name='%s']/username" % websitetest.name))
+ if username_tag.text:
+ websitetest.username = username_tag.text
+ if not websitetest.password:
+ password_tag = (
+ self.passwords_tree.find(
+ ".//*[@name='%s']/password" % websitetest.name))
+ if password_tag.text:
+ websitetest.password = password_tag.text
+ self.websitetests.append(websitetest)
+ if not disabled:
+ self.working_tests.append(websitetest.name)
+
+ def RemoveAllPasswords(self):
+ """Removes all the stored passwords."""
+ logging.info("\nRemoveAllPasswords\n")
+ self.driver.get("chrome://settings/passwords")
+ self.driver.switch_to_frame("settings")
+ while True:
+ try:
+ self.driver.execute_script("document.querySelector('"
+ "#saved-passwords-list .row-delete-button').click()")
+ time.sleep(1)
+ except NoSuchElementException:
+ break
+ except WebDriverException:
+ break
+
+ def OpenTabAndGoToInternals(self, url):
+ """If there is no |self.website_window|, opens a new tab and navigates to
+ |url| in the new tab. Navigates to the passwords internals page in the
+ first tab. Raises an exception otherwise.
+
+ Args:
+ url: Url to go to in the new tab.
+
+ Raises:
+ Exception: An exception is raised if |self.website_window| already
+ exists.
+ """
+ if self.website_window:
+ raise Exception("Error: The window was already opened.")
+
+ self.driver.get("chrome://newtab")
+ # There is no straightforward way to open a new tab with chromedriver.
+ # One work-around is to go to a website, insert a link that is going
+ # to be opened in a new tab, click on it.
+ a = self.driver.execute_script(
+ "var a = document.createElement('a');"
+ "a.target = '_blank';"
+ "a.href = arguments[0];"
+ "a.innerHTML = '.';"
+ "document.body.appendChild(a);"
+ "return a;",
+ url)
+
+ a.click()
+ time.sleep(1)
+
+ self.website_window = self.driver.window_handles[-1]
+ self.driver.get(self.internals_page)
+ self.driver.switch_to_window(self.website_window)
+
+ def SwitchToInternals(self):
+ """Switches from the Website window to internals tab."""
+ self.driver.switch_to_window(self.internals_window)
+
+ def SwitchFromInternals(self):
+ """Switches from internals tab to the Website window."""
+ self.driver.switch_to_window(self.website_window)
+
+ def _DidMessageAppearUntilTimeout(self, log_message, timeout):
+ """Checks whether the save password prompt is shown.
+
+ Args:
+ log_message: Log message to look for in the password internals.
+ timeout: There is some delay between the login and the password
+ internals update. The method checks periodically during the first
+ |timeout| seconds if the internals page reports the prompt being
+ shown. If the prompt is not reported shown within the first
+ |timeout| seconds, it is considered not shown at all.
+
+ Returns:
+ True if the save password prompt is shown.
+ False otherwise.
+ """
+ log = self.driver.find_element_by_css_selector("#log-entries")
+ count = log.text.count(log_message)
+
+ if count > self.message_count[log_message]:
+ self.message_count[log_message] = count
+ return True
+ elif timeout > 0:
+ time.sleep(1)
+ return self._DidMessageAppearUntilTimeout(log_message, timeout - 1)
+ else:
+ return False
+
+ def CheckForNewMessage(self, log_message, message_should_show_up,
+ error_message, timeout=3):
+ """Detects whether the save password prompt is shown.
+
+ Args:
+ log_message: Log message to look for in the password internals. The
+ only valid values are the constants MESSAGE_* defined at the
+ beginning of this file.
+ message_should_show_up: Whether or not the message is expected to be
+ shown.
+ error_message: Error message for the exception.
+ timeout: There is some delay between the login and the password
+ internals update. The method checks periodically during the first
+ |timeout| seconds if the internals page reports the prompt being
+ shown. If the prompt is not reported shown within the first
+ |timeout| seconds, it is considered not shown at all.
+
+ Raises:
+ Exception: An exception is raised in case the result does not match the
+ expectation
+ """
+ if (self._DidMessageAppearUntilTimeout(log_message, timeout) !=
+ message_should_show_up):
+ raise Exception(error_message)
+
+ def AllTests(self, prompt_test):
+ """Runs the tests on all the WebsiteTests.
+
+ Args:
+ prompt_test: If True, tests caring about showing the save-password
+ prompt are going to be run, otherwise tests which don't care about
+ the prompt are going to be run.
+
+ Raises:
+ Exception: An exception is raised if the tests fail.
+ """
+ if prompt_test:
+ self.PromptTestList(self.websitetests)
+ else:
+ self.TestList(self.websitetests)
+
+ def WorkingTests(self, prompt_test):
+ """Runs the tests on all the enabled WebsiteTests.
+
+ Args:
+ prompt_test: If True, tests caring about showing the save-password
+ prompt are going to be run, otherwise tests which don't care about
+ the prompt are going to be executed.
+
+ Raises:
+ Exception: An exception is raised if the tests fail.
+ """
+ self.Test(self.working_tests, prompt_test)
+
+ def Test(self, tests, prompt_test):
+ """Runs the tests on websites named in |tests|.
+
+ Args:
+ tests: A list of the names of the WebsiteTests that are going to be
+ tested.
+ prompt_test: If True, tests caring about showing the save-password
+ prompt are going to be run, otherwise tests which don't care about
+ the prompt are going to be executed.
+
+ Raises:
+ Exception: An exception is raised if the tests fail.
+ """
+ websitetests = []
+ for websitetest in self.websitetests:
+ if websitetest.name in tests:
+ websitetests.append(websitetest)
+
+ if prompt_test:
+ self.PromptTestList(websitetests)
+ else:
+ self.TestList(websitetests)
+
+ def TestList(self, websitetests):
+ """Runs the tests on the websites in |websitetests|.
+
+ Args:
+ websitetests: A list of WebsiteTests that are going to be tested.
+
+ Raises:
+ Exception: An exception is raised if the tests fail.
+ """
+ self.RemoveAllPasswords()
+
+ for websitetest in websitetests:
+ websitetest.WrongLoginTest()
+ websitetest.SuccessfulLoginTest()
+ websitetest.SuccessfulLoginWithAutofilledPasswordTest()
+
+ self.RemoveAllPasswords()
+ for websitetest in websitetests:
+ websitetest.SuccessfulLoginTest()
+
+ def PromptTestList(self, websitetests):
+ """Runs the prompt tests on the websites in |websitetests|.
+
+ Args:
+ websitetests: A list of WebsiteTests that are going to be tested.
+
+ Raises:
+ Exception: An exception is raised if the tests fail.
+ """
+ self.RemoveAllPasswords()
+
+ for websitetest in websitetests:
+ websitetest.PromptTest()
+
+ def Quit(self):
+ """Closes the tests."""
+ # Close the webdriver.
+ self.driver.quit()
diff --git a/components/test/data/password_manager/tests.py b/components/test/data/password_manager/tests.py
new file mode 100644
index 0000000..af9f44e
--- /dev/null
+++ b/components/test/data/password_manager/tests.py
@@ -0,0 +1,515 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# -*- coding: utf-8 -*-
+"""Automated tests for many websites"""
+
+import argparse
+import logging
+
+from environment import Environment
+from websitetest import WebsiteTest
+
+
+class Facebook(WebsiteTest):
+
+ def Login(self):
+ self.GoTo("https://www.facebook.com")
+ self.FillUsernameInto("[name='email']")
+ self.FillPasswordInto("[name='pass']")
+ self.Submit("[name='pass']")
+
+ def Logout(self):
+ self.WaitUntilDisplayed("#userNavigationLabel")
+ self.Click("#userNavigationLabel")
+ self.WaitUntilDisplayed("#logout_form [type='submit']")
+ self.Click("#logout_form [type='submit']")
+
+
+class Google(WebsiteTest):
+
+ def Login(self):
+ self.GoTo("https://accounts.google.com/ServiceLogin?sacu=1&continue=")
+ self.FillUsernameInto("#Email")
+ self.FillPasswordInto("#Passwd")
+ self.Submit("#Passwd")
+
+ def Logout(self):
+ self.GoTo("https://accounts.google.com/Logout")
+
+
+class Linkedin(WebsiteTest):
+
+ def Login(self):
+ self.GoTo("https://www.linkedin.com")
+ self.FillUsernameInto("#session_key-login")
+ self.FillPasswordInto("#session_password-login")
+ self.Submit("#session_password-login")
+
+ def Logout(self):
+ self.WaitUntilDisplayed(".account-toggle")
+ self.HoverOver(".account-toggle")
+ self.WaitUntilDisplayed(".account-settings .act-set-action")
+ self.Click(".account-settings .act-set-action")
+
+
+class Mailru(WebsiteTest):
+
+ def Login(self):
+ self.GoTo("https://mail.ru")
+ self.FillUsernameInto("#mailbox__login")
+ self.FillPasswordInto("#mailbox__password")
+ self.Submit("#mailbox__password")
+
+ def Logout(self):
+ self.Click("#PH_logoutLink")
+
+
+class Nytimes(WebsiteTest):
+
+ def Login(self):
+ self.GoTo("https://myaccount.nytimes.com/auth/login")
+ self.FillUsernameInto("#userid")
+ self.FillPasswordInto("#password")
+ self.Submit("#password")
+
+ def Logout(self):
+ self.GoTo("https://myaccount.nytimes.com/gst/signout")
+
+
+class Pinterest(WebsiteTest):
+
+ def Login(self):
+ self.GoTo("https://www.pinterest.com/login/")
+ self.FillUsernameInto("[name='username_or_email']")
+ self.FillPasswordInto("[name='password']")
+ self.Submit("[name='password']")
+
+ def Logout(self):
+ self.GoTo("https://www.pinterest.com/logout/")
+
+
+class Reddit(WebsiteTest):
+
+ def Login(self):
+ self.GoTo("http://www.reddit.com")
+ self.Click(".user .login-required")
+ self.FillUsernameInto("#user_login")
+ self.FillPasswordInto("#passwd_login")
+ self.Wait(2)
+ self.Submit("#passwd_login")
+
+ def Logout(self):
+ self.Click("form[action='http://www.reddit.com/logout'] a")
+
+
+class Tumblr(WebsiteTest):
+
+ def Login(self):
+ self.GoTo("https://www.tumblr.com/login")
+ self.FillUsernameInto("#signup_email")
+ self.FillPasswordInto("#signup_password")
+ self.Submit("#signup_password")
+
+ def Logout(self):
+ self.GoTo("https://www.tumblr.com/logout")
+
+
+class Wikipedia(WebsiteTest):
+
+ def Login(self):
+ self.GoTo("https://en.wikipedia.org/w/index.php?title=Special:UserLogin")
+ self.FillUsernameInto("#wpName1")
+ self.FillPasswordInto("#wpPassword1")
+ self.Submit("#wpPassword1")
+
+ def Logout(self):
+ self.GoTo("https://en.wikipedia.org/w/index.php?title=Special:UserLogout")
+
+
+class Yandex(WebsiteTest):
+
+ def Login(self):
+ self.GoTo("https://mail.yandex.com")
+ self.FillUsernameInto("#b-mail-domik-username11")
+ self.FillPasswordInto("#b-mail-domik-password11")
+ self.Click(".b-mail-button__button")
+
+ def Logout(self):
+ while not self.IsDisplayed(".b-mail-dropdown__item__content"
+ u".Выход.daria-action"):
+ self.ClickIfClickable(".header-user-pic.b-mail-dropdown__handle")
+ self.Wait(1)
+ self.Click(u".b-mail-dropdown__item__content.Выход.daria-action")
+
+
+# Disabled tests.
+
+
+# Bug not reproducible without test.
+class Amazon(WebsiteTest):
+
+ def Login(self):
+ self.GoTo(
+ "https://www.amazon.com/ap/signin?openid.assoc_handle=usflex"
+ "&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net"
+ "%2Fauth%2F2.0")
+ self.FillUsernameInto("[name='email']")
+ self.FillPasswordInto("[name='password']")
+ self.Submit("[name='password']")
+
+ def Logout(self):
+ while not self.IsDisplayed("#nav-item-signout"):
+ self.Wait(1)
+ self.HoverOver("#nav-signin-title")
+ self.Click("#nav-item-signout")
+
+
+# Password not saved.
+class Ask(WebsiteTest):
+
+ def Login(self):
+ self.GoTo("http://www.ask.com/answers/browse?qsrc=321&q=&o=0&l=dir#")
+ while not self.IsDisplayed("[name='username']"):
+ self.Click("#a16CnbSignInText")
+ self.Wait(1)
+ self.FillUsernameInto("[name='username']")
+ self.FillPasswordInto("[name='password']")
+ self.Click(".signin_show.signin_submit")
+
+ def Logout(self):
+ self.WaitUntilDisplayed("#a16CnbSignInText")
+ self.Click("#a16CnbSignInText")
+
+
+# Password not saved.
+class Baidu(WebsiteTest):
+
+ def Login(self):
+ self.GoTo("http://www.baidu.com/")
+ self.Click("[name='tj_login']")
+ self.WaitUntilDisplayed("[name='userName']")
+ self.FillUsernameInto("[name='userName']")
+ self.FillPasswordInto("[name='password']")
+ self.Submit("[name='password']")
+
+ def Logout(self):
+ self.Wait(1)
+ self.GoTo("https://passport.baidu.com/?logout&u=http://www.baidu.com")
+
+
+# http://crbug.com/368690
+class Cnn(WebsiteTest):
+
+ def Login(self):
+ self.GoTo("http://www.cnn.com")
+ self.Wait(5)
+ while not self.IsDisplayed(".cnnOvrlyBtn.cnnBtnLogIn"):
+ self.ClickIfClickable("#hdr-auth .no-border.no-pad-right a")
+ self.Wait(1)
+
+ self.Click(".cnnOvrlyBtn.cnnBtnLogIn")
+ self.FillUsernameInto("#cnnOverlayEmail1l")
+ self.FillPasswordInto("#cnnOverlayPwd")
+ self.Click(".cnnOvrlyBtn.cnnBtnLogIn")
+ self.Click(".cnnOvrlyBtn.cnnBtnLogIn")
+ self.Wait(5)
+
+ def Logout(self):
+ self.Wait(4)
+ self.Click("#hdr-auth .no-border.no-pad-right")
+
+
+# http://crbug.com/368690
+class Ebay(WebsiteTest):
+
+ def Login(self):
+ self.GoTo("https://signin.ebay.com/")
+ self.FillUsernameInto("[name='userid']")
+ self.FillPasswordInto("[name='pass']")
+ self.Submit("[name='pass']")
+
+ def Logout(self):
+ self.WaitUntilDisplayed("#gh-ug")
+ self.Click("#gh-ug")
+ self.WaitUntilDisplayed("#gh-uo")
+ self.Click("#gh-uo")
+
+
+# Iframe, password saved but not autofileld.
+class Espn(WebsiteTest):
+
+ def Login(self):
+ self.GoTo("http://espn.go.com/")
+ while not self.IsDisplayed("#cboxLoadedContent iframe"):
+ self.Click("#signin .cbOverlay")
+ self.Wait(1)
+ frame = self.driver.find_element_by_css_selector("#cboxLoadedContent "
+ "iframe")
+ self.driver.switch_to_frame(frame)
+ self.WaitUntilDisplayed("#username")
+ self.FillUsernameInto("#username")
+ self.FillPasswordInto("#password")
+ while self.IsDisplayed("#password"):
+ self.ClickIfClickable("#submitBtn")
+ self.Wait(1)
+
+ def Logout(self):
+ self.WaitUntilDisplayed("#signin .small")
+ self.Click("#signin .small")
+
+
+# http://crbug.com/367768
+class Live(WebsiteTest):
+
+ def Login(self):
+ self.GoTo("https://www.live.com")
+ self.FillUsernameInto("[name='login']")
+ self.FillPasswordInto("[name='passwd']")
+ self.Submit("[name='passwd']")
+
+ def Logout(self):
+ self.WaitUntilDisplayed("#c_meun")
+ self.Click("#c_meun")
+ self.WaitUntilDisplayed("#c_signout")
+ self.Click("#c_signout")
+
+
+# http://crbug.com/368690
+class One63(WebsiteTest):
+
+ def Login(self):
+ self.GoTo("http://www.163.com")
+ self.HoverOver("#js_N_navHighlight")
+ self.WaitUntilDisplayed("#js_loginframe_username")
+ self.FillUsernameInto("#js_loginframe_username")
+ self.FillPasswordInto(".ntes-loginframe-label-ipt[type='password']")
+ self.Click(".ntes-loginframe-btn")
+
+ def Logout(self):
+ self.WaitUntilDisplayed("#js_N_navLogout")
+ self.Click("#js_N_navLogout")
+
+
+# http://crbug.com/368690
+class Vube(WebsiteTest):
+
+ def Login(self):
+ self.GoTo("https://vube.com")
+ self.Click("[vube-login='']")
+ self.WaitUntilDisplayed("[ng-model='login.user']")
+ self.FillUsernameInto("[ng-model='login.user']")
+ self.FillPasswordInto("[ng-model='login.pass']")
+ while (self.IsDisplayed("[ng-model='login.pass']")
+ and not self.IsDisplayed(".prompt.alert")):
+ self.ClickIfClickable("[ng-click='login()']")
+ self.Wait(1)
+
+ def Logout(self):
+ self.WaitUntilDisplayed("[ng-click='user.logout()']")
+ self.Click("[ng-click='user.logout()']")
+
+
+# Tests that can cause a crash.
+
+
+class Yahoo(WebsiteTest):
+
+ def Login(self):
+ self.GoTo("https://login.yahoo.com")
+ self.FillUsernameInto("#username")
+ self.FillPasswordInto("#passwd")
+ self.Submit("#passwd")
+
+ def Logout(self):
+ self.WaitUntilDisplayed(".tab.tab-user>.mod.view_default")
+ self.HoverOver(".tab.tab-user>.mod.view_default")
+ self.WaitUntilDisplayed("[data-pos='4'] .lbl.y-link-1")
+ self.Click("[data-pos='4'] .lbl.y-link-1")
+
+
+def Tests(environment):
+
+
+ # Working tests.
+
+
+ environment.AddWebsiteTest(Facebook("facebook"))
+
+ environment.AddWebsiteTest(Google("google"))
+
+ environment.AddWebsiteTest(Linkedin("linkedin"))
+
+ environment.AddWebsiteTest(Mailru("mailru"))
+
+ environment.AddWebsiteTest(Nytimes("nytimes"))
+
+ environment.AddWebsiteTest(Pinterest("pinterest"))
+
+ environment.AddWebsiteTest(Reddit("reddit", username_not_auto=True))
+
+ environment.AddWebsiteTest(Tumblr("tumblr", username_not_auto=True))
+
+ environment.AddWebsiteTest(Wikipedia("wikipedia", username_not_auto=True))
+
+ environment.AddWebsiteTest(Yandex("yandex"))
+
+
+ # Disabled tests.
+
+
+ # Bug not reproducible without test.
+ environment.AddWebsiteTest(Amazon("amazon"), disabled=True)
+
+ # Password not saved.
+ environment.AddWebsiteTest(Ask("ask"), disabled=True)
+
+ # Password not saved.
+ environment.AddWebsiteTest(Baidu("baidu"), disabled=True)
+
+ # http://crbug.com/368690
+ environment.AddWebsiteTest(Cnn("cnn"), disabled=True)
+
+ # http://crbug.com/368690
+ environment.AddWebsiteTest(Ebay("ebay"), disabled=True)
+
+ # Iframe, password saved but not autofileld.
+ environment.AddWebsiteTest(Espn("espn"), disabled=True)
+
+ # http://crbug.com/367768
+ environment.AddWebsiteTest(Live("live", username_not_auto=True),
+ disabled=True)
+
+ # http://crbug.com/368690
+ environment.AddWebsiteTest(One63("163"), disabled=True)
+
+ # http://crbug.com/368690
+ environment.AddWebsiteTest(Vube("vube"), disabled=True)
+
+ # Tests that can cause a crash (the cause of the crash is not related to the
+ # password manager).
+ environment.AddWebsiteTest(Yahoo("yahoo", username_not_auto=True),
+ disabled=True)
+
+
+def RunTests(chrome_path, chromedriver_path, profile_path,
+ environment_passwords_path, enable_automatic_password_saving,
+ environment_numeric_level, log_to_console, environment_log_file,
+ all_tests, tests):
+
+ """Runs the the tests
+
+ Args:
+ chrome_path: The chrome binary file.
+ chromedriver_path: The chromedriver binary file.
+ profile_path: The chrome testing profile folder.
+ environment_passwords_path: The usernames and passwords file.
+ enable_automatic_password_saving: If True, the passwords are going to be
+ saved without showing the prompt.
+ environment_numeric_level: The log verbosity.
+ log_to_console: If True, the debug logs will be shown on the console.
+ environment_log_file: The file where to store the log. If it's empty, the
+ log is not stored.
+ all_tests: If True, all the tests are going to be ran.
+ tests: A list of the names of the WebsiteTests that are going to be tested.
+
+ Raises:
+ Exception: An exception is raised if the one of the tests fails.
+ """
+
+ environment = Environment(chrome_path, chromedriver_path, profile_path,
+ environment_passwords_path,
+ enable_automatic_password_saving,
+ environment_numeric_level,
+ log_to_console,
+ environment_log_file)
+
+ # Test which care about the save-password prompt need the prompt
+ # to be shown. Automatic password saving results in no prompt.
+ run_prompt_tests = not enable_automatic_password_saving
+
+ Tests(environment)
+
+ if all_tests:
+ environment.AllTests(run_prompt_tests)
+ elif tests:
+ environment.Test(tests, run_prompt_tests)
+ else:
+ environment.WorkingTests(run_prompt_tests)
+
+ environment.Quit()
+
+
+# Tests setup.
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(
+ description="Password Manager automated tests help.")
+
+ parser.add_argument(
+ "--chrome-path", action="store", dest="chrome_path",
+ help="Set the chrome path (required).", nargs=1, required=True)
+ parser.add_argument(
+ "--chromedriver-path", action="store", dest="chromedriver_path",
+ help="Set the chromedriver path (required).", nargs=1, required=True)
+ parser.add_argument(
+ "--profile-path", action="store", dest="profile_path",
+ help="Set the profile path (required). You just need to choose a "
+ "temporary empty folder. If the folder is not empty all its content "
+ "is going to be removed.",
+ nargs=1, required=True)
+
+ parser.add_argument(
+ "--passwords-path", action="store", dest="passwords_path",
+ help="Set the usernames/passwords path (required).", nargs=1,
+ required=True)
+ parser.add_argument("--all", action="store_true", dest="all",
+ help="Run all tests.")
+ parser.add_argument("--log", action="store", nargs=1, dest="log_level",
+ help="Set log level.")
+
+ parser.add_argument("--log-screen", action="store_true", dest="log_screen",
+ help="Show log on the screen.")
+ parser.add_argument("--log-file", action="store", dest="log_file",
+ help="Write the log in a file.", nargs=1)
+ parser.add_argument("tests", help="Tests to be run.", nargs="*")
+
+ args = parser.parse_args()
+
+ passwords_path = args.passwords_path[0]
+
+ numeric_level = None
+ if args.log_level:
+ numeric_level = getattr(logging, args.log_level[0].upper(), None)
+ if not isinstance(numeric_level, int):
+ raise ValueError("Invalid log level: %s" % args.log_level[0])
+
+ log_file = None
+ if args.log_file:
+ log_file = args.log_file[0]
+
+ # Run the test without enable-automatic-password-saving to check whether or
+ # not the prompt is shown in the way we expected.
+ RunTests(args.chrome_path[0],
+ args.chromedriver_path[0],
+ args.profile_path[0],
+ passwords_path,
+ False,
+ numeric_level,
+ args.log_screen,
+ log_file,
+ args.all,
+ args.tests)
+
+ # Run the test with enable-automatic-password-saving to check whether or not
+ # the passwords is stored in the the way we expected.
+ RunTests(args.chrome_path[0],
+ args.chromedriver_path[0],
+ args.profile_path[0],
+ passwords_path,
+ True,
+ numeric_level,
+ args.log_screen,
+ log_file,
+ args.all,
+ args.tests)
diff --git a/components/test/data/password_manager/websitetest.py b/components/test/data/password_manager/websitetest.py
new file mode 100644
index 0000000..a0df593
--- /dev/null
+++ b/components/test/data/password_manager/websitetest.py
@@ -0,0 +1,406 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""WebsiteTest testing class."""
+
+import logging
+import time
+
+from selenium.webdriver.common.action_chains import ActionChains
+from selenium.webdriver.common.keys import Keys
+
+import environment
+
+
+def _IsOneSubstringOfAnother(s1, s2):
+ """Checks if one of the string arguements is substring of the other.
+
+ Args:
+ s1: The first string.
+ s2: The second string.
+ Returns:
+
+ True if one of the string arguements is substring of the other.
+ False otherwise.
+ """
+ return s1 in s2 or s2 in s1
+
+
+class WebsiteTest:
+ """Handles a tested WebsiteTest."""
+
+ class Mode:
+ """Test mode."""
+ # Password and username are expected to be autofilled.
+ AUTOFILLED = 1
+ # Password and username are not expected to be autofilled.
+ NOT_AUTOFILLED = 2
+
+ def __init__(self):
+ pass
+
+ def __init__(self, name, username_not_auto=False):
+ """Creates a new WebsiteTest.
+
+ Args:
+ name: The website name.
+ username_not_auto: Username inputs in some websites (like wikipedia) are
+ sometimes filled with some messages and thus, the usernames are not
+ automatically autofilled. This flag handles that and disables us from
+ checking if the state of the DOM is the same as the username of
+ website.
+ """
+ # Name of the website
+ self.name = name
+ # Username of the website.
+ self.username = None
+ # Password of the website.
+ self.password = None
+ # Username is not automatically filled.
+ self.username_not_auto = username_not_auto
+ # Autofilling mode.
+ self.mode = self.Mode.NOT_AUTOFILLED
+ # The |remaining_time_to_wait| limits the total time in seconds spent in
+ # potentially infinite loops.
+ self.remaining_time_to_wait = 200
+ # The testing Environment.
+ self.environment = None
+ # The webdriver.
+ self.driver = None
+
+ # Mouse/Keyboard actions.
+
+ def Click(self, selector):
+ """Clicks on an element.
+
+ Args:
+ selector: The element CSS selector.
+ """
+ logging.info("action: Click %s" % selector)
+ element = self.driver.find_element_by_css_selector(selector)
+ element.click()
+
+ def ClickIfClickable(self, selector):
+ """Clicks on an element if it's clickable: If it doesn't exist in the DOM,
+ it's covered by another element or it's out viewing area, nothing is
+ done and False is returned. Otherwise, even if the element is 100%
+ transparent, the element is going to receive a click and a True is
+ returned.
+
+ Args:
+ selector: The element CSS selector.
+
+ Returns:
+ True if the click happens.
+ False otherwise.
+ """
+ logging.info("action: ClickIfVisible %s" % selector)
+ try:
+ element = self.driver.find_element_by_css_selector(selector)
+ element.click()
+ return True
+ except Exception:
+ return False
+
+ def GoTo(self, url):
+ """Navigates the main frame to the |url|.
+
+ Args:
+ url: The URL.
+ """
+ logging.info("action: GoTo %s" % self.name)
+ if self.environment.first_go_to:
+ self.environment.OpenTabAndGoToInternals(url)
+ self.environment.first_go_to = False
+ else:
+ self.driver.get(url)
+
+ def HoverOver(self, selector):
+ """Hovers over an element.
+
+ Args:
+ selector: The element CSS selector.
+ """
+ logging.info("action: Hover %s" % selector)
+ element = self.driver.find_element_by_css_selector(selector)
+ hover = ActionChains(self.driver).move_to_element(element)
+ hover.perform()
+
+ def SendEnterTo(self, selector):
+ """Sends an enter key to an element.
+
+ Args:
+ selector: The element CSS selector.
+ """
+ logging.info("action: SendEnterTo %s" % selector)
+ body = self.driver.find_element_by_tag_name("body")
+ body.send_keys(Keys.ENTER)
+
+ # Waiting/Displaying actions.
+
+ def IsDisplayed(self, selector):
+ """Returns False if an element doesn't exist in the DOM or is 100%
+ transparent. Otherwise, returns True even if it's covered by another
+ element or it's out viewing area.
+
+ Args:
+ selector: The element CSS selector.
+ """
+ logging.info("action: IsDisplayed %s" % selector)
+ try:
+ element = self.driver.find_element_by_css_selector(selector)
+ return element.is_displayed()
+ except Exception:
+ return False
+
+ def Wait(self, duration):
+ """Wait for a duration in seconds. This needs to be used in potentially
+ infinite loops, to limit their running time.
+
+ Args:
+ duration: The time to wait in seconds.
+ """
+ logging.info("action: Wait %s" % duration)
+ time.sleep(duration)
+ self.remaining_time_to_wait -= 1
+ if self.remaining_time_to_wait < 0:
+ raise Exception("Tests took more time than expected for the following "
+ "website : %s \n" % self.name)
+
+ def WaitUntilDisplayed(self, selector, timeout=10):
+ """Waits until an element is displayed.
+
+ Args:
+ selector: The element CSS selector.
+ timeout: The maximum waiting time in seconds before failing.
+ """
+ if not self.IsDisplayed(selector):
+ self.Wait(1)
+ timeout = timeout - 1
+ if (timeout <= 0):
+ raise Exception("Error: Element %s not shown before timeout is "
+ "finished for the following website: %s"
+ % (selector, self.name))
+ else:
+ self.WaitUntilDisplayed(selector, timeout)
+
+ # Form actions.
+
+ def FillPasswordInto(self, selector):
+ """If the testing mode is the Autofilled mode, compares the website
+ password to the DOM state.
+ If the testing mode is the NotAutofilled mode, checks that the DOM state
+ is empty.
+ Then, fills the input with the Website password.
+
+ Args:
+ selector: The password input CSS selector.
+
+ Raises:
+ Exception: An exception is raised if the DOM value of the password is
+ different than the one we expected.
+ """
+ logging.info("action: FillPasswordInto %s" % selector)
+
+ password_element = self.driver.find_element_by_css_selector(selector)
+ # Chrome protects the password inputs and doesn't fill them until
+ # the user interacts with the page. To be sure that such thing has
+ # happened we click on the password fields or one of its ancestors.
+ element = password_element
+ while True:
+ try:
+ element.click()
+ break
+ except Exception:
+ try:
+ element = element.parent
+ except AttributeError:
+ raise Exception("Error: unable to find a clickable element to "
+ "release the password protection for the following website: %s \n"
+ % (self.name))
+
+ if self.mode == self.Mode.AUTOFILLED:
+ autofilled_password = password_element.get_attribute("value")
+ if autofilled_password != self.password:
+ raise Exception("Error: autofilled password is different from the one "
+ "we just saved for the following website : %s p1: %s "
+ "p2:%s \n" % (self.name,
+ password_element.get_attribute("value"),
+ self.password))
+
+ elif self.mode == self.Mode.NOT_AUTOFILLED:
+ autofilled_password = password_element.get_attribute("value")
+ if autofilled_password:
+ raise Exception("Error: password is autofilled when it shouldn't be "
+ "for the following website : %s \n"
+ % self.name)
+
+ password_element.send_keys(self.password)
+
+ def FillUsernameInto(self, selector):
+ """If the testing mode is the Autofilled mode, compares the website
+ username to the input value. Then, fills the input with the website
+ username.
+
+ Args:
+ selector: The username input CSS selector.
+
+ Raises:
+ Exception: An exception is raised if the DOM value of the username is
+ different that the one we expected.
+ """
+ logging.info("action: FillUsernameInto %s" % selector)
+ username_element = self.driver.find_element_by_css_selector(selector)
+
+ if (self.mode == self.Mode.AUTOFILLED and not self.username_not_auto):
+ if not (username_element.get_attribute("value") == self.username):
+ raise Exception("Error: autofilled username is different form the one "
+ "we just saved for the following website : %s \n" %
+ self.name)
+ else:
+ username_element.clear()
+ username_element.send_keys(self.username)
+
+ def Submit(self, selector):
+ """Finds an element using CSS Selector and calls its submit() handler.
+
+ Args:
+ selector: The input CSS selector.
+ """
+ logging.info("action: Submit %s" % selector)
+ element = self.driver.find_element_by_css_selector(selector)
+ element.submit()
+
+ # Login/Logout Methods
+
+ def Login(self):
+ """Login Method. Has to be overloaded by the WebsiteTest test."""
+ raise NotImplementedError("Login is not implemented.")
+
+ def LoginWhenAutofilled(self):
+ """Logs in and checks that the password is autofilled."""
+ self.mode = self.Mode.AUTOFILLED
+ self.Login()
+
+ def LoginWhenNotAutofilled(self):
+ """Logs in and checks that the password is not autofilled."""
+ self.mode = self.Mode.NOT_AUTOFILLED
+ self.Login()
+
+ def Logout(self):
+ """Logout Method. Has to be overloaded by the Website test."""
+ raise NotImplementedError("Logout is not implemented.")
+
+ # Tests
+
+ def WrongLoginTest(self):
+ """Does the wrong login test: Tries to login with a wrong password and
+ checks that the password is not saved.
+
+ Raises:
+ Exception: An exception is raised if the test fails: If there is a
+ problem when performing the login (ex: the login button is not
+ available ...), if the state of the username and password fields is
+ not like we expected or if the password is saved.
+ """
+ logging.info("\nWrong Login Test for %s \n" % self.name)
+ correct_password = self.password
+ self.password = self.password + "1"
+ self.LoginWhenNotAutofilled()
+ self.password = correct_password
+ self.Wait(2)
+ self.environment.SwitchToInternals()
+ self.environment.CheckForNewMessage(
+ environment.MESSAGE_SAVE,
+ False,
+ "Error: password manager thinks that a login with wrong password was "
+ "successful for the following website : %s \n" % self.name)
+ self.environment.SwitchFromInternals()
+
+ def SuccessfulLoginTest(self):
+ """Does the successful login when the password is not expected to be
+ autofilled test: Checks that the password is not autofilled, tries to login
+ with a right password and checks if the password is saved. Then logs out.
+
+ Raises:
+ Exception: An exception is raised if the test fails: If there is a
+ problem when performing the login and the logout (ex: the login
+ button is not available ...), if the state of the username and
+ password fields is not like we expected or if the password is not
+ saved.
+ """
+ logging.info("\nSuccessful Login Test for %s \n" % self.name)
+ self.LoginWhenNotAutofilled()
+ self.Wait(2)
+ self.environment.SwitchToInternals()
+ self.environment.CheckForNewMessage(
+ environment.MESSAGE_SAVE,
+ True,
+ "Error: password manager hasn't detected a successful login for the "
+ "following website : %s \n"
+ % self.name)
+ self.environment.SwitchFromInternals()
+ self.Logout()
+
+ def SuccessfulLoginWithAutofilledPasswordTest(self):
+ """Does the successful login when the password is expected to be autofilled
+ test: Checks that the password is autofilled, tries to login with the
+ autofilled password and checks if the password is saved. Then logs out.
+
+ Raises:
+ Exception: An exception is raised if the test fails: If there is a
+ problem when performing the login and the logout (ex: the login
+ button is not available ...), if the state of the username and
+ password fields is not like we expected or if the password is not
+ saved.
+ """
+ logging.info("\nSuccessful Login With Autofilled Password"
+ " Test %s \n" % self.name)
+ self.LoginWhenAutofilled()
+ self.Wait(2)
+ self.environment.SwitchToInternals()
+ self.environment.CheckForNewMessage(
+ environment.MESSAGE_SAVE,
+ True,
+ "Error: password manager hasn't detected a successful login for the "
+ "following website : %s \n"
+ % self.name)
+ self.environment.SwitchFromInternals()
+ self.Logout()
+
+ def PromptTest(self):
+ """Does the prompt test: Tries to login with a wrong password and
+ checks that the prompt is not shown. Then tries to login with a right
+ password and checks that the prompt is not shown.
+
+ Raises:
+ Exception: An exception is raised if the test fails: If there is a
+ problem when performing the login (ex: the login button is not
+ available ...), if the state of the username and password fields is
+ not like we expected or if the prompt is not shown for the right
+ password or is shown for a wrong one.
+ """
+ logging.info("\nPrompt Test for %s \n" % self.name)
+ correct_password = self.password
+ self.password = self.password + "1"
+ self.LoginWhenNotAutofilled()
+ self.password = correct_password
+ self.Wait(2)
+ self.environment.SwitchToInternals()
+ self.environment.CheckForNewMessage(
+ environment.MESSAGE_ASK,
+ False,
+ "Error: password manager thinks that a login with wrong password was "
+ "successful for the following website : %s \n" % self.name)
+ self.environment.SwitchFromInternals()
+
+ self.LoginWhenNotAutofilled()
+ self.Wait(2)
+ self.environment.SwitchToInternals()
+ self.environment.CheckForNewMessage(
+ environment.MESSAGE_ASK,
+ True,
+ "Error: password manager thinks that a login with wrong password was "
+ "successful for the following website : %s \n" % self.name)
+ self.environment.SwitchFromInternals()