Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 """The testing Environment class.""" | |
| 2 | |
| 3 import shutil | |
| 4 import time | |
| 5 | |
| 6 from selenium import webdriver | |
| 7 from selenium.webdriver.chrome.options import Options | |
| 8 from xml.etree import ElementTree | |
| 9 | |
| 10 | |
| 11 class Environment: | |
| 12 """Sets up the testing Environment. """ | |
| 13 | |
| 14 def __init__(self, chrome_path, chromedriver_path, | |
| 15 profile_path, passwords_path, | |
| 16 log_to_screen, log_file): | |
| 17 """Creates a new testing Environment. | |
| 18 | |
| 19 Args: | |
| 20 chrome_path: The chrome binary file. | |
| 21 chromedriver_path: The chromedriver binary file. | |
| 22 profile_path: The testing profile folder. | |
| 23 passwords_path: The usernames and passwords file. | |
| 24 log_to_screen: If set, the tests log is going to be shown on the screen. | |
| 25 log_file: The file where to store the log. | |
| 26 """ | |
| 27 # Cleaning the profile folder. | |
| 28 try: | |
| 29 shutil.rmtree(profile_path) | |
| 30 except Exception, e: | |
| 31 self.Log(e) | |
|
vabr (Chromium)
2014/05/16 09:36:00
This deservers a comment on why is it OK to procee
rchtara
2014/05/20 08:24:47
Done.
| |
| 32 options = Options() | |
| 33 options.add_argument("enable-automatic-password-saving") | |
| 34 options.add_argument("enable-password-manager-internals-ui") | |
|
vabr (Chromium)
2014/05/16 09:36:00
nit: Since yesterday, this is no more needed. :)
rchtara
2014/05/22 08:44:38
Yes, i have an old version of code, so i need it.
| |
| 35 # Chrome path. | |
| 36 options.binary_location = chrome_path | |
| 37 # Testing profile path. | |
| 38 options.add_argument("user-data-dir=%s" % profile_path) | |
| 39 | |
| 40 # The webdriver. It's possible to choose the port the service is going to | |
| 41 # run on. If it's left to 0, a free port will be found. | |
| 42 self.driver = webdriver.Chrome(chromedriver_path, 0, options) | |
| 43 # The password internals window. | |
| 44 self.internals_window = self.driver.current_window_handle | |
| 45 # Password internals page. | |
| 46 self.internals_page = "chrome://password-manager-internals/" | |
| 47 # The Website window. | |
| 48 self.websitewindow = None | |
| 49 # The Websites list. | |
| 50 self.websites = [] | |
| 51 # An xml tree filled with logins and passwords. | |
| 52 self.passwords_tree = None | |
| 53 if passwords_path: | |
| 54 self.passwords_tree = ElementTree.parse(passwords_path).getroot() | |
| 55 # The Websites list for which we expect the test to be working. | |
| 56 self.working_tests = [] | |
| 57 # The number of the save operations done through all the tests. | |
|
vabr (Chromium)
2014/05/16 09:36:00
nit: "through all" contains 2 spaces instead of 1
rchtara
2014/05/20 08:24:47
Done.
| |
| 58 self.save_count = 0 | |
| 59 | |
| 60 self.log_to_screen = log_to_screen | |
| 61 self.log_file = None | |
| 62 if log_file: | |
| 63 self.log_file = open(log_file,'w') | |
| 64 | |
| 65 def AddWebsite(self, | |
| 66 website, | |
| 67 disabled=False): | |
| 68 """Adds a Website to the testing Environment. | |
|
vabr (Chromium)
2014/05/16 09:36:00
Actually, what do you think of renaming Website to
rchtara
2014/05/20 08:24:47
Done.
| |
| 69 | |
| 70 Args: | |
| 71 website: The Website instance that's going to be added to the testing | |
| 72 Environment. | |
| 73 disabled: Test is disabled. | |
| 74 """ | |
| 75 website.environment = self | |
| 76 website.driver = self.driver | |
| 77 if self.passwords_tree is not None: | |
|
vabr (Chromium)
2014/05/16 09:36:00
nit: Just use
if self.passwords_tree:
rchtara
2014/05/20 08:24:47
I got this warning when I tied to replace this Non
vabr (Chromium)
2014/05/20 14:47:25
Fair enough. Your test for "is not None" is actual
rchtara
2014/05/22 08:44:38
No problem
| |
| 78 if not website.username: | |
| 79 username_tag = ( | |
| 80 self.passwords_tree.find( | |
| 81 ".//*[@name='%s']/username" % website.name)) | |
| 82 if username_tag.text: | |
| 83 website.username = username_tag.text | |
| 84 if not website.password: | |
| 85 password_tag = ( | |
| 86 self.passwords_tree.find( | |
| 87 ".//*[@name='%s']/password" % website.name)) | |
| 88 if password_tag.text: | |
| 89 website.password = password_tag.text | |
| 90 self.websites.append(website) | |
| 91 if disabled == False: | |
|
vabr (Chromium)
2014/05/16 09:36:00
nit: Just use:
if not disabled:
rchtara
2014/05/20 08:24:47
Done.
| |
| 92 self.working_tests.append(website.name) | |
| 93 | |
| 94 def RemoveAllPasswords(self, websites): | |
| 95 """Removes the stored passwords for all Websites. | |
|
vabr (Chromium)
2014/05/16 09:36:00
Why don't you just flush all the stored passwords,
rchtara
2014/05/20 08:24:47
Done.
| |
| 96 | |
| 97 Args: | |
| 98 websites: The Websites which the passwords are going to be removed. | |
| 99 """ | |
| 100 self.Log("\nRemoveAllPasswords\n") | |
| 101 self.driver.get("chrome://settings/passwords") | |
| 102 self.driver.switch_to_frame("settings") | |
| 103 for website in websites: | |
| 104 urls = self.GetURLs() | |
| 105 website.RemoveAllPasswords(urls) | |
| 106 | |
| 107 def GetURLs(self): | |
| 108 """Gets all URLs of the saved passwords in the chrome://settings/passwords. | |
| 109 | |
| 110 Returns: | |
| 111 A list of the URLs. | |
| 112 """ | |
| 113 deletable_passwords = self.driver.find_elements_by_css_selector( | |
| 114 "#saved-passwords-list .deletable-item") | |
| 115 urls = [] | |
| 116 for entry in deletable_passwords: | |
| 117 urls.append(entry.find_element_by_class_name("url").text) | |
| 118 return urls | |
| 119 | |
| 120 def OpenTabAndGoInternal(self): | |
|
vabr (Chromium)
2014/05/16 09:36:00
nit: Please rename to OpenTabAndGoToInternals
("go
rchtara
2014/05/20 08:24:47
Done.
| |
| 121 """Opens a new tab and navigates to passwords internals page in the first | |
|
vabr (Chromium)
2014/05/16 09:36:00
The comment does not seem to match the code exactl
rchtara
2014/05/20 08:24:47
Done.
| |
| 122 tab.""" | |
| 123 if not self.websitewindow: | |
| 124 self.driver.get("https://google.com") | |
|
vabr (Chromium)
2014/05/16 09:36:00
Would chrome://newtab work instead of google.com?
rchtara
2014/05/20 08:24:47
I updated the test to go to the url of the first w
vabr (Chromium)
2014/05/20 14:47:25
Great, thanks for fixing this!
rchtara
2014/05/22 08:44:38
Thanks :)
| |
| 125 # There is no straightforward way to open a new tab with chromedriver. | |
| 126 # One work-around is to go to a website, insert a link that is going | |
| 127 # to be opened in a new tab, click on it. To avoid that the chrome popup | |
| 128 # blocker blocks the new tab, we need to choose a trusted website which | |
| 129 # is google.com. | |
| 130 a = self.driver.execute_script( | |
| 131 "var a = document.createElement('a');" | |
| 132 "a.target = '_blank';" | |
| 133 "a.href = arguments[0];" | |
| 134 "a.innerHTML = '.';" | |
| 135 "document.body.appendChild(a);" | |
| 136 "return a;", | |
| 137 "https://google.com") | |
| 138 | |
| 139 a.click() | |
| 140 time.sleep(1) | |
|
vabr (Chromium)
2014/05/16 09:36:00
It's a bit unfortunate that this sleep() does not
rchtara
2014/05/20 08:24:47
I don't think it's make sense to do that.max_durat
vabr (Chromium)
2014/05/20 14:47:25
OK, makes sense, I misunderstood the function of m
rchtara
2014/05/22 08:44:38
Done.
| |
| 141 | |
| 142 self.websitewindow = self.driver.window_handles[-1] | |
| 143 self.driver.get(self.internals_page) | |
| 144 self.driver.switch_to_window(self.websitewindow) | |
| 145 | |
| 146 def SwitchToInternals(self): | |
| 147 """Switches from the Website window to internals tab.""" | |
| 148 self.driver.switch_to_window(self.internals_window) | |
| 149 | |
| 150 def SwitchFromInternals(self): | |
| 151 """Switches from internals tab to the Website window.""" | |
| 152 self.driver.switch_to_window(self.websitewindow) | |
| 153 | |
| 154 def CheckPromptIsNotShown(self, expected, msg, timeout=10): | |
| 155 """Checks if the prompt was shown: If the prompt is shown when it shouldn't | |
|
vabr (Chromium)
2014/05/16 09:36:00
nit: CheckPromptIsNotShown ... Checks if the promp
rchtara
2014/05/20 08:24:47
Done.
| |
| 156 be or is not shown when it should be, raise an exception. | |
| 157 | |
| 158 Args: | |
| 159 expected: Whether or not the prompt is expected to be shown. | |
| 160 msg: Error message for the exception. | |
| 161 timeout: There is some delay between the login and the password | |
| 162 internals update. In case nothing is detected, the method is going to | |
| 163 wait and execute itself recursively until the time will end. | |
|
vabr (Chromium)
2014/05/16 09:36:00
This is not clear (and also does not mention the t
rchtara
2014/05/20 08:24:47
Done.
| |
| 164 | |
| 165 Raises: | |
| 166 Exception: An exception is raised in case there a problem. | |
| 167 """ | |
| 168 if expected: | |
| 169 self.save_count += 1 | |
| 170 log = self.driver.find_element_by_css_selector("#log-entries") | |
| 171 count = log.text.count("Message: Decision: SAVE the password") | |
|
vabr (Chromium)
2014/05/16 09:36:00
This is not correct.
The message actually says tha
rchtara
2014/05/20 08:24:47
Done.
| |
| 172 | |
| 173 if count < self.save_count and timeout > 0: | |
| 174 time.sleep(1) | |
| 175 self.CheckPromptIsNotShown(False, msg, timeout - 1) | |
| 176 | |
| 177 elif not self.save_count == count: | |
| 178 raise Exception(msg) | |
| 179 | |
| 180 def Log(self, text): | |
|
vabr (Chromium)
2014/05/16 09:36:00
Please use the standard Python logging support ins
rchtara
2014/05/20 08:24:47
Done.
| |
| 181 """Writes to the log. | |
| 182 Args: | |
| 183 text: Text to be written. | |
| 184 """ | |
| 185 if self.log_to_screen: | |
| 186 print text | |
| 187 if self.log_file: | |
| 188 self.log_file.write("%s \n" % text) | |
| 189 | |
| 190 def TestList(self, websites): | |
| 191 """Runs the tests on many Websites. | |
|
vabr (Chromium)
2014/05/16 09:36:00
nit: "many Websites" is unnecessarily vague. Just
rchtara
2014/05/20 08:24:47
Done.
vabr (Chromium)
2014/05/20 14:47:25
That's not what I meant: you still kept "many". I
rchtara
2014/05/22 08:44:38
sorry :)
| |
| 192 Args: | |
| 193 websites: A list of Websites that are going to be tested. | |
| 194 Raises: | |
| 195 Exception: An exception is raised if the tests fail. | |
| 196 """ | |
| 197 self.RemoveAllPasswords(websites) | |
| 198 | |
| 199 self.OpenTabAndGoInternal() | |
| 200 for website in websites: | |
| 201 website.WrongLoginTest() | |
| 202 website.SuccessfulLoginTest() | |
| 203 website.SuccessfulLoginWithAutofilledPasswordTest() | |
| 204 | |
| 205 self.RemoveAllPasswords(websites) | |
| 206 for website in websites: | |
| 207 website.SuccessfulLoginAfterDeletionTest() | |
| 208 | |
| 209 def AllTests(self): | |
| 210 """Runs the tests on all the websites. | |
| 211 Raises: | |
| 212 Exception: An exception is raised if the tests fail. | |
| 213 """ | |
| 214 self.TestList(self.websites) | |
| 215 | |
| 216 def WorkingTests(self): | |
| 217 """Runs the tests on all the working websites. | |
| 218 Raises: | |
| 219 Exception: An exception is raised if the tests fail. | |
| 220 """ | |
| 221 self.Test(self.working_tests) | |
| 222 | |
| 223 def Test(self, tests): | |
| 224 """Runs the tests on many websites. | |
| 225 Args: | |
| 226 tests: A list of the names of the websites that are going to be tested. | |
| 227 Raises: | |
| 228 Exception: An exception is raised if the tests fail. | |
| 229 """ | |
| 230 websites = [] | |
| 231 for website in self.websites: | |
| 232 if website.name in tests: | |
| 233 websites.append(website) | |
| 234 self.TestList(websites) | |
| 235 | |
| 236 def Quit(self): | |
| 237 """Closes the tests.""" | |
| 238 # Close the log file if it's open. | |
| 239 if self.log_file: | |
| 240 self.log_file.close() | |
| 241 # Close the webdriver. | |
| 242 self.driver.quit() | |
| OLD | NEW |