OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """PyAuto: Python Interface to Chromium's Automation Proxy. | 6 """PyAuto: Python Interface to Chromium's Automation Proxy. |
7 | 7 |
8 PyAuto uses swig to expose Automation Proxy interfaces to Python. | 8 PyAuto uses swig to expose Automation Proxy interfaces to Python. |
9 For complete documentation on the functionality available, | 9 For complete documentation on the functionality available, |
10 run pydoc on this file. | 10 run pydoc on this file. |
(...skipping 3200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3211 """ | 3211 """ |
3212 def _IsExtensionViewClosed(): | 3212 def _IsExtensionViewClosed(): |
3213 extension_views = self.GetBrowserInfo()['extension_views'] | 3213 extension_views = self.GetBrowserInfo()['extension_views'] |
3214 for extension_view in extension_views: | 3214 for extension_view in extension_views: |
3215 if view == extension_view['view']: | 3215 if view == extension_view['view']: |
3216 return False | 3216 return False |
3217 return True | 3217 return True |
3218 | 3218 |
3219 return self.WaitUntil(lambda: _IsExtensionViewClosed()) | 3219 return self.WaitUntil(lambda: _IsExtensionViewClosed()) |
3220 | 3220 |
3221 def FillAutofillProfile(self, profiles=None, credit_cards=None, | |
3222 tab_index=0, window_index=0): | |
3223 """Set the autofill profile to contain the given profiles and credit cards. | |
3224 | |
3225 If profiles or credit_cards are specified, they will overwrite existing | |
3226 profiles and credit cards. To update profiles and credit cards, get the | |
3227 existing ones with the GetAutofillProfile function and then append new | |
3228 profiles to the list and call this function. | |
3229 | |
3230 Autofill profiles (not credit cards) support multiple values for some of the | |
3231 fields. To account for this, all values in a profile must be specified as | |
3232 a list of strings. If a form field only has a single value associated with | |
3233 it, that value must still be specified as a list containing a single string. | |
3234 | |
3235 Args: | |
3236 profiles: (optional) a list of dictionaries representing each profile to | |
3237 add. Example: | |
3238 [{ | |
3239 'NAME_FIRST': ['Bob',], | |
3240 'NAME_LAST': ['Smith',], | |
3241 'ADDRESS_HOME_ZIP': ['94043',], | |
3242 }, | |
3243 { | |
3244 'EMAIL_ADDRESS': ['sue@example.com',], | |
3245 'COMPANY_NAME': ['Company X',], | |
3246 }] | |
3247 | |
3248 Other possible keys are: | |
3249 'NAME_FIRST', 'NAME_MIDDLE', 'NAME_LAST', 'EMAIL_ADDRESS', | |
3250 'COMPANY_NAME', 'ADDRESS_HOME_LINE1', 'ADDRESS_HOME_LINE2', | |
3251 'ADDRESS_HOME_CITY', 'ADDRESS_HOME_STATE', 'ADDRESS_HOME_ZIP', | |
3252 'ADDRESS_HOME_COUNTRY', 'PHONE_HOME_WHOLE_NUMBER' | |
3253 | |
3254 credit_cards: (optional) a list of dictionaries representing each credit | |
3255 card to add. Example: | |
3256 [{ | |
3257 'CREDIT_CARD_NAME': 'Bob C. Smith', | |
3258 'CREDIT_CARD_NUMBER': '5555555555554444', | |
3259 'CREDIT_CARD_EXP_MONTH': '12', | |
3260 'CREDIT_CARD_EXP_4_DIGIT_YEAR': '2011' | |
3261 }, | |
3262 { | |
3263 'CREDIT_CARD_NAME': 'Bob C. Smith', | |
3264 'CREDIT_CARD_NUMBER': '4111111111111111', | |
3265 'CREDIT_CARD_TYPE': 'Visa' | |
3266 } | |
3267 | |
3268 Other possible keys are: | |
3269 'CREDIT_CARD_NAME', 'CREDIT_CARD_NUMBER', 'CREDIT_CARD_EXP_MONTH', | |
3270 'CREDIT_CARD_EXP_4_DIGIT_YEAR' | |
3271 | |
3272 All values must be strings. | |
3273 | |
3274 tab_index: tab index, defaults to 0. | |
3275 | |
3276 window_index: window index, defaults to 0. | |
3277 | |
3278 Raises: | |
3279 pyauto_errors.JSONInterfaceError if the automation call returns an error. | |
3280 """ | |
3281 cmd_dict = { # Prepare command for the json interface | |
3282 'command': 'FillAutofillProfile', | |
3283 'tab_index': tab_index, | |
3284 'profiles': profiles, | |
3285 'credit_cards': credit_cards | |
3286 } | |
3287 self._GetResultFromJSONRequest(cmd_dict, windex=window_index) | |
3288 | |
3289 def GetAutofillProfile(self, tab_index=0, window_index=0): | |
3290 """Returns all autofill profile and credit card information. | |
3291 | |
3292 The format of the returned dictionary is described above in | |
3293 FillAutofillProfile. The general format is: | |
3294 {'profiles': [list of profile dictionaries as described above], | |
3295 'credit_cards': [list of credit card dictionaries as described above]} | |
3296 | |
3297 Args: | |
3298 tab_index: tab index, defaults to 0. | |
3299 window_index: window index, defaults to 0. | |
3300 | |
3301 Raises: | |
3302 pyauto_errors.JSONInterfaceError if the automation call returns an error. | |
3303 """ | |
3304 cmd_dict = { # Prepare command for the json interface | |
3305 'command': 'GetAutofillProfile', | |
3306 'tab_index': tab_index | |
3307 } | |
3308 return self._GetResultFromJSONRequest(cmd_dict, windex=window_index) | |
3309 | |
3310 def SubmitAutofillForm(self, js, frame_xpath='', tab_index=0, windex=0): | |
3311 """Submits a webpage autofill form and waits for autofill to be updated. | |
3312 | |
3313 This function should be called when submitting autofill profiles via | |
3314 webpage forms. It waits until the autofill data has been updated internally | |
3315 before returning. | |
3316 | |
3317 Args: | |
3318 js: The string Javascript code that can be injected into the given webpage | |
3319 to submit an autofill form. This Javascript MUST submit the form. | |
3320 frame_xpath: The string xpath for the frame in which to inject javascript. | |
3321 tab_index: Integer index of the tab to work on; defaults to 0 (first tab). | |
3322 windex: Integer index of the browser window to use; defaults to 0 | |
3323 (first window). | |
3324 """ | |
3325 cmd_dict = { # Prepare command for the json interface. | |
3326 'command': 'SubmitAutofillForm', | |
3327 'javascript': js, | |
3328 'frame_xpath': frame_xpath, | |
3329 'tab_index': tab_index, | |
3330 } | |
3331 self._GetResultFromJSONRequest(cmd_dict, windex=windex) | |
3332 | |
3333 def AutofillTriggerSuggestions(self, field_id=None, tab_index=0, windex=0): | |
3334 """Focuses a webpage form field and triggers the autofill popup in it. | |
3335 | |
3336 This function focuses the specified input field in a webpage form, then | |
3337 causes the autofill popup to appear in that field. The underlying | |
3338 automation hook sends a "down arrow" keypress event to trigger the autofill | |
3339 popup. This function waits until the popup is displayed before returning. | |
3340 | |
3341 Args: | |
3342 field_id: The string ID of the webpage form field to focus. Can be | |
3343 'None' (the default), in which case nothing is focused. This | |
3344 can be useful if the field has already been focused by other | |
3345 means. | |
3346 tab_index: Integer index of the tab to work on; defaults to 0 (first tab). | |
3347 windex: Integer index of the browser window to work on; defaults to 0 | |
3348 (first window). | |
3349 | |
3350 Returns: | |
3351 True, if no errors were encountered, or False otherwise. | |
3352 | |
3353 Raises: | |
3354 pyauto_errors.JSONInterfaceError if the automation call returns an error. | |
3355 """ | |
3356 # Focus the field with the specified ID, if necessary. | |
3357 if field_id: | |
3358 if not self.JavascriptFocusElementById(field_id, tab_index, windex): | |
3359 return False | |
3360 | |
3361 # Cause the autofill popup to be shown in the focused form field. | |
3362 cmd_dict = { | |
3363 'command': 'AutofillTriggerSuggestions', | |
3364 'tab_index': tab_index, | |
3365 } | |
3366 self._GetResultFromJSONRequest(cmd_dict, windex=windex) | |
3367 return True | |
3368 | |
3369 def AutofillHighlightSuggestion(self, direction, tab_index=0, windex=0): | |
3370 """Highlights the previous or next suggestion in an existing autofill popup. | |
3371 | |
3372 This function assumes that an existing autofill popup is currently displayed | |
3373 in a webpage form. The underlying automation hook sends either a | |
3374 "down arrow" or an "up arrow" keypress event to cause the next or previous | |
3375 suggestion to be highlighted, respectively. This function waits until | |
3376 autofill displays a preview of the form's filled state before returning. | |
3377 | |
3378 Use AutofillTriggerSuggestions() to trigger the autofill popup before | |
3379 calling this function. Use AutofillAcceptSelection() after calling this | |
3380 function to accept a selection. | |
3381 | |
3382 Args: | |
3383 direction: The string direction in which to highlight an autofill | |
3384 suggestion. Must be either "up" or "down". | |
3385 tab_index: Integer index of the tab to work on; defaults to 0 (first tab). | |
3386 windex: Integer index of the browser window to work on; defaults to 0 | |
3387 (first window). | |
3388 | |
3389 Raises: | |
3390 pyauto_errors.JSONInterfaceError if the automation call returns an error. | |
3391 """ | |
3392 assert direction in ('up', 'down') | |
3393 cmd_dict = { | |
3394 'command': 'AutofillHighlightSuggestion', | |
3395 'direction': direction, | |
3396 'tab_index': tab_index, | |
3397 } | |
3398 self._GetResultFromJSONRequest(cmd_dict, windex=windex) | |
3399 | |
3400 def AutofillAcceptSelection(self, tab_index=0, windex=0): | |
3401 """Accepts the current selection in an already-displayed autofill popup. | |
3402 | |
3403 This function assumes that a profile is already highlighted in an existing | |
3404 autofill popup in a webpage form. The underlying automation hook sends a | |
3405 "return" keypress event to cause the highlighted profile to be accepted. | |
3406 This function waits for the webpage form to be filled in with autofill data | |
3407 before returning. This function does not submit the webpage form. | |
3408 | |
3409 Raises: | |
3410 pyauto_errors.JSONInterfaceError if the automation call returns an error. | |
3411 """ | |
3412 cmd_dict = { | |
3413 'command': 'AutofillAcceptSelection', | |
3414 'tab_index': tab_index, | |
3415 } | |
3416 self._GetResultFromJSONRequest(cmd_dict, windex=windex) | |
3417 | |
3418 def AutofillPopulateForm(self, field_id, profile_index=0, tab_index=0, | |
3419 windex=0): | |
3420 """Populates a webpage form using autofill data and keypress events. | |
3421 | |
3422 This function focuses the specified input field in the form, and then | |
3423 sends keypress events to the associated tab to cause the form to be | |
3424 populated with information from the requested autofill profile. | |
3425 | |
3426 Args: | |
3427 field_id: The string ID of the webpage form field to focus for autofill | |
3428 purposes. | |
3429 profile_index: The index of the profile in the autofill popup to use to | |
3430 populate the form; defaults to 0 (first profile). | |
3431 tab_index: Integer index of the tab to work on; defaults to 0 (first tab). | |
3432 windex: Integer index of the browser window to work on; defaults to 0 | |
3433 (first window). | |
3434 | |
3435 Returns: | |
3436 True, if the webpage form is populated successfully, or False if not. | |
3437 | |
3438 Raises: | |
3439 pyauto_errors.JSONInterfaceError if an automation call returns an error. | |
3440 """ | |
3441 if not self.AutofillTriggerSuggestions(field_id, tab_index, windex): | |
3442 return False | |
3443 | |
3444 for _ in range(profile_index + 1): | |
3445 self.AutofillHighlightSuggestion('down', tab_index, windex) | |
3446 | |
3447 self.AutofillAcceptSelection(tab_index, windex) | |
3448 return True | |
3449 | |
3450 def AddHistoryItem(self, item): | 3221 def AddHistoryItem(self, item): |
3451 """Forge a history item for Chrome. | 3222 """Forge a history item for Chrome. |
3452 | 3223 |
3453 Args: | 3224 Args: |
3454 item: a python dictionary representing the history item. Example: | 3225 item: a python dictionary representing the history item. Example: |
3455 { | 3226 { |
3456 # URL is the only mandatory item. | 3227 # URL is the only mandatory item. |
3457 'url': 'http://news.google.com', | 3228 'url': 'http://news.google.com', |
3458 # Title is optional. | 3229 # Title is optional. |
3459 'title': 'Google News', | 3230 'title': 'Google News', |
(...skipping 840 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4300 windex: index of the window. | 4071 windex: index of the window. |
4301 | 4072 |
4302 Returns: | 4073 Returns: |
4303 a string that was sent back via the domAutomationController.send method | 4074 a string that was sent back via the domAutomationController.send method |
4304 """ | 4075 """ |
4305 converted_args = map(lambda arg: json.dumps(arg), args) | 4076 converted_args = map(lambda arg: json.dumps(arg), args) |
4306 js = '%s(%s)' % (function, ', '.join(converted_args)) | 4077 js = '%s(%s)' % (function, ', '.join(converted_args)) |
4307 logging.debug('Executing javascript: %s', js) | 4078 logging.debug('Executing javascript: %s', js) |
4308 return self.ExecuteJavascript(js, tab_index, windex) | 4079 return self.ExecuteJavascript(js, tab_index, windex) |
4309 | 4080 |
4310 def JavascriptFocusElementById(self, field_id, tab_index=0, windex=0): | |
4311 """Uses Javascript to focus an element with the given ID in a webpage. | |
4312 | |
4313 Args: | |
4314 field_id: The string ID of the webpage form field to focus. | |
4315 tab_index: Integer index of the tab to work on; defaults to 0 (first tab). | |
4316 windex: Integer index of the browser window to work on; defaults to 0 | |
4317 (first window). | |
4318 | |
4319 Returns: | |
4320 True, on success, or False on failure. | |
4321 """ | |
4322 focus_field_js = """ | |
4323 var field = document.getElementById("%s"); | |
4324 if (!field) { | |
4325 window.domAutomationController.send("error"); | |
4326 } else { | |
4327 field.focus(); | |
4328 window.domAutomationController.send("done"); | |
4329 } | |
4330 """ % field_id | |
4331 return self.ExecuteJavascript(focus_field_js, tab_index, windex) == 'done' | |
4332 | |
4333 def SignInToSync(self, username, password): | 4081 def SignInToSync(self, username, password): |
4334 """Signs in to sync using the given username and password. | 4082 """Signs in to sync using the given username and password. |
4335 | 4083 |
4336 Args: | 4084 Args: |
4337 username: The account with which to sign in. Example: "user@gmail.com". | 4085 username: The account with which to sign in. Example: "user@gmail.com". |
4338 password: Password for the above account. Example: "pa$$w0rd". | 4086 password: Password for the above account. Example: "pa$$w0rd". |
4339 | 4087 |
4340 Returns: | 4088 Returns: |
4341 True, on success. | 4089 True, on success. |
4342 | 4090 |
(...skipping 2659 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7002 successful = result.wasSuccessful() | 6750 successful = result.wasSuccessful() |
7003 if not successful: | 6751 if not successful: |
7004 pyauto_tests_file = os.path.join(self.TestsDir(), self._tests_filename) | 6752 pyauto_tests_file = os.path.join(self.TestsDir(), self._tests_filename) |
7005 print >>sys.stderr, 'Tests can be disabled by editing %s. ' \ | 6753 print >>sys.stderr, 'Tests can be disabled by editing %s. ' \ |
7006 'Ref: %s' % (pyauto_tests_file, _PYAUTO_DOC_URL) | 6754 'Ref: %s' % (pyauto_tests_file, _PYAUTO_DOC_URL) |
7007 sys.exit(not successful) | 6755 sys.exit(not successful) |
7008 | 6756 |
7009 | 6757 |
7010 if __name__ == '__main__': | 6758 if __name__ == '__main__': |
7011 Main() | 6759 Main() |
OLD | NEW |