Commit 416f31aa authored by craigdh@chromium.org's avatar craigdh@chromium.org

Added a new PyAuto method WaitForDomNode() which allows tests to block until a...

Added a new PyAuto method WaitForDomNode() which allows tests to block until a specified node exists in the DOM.


BUG=None
TEST=functional/apptest.py


Review URL: http://codereview.chromium.org/10095018

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@132506 0039d316-1c4b-4281-b951-d872f2087c98
parent 77346ccd
......@@ -24,11 +24,19 @@ class PyAutoEventsTest(pyauto.PyUITest):
self.GetNextEvent(success_id)
def testDomMutationEvents(self):
"""Basic tests for Dom Mutation observers."""
"""Basic tests for WaitForDomNode."""
url = self.GetHttpURLForDataPath('apptest', 'dom_mutations.html')
self.NavigateToURL(url)
self.WaitForDomNode(domselector.CSSSelector('#login'), 'Log In')
self.NewWebDriver().find_element_by_id('login').click()
self.WaitForDomNode(domselector.XPath('id(\'console\')'), '.*succeeded.*')
def testDomMutationObservers(self):
"""Tests for the various types of Dom Mutation observers."""
url = self.GetHttpURLForDataPath('apptest', 'dom_mutations.html')
self.NavigateToURL(url)
self.GetNextEvent(self.AddDomMutationObserver(
'add', domselector.XPath('/html/body')))
'exists', domselector.XPath('/html/body')))
self.GetNextEvent(self.AddDomMutationObserver(
'add', domselector.CSSSelector('#login'), expected_value='Log In'))
success_id = self.AddDomMutationObserver(
......
......@@ -11,7 +11,7 @@
* Args:
* automation_id: Automation id used to route DomAutomationController messages.
* observer_id: Id of the observer who will be receiving the messages.
* observer_type: One of 'add', 'remove', or 'change'.
* observer_type: One of 'add', 'remove', 'change', or 'exists'.
* pattern: Pattern used to select the DOM node of interest.
* ptype: Type of |pattern|, either 'xpath' or 'css'.
* expected_value: If not null, regular expression matching text contents
......@@ -102,6 +102,22 @@ function(automation_id, observer_id, observer_type, pattern, ptype,
}
}
/* Calls raiseEvent if the expected node exists in the DOM.
*
* Args:
* mutations: A list of mutation objects.
* observer: The mutation observer object associated with this callback.
*/
function existsNodeCallback(mutations, observer) {
var node = firstMatchingNode(pattern, ptype);
if (node && nodeValueTextEquals(node, expected_value)) {
raiseEvent();
observer.disconnect();
delete observer;
return;
}
}
/* Return true if the xpath matches the given node.
*
* Args:
......@@ -184,7 +200,8 @@ function(automation_id, observer_id, observer_type, pattern, ptype,
*/
function observeAdd(pattern, ptype) {
window.domAutomationController.send("success");
if (firstMatchingNode(pattern, ptype)) {
var node = firstMatchingNode(pattern, ptype);
if (node && nodeValueTextEquals(node, expected_value)) {
raiseEvent();
console.log("Matching node in DOM, assuming it was previously added.");
return;
......@@ -243,6 +260,27 @@ function(automation_id, observer_id, observer_type, pattern, ptype,
subtree: true});
}
/* Watch for a node matching pattern to exist in the DOM.
*
* Args:
* pattern: A string in the format of either an XPath or CSS Selector.
* ptype: Either 'xpath' or 'css'.
*/
function observeExists(pattern, ptype) {
window.domAutomationController.send("success");
var node = firstMatchingNode(pattern, ptype);
if (node && nodeValueTextEquals(node, expected_value)) {
raiseEvent();
console.log("Node already exists in DOM.");
return;
}
var obs = new WebKitMutationObserver(existsNodeCallback);
obs.observe(document,
{ childList: true,
attributes: true,
subtree: true});
}
/* Interpret arguments and launch the requested observer function. */
var observer;
......@@ -256,6 +294,9 @@ function(automation_id, observer_id, observer_type, pattern, ptype,
case "change":
observeChange(pattern, ptype);
break;
case "exists":
observeExists(pattern, ptype);
break;
}
console.log("MutationObserver javscript injection completed.")
......
......@@ -2975,7 +2975,7 @@ class PyUITest(pyautolib.PyUITestBase, unittest.TestCase):
occurs on a DOM node specified by |selector|.
Args:
mutation_type: One of 'add', 'remove', or 'change'.
mutation_type: One of 'add', 'remove', 'change', or 'exists'.
selector: A DOMSelector object defining the DOM node to watch. The node
must already exist if |mutation_type| is 'change'.
expected_value: Optional regular expression to match against the node's
......@@ -2992,9 +2992,10 @@ class PyUITest(pyautolib.PyUITestBase, unittest.TestCase):
Raises:
pyauto_errors.JSONInterfaceError if the automation call returns an error.
RuntimeError if the injected javascript MutationObserver returns an error.
pyauto_errors.JavascriptRuntimeError if the injected javascript
MutationObserver returns an error.
"""
assert mutation_type in ('add', 'remove', 'change'), \
assert mutation_type in ('add', 'remove', 'change', 'exists'), \
'Unexpected value "%s" for mutation_type.' % mutation_type
assert isinstance(selector, domselector.DOMSelector), \
'Unexpected type: selector is not a instance of DOMSelector.'
......@@ -3020,9 +3021,34 @@ class PyUITest(pyautolib.PyUITestBase, unittest.TestCase):
jsreturn = self.ExecuteJavascript(js, **kwargs)
if jsreturn != 'success':
self.RemoveEventObserver(observer_id)
raise RuntimeError(jsreturn)
raise pyauto_errors.JavascriptRuntimeError(jsreturn)
return observer_id
def WaitForDomNode(self, selector, expected_value=None, timeout=-1, **kwargs):
"""Waits until a node matching selector exists in the DOM.
NOTE: This does NOT poll. It returns as soon as the node appears, or
immediately if the node already exists.
Args:
selector: A DOMSelector object defining the DOM node to wait for.
expected_value: Optional regular expression to match against the node's
textContent attribute. Defaults to None.
timeout: Time to wait for the node to exist before raising an exception,
defaults to the default automation timeout.
Any additional keyword arguments are passed on to ExecuteJavascript and
can be used to select the tab where the DOM MutationObserver is created.
Raises:
pyauto_errors.JSONInterfaceError if the automation call returns an error.
pyauto_errors.JavascriptRuntimeError if the injected javascript
MutationObserver returns an error.
"""
observer_id = self.AddDomMutationObserver('exists', selector,
expected_value, **kwargs)
self.GetNextEvent(observer_id, timeout=timeout)
def GetNextEvent(self, observer_id=-1, blocking=True, timeout=-1):
"""Waits for an observed event to occur.
......
# Copyright (c) 2011 The Chromium Authors. All rights reserved.
# Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""PyAuto Errors."""
class JavascriptRuntimeError(RuntimeError):
"""Represent an error raised by injected Javascript."""
pass
class JSONInterfaceError(RuntimeError):
"""Represent an error in the JSON ipc interface."""
pass
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment