summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/automation/automation_event_observer.cc63
-rw-r--r--chrome/browser/automation/automation_event_observer.h56
-rw-r--r--chrome/browser/automation/automation_event_queue.cc127
-rw-r--r--chrome/browser/automation/automation_event_queue.h76
-rw-r--r--chrome/browser/automation/testing_automation_provider.cc80
-rw-r--r--chrome/browser/automation/testing_automation_provider.h43
-rw-r--r--chrome/chrome_browser.gypi4
-rw-r--r--chrome/test/data/apptest/basic.html74
-rw-r--r--chrome/test/functional/PYAUTO_TESTS1
-rw-r--r--chrome/test/functional/apptest.py38
-rwxr-xr-xchrome/test/pyautolib/pyauto.py86
11 files changed, 648 insertions, 0 deletions
diff --git a/chrome/browser/automation/automation_event_observer.cc b/chrome/browser/automation/automation_event_observer.cc
new file mode 100644
index 0000000..feadd29
--- /dev/null
+++ b/chrome/browser/automation/automation_event_observer.cc
@@ -0,0 +1,63 @@
+// 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.
+
+#include "base/logging.h"
+#include "chrome/browser/automation/automation_event_observer.h"
+#include "chrome/browser/automation/automation_event_queue.h"
+#include "chrome/browser/automation/automation_provider.h"
+#include "chrome/browser/automation/automation_provider_json.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_types.h"
+
+AutomationEventObserver::AutomationEventObserver(
+ AutomationEventQueue* event_queue)
+ : event_queue_(event_queue), observer_id_(-1) {
+ DCHECK(event_queue_ != NULL);
+}
+
+AutomationEventObserver::~AutomationEventObserver() {}
+
+void AutomationEventObserver::NotifyEvent(DictionaryValue* value) {
+ if (event_queue_) {
+ event_queue_->NotifyEvent(
+ new AutomationEventQueue::AutomationEvent(
+ GetId(), value));
+ }
+}
+
+void AutomationEventObserver::Init(int observer_id) {
+ if (observer_id_ < 0) {
+ observer_id_ = observer_id;
+ }
+}
+
+int AutomationEventObserver::GetId() const {
+ return observer_id_;
+}
+
+DomRaisedEventObserver::DomRaisedEventObserver(
+ AutomationEventQueue* event_queue, const std::string& event_name)
+ : AutomationEventObserver(event_queue), event_name_(event_name) {}
+
+DomRaisedEventObserver::~DomRaisedEventObserver() {}
+
+void DomRaisedEventObserver::OnDomOperationCompleted(const std::string& json) {
+ DictionaryValue* dict = new DictionaryValue;
+ dict->SetString("type", "raised");
+ dict->SetString("name", json);
+ dict->SetInteger("observer_id", GetId());
+ NotifyEvent(dict);
+}
+
+void DomRaisedEventObserver::OnModalDialogShown() {
+ DictionaryValue* dict = new DictionaryValue;
+ dict->SetString("error", "Blocked by modal dialogue");
+ NotifyEvent(dict);
+}
+
+void DomRaisedEventObserver::OnJavascriptBlocked() {
+ DictionaryValue* dict = new DictionaryValue;
+ dict->SetString("error", "Javascript execution was blocked");
+ NotifyEvent(dict);
+}
diff --git a/chrome/browser/automation/automation_event_observer.h b/chrome/browser/automation/automation_event_observer.h
new file mode 100644
index 0000000..3915648
--- /dev/null
+++ b/chrome/browser/automation/automation_event_observer.h
@@ -0,0 +1,56 @@
+// 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.
+
+#ifndef CHROME_BROWSER_AUTOMATION_AUTOMATION_EVENT_OBSERVER_H_
+#define CHROME_BROWSER_AUTOMATION_AUTOMATION_EVENT_OBSERVER_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+#include "chrome/browser/automation/automation_provider_observers.h"
+#include "chrome/browser/automation/automation_event_queue.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+
+// AutomationEventObserver watches for a specific event, and pushes an
+// AutomationEvent into the AutomationEventQueue for each occurance.
+class AutomationEventObserver {
+ public:
+ explicit AutomationEventObserver(AutomationEventQueue* event_queue);
+ virtual ~AutomationEventObserver();
+
+ void Init(int observer_id);
+ void NotifyEvent(DictionaryValue* value);
+ int GetId() const;
+
+ private:
+ AutomationEventQueue* event_queue_;
+ int observer_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(AutomationEventObserver);
+};
+
+// AutomationEventObserver implementation that listens for explicitly raised
+// events. A webpage currently raises events by calling:
+// window.domAutomationController.setAutomationId(42); // Any integer works.
+// window.domAutomationController("EVENT_NAME");
+// TODO(craigdh): This method is a temporary hack.
+class DomRaisedEventObserver
+ : public AutomationEventObserver, public DomOperationObserver {
+ public:
+ DomRaisedEventObserver(AutomationEventQueue* event_queue,
+ const std::string& event_name);
+ virtual ~DomRaisedEventObserver();
+
+ virtual void OnDomOperationCompleted(const std::string& json) OVERRIDE;
+ virtual void OnModalDialogShown() OVERRIDE;
+ virtual void OnJavascriptBlocked() OVERRIDE;
+
+ private:
+ std::string event_name_;
+ content::NotificationRegistrar registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(DomRaisedEventObserver);
+};
+
+#endif // CHROME_BROWSER_AUTOMATION_AUTOMATION_EVENT_OBSERVER_H_
diff --git a/chrome/browser/automation/automation_event_queue.cc b/chrome/browser/automation/automation_event_queue.cc
new file mode 100644
index 0000000..fd4f792
--- /dev/null
+++ b/chrome/browser/automation/automation_event_queue.cc
@@ -0,0 +1,127 @@
+// 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.
+
+#include <algorithm>
+
+#include "chrome/browser/automation/automation_event_observer.h"
+#include "chrome/browser/automation/automation_event_queue.h"
+#include "chrome/browser/automation/automation_provider_json.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_types.h"
+
+AutomationEventQueue::CompareObserverId::CompareObserverId(int id) : id_(id) {}
+
+bool AutomationEventQueue::CompareObserverId::operator()(
+ AutomationEvent* event) const {
+ return event->GetId() < 0 || event->GetId() == id_;
+}
+
+AutomationEventQueue::AutomationEventQueue()
+ : observer_id_count_(0),
+ wait_automation_reply_(NULL),
+ wait_observer_id_(-1) {}
+
+AutomationEventQueue::~AutomationEventQueue() {
+ Clear();
+}
+
+AutomationEventQueue::AutomationEvent::AutomationEvent(
+ int observer_id, DictionaryValue* event_value)
+ : observer_id_(observer_id), event_value_(event_value) {}
+
+void AutomationEventQueue::GetNextEvent(AutomationJSONReply* reply,
+ int observer_id,
+ bool blocking) {
+ wait_automation_reply_.reset(reply);
+ wait_observer_id_ = observer_id;
+ if (!CheckReturnEvent() && !blocking && wait_automation_reply_.get()) {
+ wait_automation_reply_->SendSuccess(NULL);
+ wait_automation_reply_.reset();
+ }
+}
+
+void AutomationEventQueue::Clear() {
+ ClearObservers();
+ ClearEvents();
+}
+
+bool AutomationEventQueue::IsEmpty() const {
+ return event_queue_.empty();
+}
+
+AutomationEventQueue::AutomationEvent* AutomationEventQueue::PopEvent() {
+ if (event_queue_.empty()) {
+ return NULL;
+ }
+ AutomationEvent* event = event_queue_.back();
+ event_queue_.pop_back();
+ return event;
+}
+
+AutomationEventQueue::AutomationEvent* AutomationEventQueue::PopEvent(
+ int observer_id) {
+ AutomationEvent* event = NULL;
+ std::list<AutomationEvent*>::reverse_iterator it =
+ std::find_if(event_queue_.rbegin(), event_queue_.rend(),
+ CompareObserverId(observer_id));
+ if (it != event_queue_.rend()) {
+ event = *it;
+ event_queue_.remove(event);
+ }
+ return event;
+}
+
+void AutomationEventQueue::NotifyEvent(
+ AutomationEventQueue::AutomationEvent* event) {
+ event_queue_.push_front(event);
+ CheckReturnEvent();
+}
+
+int AutomationEventQueue::AddObserver(AutomationEventObserver* observer) {
+ int id = observer_id_count_++;
+ observer->Init(id);
+ observers_[id] = observer;
+ return id;
+}
+
+bool AutomationEventQueue::RemoveObserver(int observer_id) {
+ if (observers_.find(observer_id) != observers_.end()) {
+ delete observers_[observer_id];
+ observers_.erase(observer_id);
+ return true;
+ }
+ return false;
+}
+
+void AutomationEventQueue::ClearObservers() {
+ std::map<int, AutomationEventObserver*>::iterator it;
+ for (it = observers_.begin(); it != observers_.end(); it++) {
+ delete it->second;
+ }
+ observers_.clear();
+}
+
+void AutomationEventQueue::ClearEvents() {
+ std::list<AutomationEvent*>::iterator it;
+ for (it = event_queue_.begin(); it != event_queue_.end(); it++) {
+ delete *it;
+ }
+ event_queue_.clear();
+}
+
+bool AutomationEventQueue::CheckReturnEvent() {
+ if (wait_automation_reply_.get()) {
+ AutomationEventQueue::AutomationEvent* event = wait_observer_id_ < 0 ?
+ PopEvent() :
+ PopEvent(wait_observer_id_);
+ if (event) {
+ wait_automation_reply_->SendSuccess(event->GetValue());
+ wait_automation_reply_.reset();
+ wait_observer_id_ = -1;
+ delete event;
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/chrome/browser/automation/automation_event_queue.h b/chrome/browser/automation/automation_event_queue.h
new file mode 100644
index 0000000..1633e8a
--- /dev/null
+++ b/chrome/browser/automation/automation_event_queue.h
@@ -0,0 +1,76 @@
+// 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.
+
+#ifndef CHROME_BROWSER_AUTOMATION_AUTOMATION_EVENT_QUEUE_H_
+#define CHROME_BROWSER_AUTOMATION_AUTOMATION_EVENT_QUEUE_H_
+
+#include <list>
+#include <map>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+
+class AutomationEventObserver;
+class AutomationJSONReply;
+
+// AutomationEventQueue maintains a queue of unhandled automation events.
+class AutomationEventQueue {
+ public:
+ AutomationEventQueue();
+ virtual ~AutomationEventQueue();
+
+ // AutomationEvent stores return data dictionay for a single event.
+ class AutomationEvent {
+ public:
+ AutomationEvent(int observer_id, DictionaryValue* event_value);
+ virtual ~AutomationEvent() {}
+
+ int GetId() const { return observer_id_; }
+ DictionaryValue* GetValue() { return event_value_.get(); }
+ DictionaryValue* ReleaseValue() { return event_value_.release(); }
+
+ private:
+ int observer_id_;
+ scoped_ptr<DictionaryValue> event_value_;
+ };
+
+ void GetNextEvent(AutomationJSONReply* reply,
+ int observer_id,
+ bool blocking);
+ void NotifyEvent(AutomationEvent* event);
+ void Clear();
+ bool IsEmpty() const;
+ AutomationEvent* PopEvent();
+ AutomationEvent* PopEvent(int observer_id);
+
+ int AddObserver(AutomationEventObserver* observer);
+ bool RemoveObserver(int observer_id);
+
+ private:
+ class CompareObserverId {
+ public:
+ explicit CompareObserverId(int id);
+ bool operator()(AutomationEvent* event) const;
+
+ private:
+ int id_;
+ };
+
+ void ClearEvents();
+ void ClearObservers();
+ bool CheckReturnEvent();
+
+ std::list<AutomationEvent*> event_queue_;
+ std::map<int, AutomationEventObserver*> observers_;
+ int observer_id_count_;
+
+ // These store the automation reply data when GetNextEvent is called with no
+ // matching event in the queue and blocking is requested.
+ scoped_ptr<AutomationJSONReply> wait_automation_reply_;
+ int wait_observer_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(AutomationEventQueue);
+};
+
+#endif // CHROME_BROWSER_AUTOMATION_AUTOMATION_EVENT_QUEUE_H_
diff --git a/chrome/browser/automation/testing_automation_provider.cc b/chrome/browser/automation/testing_automation_provider.cc
index 11f239a..ba0df97 100644
--- a/chrome/browser/automation/testing_automation_provider.cc
+++ b/chrome/browser/automation/testing_automation_provider.cc
@@ -2316,6 +2316,14 @@ void TestingAutomationProvider::SendJSONRequest(int handle,
handler_map["SetPrefs"] = &TestingAutomationProvider::SetPrefs;
handler_map["ExecuteJavascript"] =
&TestingAutomationProvider::ExecuteJavascriptJSON;
+ handler_map["AddDomRaisedEventObserver"] =
+ &TestingAutomationProvider::AddDomRaisedEventObserver;
+ handler_map["RemoveEventObserver"] =
+ &TestingAutomationProvider::RemoveEventObserver;
+ handler_map["GetNextEvent"] =
+ &TestingAutomationProvider::GetNextEvent;
+ handler_map["ClearEventQueue"] =
+ &TestingAutomationProvider::ClearEventQueue;
handler_map["ExecuteJavascriptInRenderView"] =
&TestingAutomationProvider::ExecuteJavascriptInRenderView;
handler_map["GoForward"] =
@@ -6445,6 +6453,78 @@ void TestingAutomationProvider::ExecuteJavascriptInRenderView(
rvh);
}
+void TestingAutomationProvider::AddDomRaisedEventObserver(
+ DictionaryValue* args,
+ IPC::Message* reply_message) {
+ if (SendErrorIfModalDialogActive(this, reply_message))
+ return;
+
+ AutomationJSONReply reply(this, reply_message);
+ std::string event_name;
+ if (!args->GetString("event_name", &event_name)) {
+ reply.SendError("'event_name' missing or invalid");
+ return;
+ }
+
+ if (!automation_event_queue_.get())
+ automation_event_queue_.reset(new AutomationEventQueue);
+
+ int observer_id = automation_event_queue_->AddObserver(
+ new DomRaisedEventObserver(automation_event_queue_.get(), event_name));
+ scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
+ return_value->SetInteger("observer_id", observer_id);
+ reply.SendSuccess(return_value.get());
+}
+
+void TestingAutomationProvider::RemoveEventObserver(
+ DictionaryValue* args,
+ IPC::Message* reply_message) {
+ AutomationJSONReply reply(this, reply_message);
+ int observer_id;
+ if (!args->GetInteger("observer_id", &observer_id) ||
+ !automation_event_queue_.get()) {
+ reply.SendError("'observer_id' missing or invalid");
+ return;
+ }
+ if (automation_event_queue_->RemoveObserver(observer_id)) {
+ reply.SendSuccess(NULL);
+ return;
+ }
+ reply.SendError("Invalid observer id.");
+}
+
+void TestingAutomationProvider::ClearEventQueue(
+ DictionaryValue* args,
+ IPC::Message* reply_message) {
+ automation_event_queue_.reset();
+ AutomationJSONReply(this, reply_message).SendSuccess(NULL);
+}
+
+void TestingAutomationProvider::GetNextEvent(
+ DictionaryValue* args,
+ IPC::Message* reply_message) {
+ scoped_ptr<AutomationJSONReply> reply(
+ new AutomationJSONReply(this, reply_message));
+ int observer_id;
+ bool blocking;
+ if (!args->GetInteger("observer_id", &observer_id)) {
+ reply->SendError("'observer_id' missing or invalid");
+ return;
+ }
+ if (!args->GetBoolean("blocking", &blocking)) {
+ reply->SendError("'blocking' missing or invalid");
+ return;
+ }
+ if (!automation_event_queue_.get()) {
+ reply->SendError(
+ "No observers are attached to the queue. Did you forget to add one?");
+ return;
+ }
+
+ // The reply will be freed once a matching event is added to the queue.
+ automation_event_queue_->GetNextEvent(reply.release(), observer_id, blocking);
+}
+
void TestingAutomationProvider::GoForward(
DictionaryValue* args,
IPC::Message* reply_message) {
diff --git a/chrome/browser/automation/testing_automation_provider.h b/chrome/browser/automation/testing_automation_provider.h
index 50c4c5e..2df1da2 100644
--- a/chrome/browser/automation/testing_automation_provider.h
+++ b/chrome/browser/automation/testing_automation_provider.h
@@ -13,6 +13,8 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/automation/automation_event_observer.h"
+#include "chrome/browser/automation/automation_event_queue.h"
#include "chrome/browser/automation/automation_provider.h"
#include "chrome/browser/automation/automation_provider_json.h"
#include "chrome/browser/history/history.h"
@@ -944,6 +946,43 @@ class TestingAutomationProvider : public AutomationProvider,
void ExecuteJavascriptJSON(
base::DictionaryValue* args, IPC::Message* reply_message);
+ // Creates a DomRaisedEventObserver associated with the AutomationEventQueue.
+ // Example:
+ // input: { "event_name": "login complete",
+ // "windex": 1,
+ // "tab_index": 1,
+ // "frame_xpath": "//frames[1]",
+ // }
+ // output: { "observer_id": 1 }
+ void AddDomRaisedEventObserver(
+ base::DictionaryValue* args, IPC::Message* reply_message);
+
+ // Removes an event observer associated with the AutomationEventQueue.
+ // Example:
+ // input: { "observer_id": 1 }
+ // output: none
+ void RemoveEventObserver(
+ base::DictionaryValue* args, IPC::Message* reply_message);
+
+ // Retrieves an event from the AutomationEventQueue.
+ // Blocks if 'blocking' is true, otherwise returns immediately.
+ // Example:
+ // input: { "observer_id": 1,
+ // "blocking": true,
+ // }
+ // output: { "type": "raised",
+ // "name": "login complete"
+ // "id": 1,
+ // }
+ void GetNextEvent(base::DictionaryValue* args, IPC::Message* reply_message);
+
+ // Removes all events and observers attached to the AutomationEventQueue.
+ // Example:
+ // input: none
+ // output: none
+ void ClearEventQueue(
+ base::DictionaryValue* args, IPC::Message* reply_message);
+
// Executes javascript in the specified frame of a render view.
// Uses the JSON interface. Waits for a result from the
// |DOMAutomationController|. The javascript must send a string.
@@ -1563,6 +1602,10 @@ class TestingAutomationProvider : public AutomationProvider,
// The stored data for the ImportSettings operation.
ImportSettingsData import_settings_data_;
+ // The automation event observer queue. It is lazily created when an observer
+ // is added to avoid overhead when not needed.
+ scoped_ptr<AutomationEventQueue> automation_event_queue_;
+
DISALLOW_COPY_AND_ASSIGN(TestingAutomationProvider);
};
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 0697c90..e6655c8 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -214,6 +214,10 @@
'browser/auto_launch_trial.h',
'browser/automation/automation_browser_tracker.cc',
'browser/automation/automation_browser_tracker.h',
+ 'browser/automation/automation_event_observer.cc',
+ 'browser/automation/automation_event_observer.h',
+ 'browser/automation/automation_event_queue.cc',
+ 'browser/automation/automation_event_queue.h',
'browser/automation/automation_extension_tracker.cc',
'browser/automation/automation_extension_tracker.h',
'browser/automation/automation_provider.cc',
diff --git a/chrome/test/data/apptest/basic.html b/chrome/test/data/apptest/basic.html
new file mode 100644
index 0000000..2bce174
--- /dev/null
+++ b/chrome/test/data/apptest/basic.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<!-- This is an example app used by chrome/functional/apptest.py to demonstrate
+ use of the Automation Event Queue for testing webapps.
+
+ This example webapp uses explicitly raised events in a simulated
+ asyncronous login flow. -->
+<html>
+
+ <head>
+ <title>AppTest Example</title>
+ <script type="text/javascript">
+ var globalTimeout;
+
+ function write(str) {
+ document.getElementById("console").innerHTML += "> " + str + "<br \>";
+ }
+
+ /* Calls a function after a specified number of miliseconds. */
+ function delayedCallback(f, ms) {
+ globalTimeout = setTimeout(f, ms);
+ }
+
+ /* Adds an event with the given name to the AutomationEventQueue. */
+ function raiseEvent(str) {
+ if (window.domAutomationController) {
+ window.domAutomationController.setAutomationId(424242)
+ window.domAutomationController.send(str);
+ }
+ }
+
+ function init() {
+ write("Initializing...");
+ delayedCallback(createLoginLink, 2000);
+ raiseEvent("init");
+ }
+
+ function createLoginLink() {
+ write("<a id='login' href='' onclick='return login();'>Log In</a>");
+ raiseEvent("login ready");
+ }
+
+ function login() {
+ write("Logging in...");
+ delayedCallback(loginSuccess, 2000);
+ raiseEvent("login start");
+ return false;
+ }
+
+ function loginSuccess() {
+ write("Login succeeded!");
+ raiseEvent("login done");
+ }
+
+ function fail() {
+ clearTimeout(globalTimeout);
+ write("App failed!");
+ raiseEvent("error");
+ return false;
+ }
+ </script>
+ </head>
+
+ <body onload="init()">
+ <div id="s-1">
+ [ <a id='fail' href='' onclick='return fail();'>Fail Test</a> ]
+ <br /><br />
+ </div>
+
+ <div id="console">
+ </div>
+
+ </body>
+
+</html>
diff --git a/chrome/test/functional/PYAUTO_TESTS b/chrome/test/functional/PYAUTO_TESTS
index ece55df..df43a08 100644
--- a/chrome/test/functional/PYAUTO_TESTS
+++ b/chrome/test/functional/PYAUTO_TESTS
@@ -33,6 +33,7 @@
# This is the suite that gets run on 'Chromium' builds.
'CONTINUOUS': {
'all': [
+ 'apptest',
'autofill',
'about_plugins_ui.AboutPluginsTest.testAboutPluginDetailInfo',
'bookmark_bar',
diff --git a/chrome/test/functional/apptest.py b/chrome/test/functional/apptest.py
new file mode 100644
index 0000000..fb351c0
--- /dev/null
+++ b/chrome/test/functional/apptest.py
@@ -0,0 +1,38 @@
+# 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.
+
+import json
+
+import pyauto_functional # must be imported before pyauto
+import pyauto
+
+
+class PyAutoEventsTest(pyauto.PyUITest):
+
+ def testBasicEvents(self):
+ """Basic test for the event queue."""
+ url = self.GetHttpURLForDataPath('apptest', 'basic.html')
+ driver = self.NewWebDriver()
+ event_id = self.AddDomRaisedEventObserver();
+ self.NavigateToURL(url)
+ self._ExpectEvent(event_id, 'init')
+ self._ExpectEvent(event_id, 'login ready')
+ driver.find_element_by_id('login').click()
+ self._ExpectEvent(event_id, 'login start')
+ self._ExpectEvent(event_id, 'login done')
+
+ def _ExpectEvent(self, event_id, event_name):
+ # TODO(craigdh): Temporary hack to ignore unexpected events generated by
+ # chromedriver's use of DomAutomationController. The upcoming revision to
+ # RaisedEvents will fix this. Note this isn't polling, just ignoring
+ # chromedriver events.
+ while True:
+ event = json.loads(self.GetNextEvent(event_id).get('name'))
+ if event.find('{') == -1:
+ break
+ self.assertEqual(event, event_name)
+
+
+if __name__ == '__main__':
+ pyauto_functional.Main()
diff --git a/chrome/test/pyautolib/pyauto.py b/chrome/test/pyautolib/pyauto.py
index d605a6b..74861b4 100755
--- a/chrome/test/pyautolib/pyauto.py
+++ b/chrome/test/pyautolib/pyauto.py
@@ -2806,6 +2806,92 @@ class PyUITest(pyautolib.PyUITestBase, unittest.TestCase):
return self._GetResultFromJSONRequest(cmd_dict, windex=windex,
timeout=timeout)
+ def AddDomRaisedEventObserver(self, event_name=''):
+ """Adds a DomRaisedEventObserver associated with the AutomationEventQueue.
+
+ Args:
+ event_name: The raised event name to watch for. By default all raised
+ events are observed.
+
+ Returns:
+ The id of the created observer, which can be used with GetNextEvent(id)
+ and RemoveEventObserver(id).
+
+ Raises:
+ pyauto_errors.JSONInterfaceError if the automation call returns an error.
+ """
+ # TODO(craigdh): Add documentation for raising an event once it has been
+ # implemented.
+ cmd_dict = {
+ 'command': 'AddDomRaisedEventObserver',
+ 'event_name': event_name,
+ }
+ return self._GetResultFromJSONRequest(cmd_dict, windex=None)['observer_id']
+
+ def GetNextEvent(self, observer_id=-1, blocking=True, timeout=-1):
+ """Waits for an observed event to occur.
+
+ The returned event is removed from the Event Queue. If there is already a
+ matching event in the queue it is returned immediately, otherwise the call
+ blocks until a matching event occurs. If blocking is disabled and no
+ matching event is in the queue this function will immediately return None.
+
+ Args:
+ observer_id: The id of the observer to wait for, matches any event by
+ default.
+ blocking: If True waits until there is a matching event in the queue,
+ if False and there is no event waiting in the queue returns None
+ immediately.
+ timeout: Time to wait for a matching event, defaults to the default
+ automation timeout.
+
+ Returns:
+ Event response dictionary, or None if blocking is disabled and there is no
+ matching event in the queue.
+ SAMPLE:
+ { 'observer_id': 1,
+ 'name': 'login completed',
+ 'type': 'raised_event'}
+
+ Raises:
+ pyauto_errors.JSONInterfaceError if the automation call returns an error.
+ """
+ cmd_dict = {
+ 'command': 'GetNextEvent',
+ 'observer_id' : observer_id,
+ 'blocking' : blocking,
+ }
+ return self._GetResultFromJSONRequest(cmd_dict, windex=None,
+ timeout=timeout)
+
+ def RemoveEventObserver(self, observer_id):
+ """Removes an Event Observer from the AutomationEventQueue.
+
+ Expects a valid observer_id.
+
+ Args:
+ observer_id: The id of the observer to remove.
+
+ Raises:
+ pyauto_errors.JSONInterfaceError if the automation call returns an error.
+ """
+ cmd_dict = {
+ 'command': 'RemoveEventObserver',
+ 'observer_id' : observer_id,
+ }
+ return self._GetResultFromJSONRequest(cmd_dict, windex=None)
+
+ def ClearEventQueue(self):
+ """Removes all events currently in the AutomationEventQueue.
+
+ Raises:
+ pyauto_errors.JSONInterfaceError if the automation call returns an error.
+ """
+ cmd_dict = {
+ 'command': 'ClearEventQueue',
+ }
+ return self._GetResultFromJSONRequest(cmd_dict, windex=None)
+
def ExecuteJavascript(self, js, tab_index=0, windex=0, frame_xpath=''):
"""Executes a script in the specified frame of a tab.