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

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

Issue 273523004: Password Manager testing automation (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: log 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 """Website testing class."""
2
3
4 import time
5
6 from selenium.common.exceptions import ElementNotVisibleException
7 from selenium.common.exceptions import NoSuchElementException
8 from selenium.common.exceptions import StaleElementReferenceException
9 from selenium.webdriver.common.action_chains import ActionChains
10 from selenium.webdriver.common.keys import Keys
11
12
13 def _IsOneSubstringOfAnother(s1, s2):
vabr (Chromium) 2014/05/16 09:36:00 Please add a doc string, explaining what this func
rchtara 2014/05/20 08:24:47 Done.
14 return s1 in s2 or s2 in s1
15
16
17 class Website:
18 """Handles a tested Website."""
19
20 class Mode:
21 """Test mode."""
22 # Password and username are expected to be autofilled.
23 Autofilled = 1
vabr (Chromium) 2014/05/16 09:36:00 Please use all caps for consistency with the C++ e
rchtara 2014/05/20 08:24:47 Done.
24 # Password and username are not expected to be autofilled.
25 NotAutofilled = 2
26
27 def __init__(self):
28 pass
29
30 def __init__(
31 self, name, url, username=None, password=None,
vabr (Chromium) 2014/05/16 09:36:00 Please remove |url|. You don't seem to use it, and
vabr (Chromium) 2014/05/16 09:36:00 Are you actually using the username and password a
rchtara 2014/05/20 08:24:47 Yes, I use them to sign in
rchtara 2014/05/20 08:24:47 Done.
vabr (Chromium) 2014/05/20 14:47:25 But you don't seem to use the __init__ arguments u
32 username_not_auto=False):
33 """Creates a new Website.
34
35 Args:
36 name: The Website name.
37 url: The Website URL.
38 username: The Website username. If it's None, the username is going to be
39 replaced by the value in the usernames and passwords file.
40 password: The Website password. If it's None, the password is going to be
41 replaced by the value in the usernames and passwords file.
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 # URL of the Website
51 self.url = url
52 # Username of the Website.
53 self.username = username
54 # Password of the Website.
55 self.password = password
56 # Username is not automatically filled.
57 self.username_not_auto = username_not_auto
vabr (Chromium) 2014/05/16 09:36:00 For pages like Wikipedia, where the username is no
rchtara 2014/05/20 08:24:47 username_not_auto affects only the username, but t
vabr (Chromium) 2014/05/20 14:47:25 You are correct, thanks for explanation.
rchtara 2014/05/22 08:44:38 you re welcome :)
58 # Autofilling mode.
59 self.mode = self.Mode.NotAutofilled
60 # Waiting duration before stopping the test.
vabr (Chromium) 2014/05/16 09:36:00 Note: max_duration limits the total time spent in
rchtara 2014/05/20 08:24:47 Done.
61 self.max_duration = 200
62 # The testing Environment.
63 self.environment = None
64 # The webdriver.
65 self.driver = None
66
67 # Mouse/Keyboard actions.
68
69 def Click(self, selector):
70 """Clicks on an element.
71
72 Args:
73 selector: The element CSS selector.
74 """
75 self.environment.Log("action: Click %s" % selector)
76 element = self.driver.find_element_by_css_selector(selector)
77 element.click()
78
79 def ClickIfVisible(self, selector):
80 """Clicks on an element, if it's available.
vabr (Chromium) 2014/05/16 09:36:00 So, is this about visibility, or availability? If
rchtara 2014/05/20 08:24:47 Done.
81
82 Args:
83 selector: The element CSS selector.
84 """
85 self.environment.Log("action: ClickIfVisible %s" % selector)
86 try:
87 element = self.driver.find_element_by_css_selector(selector)
88 element.click()
89 except NoSuchElementException:
90 return False
vabr (Chromium) 2014/05/16 09:36:00 The method returns False if the element is not cli
rchtara 2014/05/20 08:24:47 Done.
91 except StaleElementReferenceException:
92 return False
93
94 def GoTo(self, url):
95 """Navigates the main frame to a url.
vabr (Chromium) 2014/05/16 09:36:00 nit: "a url" -> "|url|" (It does not navigate to j
rchtara 2014/05/20 08:24:47 Done.
96
97 Args:
98 url: The URL.
99 """
100 self.environment.Log("action: GoTo %s" % self.url)
101 self.driver.get(url)
102
103 def HoverOver(self, selector):
104 """Hovers over an element.
105
106 Args:
107 selector: The element CSS selector.
108 """
109 self.environment.Log("action: Hover %s" % selector)
110 element = self.driver.find_element_by_css_selector(selector)
111 hover = ActionChains(self.driver).move_to_element(element)
112 hover.perform()
113
114 def SendEnterTo(self, selector):
115 """Sends an enter key to an element.
116
117 Args:
118 selector: The element CSS selector.
119 """
120 self.environment.Log("action: SendEnterTo %s" % selector)
121 body = self.driver.find_element_by_tag_name("body")
122 body.send_keys(Keys.ENTER)
123
124 # Waiting/Displaying actions.
125
126 def IsDisplayed(self, selector):
127 """Checks if an element is displayed.
128
129 Args:
130 selector: The element CSS selector.
131 """
132 self.environment.Log("action: IsDisplayed %s" % selector)
133 try:
134 element = self.driver.find_element_by_css_selector(selector)
135 return element.is_displayed()
136 except NoSuchElementException:
137 return False
138 except StaleElementReferenceException:
139 return False
140
141 def Wait(self, duration):
142 """Wait for a duration.
vabr (Chromium) 2014/05/16 09:36:00 Please specify time units.
rchtara 2014/05/20 08:24:47 Done.
143
144 Args:
145 duration: The element.
146 """
147 self.environment.Log("action: Wait %s" % duration)
148 time.sleep(duration)
149 self.max_duration -= 1
150 if self.max_duration < 0:
151 raise Exception("Tests took more time than expected for the following "
152 "website : %s \n" % self.name)
153
154 def WaitUntilDisplayed(self, selector, timeout=10):
155 """Waits until an element is displayed.
156
157 Args:
158 selector: The element CSS selector.
159 """
160 if not self.IsDisplayed(selector):
161 time.sleep(1)
vabr (Chromium) 2014/05/16 09:36:00 Please call Wait() instead of manually decrementin
rchtara 2014/05/20 08:24:47 Done.
162 timeout = timeout - 1
163 if (timeout <= 0):
164 raise Exception("Error: Element %s not shown before timeout is "
165 "finished for the following website: %s"
166 % (selector, self.name))
167 else:
168 self.WaitUntilDisplayed(selector, timeout)
169 self.max_duration -= 1
170 if self.max_duration < 0:
171 raise Exception("Tests took more time than expected for the "
172 "following website : %s \n" % self.name)
173
174 # Form actions.
175
176 def FillPasswordInto(self, selector):
177 """If the testing mode is the Autofilled mode, compares the Website
178 password to the DOM state.
179 If the testing mode is the NotAutofilled mode, checks that the DOM state
180 is empty.
181 Then, fills the input with the Website password.
182
183 Args:
184 selector: The password input CSS selector.
185
186 Raises:
187 Exception: An exception is raised if the DOM value of the password is
188 different that the one we expected.
189 """
190 self.environment.Log("action: FillPasswordInto %s" % selector)
191 password_element = self.driver.find_element_by_css_selector(selector)
192 if self.mode == self.Mode.Autofilled:
193 # Chrome protects the password inputs and doesn't fill them until
194 # the user interacts with the page. To guarantee that, we just
195 # send a key to the password input. Clicking on the password input was
196 # tried too, but because the password is sometimes hidden, this didn't
vabr (Chromium) 2014/05/16 09:36:00 I'm not sure I understand the issue here -- if the
rchtara 2014/05/20 08:24:47 In www.163.com, we the driver fills the username w
197 # worked out.
vabr (Chromium) 2014/05/16 09:36:00 nit: worked -> work
rchtara 2014/05/20 08:24:47 Done.
198 password_element.send_keys("a")
199 ps = password_element.get_attribute("value")[:-1]
vabr (Chromium) 2014/05/16 09:36:00 Pleas do not use cryptic abbreviations as names of
rchtara 2014/05/20 08:24:47 Done.
200 password_element.clear()
201 password_element.send_keys(ps)
202 if password_element.get_attribute("value") != self.password:
203 raise Exception("Error: autofilled password is different from the one "
204 "we just saved for the following website : %s p1: %s "
205 "p2:%s \n" % (self.name,
206 password_element.get_attribute("value"),
vabr (Chromium) 2014/05/16 09:36:00 nit: indenting is off
rchtara 2014/05/20 08:24:47 Done.
207 self.password))
208 elif self.mode == self.Mode.NotAutofilled:
209 # Chrome protects the password inputs and doesn't fill them until
210 # the user interacts with the page. To guarantee that, we just
211 # send a key to the password input. Clicking on the password input was
212 # tried too, but because the password is sometimes hidden, this didn't
213 # worked out.
214 password_element.send_keys("a")
215 ps = password_element.get_attribute("value")[1:]
vabr (Chromium) 2014/05/16 09:36:00 Again, please rename |ps| appropriately.
rchtara 2014/05/20 08:24:47 Done.
216 password_element.clear()
217 password_element.send_keys(ps)
vabr (Chromium) 2014/05/16 09:36:00 Why do you send |ps| to password_element here, and
rchtara 2014/05/20 08:24:47 I' m going to replace all this by a click on the u
218 if ps:
219 raise Exception("Error: password is autofilled when it shouldn't be "
220 "for the following website : %s \n"
221 % self.name)
222
223 # Chrome protects the password inputs and doesn't fill them until
224 # the user interacts with the page. To guarantee that, we just
225 # send a key to the password. Clicking on the password input was tried
226 # too, but because the password is sometime hidden, this didn't worked
227 # out.
228 password_element.send_keys("a")
229 password_element.clear()
230 password_element.send_keys(self.password)
231
232 def FillUsernameInto(self, selector):
vabr (Chromium) 2014/05/16 09:36:00 In the concrete Websites, FillUsernameInto and Fil
rchtara 2014/05/20 08:24:47 I think it's more flexible to keep it as it's now.
vabr (Chromium) 2014/05/20 14:47:25 Fair enough, let's keep them separate.
rchtara 2014/05/22 08:44:38 Done.
233 """If the testing mode is the Autofilled mode, compares the Website username
234 to the input value.
235 Then, fills the input with the Website username.
236
237 Args:
238 selector: The username input CSS selector.
239
240 Raises:
241 Exception: An exception is raised if the DOM value of the username is
242 different that the one we expected.
243 """
244 self.environment.Log("action: FillUsernameInto %s" % selector)
245 username_element = self.driver.find_element_by_css_selector(selector)
246
247 if (self.mode == self.Mode.Autofilled and not self.username_not_auto):
248 if not (username_element.get_attribute("value") == self.username):
249 raise Exception("Error: autofilled username is different form the one "
250 "we just saved for the following website : %s \n" %
251 self.name)
252
253 else:
254 username_element.clear()
vabr (Chromium) 2014/05/16 09:36:00 Should you check that either self.username_not_aut
rchtara 2014/05/20 08:24:47 I don't think it's important it important to do so
vabr (Chromium) 2014/05/20 14:47:25 Ah right, that's a good point, I forgot about the
rchtara 2014/05/22 08:44:38 You re welcome
255 username_element.send_keys(self.username)
256
257 def FillUsernameIfVisible(self, selector):
258 """Fills the input with the website username, if the input exists.
vabr (Chromium) 2014/05/16 09:36:00 Please comment on ignoring self.mode here.
rchtara 2014/05/20 08:24:47 I removed the method, not needed
259
260 Args:
261 selector: The username input CSS selector.
262 """
263 self.environment.Log("action: FillUsernameIfVisible %s" % selector)
264 username_element = self.driver.find_element_by_css_selector(selector)
265 try:
266 username_element.clear()
267 username_element.send_keys(self.username)
268 except ElementNotVisibleException:
269 pass
270
271 def Submit(self, selector):
272 """Finds an element using CSS Selector and calls its submit() handler.
273
274 Args:
275 selector: The input CSS selector.
276 """
277 self.environment.Log("action: Submit %s" % selector)
278 element = self.driver.find_element_by_css_selector(selector)
279 element.submit()
280
281 # Login/Logout Methods
282
283 def Login(self):
284 """Login Method. Has to be overloaded by the Website test."""
285 raise NotImplementedError("Login is not implemented.")
286
287 def LoginWhenAutofilled(self):
288 """Logs in and checks that the password is autofilled."""
289 self.mode = self.Mode.Autofilled
290 self.Login()
291
292 def LoginWhenNotAutofilled(self):
293 """Logs in and checks that the password is not autofilled."""
294 self.mode = self.Mode.NotAutofilled
295 self.Login()
296
297 def Logout(self):
298 """Logout Method. Has to be overloaded by the Website test."""
299 raise NotImplementedError("Logout is not implemented.")
300
301 # TestsTools
302
303 def RemoveAllPasswords(self, urls):
rchtara 2014/05/20 08:24:47 Function removed
304 """Removes all the saved passwords for the current Website.
305
306 Args:
307 urls: All the available URLs in the saved passwords list.
308 """
309 if (self.url != ""):
vabr (Chromium) 2014/05/16 09:36:00 nit: Just use if self.url:
rchtara 2014/05/20 08:24:47 Done.
310 i = 0
311 for current_url in urls:
312 if _IsOneSubstringOfAnother(current_url, self.url):
313 self.driver.execute_script(
vabr (Chromium) 2014/05/16 09:36:00 Please comment on what the script does. In particu
rchtara 2014/05/20 08:24:47 Done.
314 "document.querySelectorAll('#saved-passwords-list "
315 ".row-delete-button')[%d].click()" % i)
vabr (Chromium) 2014/05/16 09:36:00 Actually, I don't think you use |i| correctly here
rchtara 2014/05/20 08:24:47 we get a fresh copy of |urls|, after each deletion
vabr (Chromium) 2014/05/20 14:47:25 Ah, that makes sense, thanks for your explanation.
316 time.sleep(1) # Wait until command is executed.
vabr (Chromium) 2014/05/16 09:36:00 Please use Wait().
rchtara 2014/05/20 08:24:47 Done.
317 else:
318 i = i + 1
319
320
321 # Tests
322
323 def WrongLoginTest(self):
324 """Does the wrong login test: Tries to login with a wrong password and
325 checks that the prompt is not shown.
326
327 Raises:
328 Exception: An exception is raised if the tests fail.
329 """
330 self.environment.Log("\nWrong Login Test for %s \n" % self.name)
331 correct_password = self.password
332 self.password = self.password + "1"
333 self.LoginWhenNotAutofilled()
334 self.password = correct_password
vabr (Chromium) 2014/05/16 09:36:00 Why do you not Wait() here, but you do wait at the
rchtara 2014/05/20 08:24:47 Done.
335 self.environment.SwitchToInternals()
336 self.environment.CheckPromptIsNotShown(
337 False,
338 "Error: password manager thinks that a login with wrong password was "
339 "successful for the following website : %s \n" % self.name)
340 self.environment.SwitchFromInternals()
341
342 def SuccessfulLoginTest(self):
343 """Does the successful login when the password is not expected to be
344 autofilled test: Checks that the password is not autofilled, tries to login
345 with a right password and checks if the that the prompt is shown. Then logs
346 out.
347
348 Raises:
349 Exception: An exception is raised if the tests fail.
350 """
351 self.environment.Log("\nSuccessful Login Test for %s \n" % self.name)
352 self.LoginWhenNotAutofilled()
353 time.sleep(2)
vabr (Chromium) 2014/05/16 09:36:00 Please use Wait().
rchtara 2014/05/20 08:24:47 Done.
354 self.environment.SwitchToInternals()
355 self.environment.CheckPromptIsNotShown(True,
356 "Error: password manager hasn't detected a successful login for the "
357 "following website : %s \n"
358 % self.name)
359 self.environment.SwitchFromInternals()
360 self.Logout()
361
362 def SuccessfulLoginWithAutofilledPasswordTest(self):
363 """Does the successful login when the password is expected to be autofilled
364 test: Checks that the password is autofilled, tries to login with a right
365 password and checks if the that the prompt is shown. Then logs out.
366
367 Raises:
368 Exception: An exception is raised if the tests fail.
369 """
370 self.environment.Log("\nSuccessful Login With Autofilled Password"
371 " Test %s \n" % self.name)
372 self.LoginWhenAutofilled()
373 time.sleep(2)
vabr (Chromium) 2014/05/16 09:36:00 Please use Wait().
rchtara 2014/05/20 08:24:47 Done.
374 self.environment.SwitchToInternals()
375 self.environment.CheckPromptIsNotShown(True,
376 "Error: password manager hasn't detected a successful login for the "
377 "following website : %s \n"
378 % self.name)
379 self.environment.SwitchFromInternals()
380 self.Logout()
381
382 def SuccessfulLoginAfterDeletionTest(self):
vabr (Chromium) 2014/05/16 09:36:00 This does exactly the same thing as SuccessfulLogi
rchtara 2014/05/20 08:24:47 Done.
383 """Does the successful login after the deletion of the password test: Checks
384 that the password is not autofilled, tries to login with a right password
385 and checks if the that the prompt is shown. Then logs out.
386
387 Raises:
388 Exception: An exception is raised if the tests fail.
389 """
390 self.environment.Log("\nSuccessful Login After Deletion Test"
391 " for %s \n" % self.name)
392 self.LoginWhenNotAutofilled()
393 self.environment.SwitchToInternals()
394 self.environment.CheckPromptIsNotShown(
395 True,
396 "Error: password manager hasn't detected a successful login for the "
397 "following website : %s \n" % self.name)
398 self.environment.SwitchFromInternals()
399 self.Logout()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698