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 |