summaryrefslogtreecommitdiffstats
path: root/chrome/renderer
diff options
context:
space:
mode:
authorkkania@chromium.org <kkania@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-17 00:19:32 +0000
committerkkania@chromium.org <kkania@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-17 00:19:32 +0000
commitc158a6699a9f5e5f56d913c0b06e0d83e8358591 (patch)
tree727e3eb0a5aac10658e35d2e389b057faed103bf /chrome/renderer
parentc7eca5b2c6f9a527d18d00486d2d7cd7dca9c7b1 (diff)
downloadchromium_src-c158a6699a9f5e5f56d913c0b06e0d83e8358591.zip
chromium_src-c158a6699a9f5e5f56d913c0b06e0d83e8358591.tar.gz
chromium_src-c158a6699a9f5e5f56d913c0b06e0d83e8358591.tar.bz2
Add support for DOM interaction in browser tests via C++.
BUG=none TEST=none Review URL: http://codereview.chromium.org/660046 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@41789 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer')
-rw-r--r--chrome/renderer/automation/dom_automation_controller.cc31
-rw-r--r--chrome/renderer/automation/dom_automation_controller.h5
-rw-r--r--chrome/renderer/automation/dom_automation_v8_extension.cc19
-rw-r--r--chrome/renderer/automation/dom_automation_v8_extension.h16
-rw-r--r--chrome/renderer/render_thread.cc5
-rw-r--r--chrome/renderer/renderer_resources.grd1
-rw-r--r--chrome/renderer/resources/dom_automation.js234
7 files changed, 311 insertions, 0 deletions
diff --git a/chrome/renderer/automation/dom_automation_controller.cc b/chrome/renderer/automation/dom_automation_controller.cc
index 3b7ac43..6c3e8a5 100644
--- a/chrome/renderer/automation/dom_automation_controller.cc
+++ b/chrome/renderer/automation/dom_automation_controller.cc
@@ -14,6 +14,7 @@ DomAutomationController::DomAutomationController()
automation_id_(MSG_ROUTING_NONE) {
BindMethod("send", &DomAutomationController::Send);
BindMethod("setAutomationId", &DomAutomationController::SetAutomationId);
+ BindMethod("sendJSON", &DomAutomationController::SendJSON);
}
void DomAutomationController::Send(const CppArgumentList& args,
@@ -86,6 +87,36 @@ void DomAutomationController::Send(const CppArgumentList& args,
return;
}
+void DomAutomationController::SendJSON(const CppArgumentList& args,
+ CppVariant* result) {
+ if (args.size() != 1) {
+ result->SetNull();
+ return;
+ }
+
+ if (automation_id_ == MSG_ROUTING_NONE) {
+ result->SetNull();
+ return;
+ }
+
+ if (!sender_) {
+ NOTREACHED();
+ result->SetNull();
+ return;
+ }
+
+ if (args[0].type != NPVariantType_String) {
+ result->SetNull();
+ return;
+ }
+
+ std::string json = args[0].ToString();
+ result->Set(sender_->Send(
+ new ViewHostMsg_DomOperationResponse(routing_id_, json, automation_id_)));
+
+ automation_id_ = MSG_ROUTING_NONE;
+}
+
void DomAutomationController::SetAutomationId(
const CppArgumentList& args, CppVariant* result) {
if (args.size() != 1) {
diff --git a/chrome/renderer/automation/dom_automation_controller.h b/chrome/renderer/automation/dom_automation_controller.h
index bc6f5fe..c815418 100644
--- a/chrome/renderer/automation/dom_automation_controller.h
+++ b/chrome/renderer/automation/dom_automation_controller.h
@@ -84,6 +84,11 @@ class DomAutomationController : public CppBoundClass {
// IPC. It sets the return value to null on unexpected errors or arguments.
void Send(const CppArgumentList& args, CppVariant* result);
+ // Makes the renderer send a javascript value to the app.
+ // The value must be a NPString and should be properly formed JSON.
+ // This function does not modify/escape the returned string in any way.
+ void SendJSON(const CppArgumentList& args, CppVariant* result);
+
void SetAutomationId(const CppArgumentList& args, CppVariant* result);
// TODO(vibhor): Implement later
diff --git a/chrome/renderer/automation/dom_automation_v8_extension.cc b/chrome/renderer/automation/dom_automation_v8_extension.cc
new file mode 100644
index 0000000..efe5ada
--- /dev/null
+++ b/chrome/renderer/automation/dom_automation_v8_extension.cc
@@ -0,0 +1,19 @@
+// Copyright (c) 2010 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 "chrome/renderer/automation/dom_automation_v8_extension.h"
+
+#include "chrome/renderer/extensions/bindings_utils.h"
+#include "grit/renderer_resources.h"
+
+using bindings_utils::GetStringResource;
+
+const char* DomAutomationV8Extension::kName = "chrome/domautomation";
+
+v8::Extension* DomAutomationV8Extension::Get() {
+ static v8::Extension* extension =
+ new bindings_utils::ExtensionBase(
+ kName, GetStringResource<IDR_DOM_AUTOMATION_JS>(), 0, NULL);
+ return extension;
+}
diff --git a/chrome/renderer/automation/dom_automation_v8_extension.h b/chrome/renderer/automation/dom_automation_v8_extension.h
new file mode 100644
index 0000000..94201e7
--- /dev/null
+++ b/chrome/renderer/automation/dom_automation_v8_extension.h
@@ -0,0 +1,16 @@
+// Copyright (c) 2010 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_RENDERER_AUTOMATION_DOM_AUTOMATION_V8_EXTENSION_H_
+#define CHROME_RENDERER_AUTOMATION_DOM_AUTOMATION_V8_EXTENSION_H_
+
+#include "v8/include/v8.h"
+
+class DomAutomationV8Extension {
+ public:
+ static const char* kName;
+ static v8::Extension* Get();
+};
+
+#endif // CHROME_RENDERER_AUTOMATION_DOM_AUTOMATION_V8_EXTENSION_H_
diff --git a/chrome/renderer/render_thread.cc b/chrome/renderer/render_thread.cc
index bc9a2a5..25ce100 100644
--- a/chrome/renderer/render_thread.cc
+++ b/chrome/renderer/render_thread.cc
@@ -42,6 +42,7 @@
#include "base/scoped_handle.h"
#include "chrome/plugin/plugin_channel_base.h"
#endif
+#include "chrome/renderer/automation/dom_automation_v8_extension.h"
#include "chrome/renderer/cookie_message_filter.h"
#include "chrome/renderer/devtools_agent_filter.h"
#include "chrome/renderer/extension_groups.h"
@@ -789,6 +790,10 @@ void RenderThread::EnsureWebKitInitialized() {
extensions_v8::PlaybackExtension::Get());
}
+ if (command_line.HasSwitch(switches::kDomAutomationController)) {
+ WebScriptController::registerExtension(DomAutomationV8Extension::Get());
+ }
+
WebRuntimeFeatures::enableMediaPlayer(
RenderProcess::current()->HasInitializedMediaLibrary());
diff --git a/chrome/renderer/renderer_resources.grd b/chrome/renderer/renderer_resources.grd
index 15c8f90..ac2f91c 100644
--- a/chrome/renderer/renderer_resources.grd
+++ b/chrome/renderer/renderer_resources.grd
@@ -22,6 +22,7 @@ without changes to the corresponding grd file. fb9 -->
<include name="IDR_SAD_PLUGIN" file="resources\sadplugin.png" type="BINDATA" />
<include name="IDR_EXTENSION_APITEST_JS" file="resources\extension_apitest.js" type="BINDATA" />
<include name="IDR_EXTENSION_TOOLSTRIP_CSS" file="resources\extension_toolstrip.css" flattenhtml="true" type="BINDATA" />
+ <include name="IDR_DOM_AUTOMATION_JS" file="resources\dom_automation.js" type="BINDATA" />
<include name="IDR_BASE_JS" file="resources\base.js" type="BINDATA" />
</includes>
</release>
diff --git a/chrome/renderer/resources/dom_automation.js b/chrome/renderer/resources/dom_automation.js
new file mode 100644
index 0000000..16a4dd0
--- /dev/null
+++ b/chrome/renderer/resources/dom_automation.js
@@ -0,0 +1,234 @@
+// Copyright (c) 2010 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.
+
+// dom_automation.js
+// Methods for performing common DOM operations. Used in Chrome testing
+// involving the DomAutomationController.
+
+var domAutomation = domAutomation || {};
+
+(function() {
+ // |objects| is used to track objects which are sent back to the
+ // DomAutomationController. Since JavaScript does not have a map type,
+ // |objects| is simply an object in which the property name and
+ // property value serve as the key-value pair. The key is the handle number
+ // and the value is the tracked object.
+ domAutomation.objects = {};
+ domAutomation.nextHandle = 1;
+
+ // Returns |value| after converting it to an acceptable type for return, if
+ // necessary.
+ function getConvertedValue(value) {
+ if (typeof value == "undefined" || !value) {
+ return "";
+ }
+ if (value instanceof Array) {
+ var result = [];
+ for (var i = 0; i < value.length; i++) {
+ result.push(getConvertedValue(value[i]));
+ }
+ return result;
+ }
+ if (typeof(value) == "object") {
+ var handle = getHandleForObject(value);
+ if (handle == -1) {
+ // Track this object.
+ var handle = domAutomation.nextHandle++;
+ domAutomation.objects[handle] = value;
+ }
+ return handle;
+ }
+ return value;
+ }
+
+ // Returns the handle for |obj|, or -1 if no handle exists.
+ function getHandleForObject(obj) {
+ for (var property in domAutomation.objects) {
+ if (domAutomation.objects[property] == obj)
+ return parseInt(property);
+ }
+ return -1;
+ }
+
+ // Safely evaluates |javascript| and sends a response back via the
+ // DomAutomationController. See javascript_execution_controller.cc
+ // for more details.
+ domAutomation.evaluateJavaScript = function(javascript) {
+ try {
+ var result = [true, "", getConvertedValue(eval(javascript))];
+ }
+ catch (exception) {
+ var message = exception.message;
+ if (typeof message != "string")
+ message = JSON.stringify(message);
+ var result = [false, message, exception];
+ }
+ domAutomationController.sendJSON(JSON.stringify(result));
+ }
+
+ // Stops tracking the object associated with |handle|.
+ domAutomation.removeObject = function(handle) {
+ delete domAutomation.objects[handle];
+ }
+
+ // Stops tracking all objects.
+ domAutomation.removeAll = function() {
+ domAutomation.objects = {};
+ domAutomation.nextHandle = 1;
+ }
+
+ // Gets the object associated with this |handle|.
+ domAutomation.getObject = function(handle) {
+ return domAutomation.objects[handle];
+ }
+
+ // Converts an indexable list with a length property to an array.
+ function getArray(list) {
+ var arr = [];
+ for (var i = 0; i < list.length; i++) {
+ arr.push(list[i]);
+ }
+ return arr;
+ }
+
+ // Removes whitespace at the beginning and end of |text|.
+ function trim(text) {
+ return text.replace(/^\s+|\s+$/g, "");
+ }
+
+ // Returns the window (which is a sub window of |win|) which
+ // directly contains |doc|. May return null.
+ function findWindowForDocument(win, doc) {
+ if (win.document == doc)
+ return win;
+ for (var i = 0; i < win.frames.length; i++) {
+ if (findWindowForDocument(win.frames[i], doc))
+ return win.frames[i];
+ }
+ return null;
+ }
+
+ //// DOM Element automation methods
+ //// See dom_element_proxy.h for method details.
+
+ domAutomation.getDocumentFromFrame = function(element, frameNames) {
+ // Find the window this element is in.
+ var containingDocument = element.ownerDocument || element;
+ var frame = findWindowForDocument(window, containingDocument);
+
+ for (var i = 0; i < frameNames.length; i++) {
+ frame = frame.frames[frameNames[i]];
+ if (typeof frame == "undefined" || !frame) {
+ return null;
+ }
+ }
+ return frame.document;
+ }
+
+ domAutomation.findByXPath = function(context, xpath) {
+ var xpathResult =
+ document.evaluate(xpath, context, null,
+ XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
+ var elements = [];
+ for (var i = 0; i < xpathResult.snapshotLength; i++) {
+ elements.push(xpathResult.snapshotItem(i));
+ }
+ return elements;
+ }
+
+ domAutomation.find1ByXPath = function(context, xpath) {
+ var xpathResult =
+ document.evaluate(xpath, context, null,
+ XPathResult.FIRST_ORDERED_NODE_TYPE, null);
+ return xpathResult.singleNodeValue;
+ }
+
+ domAutomation.findBySelectors = function(context, selectors) {
+ return getArray(context.querySelectorAll(selectors));
+ }
+
+ domAutomation.find1BySelectors = function(context, selectors) {
+ return context.querySelector(selectors);
+ }
+
+ domAutomation.findByText = function(context, text) {
+ // Find all elements containing this text and all inputs containing
+ // this text.
+ var xpath = ".//*[contains(text(), '" + text + "')] | " +
+ ".//input[contains(@value, '" + text + "')]";
+ var elements = domAutomation.findByXPath(context, xpath);
+
+ // Limit to what is visible.
+ var final_list = [];
+ for (var i = 0; i < elements.length; i++) {
+ if (domAutomation.isVisible(elements[i]))
+ final_list.push(elements[i]);
+ }
+ return final_list;
+ }
+
+ domAutomation.find1ByText = function(context, text) {
+ return domAutomation.findByText(context, text)[0];
+ }
+
+ domAutomation.click = function(element) {
+ var evt = document.createEvent('MouseEvents');
+ evt.initMouseEvent('click', true, true, window,
+ 0, 0, 0, 0, 0, false, false,
+ false, false, 0, null);
+ while (element) {
+ element.dispatchEvent(evt);
+ element = element.parentNode;
+ }
+ }
+
+ domAutomation.type = function(element, text) {
+ if (element instanceof HTMLTextAreaElement ||
+ (element instanceof HTMLInputElement && element.type == "text")) {
+ element.value += text;
+ return true;
+ }
+ return false;
+ }
+
+ domAutomation.setText = function(element, text) {
+ if (element instanceof HTMLTextAreaElement ||
+ (element instanceof HTMLInputElement && element.type == "text")) {
+ element.value = text;
+ return true;
+ }
+ return false;
+ }
+
+ domAutomation.getText = function(element) {
+ if (element instanceof Text) {
+ return trim(element.textContent);
+ }
+ else if (element instanceof HTMLTextAreaElement ||
+ (element instanceof HTMLInputElement)) {
+ return element.value || "";
+ }
+ var childrenText = "";
+ for (var i = 0; i < element.childNodes.length; i++) {
+ childrenText += domAutomation.getText(element.childNodes[i]);
+ }
+ return childrenText;
+ }
+
+ domAutomation.getInnerHTML = function(element) {
+ return trim(element.innerHTML);
+ }
+
+ domAutomation.isVisible = function(element) {
+ while (element.style) {
+ if (element.style.display == 'none' ||
+ element.style.visibility == 'hidden' ||
+ element.style.visibility == 'collapse') {
+ return false;
+ }
+ element = element.parentNode;
+ }
+ return true;
+ }
+})();