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

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

Powered by Google App Engine
This is Rietveld 408576698