Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(876)

Side by Side Diff: components/test/data/password_manager/websitetest.py

Issue 273523004: Password Manager testing automation (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rev Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 """WebsiteTest testing class."""
2
3 import logging
4 import time
5
6 from selenium.webdriver.common.action_chains import ActionChains
7 from selenium.webdriver.common.keys import Keys
8
9
10 def _IsOneSubstringOfAnother(s1, s2):
11 """Checks if one of the string arguements is substring of the other.
12
13 Args:
14 s1: The first string.
15 s2: The second string.
16 Returns:
17
18 True if one of the string arguements is substring of the other.
19 False otherwise.
20 """
21 return s1 in s2 or s2 in s1
22
23
24 class WebsiteTest:
25 """Handles a tested WebsiteTest."""
26
27 class Mode:
28 """Test mode."""
29 # Password and username are expected to be autofilled.
30 AUTOFILLED = 1
31 # Password and username are not expected to be autofilled.
32 NOT_AUTOFILLED = 2
33
34 def __init__(self):
35 pass
36
37 def __init__(
38 self, name, username=None, password=None,
39 username_not_auto=False):
40 """Creates a new WebsiteTest.
41
42 Args:
43 name: The website name.
44 username: The website username. If it's None, the username is going to be
45 replaced with the value in the usernames and passwords file.
46 password: The website password. If it's None, the password is going to be
47 replaced with the value in the usernames and passwords file.
48 username_not_auto: Username inputs in some websites (like wikipedia) are
49 sometimes filled with some messages and thus, the usernames are not
50 automatically autofilled. This flag handles that and disables us from
51 checking if the state of the DOM is the same as the username of
52 website.
53 """
54 # Name of the website
55 self.name = name
56 # Username of the website.
57 self.username = username
58 # Password of the website.
59 self.password = password
60 # Username is not automatically filled.
61 self.username_not_auto = username_not_auto
62 # Autofilling mode.
63 self.mode = self.Mode.NOT_AUTOFILLED
64 # The |remaining_time_to_wait| limits the total time spent in potentially
vabr (Chromium) 2014/05/22 10:07:02 nit: add units (seconds?)
rchtara 2014/05/22 12:42:01 Done.
65 # infinite loops.
66 self.remaining_time_to_wait = 200
67 # The testing Environment.
68 self.environment = None
69 # The webdriver.
70 self.driver = None
71
72 # Mouse/Keyboard actions.
73
74 def Click(self, selector):
75 """Clicks on an element.
76
77 Args:
78 selector: The element CSS selector.
79 """
80 logging.info("action: Click %s" % selector)
81 element = self.driver.find_element_by_css_selector(selector)
82 element.click()
83
84 def ClickIfClickable(self, selector):
85 """Clicks on an element if it's clickable: If it doesn't exist in the DOM,
86 it's covered by another element or it's out viewing area, nothing is
87 done and False is returned. Otherwise, even if the element is 100%
88 transparent, the element is going to receive a click and a True is
89 returned.
90
91 Args:
92 selector: The element CSS selector.
93
94 Returns:
95 True if the click happens.
96 False otherwise.
97 """
98 logging.info("action: ClickIfVisible %s" % selector)
99 try:
100 element = self.driver.find_element_by_css_selector(selector)
101 element.click()
102 return True
103 except Exception:
104 return False
105
106 def GoTo(self, url):
107 """Navigates the main frame to the |url|.
108
109 Args:
110 url: The URL.
111 """
112 logging.info("action: GoTo %s" % self.name)
113 if self.environment.first_go_to:
114 self.environment.OpenTabAndGoToInternals(url)
115 self.environment.first_go_to = False
116 else:
117 self.driver.get(url)
118
119 def HoverOver(self, selector):
120 """Hovers over an element.
121
122 Args:
123 selector: The element CSS selector.
124 """
125 logging.info("action: Hover %s" % selector)
126 element = self.driver.find_element_by_css_selector(selector)
127 hover = ActionChains(self.driver).move_to_element(element)
128 hover.perform()
129
130 def SendEnterTo(self, selector):
131 """Sends an enter key to an element.
132
133 Args:
134 selector: The element CSS selector.
135 """
136 logging.info("action: SendEnterTo %s" % selector)
137 body = self.driver.find_element_by_tag_name("body")
138 body.send_keys(Keys.ENTER)
139
140 # Waiting/Displaying actions.
141
142 def IsDisplayed(self, selector):
143 """Checks whether an element would be visible to the user: If it doesn't
vabr (Chromium) 2014/05/22 10:07:02 The "visible to the user" contradicts both "100% t
rchtara 2014/05/22 12:42:01 Done.
144 exist in the DOM or is 100% transparent True is returned. Otherwise, even
vabr (Chromium) 2014/05/22 10:07:02 You mentioned True twice. Did you mean "False" in
rchtara 2014/05/22 12:42:01 Done.
145 if it's covered by another element or it's out viewing area, True is
146 returned.
147
148 Args:
149 selector: The element CSS selector.
150
151 Returns:
152 True if the element is visible.
153 False otherwise.
154 """
155 logging.info("action: IsDisplayed %s" % selector)
156 try:
157 element = self.driver.find_element_by_css_selector(selector)
158 return element.is_displayed()
159 except Exception:
160 return False
161
162 def Wait(self, duration):
163 """Wait for a duration in seconds. This needs to be used in potentially
164 infinite loops, to limit their running time.
165
166 Args:
167 duration: The time to wait in seconds.
168 """
169 logging.info("action: Wait %s" % duration)
170 time.sleep(duration)
171 self.remaining_time_to_wait -= 1
172 if self.remaining_time_to_wait < 0:
173 raise Exception("Tests took more time than expected for the following "
174 "website : %s \n" % self.name)
175
176 def WaitUntilDisplayed(self, selector, timeout=10):
177 """Waits until an element is displayed.
178
179 Args:
180 selector: The element CSS selector.
181 timeout: The maximum waiting time in seconds before failing.
182 """
183 if not self.IsDisplayed(selector):
184 self.Wait(1)
185 timeout = timeout - 1
186 if (timeout <= 0):
187 raise Exception("Error: Element %s not shown before timeout is "
188 "finished for the following website: %s"
189 % (selector, self.name))
190 else:
191 self.WaitUntilDisplayed(selector, timeout)
192
193 # Form actions.
194
195 def FillPasswordInto(self, selector):
196 """If the testing mode is the Autofilled mode, compares the website
197 password to the DOM state.
198 If the testing mode is the NotAutofilled mode, checks that the DOM state
199 is empty.
200 Then, fills the input with the Website password.
201
202 Args:
203 selector: The password input CSS selector.
204
205 Raises:
206 Exception: An exception is raised if the DOM value of the password is
207 different than the one we expected.
208 """
209 logging.info("action: FillPasswordInto %s" % selector)
210
211 password_element = self.driver.find_element_by_css_selector(selector)
212 # Chrome protects the password inputs and doesn't fill them until
213 # the user interacts with the page. To be sure that such thing has
214 # happened we click on the password fields or one of its ancestors.
215 element = password_element
216 while True:
217 try:
218 element.click()
vabr (Chromium) 2014/05/22 10:07:02 Why don't you use ClickIfClickable? That would be
rchtara 2014/05/22 12:42:01 I don't used because ClickIfClickable because I ne
vabr (Chromium) 2014/05/22 13:39:24 Fair enough, let's keep it this way then.
rchtara 2014/05/22 15:20:56 Done.
219 break
220 except Exception:
221 try:
222 element = element.parent
223 except AttributeError:
224 raise Exception("Error: unable to find a clickable element to "
225 "release the password protection for the following website: %s \n"
226 % (self.name))
227
228 if self.mode == self.Mode.AUTOFILLED:
229 autofilled_password = password_element.get_attribute("value")
230 if autofilled_password != self.password:
231 raise Exception("Error: autofilled password is different from the one "
232 "we just saved for the following website : %s p1: %s "
233 "p2:%s \n" % (self.name,
234 password_element.get_attribute("value"),
235 self.password))
236
237 elif self.mode == self.Mode.NOT_AUTOFILLED:
238 autofilled_password = password_element.get_attribute("value")
239 if autofilled_password:
240 raise Exception("Error: password is autofilled when it shouldn't be "
241 "for the following website : %s \n"
242 % self.name)
243
244 password_element.send_keys(self.password)
245
246 def FillUsernameInto(self, selector):
247 """If the testing mode is the Autofilled mode, compares the website
248 username to the input value. Then, fills the input with the website
249 username.
250
251 Args:
252 selector: The username input CSS selector.
253
254 Raises:
255 Exception: An exception is raised if the DOM value of the username is
256 different that the one we expected.
257 """
258 logging.info("action: FillUsernameInto %s" % selector)
259 username_element = self.driver.find_element_by_css_selector(selector)
260
261 if (self.mode == self.Mode.AUTOFILLED and not self.username_not_auto):
262 if not (username_element.get_attribute("value") == self.username):
263 raise Exception("Error: autofilled username is different form the one "
264 "we just saved for the following website : %s \n" %
265 self.name)
266 else:
267 username_element.clear()
268 username_element.send_keys(self.username)
269
270 def Submit(self, selector):
271 """Finds an element using CSS Selector and calls its submit() handler.
272
273 Args:
274 selector: The input CSS selector.
275 """
276 logging.info("action: Submit %s" % selector)
277 element = self.driver.find_element_by_css_selector(selector)
278 element.submit()
279
280 # Login/Logout Methods
281
282 def Login(self):
283 """Login Method. Has to be overloaded by the WebsiteTest test."""
284 raise NotImplementedError("Login is not implemented.")
285
286 def LoginWhenAutofilled(self):
287 """Logs in and checks that the password is autofilled."""
288 self.mode = self.Mode.AUTOFILLED
289 self.Login()
290
291 def LoginWhenNotAutofilled(self):
292 """Logs in and checks that the password is not autofilled."""
293 self.mode = self.Mode.NOT_AUTOFILLED
294 self.Login()
295
296 def Logout(self):
297 """Logout Method. Has to be overloaded by the Website test."""
298 raise NotImplementedError("Logout is not implemented.")
299
300 # Tests
301
302 def WrongLoginTest(self):
303 """Does the wrong login test: Tries to login with a wrong password and
304 checks that the password is not saved.
305
306 Raises:
307 Exception: An exception is raised if the test fails: If there is a
308 problem when performing the login (ex: the login button is not
309 available ...), if the state of the username and password fields is
310 not like we expected or if the password is saved.
311 """
312 logging.info("\nWrong Login Test for %s \n" % self.name)
313 correct_password = self.password
314 self.password = self.password + "1"
315 self.LoginWhenNotAutofilled()
316 self.password = correct_password
317 self.Wait(2)
318 self.environment.SwitchToInternals()
319 self.environment.CheckPrompt(
320 "Message: Decision: SAVE the password",
321 False,
322 "Error: password manager thinks that a login with wrong password was "
323 "successful for the following website : %s \n" % self.name)
324 self.environment.SwitchFromInternals()
325
326 def SuccessfulLoginTest(self):
327 """Does the successful login when the password is not expected to be
328 autofilled test: Checks that the password is not autofilled, tries to login
329 with a right password and checks if the password is saved. Then logs out.
330
331 Raises:
332 Exception: An exception is raised if the test fails: If there is a
333 problem when performing the login and the logout (ex: the login
334 button is not available ...), if the state of the username and
335 password fields is not like we expected or if the password is not
336 saved.
337 """
338 logging.info("\nSuccessful Login Test for %s \n" % self.name)
339 self.LoginWhenNotAutofilled()
340 self.Wait(2)
341 self.environment.SwitchToInternals()
342 self.environment.CheckPrompt(
343 "Message: Decision: SAVE the password",
344 True,
345 "Error: password manager hasn't detected a successful login for the "
346 "following website : %s \n"
347 % self.name)
348 self.environment.SwitchFromInternals()
349 self.Logout()
350
351 def SuccessfulLoginWithAutofilledPasswordTest(self):
352 """Does the successful login when the password is expected to be autofilled
353 test: Checks that the password is autofilled, tries to login with a right
vabr (Chromium) 2014/05/22 10:07:02 nit: "a right" -> "the autofilled"
rchtara 2014/05/22 12:42:01 Done.
354 password and checks if the password is saved. Then logs out.
355
356 Raises:
357 Exception: An exception is raised if the test fails: If there is a
358 problem when performing the login and the logout (ex: the login
359 button is not available ...), if the state of the username and
360 password fields is not like we expected or if the password is not
361 saved.
362 """
363 logging.info("\nSuccessful Login With Autofilled Password"
364 " Test %s \n" % self.name)
365 self.LoginWhenAutofilled()
366 self.Wait(2)
367 self.environment.SwitchToInternals()
368 self.environment.CheckPrompt(
369 "Message: Decision: SAVE the password",
370 True,
371 "Error: password manager hasn't detected a successful login for the "
372 "following website : %s \n"
373 % self.name)
374 self.environment.SwitchFromInternals()
375 self.Logout()
376
377 def PromptTest(self):
378 """Does the prompt test: Tries to login with a wrong password and
379 checks that the prompt is not shown. Then tries to login with a right
380 password and checks that the prompt is not shown.
381
382 Raises:
383 Exception: An exception is raised if the test fails: If there is a
384 problem when performing the login (ex: the login button is not
385 available ...), if the state of the username and password fields is
386 not like we expected or if the prompt is not shown for the right
387 password or is shown for a wrong one.
388 """
389 logging.info("\nPrompt Test for %s \n" % self.name)
390 correct_password = self.password
391 self.password = self.password + "1"
392 self.LoginWhenNotAutofilled()
393 self.password = correct_password
394 self.Wait(2)
395 self.environment.SwitchToInternals()
396 self.environment.CheckPrompt(
397 "Message: Decision: ASK the user",
398 False,
399 "Error: password manager thinks that a login with wrong password was "
400 "successful for the following website : %s \n" % self.name)
401 self.environment.SwitchFromInternals()
402
403 self.LoginWhenNotAutofilled()
404 self.Wait(2)
405 self.environment.SwitchToInternals()
406 self.environment.CheckPrompt(
407 "Message: Decision: ASK the user",
408 True,
409 "Error: password manager thinks that a login with wrong password was "
410 "successful for the following website : %s \n" % self.name)
411 self.environment.SwitchFromInternals()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698