diff options
author | dennisjeffrey@chromium.org <dennisjeffrey@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-10 16:28:10 +0000 |
---|---|---|
committer | dennisjeffrey@chromium.org <dennisjeffrey@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-10 16:28:10 +0000 |
commit | 535773382e9f47db97d83bcbe34cb4b89405cfba (patch) | |
tree | 3b4ed48a23562643ee94ef72505c1364c5e2eb7c /chrome/test | |
parent | 2136da4abd2aa67873010ee3a3294d7fdf1d2fe8 (diff) | |
download | chromium_src-535773382e9f47db97d83bcbe34cb4b89405cfba.zip chromium_src-535773382e9f47db97d83bcbe34cb4b89405cfba.tar.gz chromium_src-535773382e9f47db97d83bcbe34cb4b89405cfba.tar.bz2 |
Fix for pyauto autofill flakiness when sending key events to populate a form.
This change should eliminate flakiness in a few pyauto autofill tests,
which are now re-enabled.
BUG=80190,80336
TEST=None
Review URL: http://codereview.chromium.org/6929052
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@84791 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/test')
-rw-r--r-- | chrome/test/functional/PYAUTO_TESTS | 6 | ||||
-rw-r--r-- | chrome/test/functional/autofill.py | 37 | ||||
-rw-r--r-- | chrome/test/pyautolib/pyauto.py | 158 | ||||
-rw-r--r-- | chrome/test/pyautolib/pyautolib.h | 2 |
4 files changed, 155 insertions, 48 deletions
diff --git a/chrome/test/functional/PYAUTO_TESTS b/chrome/test/functional/PYAUTO_TESTS index 2f6c94d..f106e29 100644 --- a/chrome/test/functional/PYAUTO_TESTS +++ b/chrome/test/functional/PYAUTO_TESTS @@ -28,14 +28,8 @@ 'CONTINUOUS': { 'all': [ 'autofill', - '-autofill.AutofillTest.testComparePhoneNumbers', - '-autofill.AutofillTest.testNoAutofillForReadOnlyFields', # crbug.com/77113 - M13 feature. '-autofill.AutofillTest.testProfileWithEmailInOtherFieldNotSaved', - # crbug.com/80190 - '-autofill.AutofillTest.testDistinguishMiddleInitialWithinName', - '-autofill.AutofillTest.testFormFillableOnReset', - '-autofill.AutofillTest.testMultipleEmailFilledByOneUserGesture', # crbug.com/81271 '-autofill.AutofillTest.testMergeAggregatedProfilesWithSameAddress', '-autofill.AutofillTest.testProfilesNotMergedWhenNoMinAddressData', diff --git a/chrome/test/functional/autofill.py b/chrome/test/functional/autofill.py index 59f27d0..e9cc444 100644 --- a/chrome/test/functional/autofill.py +++ b/chrome/test/functional/autofill.py @@ -279,22 +279,6 @@ class AutofillTest(pyauto.PyUITest): self.assertFalse(self.GetAutofillProfile()['profiles'], msg='Profile with invalid email was aggregated.') - def _SendKeyEventsToPopulateForm(self, tab_index=0, windex=0): - """Send key events to populate a web form with Autofill profile data. - - Args: - tab_index: The tab index, default is 0. - windex: The window index, default is 0. - """ - TAB_KEYPRESS = 0x09 # Tab keyboard key press. - DOWN_KEYPRESS = 0x28 # Down arrow keyboard key press. - RETURN_KEYPRESS = 0x0D # Return keyboard key press. - - self.SendWebkitKeypressEvent(TAB_KEYPRESS, tab_index, windex) - self.SendWebkitKeypressEvent(DOWN_KEYPRESS, tab_index, windex) - self.SendWebkitKeypressEvent(DOWN_KEYPRESS, tab_index, windex) - self.SendWebkitKeypressEvent(RETURN_KEYPRESS, tab_index, windex) - def testComparePhoneNumbers(self): """Test phone fields parse correctly from a given profile. @@ -314,7 +298,8 @@ class AutofillTest(pyauto.PyUITest): os.path.join('autofill', 'functional', 'form_phones.html')) for profile_expected in profiles_expected: self.NavigateToURL(url) - self._SendKeyEventsToPopulateForm() + self.assertTrue(self.AutofillPopulateForm('NAME_FIRST'), + msg='Autofill form could not be populated.') form_values = {} for key, value in profile_expected.iteritems(): js_returning_field_value = ( @@ -379,7 +364,8 @@ class AutofillTest(pyauto.PyUITest): url = self.GetHttpURLForDataPath( os.path.join('autofill', 'functional', 'read_only_field_test.html')) self.NavigateToURL(url) - self._SendKeyEventsToPopulateForm() + self.assertTrue(self.AutofillPopulateForm('firstname'), + msg='Autofill form could not be populated.') js_return_readonly_field = ( 'var field_value = document.getElementById("email").value;' 'window.domAutomationController.send(field_value);') @@ -418,13 +404,15 @@ class AutofillTest(pyauto.PyUITest): os.path.join('autofill', 'functional', 'autofill_test_form.html')) self.NavigateToURL(url) # Fill form using an address profile. - self._SendKeyEventsToPopulateForm() + self.assertTrue(self.AutofillPopulateForm('NAME_FIRST'), + msg='Autofill form could not be populated.') # Reset the form. self.ExecuteJavascript('document.getElementById("testform").reset();' 'window.domAutomationController.send("done");', 0, 0) # Fill in the form using an Autofill profile. - self._SendKeyEventsToPopulateForm() + self.assertTrue(self.AutofillPopulateForm('NAME_FIRST'), + msg='Autofill form could not be populated.') # Verify value in fields match value in the profile dictionary. form_values = {} for key, value in profile.iteritems(): @@ -456,7 +444,8 @@ class AutofillTest(pyauto.PyUITest): os.path.join('autofill', 'functional', 'autofill_middleinit_form.html')) self.NavigateToURL(url) # Fill form using an address profile. - self._SendKeyEventsToPopulateForm() + self.assertTrue(self.AutofillPopulateForm('NAME_FIRST'), + msg='Autofill form could not be populated.') js_return_middleinit_field = ( 'var field_value = document.getElementById("NAME_MIDDLE").value;' 'window.domAutomationController.send(field_value);') @@ -482,7 +471,8 @@ class AutofillTest(pyauto.PyUITest): 'autofill_confirmemail_form.html')) self.NavigateToURL(url) # Fill form using an address profile. - self._SendKeyEventsToPopulateForm() + self.assertTrue(self.AutofillPopulateForm('NAME_FIRST'), + msg='Autofill form could not be populated.') js_return_confirmemail_field = ( 'var field_value = document.getElementById("EMAIL_CONFIRM").value;' 'window.domAutomationController.send(field_value);') @@ -550,7 +540,8 @@ class AutofillTest(pyauto.PyUITest): list_of_dict = gen.GenerateDataset(num_of_dict_to_generate=1501) self.FillAutofillProfile(profiles=list_of_dict) self.NavigateToURL(url) - self._SendKeyEventsToPopulateForm() + self.assertTrue(self.AutofillPopulateForm('NAME_FIRST'), + msg='Autofill form could not be populated.') # TODO(dyu): add automated form hang or crash verification. raw_input( 'Verify the test manually. Test hang time after submitting the form.') diff --git a/chrome/test/pyautolib/pyauto.py b/chrome/test/pyautolib/pyauto.py index d14336d..be591ed 100644 --- a/chrome/test/pyautolib/pyauto.py +++ b/chrome/test/pyautolib/pyauto.py @@ -844,24 +844,6 @@ class PyUITest(pyautolib.PyUITestBase, unittest.TestCase): } self._GetResultFromJSONRequest(cmd_dict) - def SendWebkitKeypressEvent(self, key_code, tab_index=0, windex=0): - """Send webkit key press event to the browser. - - Used to simulate key press from the keyboard to interact with the browser. - Simulates a key press which consists of a down key press and up key press. - - Args: - key_code: the hex value associated with the keypress (virtual key code). - tab_index: tab index to work on. Defaults to 0 (first tab). - windex: window index to work on. Defaults to 0 (first window). - """ - KEY_DOWN_TYPE = 0 # kRawKeyDownType - KEY_UP_TYPE = 3 # kKeyUpType - - # Sending two requests, one each for "key down" and "key up". - self.SendWebkitKeyEvent(KEY_DOWN_TYPE, key_code, tab_index, windex) - self.SendWebkitKeyEvent(KEY_UP_TYPE, key_code, tab_index, windex) - def SendWebkitKeyEvent(self, key_type, key_code, tab_index=0, windex=0): """Send a webkit key event to the browser. @@ -1537,6 +1519,123 @@ class PyUITest(pyautolib.PyUITestBase, unittest.TestCase): } return self._GetResultFromJSONRequest(cmd_dict, windex=window_index) + def AutofillTriggerSuggestions(self, field_id=None, tab_index=0, windex=0): + """Focuses a webpage form field and triggers the autofill popup in it. + + This function focuses the specified input field in a webpage form, then + causes the autofill popup to appear in that field. The underlying + automation hook sends a "down arrow" keypress event to trigger the autofill + popup. This function waits until the popup is displayed before returning. + + Args: + field_id: The string ID of the webpage form field to focus. Can be + 'None' (the default), in which case nothing is focused. This + can be useful if the field has already been focused by other + means. + tab_index: Integer index of the tab to work on; defaults to 0 (first tab). + windex: Integer index of the browser window to work on; defaults to 0 + (first window). + + Returns: + True, if no errors were encountered, or False otherwise. + + Raises: + pyauto_errors.JSONInterfaceError if the automation call returns an error. + """ + # Focus the field with the specified ID, if necessary. + if field_id: + if not self.JavascriptFocusElementById(field_id, tab_index, windex): + return False + + # Cause the autofill popup to be shown in the focused form field. + cmd_dict = { + 'command': 'AutofillTriggerSuggestions', + 'tab_index': tab_index, + } + self._GetResultFromJSONRequest(cmd_dict, windex=windex) + return True + + def AutofillHighlightSuggestion(self, direction, tab_index=0, windex=0): + """Highlights the previous or next suggestion in an existing autofill popup. + + This function assumes that an existing autofill popup is currently displayed + in a webpage form. The underlying automation hook sends either a + "down arrow" or an "up arrow" keypress event to cause the next or previous + suggestion to be highlighted, respectively. This function waits until + autofill displays a preview of the form's filled state before returning. + + Use AutofillTriggerSuggestions() to trigger the autofill popup before + calling this function. Use AutofillAcceptSelection() after calling this + function to accept a selection. + + Args: + direction: The string direction in which to highlight an autofill + suggestion. Must be either "up" or "down". + tab_index: Integer index of the tab to work on; defaults to 0 (first tab). + windex: Integer index of the browser window to work on; defaults to 0 + (first window). + + Raises: + pyauto_errors.JSONInterfaceError if the automation call returns an error. + """ + assert direction in ('up', 'down') + cmd_dict = { + 'command': 'AutofillHighlightSuggestion', + 'direction': direction, + 'tab_index': tab_index, + } + self._GetResultFromJSONRequest(cmd_dict, windex=windex) + + def AutofillAcceptSelection(self, tab_index=0, windex=0): + """Accepts the current selection in an already-displayed autofill popup. + + This function assumes that a profile is already highlighted in an existing + autofill popup in a webpage form. The underlying automation hook sends a + "return" keypress event to cause the highlighted profile to be accepted. + This function waits for the webpage form to be filled in with autofill data + before returning. This function does not submit the webpage form. + + Raises: + pyauto_errors.JSONInterfaceError if the automation call returns an error. + """ + cmd_dict = { + 'command': 'AutofillAcceptSelection', + 'tab_index': tab_index, + } + self._GetResultFromJSONRequest(cmd_dict, windex=windex) + + def AutofillPopulateForm(self, field_id, profile_index=0, tab_index=0, + windex=0): + """Populates a webpage form using autofill data and keypress events. + + This function focuses the specified input field in the form, and then + sends keypress events to the associated tab to cause the form to be + populated with information from the requested autofill profile. + + Args: + field_id: The string ID of the webpage form field to focus for autofill + purposes. + profile_index: The index of the profile in the autofill popup to use to + populate the form; defaults to 0 (first profile). + tab_index: Integer index of the tab to work on; defaults to 0 (first tab). + windex: Integer index of the browser window to work on; defaults to 0 + (first window). + + Returns: + True, if the webpage form is populated successfully, or False if not. + + Raises: + pyauto_errors.JSONInterfaceError if an automation call returns an error. + """ + if not self.AutofillTriggerSuggestions(field_id, tab_index, windex): + return False + + for _ in range(profile_index + 1): + self.AutofillHighlightSuggestion('down', tab_index, windex) + + self.AutofillAcceptSelection(tab_index, windex) + return True + def AddHistoryItem(self, item): """Forge a history item for Chrome. @@ -1966,6 +2065,29 @@ class PyUITest(pyautolib.PyUITestBase, unittest.TestCase): logging.debug('Executing javascript: %s', js) return self.ExecuteJavascript(js, windex, tab_index) + def JavascriptFocusElementById(self, field_id, tab_index=0, windex=0): + """Uses Javascript to focus an element with the given ID in a webpage. + + Args: + field_id: The string ID of the webpage form field to focus. + tab_index: Integer index of the tab to work on; defaults to 0 (first tab). + windex: Integer index of the browser window to work on; defaults to 0 + (first window). + + Returns: + True, on success, or False on failure. + """ + focus_field_js = """ + var field = document.getElementById("%s"); + if (!field) { + window.domAutomationController.send("error"); + } else { + field.focus(); + window.domAutomationController.send("done"); + } + """ % field_id + return self.ExecuteJavascript(focus_field_js, windex, tab_index) == 'done' + def SignInToSync(self, username, password): """Signs in to sync using the given username and password. diff --git a/chrome/test/pyautolib/pyautolib.h b/chrome/test/pyautolib/pyautolib.h index fc90687..d3fbc4d 100644 --- a/chrome/test/pyautolib/pyautolib.h +++ b/chrome/test/pyautolib/pyautolib.h @@ -176,7 +176,7 @@ class PyUITestBase : public UITestBase { // a low-level method intended for use mostly by GetDOMValue(). Note that // any complicated manipulation of the page should be done by something // like WebDriver, not PyAuto. Also note that in order for the script to - // return a value to the calling code, it invoke + // return a value to the calling code, it invokes // window.domAutomationController.send(), passing in the intended return // value. std::wstring ExecuteJavascript(const std::wstring& script, |