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=None, log_to_console=False, log_file=""): | |
20 """Creates a new testing Environment. | |
21 | |
22 Args: | |
23 chrome_path: The chrome binary file. | |
24 chromedriver_path: The chromedriver binary file. | |
25 profile_path: The chrome testing profile folder. | |
26 passwords_path: The usernames and passwords file. | |
27 enable_automatic_password_saving: If True, the passwords are going to be | |
28 saved without showing the prompt. | |
29 numeric_level: The log verbosity. | |
30 log_to_console: If True, the debug logs will be shown on the console. | |
31 log_file: The file where to store the log. If it's empty, the log will | |
32 not be stored. | |
33 | |
34 Raises: | |
35 Exception: An exception is raised if |profile_path| folder could not be | |
36 removed. | |
37 """ | |
38 # Setting up the login. | |
39 if numeric_level is not None: | |
40 if log_file: | |
41 # Set up logging to file. | |
42 logging.basicConfig(level=numeric_level, | |
43 filename=log_file, | |
44 filemode='w') | |
45 | |
46 if log_to_console: | |
47 console = logging.StreamHandler() | |
48 console.setLevel(numeric_level) | |
49 # Add the handler to the root logger. | |
50 logging.getLogger('').addHandler(console) | |
51 | |
52 elif log_to_console: | |
53 logging.basicConfig(level=numeric_level) | |
54 | |
55 # Cleaning the chrome testing profile folder. | |
56 try: | |
57 shutil.rmtree(profile_path) | |
58 except Exception, e: | |
59 # The tests execution can continue, but this make them less stable. | |
60 logging.error("Error: Could not wipe the chrome profile directory (%s). \ | |
61 This affects the stability of the tests. Continuing to run tests." | |
62 % e) | |
63 options = Options() | |
64 if enable_automatic_password_saving: | |
65 options.add_argument("enable-automatic-password-saving") | |
66 # Chrome path. | |
67 options.binary_location = chrome_path | |
68 # Chrome testing profile path. | |
69 options.add_argument("user-data-dir=%s" % profile_path) | |
70 | |
71 # The webdriver. It's possible to choose the port the service is going to | |
72 # run on. If it's left to 0, a free port will be found. | |
73 self.driver = webdriver.Chrome(chromedriver_path, 0, options) | |
74 # The password internals window. | |
75 self.internals_window = self.driver.current_window_handle | |
76 # Password internals page. | |
77 self.internals_page = "chrome://password-manager-internals/" | |
78 # The Website window. | |
79 self.website_window = None | |
80 # The WebsiteTests list. | |
81 self.websitetests = [] | |
82 # An xml tree filled with logins and passwords. | |
83 self.passwords_tree = None | |
84 if passwords_path: | |
vabr (Chromium)
2014/05/22 13:39:24
Once the path to the passwords is no longer option
rchtara
2014/05/22 15:20:56
Done.
| |
85 self.passwords_tree = ElementTree.parse(passwords_path).getroot() | |
86 # The enabled WebsiteTests list. | |
87 self.working_tests = [] | |
88 # The number of the save operations done through all the tests. | |
89 self.save_count = 0 | |
vabr (Chromium)
2014/05/22 13:39:24
I see a potential problem: |save_count| is used to
rchtara
2014/05/22 15:20:56
Done.
| |
90 # The tests needs two tabs to work. A new tab is opened with the first | |
91 # GoTo. This is why we store here whether or not it's the first time to | |
92 # execute GoTo. | |
93 self.first_go_to = True | |
94 | |
95 def AddWebsiteTest(self, websitetest, disabled=False): | |
96 """Adds a WebsiteTest to the testing Environment. | |
97 | |
98 Args: | |
99 websitetest: The WebsiteTest instance to be added. | |
100 disabled: Whether test is disabled. | |
101 """ | |
102 websitetest.environment = self | |
103 websitetest.driver = self.driver | |
104 if self.passwords_tree is not None: | |
105 if not websitetest.username: | |
106 username_tag = ( | |
107 self.passwords_tree.find( | |
108 ".//*[@name='%s']/username" % websitetest.name)) | |
109 if username_tag.text: | |
110 websitetest.username = username_tag.text | |
111 if not websitetest.password: | |
112 password_tag = ( | |
113 self.passwords_tree.find( | |
114 ".//*[@name='%s']/password" % websitetest.name)) | |
115 if password_tag.text: | |
116 websitetest.password = password_tag.text | |
117 self.websitetests.append(websitetest) | |
118 if not disabled: | |
119 self.working_tests.append(websitetest.name) | |
120 | |
121 def RemoveAllPasswords(self): | |
122 """Removes all the stored passwords.""" | |
123 logging.info("\nRemoveAllPasswords\n") | |
124 self.driver.get("chrome://settings/passwords") | |
125 self.driver.switch_to_frame("settings") | |
126 while True: | |
127 try: | |
128 self.driver.execute_script("document.querySelector('" | |
129 "#saved-passwords-list .row-delete-button').click()") | |
130 time.sleep(1) | |
131 except NoSuchElementException: | |
132 break | |
133 except WebDriverException: | |
134 break | |
135 | |
136 def OpenTabAndGoToInternals(self, url): | |
137 """If there is no |self.website_window|, opens a new tab and navigates to | |
138 |url| in the new tab. Navigates to the passwords internals page in the | |
139 first tab. Raises an exception otherwise. | |
140 | |
141 Args: | |
142 url: Url to go to in the new tab. | |
143 | |
144 Raises: | |
145 Exception: An exception is raised if |self.website_window| already | |
146 exists. | |
147 """ | |
148 if self.website_window: | |
149 raise Exception("Error: The window was already opened.") | |
150 | |
151 self.driver.get("chrome://newtab") | |
152 # There is no straightforward way to open a new tab with chromedriver. | |
153 # One work-around is to go to a website, insert a link that is going | |
154 # to be opened in a new tab, click on it. | |
155 a = self.driver.execute_script( | |
156 "var a = document.createElement('a');" | |
157 "a.target = '_blank';" | |
158 "a.href = arguments[0];" | |
159 "a.innerHTML = '.';" | |
160 "document.body.appendChild(a);" | |
161 "return a;", | |
162 url) | |
163 | |
164 a.click() | |
165 time.sleep(1) | |
166 | |
167 self.website_window = self.driver.window_handles[-1] | |
168 self.driver.get(self.internals_page) | |
169 self.driver.switch_to_window(self.website_window) | |
170 | |
171 def SwitchToInternals(self): | |
172 """Switches from the Website window to internals tab.""" | |
173 self.driver.switch_to_window(self.internals_window) | |
174 | |
175 def SwitchFromInternals(self): | |
176 """Switches from internals tab to the Website window.""" | |
177 self.driver.switch_to_window(self.website_window) | |
178 | |
179 def _DidPromptAppearUntilTimeout(self, log_message, timeout): | |
vabr (Chromium)
2014/05/22 13:39:24
Looking at the code again, this actually does not
rchtara
2014/05/22 15:20:56
no problem :)
Done.
| |
180 """Checks whether the save password prompt is shown. | |
181 | |
182 Args: | |
183 log_message: Log message to look for in the password internals. | |
184 timeout: There is some delay between the login and the password | |
185 internals update. The method checks periodically during the first | |
186 |timeout| seconds if the internals page reports the prompt being | |
187 shown. If the prompt is not reported shown within the first | |
188 |timeout| seconds, it is considered not shown at all. | |
189 | |
190 Returns: | |
191 True if the save password prompt is shown. | |
192 False otherwise. | |
193 """ | |
194 log = self.driver.find_element_by_css_selector("#log-entries") | |
195 count = log.text.count(log_message) | |
196 if count > self.save_count: | |
197 self.save_count = count | |
198 return True | |
199 elif timeout > 0: | |
200 time.sleep(1) | |
201 return self._WaitUntilPromptAppear(log_message, timeout - 1) | |
202 else: | |
203 return False | |
204 | |
205 def CheckPrompt(self, log_message, prompt_should_show_up, | |
vabr (Chromium)
2014/05/22 13:39:24
Also here: I suggest renaming to CheckForNewMessag
rchtara
2014/05/22 15:20:56
Done.
| |
206 error_message, timeout=3): | |
207 """Detects whether the save password prompt is shown. | |
208 | |
209 Args: | |
210 log_message: Log message to look for in the password internals. | |
211 prompt_should_show_up: Whether or not the prompt is expected to be shown. | |
212 error_message: Error message for the exception. | |
213 timeout: There is some delay between the login and the password | |
214 internals update. The method checks periodically during the first | |
215 |timeout| seconds if the internals page reports the prompt being | |
216 shown. If the prompt is not reported shown within the first | |
217 |timeout| seconds, it is considered not shown at all. | |
218 | |
219 Raises: | |
220 Exception: An exception is raised in case the result does not match the | |
221 expectation | |
222 """ | |
223 if (self._WaitUntilPromptAppear(log_message, timeout) != | |
vabr (Chromium)
2014/05/22 13:39:24
Outdated method name.
rchtara
2014/05/22 15:20:56
Done.
| |
224 prompt_should_show_up): | |
225 raise Exception(error_message) | |
226 | |
227 def AllTests(self, prompt_test): | |
228 """Runs the tests on all the WebsiteTests. | |
229 | |
230 Args: | |
231 prompt_test: If True, tests caring about showing the save-password | |
232 prompt are going to be run, otherwise tests which don't care about | |
233 the prompt are going to be executed. | |
vabr (Chromium)
2014/05/22 13:39:24
nit: Be consistent: either use "run" or "executed"
rchtara
2014/05/22 15:20:56
Done.
| |
234 | |
235 Raises: | |
236 Exception: An exception is raised if the tests fail. | |
237 """ | |
238 if prompt_test: | |
239 self.PromptTestList(self.websitetests) | |
240 else: | |
241 self.TestList(self.websitetests) | |
242 | |
243 def WorkingTests(self, prompt_test): | |
244 """Runs the tests on all the enabled WebsiteTests. | |
245 | |
246 Args: | |
247 prompt_test: If True, tests caring about showing the save-password | |
248 prompt are going to be run, otherwise tests which don't care about | |
249 the prompt are going to be executed. | |
250 | |
251 Raises: | |
252 Exception: An exception is raised if the tests fail. | |
253 """ | |
254 self.Test(self.working_tests, prompt_test) | |
255 | |
256 def Test(self, tests, prompt_test): | |
257 """Runs the tests on websites named in |tests|. | |
258 | |
259 Args: | |
260 tests: A list of the names of the WebsiteTests that are going to be | |
261 tested. | |
262 prompt_test: If True, tests caring about showing the save-password | |
263 prompt are going to be run, otherwise tests which don't care about | |
264 the prompt are going to be executed. | |
265 | |
266 Raises: | |
267 Exception: An exception is raised if the tests fail. | |
268 """ | |
269 websitetests = [] | |
270 for websitetest in self.websitetests: | |
271 if websitetest.name in tests: | |
272 websitetests.append(websitetest) | |
273 | |
274 if prompt_test: | |
275 self.PromptTestList(websitetests) | |
276 else: | |
277 self.TestList(websitetests) | |
278 | |
279 def TestList(self, websitetests): | |
280 """Runs the tests on the websites in |websitetests|. | |
281 | |
282 Args: | |
283 websitetests: A list of WebsiteTests that are going to be tested. | |
284 | |
285 Raises: | |
286 Exception: An exception is raised if the tests fail. | |
287 """ | |
288 self.RemoveAllPasswords() | |
289 | |
290 for websitetest in websitetests: | |
291 websitetest.WrongLoginTest() | |
292 websitetest.SuccessfulLoginTest() | |
293 websitetest.SuccessfulLoginWithAutofilledPasswordTest() | |
294 | |
295 self.RemoveAllPasswords() | |
296 for websitetest in websitetests: | |
297 websitetest.SuccessfulLoginTest() | |
298 | |
299 def PromptTestList(self, websitetests): | |
300 """Runs the prompt tests on the websites in |websitetests|. | |
301 | |
302 Args: | |
303 websitetests: A list of WebsiteTests that are going to be tested. | |
304 | |
305 Raises: | |
306 Exception: An exception is raised if the tests fail. | |
307 """ | |
308 self.RemoveAllPasswords() | |
309 | |
310 for websitetest in websitetests: | |
311 websitetest.PromptTest() | |
312 | |
313 def Quit(self): | |
314 """Closes the tests.""" | |
315 # Close the webdriver. | |
316 self.driver.quit() | |
OLD | NEW |