Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 """The testing Environment class.""" | |
| 2 | |
| 3 import logging | |
| 4 import shutil | |
| 5 import time | |
| 6 | |
| 7 from selenium import webdriver | |
| 8 from selenium.common.exceptions import NoSuchElementException | |
| 9 from selenium.common.exceptions import WebDriverException | |
| 10 from selenium.webdriver.chrome.options import Options | |
| 11 from xml.etree import ElementTree | |
| 12 | |
| 13 | |
| 14 class Environment: | |
| 15 """Sets up the testing Environment. """ | |
| 16 | |
| 17 def __init__(self, chrome_path, chromedriver_path, profile_path, | |
| 18 passwords_path, enable_automatic_password_saving, | |
| 19 numeric_level, log_screen, log_file): | |
|
vabr (Chromium)
2014/05/20 14:47:25
nit: log_screen -> log_to_console
vabr (Chromium)
2014/05/20 14:47:25
Please provide default values for numeric_level, l
rchtara
2014/05/22 08:44:38
Done.
rchtara
2014/05/22 08:44:38
Done.
| |
| 20 """Creates a new testing Environment. | |
| 21 | |
| 22 Args: | |
| 23 chrome_path: The chrome binary file.y | |
|
vabr (Chromium)
2014/05/20 14:47:25
typo: "y" at the end of the line
rchtara
2014/05/22 08:44:38
Done.
| |
| 24 chromedriver_path: The chromedriver binary file. | |
| 25 profile_path: The testing profile folder. | |
|
vabr (Chromium)
2014/05/20 14:47:25
nit: "profile" -> "Chrome profile", just for clari
rchtara
2014/05/22 08:44:38
Done.
| |
| 26 passwords_path: The usernames and passwords file. | |
| 27 enable_automatic_password_saving: If set, the passwords are going to be | |
| 28 saved without showing the prompt. | |
| 29 numeric_level: The log numeric level. | |
|
vabr (Chromium)
2014/05/20 14:47:25
nit: "log" -> "log verbosity"
rchtara
2014/05/22 08:44:38
Done.
| |
| 30 log_screen: If set, the tests log is going to be shown on the screen. | |
|
vabr (Chromium)
2014/05/20 14:47:25
nit: change "screen" to console also in the commen
vabr (Chromium)
2014/05/20 14:47:25
nit: "tests log is going to be" -> "debug logs wil
vabr (Chromium)
2014/05/20 14:47:25
nit: "set" -> "true"
rchtara
2014/05/22 08:44:38
Done.
rchtara
2014/05/22 08:44:38
Done.
rchtara
2014/05/22 08:44:38
Done.
| |
| 31 log_file: The file where to store the log. | |
|
vabr (Chromium)
2014/05/20 14:47:25
nit: Comment on what happens if it is empty.
rchtara
2014/05/22 08:44:38
Done.
| |
| 32 | |
| 33 Raises: | |
| 34 Exception: An exception is raised if |profile_path| folder could not be | |
| 35 removed. | |
| 36 """ | |
| 37 # Setting up the login. | |
| 38 if numeric_level is not None: | |
| 39 if log_file: | |
| 40 # Set up logging to file. | |
| 41 logging.basicConfig(level=numeric_level, | |
| 42 filename=log_file, | |
| 43 filemode='w') | |
| 44 | |
| 45 if log_screen: | |
| 46 console = logging.StreamHandler() | |
| 47 console.setLevel(numeric_level) | |
| 48 # Add the handler to the root logger. | |
| 49 logging.getLogger('').addHandler(console) | |
| 50 | |
| 51 elif log_screen: | |
| 52 logging.basicConfig(level=numeric_level) | |
| 53 | |
| 54 # Cleaning the profile folder. | |
| 55 try: | |
| 56 shutil.rmtree(profile_path) | |
| 57 except Exception, e: | |
| 58 # The tests execution can continue, but this make them less stable. | |
| 59 logging.error("""Error: %s.\n The tests execution is continuing. But | |
|
vabr (Chromium)
2014/05/20 14:47:25
I don't think you use """ correctly here. If you o
rchtara
2014/05/22 08:44:38
Done.
| |
| 60 the tests are going to be less stable.""" % e) | |
|
vabr (Chromium)
2014/05/20 14:47:25
Please be more specific: write what is the error,
rchtara
2014/05/22 08:44:38
Done.
| |
| 61 options = Options() | |
| 62 if enable_automatic_password_saving: | |
| 63 options.add_argument("enable-automatic-password-saving") | |
| 64 options.add_argument("enable-password-manager-internals-ui") | |
|
vabr (Chromium)
2014/05/20 14:47:25
You probably missed my comment earlier: enable-pas
rchtara
2014/05/22 08:44:38
I didn't update my chromium yet, so I will keep us
| |
| 65 # Chrome path. | |
| 66 options.binary_location = chrome_path | |
| 67 # Testing profile path. | |
| 68 options.add_argument("user-data-dir=%s" % profile_path) | |
| 69 | |
| 70 # The webdriver. It's possible to choose the port the service is going to | |
| 71 # run on. If it's left to 0, a free port will be found. | |
| 72 self.driver = webdriver.Chrome(chromedriver_path, 0, options) | |
| 73 # The password internals window. | |
| 74 self.internals_window = self.driver.current_window_handle | |
| 75 # Password internals page. | |
| 76 self.internals_page = "chrome://password-manager-internals/" | |
| 77 # The Website window. | |
| 78 self.website_window = None | |
| 79 # The WebsiteTests list. | |
| 80 self.websitetests = [] | |
| 81 # An xml tree filled with logins and passwords. | |
| 82 self.passwords_tree = None | |
| 83 if passwords_path: | |
| 84 self.passwords_tree = ElementTree.parse(passwords_path).getroot() | |
| 85 # The enabled WebsiteTests list. | |
| 86 self.working_tests = [] | |
| 87 # The number of the save operations done through all the tests. | |
| 88 self.save_count = 0 | |
|
vabr (Chromium)
2014/05/20 14:47:25
Note: I see you use this to deal with the internal
rchtara
2014/05/22 08:44:38
No, it's going make it harder, because I will need
| |
| 89 # Show whether or not it's the first time to execute GoTo. | |
|
vabr (Chromium)
2014/05/20 14:47:25
"Show"? It's not clear how and to whom this is sho
rchtara
2014/05/22 08:44:38
Done.
| |
| 90 self.first_go_to = True | |
| 91 | |
| 92 def AddWebsiteTest(self, websitetest, disabled=False): | |
| 93 """Adds a WebsiteTest to the testing Environment. | |
| 94 | |
| 95 Args: | |
| 96 websitetest: The WebsiteTest instance that's going to be added to the | |
|
vabr (Chromium)
2014/05/20 14:47:25
nit: You can simply write:
"The WebsiteTest instan
rchtara
2014/05/22 08:44:38
Done.
| |
| 97 testing Environment. | |
| 98 disabled: Test is disabled. | |
|
vabr (Chromium)
2014/05/20 14:47:25
nit: Whether test is disabled.
rchtara
2014/05/22 08:44:38
Done.
| |
| 99 """ | |
| 100 websitetest.environment = self | |
| 101 websitetest.driver = self.driver | |
| 102 if self.passwords_tree is not None: | |
| 103 if not websitetest.username: | |
| 104 username_tag = ( | |
| 105 self.passwords_tree.find( | |
| 106 ".//*[@name='%s']/username" % websitetest.name)) | |
| 107 if username_tag.text: | |
| 108 websitetest.username = username_tag.text | |
| 109 if not websitetest.password: | |
| 110 password_tag = ( | |
| 111 self.passwords_tree.find( | |
| 112 ".//*[@name='%s']/password" % websitetest.name)) | |
| 113 if password_tag.text: | |
| 114 websitetest.password = password_tag.text | |
| 115 self.websitetests.append(websitetest) | |
| 116 if not disabled: | |
| 117 self.working_tests.append(websitetest.name) | |
| 118 | |
| 119 def RemoveAllPasswords(self): | |
| 120 """Removes all the stored passwords.""" | |
| 121 logging.info("\nRemoveAllPasswords\n") | |
| 122 self.driver.get("chrome://settings/passwords") | |
| 123 self.driver.switch_to_frame("settings") | |
| 124 while True: | |
| 125 try: | |
| 126 self.driver.execute_script("document.querySelector('" | |
| 127 "#saved-passwords-list .row-delete-button').click()") | |
| 128 time.sleep(1) | |
| 129 except NoSuchElementException: | |
| 130 break | |
| 131 except WebDriverException: | |
| 132 break | |
| 133 | |
| 134 def OpenTabAndGoToInternals(self, url): | |
| 135 """If there is no |self.website_window|, opens a new tab and navigates to | |
| 136 |url| in the new tab. Navigates to the passwords internals page in the | |
| 137 first tab. Raises an exception otherwise. | |
|
vabr (Chromium)
2014/05/20 14:47:25
It's not clear what "otherwise" refers to.
I belie
rchtara
2014/05/22 08:44:38
Done.
| |
| 138 | |
| 139 Args: | |
| 140 url: Url to go to in the new tab. | |
| 141 | |
| 142 Raises: | |
| 143 Exception: An exception is raised if |self.website_window| already exists. | |
| 144 """ | |
| 145 if not self.website_window: | |
|
vabr (Chromium)
2014/05/20 14:47:25
nit: Consider starting with
if self.website_window
rchtara
2014/05/22 08:44:38
Done.
| |
| 146 self.driver.get("chrome://newtab") | |
| 147 # There is no straightforward way to open a new tab with chromedriver. | |
| 148 # One work-around is to go to a website, insert a link that is going | |
| 149 # to be opened in a new tab, click on it. | |
| 150 a = self.driver.execute_script( | |
| 151 "var a = document.createElement('a');" | |
| 152 "a.target = '_blank';" | |
| 153 "a.href = arguments[0];" | |
| 154 "a.innerHTML = '.';" | |
| 155 "document.body.appendChild(a);" | |
| 156 "return a;", | |
| 157 url) | |
| 158 | |
| 159 a.click() | |
| 160 time.sleep(1) | |
| 161 | |
| 162 self.website_window = self.driver.window_handles[-1] | |
| 163 self.driver.get(self.internals_page) | |
| 164 self.driver.switch_to_window(self.website_window) | |
| 165 else: | |
| 166 raise Exception("Error: The window was already opened.") | |
| 167 | |
| 168 def SwitchToInternals(self): | |
| 169 """Switches from the Website window to internals tab.""" | |
| 170 self.driver.switch_to_window(self.internals_window) | |
| 171 | |
| 172 def SwitchFromInternals(self): | |
| 173 """Switches from internals tab to the Website window.""" | |
| 174 self.driver.switch_to_window(self.website_window) | |
| 175 | |
| 176 def CheckPrompt(self, log_message, prompt_should_show_up, | |
| 177 error_message, timeout=10): | |
| 178 """Detects whether the save password prompt is shown, and raises an | |
| 179 exception if the result does not match the expectation. | |
| 180 | |
| 181 Args: | |
| 182 log_message: Log message to look for in the password internals. | |
| 183 prompt_should_show_up: Whether or not the prompt is expected to be shown. | |
| 184 error_message: Error message for the exception . | |
|
vabr (Chromium)
2014/05/20 14:47:25
nit: Remove the two spaces at the end of the sente
rchtara
2014/05/22 08:44:38
Done.
| |
| 185 timeout: There is some delay between the login and the password | |
| 186 internals update. The method checks periodically during the first | |
| 187 |timeout| seconds if the internals page reports the prompt being | |
| 188 shown. If the prompt is not reported shown within the first | |
| 189 |timeout| seconds, it is considered not shown at all. | |
| 190 | |
| 191 Raises: | |
| 192 Exception: An exception is raised in case there is a problem. | |
|
vabr (Chromium)
2014/05/20 14:47:25
nit: "there is a problem" -> "the result does not
rchtara
2014/05/22 08:44:38
Done.
| |
| 193 """ | |
| 194 if prompt_should_show_up: | |
| 195 self.save_count += 1 | |
| 196 log = self.driver.find_element_by_css_selector("#log-entries") | |
| 197 count = log.text.count(log_message) | |
| 198 | |
| 199 if count < self.save_count and timeout > 0: | |
| 200 time.sleep(1) | |
| 201 self.CheckPrompt(log_message, False, error_message, timeout - 1) | |
|
vabr (Chromium)
2014/05/20 14:47:25
You hard-code False as the "prompt_should_show_up"
rchtara
2014/05/22 08:44:38
Done.
| |
| 202 | |
| 203 elif not self.save_count == count: | |
| 204 raise Exception(error_message) | |
| 205 | |
| 206 def AllTests(self, prompt_test): | |
| 207 """Runs the tests on all the WebsiteTests. | |
|
vabr (Chromium)
2014/05/20 14:47:25
typo: two consequent spaces between "the" and "Web
rchtara
2014/05/22 08:44:38
Done.
| |
| 208 | |
| 209 Args: | |
| 210 prompt_test: Prompt tests or normal tests. | |
|
vabr (Chromium)
2014/05/20 14:47:25
Please explain what are "prompt tests". The most p
rchtara
2014/05/22 08:44:38
Done.
| |
| 211 | |
| 212 Raises: | |
| 213 Exception: An exception is raised if the tests fail. | |
| 214 """ | |
| 215 if prompt_test: | |
| 216 self.PromptTestList(self.websitetests) | |
| 217 else: | |
| 218 self.TestList(self.websitetests) | |
| 219 | |
| 220 def WorkingTests(self, prompt_test): | |
| 221 """Runs the tests on all the enabled WebsiteTests. | |
| 222 | |
| 223 Args: | |
| 224 prompt_test: Prompt tests or normal tests. | |
| 225 | |
| 226 Raises: | |
| 227 Exception: An exception is raised if the tests fail. | |
| 228 """ | |
| 229 self.Test(self.working_tests, prompt_test) | |
| 230 | |
| 231 def Test(self, tests, prompt_test): | |
| 232 """Runs the tests on many WebsiteTests. | |
|
vabr (Chromium)
2014/05/20 14:47:25
many WebsiteTests -> websites named in |tests|
Al
rchtara
2014/05/22 08:44:38
Done.
| |
| 233 | |
| 234 Args: | |
| 235 tests: A list of the names of the WebsiteTests that are going to be | |
| 236 tested. | |
| 237 prompt_test: Prompt tests or normal tests. | |
| 238 | |
| 239 Raises: | |
| 240 Exception: An exception is raised if the tests fail. | |
| 241 """ | |
| 242 websitetests = [] | |
| 243 for websitetest in self.websitetests: | |
| 244 if websitetest.name in tests: | |
| 245 websitetests.append(websitetest) | |
| 246 | |
| 247 if prompt_test: | |
| 248 self.PromptTestList(websitetests) | |
| 249 else: | |
| 250 self.TestList(websitetests) | |
| 251 | |
| 252 def TestList(self, websitetests): | |
| 253 """Runs the tests on many WebsiteTests. | |
| 254 | |
| 255 Args: | |
| 256 websitetests: A list of WebsiteTests that are going to be tested. | |
| 257 | |
| 258 Raises: | |
| 259 Exception: An exception is raised if the tests fail. | |
| 260 """ | |
| 261 self.RemoveAllPasswords() | |
| 262 | |
| 263 for websitetest in websitetests: | |
| 264 websitetest.WrongLoginTest() | |
| 265 websitetest.SuccessfulLoginTest() | |
| 266 websitetest.SuccessfulLoginWithAutofilledPasswordTest() | |
| 267 | |
| 268 self.RemoveAllPasswords() | |
| 269 for websitetest in websitetests: | |
| 270 websitetest.SuccessfulLoginTest() | |
| 271 | |
| 272 def PromptTestList(self, websitetests): | |
| 273 """Runs the prompt tests on many WebsiteTests. | |
| 274 | |
| 275 Args: | |
| 276 websitetests: A list of WebsiteTests that are going to be tested. | |
| 277 | |
| 278 Raises: | |
| 279 Exception: An exception is raised if the tests fail. | |
| 280 """ | |
| 281 self.RemoveAllPasswords() | |
| 282 | |
| 283 for websitetest in websitetests: | |
| 284 websitetest.PromptTest() | |
| 285 | |
| 286 def Quit(self): | |
| 287 """Closes the tests.""" | |
| 288 # Close the webdriver. | |
| 289 self.driver.quit() | |
| OLD | NEW |