1cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)# Copyright 2014 The Chromium Authors. All rights reserved.
2cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
3cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)# found in the LICENSE file.
4cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
5cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)"""The testing Environment class."""
6cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
7cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)import logging
8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)import shutil
9116680a4aac90f2aa7413d9095a592090648e557Ben Murdochimport sys
10cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)import time
11116680a4aac90f2aa7413d9095a592090648e557Ben Murdochimport traceback
12116680a4aac90f2aa7413d9095a592090648e557Ben Murdochfrom xml.etree import ElementTree
13116680a4aac90f2aa7413d9095a592090648e557Ben Murdochfrom xml.sax.saxutils import escape
14116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
15116680a4aac90f2aa7413d9095a592090648e557Ben Murdochsys.path.insert(0, '../../../../third_party/webdriver/pylib/')
16cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
17cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)from selenium import webdriver
18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)from selenium.common.exceptions import NoSuchElementException
19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)from selenium.common.exceptions import WebDriverException
20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)from selenium.webdriver.chrome.options import Options
21116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
23cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)# Message strings to look for in chrome://password-manager-internals
24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)MESSAGE_ASK = "Message: Decision: ASK the user"
25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)MESSAGE_SAVE = "Message: Decision: SAVE the password"
26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
28116680a4aac90f2aa7413d9095a592090648e557Ben Murdochclass TestResult:
29116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  """Stores the information related to a test result. """
30116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  def __init__(self, name, test_type, successful, message):
31116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    """Creates a new TestResult.
32116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
33116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    Args:
34116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      name: The tested website name.
35116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      test_type: The test type.
36116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      successful: Whether or not the test was successful.
37116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      message: The error message of the test.
38116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    """
39116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    self.name = name
40116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    self.test_type = test_type
41116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    self.successful = successful
42116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    self.message = message
43116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)class Environment:
46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  """Sets up the testing Environment. """
47cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
48cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  def __init__(self, chrome_path, chromedriver_path, profile_path,
49cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)               passwords_path, enable_automatic_password_saving,
50cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)               numeric_level=None, log_to_console=False, log_file=""):
51cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    """Creates a new testing Environment.
52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    Args:
54cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      chrome_path: The chrome binary file.
55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      chromedriver_path: The chromedriver binary file.
56cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      profile_path: The chrome testing profile folder.
57cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      passwords_path: The usernames and passwords file.
58cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      enable_automatic_password_saving: If True, the passwords are going to be
59cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          saved without showing the prompt.
60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      numeric_level: The log verbosity.
61cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      log_to_console: If True, the debug logs will be shown on the console.
62cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      log_file: The file where to store the log. If it's empty, the log will
63116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          not be stored.
64cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
65cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    Raises:
66cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      Exception: An exception is raised if |profile_path| folder could not be
67cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      removed.
68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    """
69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    # Setting up the login.
70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if numeric_level is not None:
71cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if log_file:
72cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        # Set up logging to file.
73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        logging.basicConfig(level=numeric_level,
74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                            filename=log_file,
75cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                            filemode='w')
76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
77cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        if log_to_console:
78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          console = logging.StreamHandler()
79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          console.setLevel(numeric_level)
80cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          # Add the handler to the root logger.
81cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          logging.getLogger('').addHandler(console)
82cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
83cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      elif log_to_console:
84cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        logging.basicConfig(level=numeric_level)
85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    # Cleaning the chrome testing profile folder.
87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    try:
88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      shutil.rmtree(profile_path)
89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    except Exception, e:
90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      # The tests execution can continue, but this make them less stable.
91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      logging.error("Error: Could not wipe the chrome profile directory (%s). \
92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          This affects the stability of the tests. Continuing to run tests."
93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          % e)
94116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    # If |chrome_path| is not defined, this means that we are in the dashboard
95116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    # website, and we just need to get the list of all websites. In this case,
96116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    # we don't need to initilize the webdriver.
97116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if chrome_path:
98116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      options = Options()
99116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      self.enable_automatic_password_saving = enable_automatic_password_saving
100116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if enable_automatic_password_saving:
101116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        options.add_argument("enable-automatic-password-saving")
102116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      # Chrome path.
103116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      options.binary_location = chrome_path
104116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      # Chrome testing profile path.
105116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      options.add_argument("user-data-dir=%s" % profile_path)
106116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
107116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      # The webdriver. It's possible to choose the port the service is going to
108116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      # run on. If it's left to 0, a free port will be found.
109116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      self.driver = webdriver.Chrome(chromedriver_path, 0, options)
110116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      # The password internals window.
111116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      self.internals_window = self.driver.current_window_handle
112116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if passwords_path:
113116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        # An xml tree filled with logins and passwords.
114116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        self.passwords_tree = ElementTree.parse(passwords_path).getroot()
115116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      else:
116116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        raise Exception("Error: |passwords_path| needs to be provided if"
117116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch            "|chrome_path| is provided, otherwise the tests could not be run")
118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    # Password internals page.
119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    self.internals_page = "chrome://password-manager-internals/"
120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    # The Website window.
121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    self.website_window = None
122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    # The WebsiteTests list.
123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    self.websitetests = []
124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    # The enabled WebsiteTests list.
125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    self.working_tests = []
126116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    # The disabled WebsiteTests list.
127116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    self.disabled_tests = []
128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    # Map messages to the number of their appearance in the log.
129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    self.message_count = dict()
130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    self.message_count[MESSAGE_ASK] = 0
131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    self.message_count[MESSAGE_SAVE] = 0
132cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    # The tests needs two tabs to work. A new tab is opened with the first
133cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    # GoTo. This is why we store here whether or not it's the first time to
134cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    # execute GoTo.
135cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    self.first_go_to = True
136116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    # List of all tests results.
137116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    self.tests_results = []
138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
139cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  def AddWebsiteTest(self, websitetest, disabled=False):
140cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    """Adds a WebsiteTest to the testing Environment.
141cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    Args:
143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      websitetest: The WebsiteTest instance to be added.
144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      disabled: Whether test is disabled.
145cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    """
146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    websitetest.environment = self
147116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if hasattr(self, "driver"):
148116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      websitetest.driver = self.driver
149116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if hasattr(self, "passwords_tree") and self.passwords_tree is not None:
150cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if not websitetest.username:
151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        username_tag = (
152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            self.passwords_tree.find(
153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                ".//*[@name='%s']/username" % websitetest.name))
154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        if username_tag.text:
155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          websitetest.username = username_tag.text
156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if not websitetest.password:
157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        password_tag = (
158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            self.passwords_tree.find(
159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                ".//*[@name='%s']/password" % websitetest.name))
160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        if password_tag.text:
161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          websitetest.password = password_tag.text
162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    self.websitetests.append(websitetest)
163116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if disabled:
164116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      self.disabled_tests.append(websitetest.name)
165116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    else:
166cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      self.working_tests.append(websitetest.name)
167cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
1681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def ClearCache(self, clear_passwords):
1691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    """Clear the browser cookies. If |clear_passwords| is true, clear all the
1701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    saved passwords too.
1711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    Args:
1731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      clear_passwords : Clear all the passwords if the bool value is true.
1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    """
1751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    logging.info("\nClearCache\n")
1766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    self.driver.get("chrome://settings/clearBrowserData")
1776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    self.driver.switch_to_frame("settings")
1781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    script = (
1791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        "if (!document.querySelector('#delete-cookies-checkbox').checked)"
1801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        "  document.querySelector('#delete-cookies-checkbox').click();"
1811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        )
1821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    negation = ""
1831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if clear_passwords:
1841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      negation = "!"
1851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    script += (
1861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        "if (%sdocument.querySelector('#delete-passwords-checkbox').checked)"
1871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        "  document.querySelector('#delete-passwords-checkbox').click();"
1881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        % negation)
1891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    script += "document.querySelector('#clear-browser-data-commit').click();"
1901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self.driver.execute_script(script)
1916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    time.sleep(2)
1926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
193cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  def OpenTabAndGoToInternals(self, url):
194cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    """If there is no |self.website_window|, opens a new tab and navigates to
195cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    |url| in the new tab. Navigates to the passwords internals page in the
196cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    first tab. Raises an exception otherwise.
197cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
198cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    Args:
199cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      url: Url to go to in the new tab.
200cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
201cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    Raises:
202cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      Exception: An exception is raised if |self.website_window| already
203cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          exists.
204cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    """
205cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if self.website_window:
206cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      raise Exception("Error: The window was already opened.")
207cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
208cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    self.driver.get("chrome://newtab")
209cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    # There is no straightforward way to open a new tab with chromedriver.
210cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    # One work-around is to go to a website, insert a link that is going
211cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    # to be opened in a new tab, click on it.
212cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    a = self.driver.execute_script(
213cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        "var a = document.createElement('a');"
214cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        "a.target = '_blank';"
215cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        "a.href = arguments[0];"
216cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        "a.innerHTML = '.';"
217cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        "document.body.appendChild(a);"
218cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        "return a;",
219cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        url)
220cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
221cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    a.click()
222cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    time.sleep(1)
223cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
224cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    self.website_window = self.driver.window_handles[-1]
225cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    self.driver.get(self.internals_page)
226cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    self.driver.switch_to_window(self.website_window)
227cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
228cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  def SwitchToInternals(self):
229cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    """Switches from the Website window to internals tab."""
230cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    self.driver.switch_to_window(self.internals_window)
231cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
232cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  def SwitchFromInternals(self):
233cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    """Switches from internals tab to the Website window."""
234cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    self.driver.switch_to_window(self.website_window)
235cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
236cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  def _DidMessageAppearUntilTimeout(self, log_message, timeout):
237cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    """Checks whether the save password prompt is shown.
238cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
239cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    Args:
240cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      log_message: Log message to look for in the password internals.
241cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      timeout: There is some delay between the login and the password
242cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          internals update. The method checks periodically during the first
243cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          |timeout| seconds if the internals page reports the prompt being
244cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          shown. If the prompt is not reported shown within the first
245cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          |timeout| seconds, it is considered not shown at all.
246cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
247cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    Returns:
248cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      True if the save password prompt is shown.
249cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      False otherwise.
250cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    """
251cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    log = self.driver.find_element_by_css_selector("#log-entries")
252cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    count = log.text.count(log_message)
253cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
254cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if count > self.message_count[log_message]:
255cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      self.message_count[log_message] = count
256cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return True
257cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    elif timeout > 0:
258cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      time.sleep(1)
259cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return self._DidMessageAppearUntilTimeout(log_message, timeout - 1)
260cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    else:
261cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return False
262cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
263cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  def CheckForNewMessage(self, log_message, message_should_show_up,
264cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                         error_message, timeout=3):
265cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    """Detects whether the save password prompt is shown.
266cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
267cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    Args:
268cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      log_message: Log message to look for in the password internals. The
269cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          only valid values are the constants MESSAGE_* defined at the
270cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          beginning of this file.
271cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      message_should_show_up: Whether or not the message is expected to be
272cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          shown.
273cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      error_message: Error message for the exception.
274cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      timeout: There is some delay between the login and the password
275cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          internals update. The method checks periodically during the first
276cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          |timeout| seconds if the internals page reports the prompt being
277cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          shown. If the prompt is not reported shown within the first
278cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          |timeout| seconds, it is considered not shown at all.
279cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
280cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    Raises:
281cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      Exception: An exception is raised in case the result does not match the
282cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          expectation
283cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    """
284cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (self._DidMessageAppearUntilTimeout(log_message, timeout) !=
285cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        message_should_show_up):
286cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      raise Exception(error_message)
287cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
288cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  def AllTests(self, prompt_test):
289cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    """Runs the tests on all the WebsiteTests.
290cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
291cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    Args:
292cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      prompt_test: If True, tests caring about showing the save-password
293cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          prompt are going to be run, otherwise tests which don't care about
294cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          the prompt are going to be run.
295cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
296cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    Raises:
297cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      Exception: An exception is raised if the tests fail.
298cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    """
299cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if prompt_test:
300cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      self.PromptTestList(self.websitetests)
301cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    else:
302cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      self.TestList(self.websitetests)
303cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
304116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  def DisabledTests(self, prompt_test):
305116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    """Runs the tests on all the disabled WebsiteTests.
306116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
307116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    Args:
308116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      prompt_test: If True, tests caring about showing the save-password
309116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          prompt are going to be run, otherwise tests which don't care about
310116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          the prompt are going to be executed.
311116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
312116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    Raises:
313116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      Exception: An exception is raised if the tests fail.
314116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    """
315116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    self.Test(self.disabled_tests, prompt_test)
316116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
317cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  def WorkingTests(self, prompt_test):
318cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    """Runs the tests on all the enabled WebsiteTests.
319cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
320cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    Args:
321cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      prompt_test: If True, tests caring about showing the save-password
322cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          prompt are going to be run, otherwise tests which don't care about
323cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          the prompt are going to be executed.
324cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
325cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    Raises:
326cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      Exception: An exception is raised if the tests fail.
327cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    """
328cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    self.Test(self.working_tests, prompt_test)
329cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
330cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  def Test(self, tests, prompt_test):
331cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    """Runs the tests on websites named in |tests|.
332cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
333cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    Args:
334cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      tests: A list of the names of the WebsiteTests that are going to be
335cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          tested.
336cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      prompt_test: If True, tests caring about showing the save-password
337cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          prompt are going to be run, otherwise tests which don't care about
338cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          the prompt are going to be executed.
339cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
340cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    Raises:
341cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      Exception: An exception is raised if the tests fail.
342cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    """
343cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    websitetests = []
344cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    for websitetest in self.websitetests:
345cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if websitetest.name in tests:
346cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        websitetests.append(websitetest)
347cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
348cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if prompt_test:
349cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      self.PromptTestList(websitetests)
350cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    else:
351cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      self.TestList(websitetests)
352cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
353cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  def TestList(self, websitetests):
354cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    """Runs the tests on the websites in |websitetests|.
355cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
356cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    Args:
357cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      websitetests: A list of WebsiteTests that are going to be tested.
358cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
359cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    Raises:
360cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      Exception: An exception is raised if the tests fail.
361cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    """
3621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self.ClearCache(True)
363cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
364cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    for websitetest in websitetests:
365116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      successful = True
366116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      error = ""
367116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      try:
368116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        websitetest.was_run = True
369116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        websitetest.WrongLoginTest()
370116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        websitetest.SuccessfulLoginTest()
3711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        self.ClearCache(False)
372116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        websitetest.SuccessfulLoginWithAutofilledPasswordTest()
3731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        self.ClearCache(True)
374116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        websitetest.SuccessfulLoginTest()
3751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        self.ClearCache(True)
376116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      except Exception:
377116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        successful = False
378116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        error = traceback.format_exc()
379116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      self.tests_results.append(TestResult(websitetest.name, "normal",
380116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          successful, escape(error)))
381cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
3821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
383cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  def PromptTestList(self, websitetests):
384cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    """Runs the prompt tests on the websites in |websitetests|.
385cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
386cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    Args:
387cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      websitetests: A list of WebsiteTests that are going to be tested.
388cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
389cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    Raises:
390cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      Exception: An exception is raised if the tests fail.
391cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    """
3921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self.ClearCache(True)
393cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
394cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    for websitetest in websitetests:
395116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      successful = True
396116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      error = ""
397116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      try:
398116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        websitetest.was_run = True
399116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        websitetest.PromptTest()
400116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      except Exception:
401116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        successful = False
402116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        error = traceback.format_exc()
403116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      self.tests_results.append(TestResult(websitetest.name, "prompt",
404116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          successful, escape(error)))
405cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
406cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  def Quit(self):
407cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    """Closes the tests."""
408cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    # Close the webdriver.
409cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    self.driver.quit()
410