From 7ad1cac85e099546dc5ff4424d5c37cbc0fe473e Mon Sep 17 00:00:00 2001
From: "dpranke@chromium.org"
 <dpranke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>
Date: Thu, 5 Aug 2010 01:01:50 +0000
Subject: [PATCH] Add ExecuteJavascript() method to PyUITestBase

This allows us to evaluate JavaScript expressions in the renderer and
read values out of the DOM of the page, which is useful for testing things
like the PasswordManager.

    R=nirimesh@chromium.org, jrg@chromium.org, alyssad@chromium.org
    TEST=chrome/test/functional/test_execute_javascript.py
    BUG=none

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@55013 0039d316-1c4b-4281-b951-d872f2087c98
---
 chrome/test/functional/execute_javascript.py | 37 ++++++++++++++++++++
 chrome/test/pyautolib/pyauto.py              |  8 +++--
 chrome/test/pyautolib/pyautolib.cc           | 30 ++++++++++++++++
 chrome/test/pyautolib/pyautolib.h            | 19 ++++++++++
 chrome/test/pyautolib/pyautolib.i            | 17 +++++++++
 5 files changed, 109 insertions(+), 2 deletions(-)
 create mode 100644 chrome/test/functional/execute_javascript.py

diff --git a/chrome/test/functional/execute_javascript.py b/chrome/test/functional/execute_javascript.py
new file mode 100644
index 0000000000000..f999f3a854678
--- /dev/null
+++ b/chrome/test/functional/execute_javascript.py
@@ -0,0 +1,37 @@
+#!/usr/bin/python
+# 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.
+
+import os
+import sys
+import unittest
+
+import pyauto_functional
+from pyauto import PyUITest
+
+
+class ExecuteJavascriptTest(PyUITest):
+
+  def testExecuteJavascript(self):
+    path = os.path.join(self.DataDir(), "frame_dom_access",
+                       "frame_dom_access.html")
+
+    self.NavigateToURL(self.GetFileURLForPath(path))
+
+    v = self.ExecuteJavascript("window.domAutomationController.send(" +
+                               "document.getElementById('myinput').nodeName)")
+    self.assertEqual(v, "INPUT")
+
+  def testGetDOMValue(self):
+    path = os.path.join(self.DataDir(), "frame_dom_access",
+                       "frame_dom_access.html")
+
+    self.NavigateToURL(self.GetFileURLForPath(path))
+
+    v = self.GetDOMValue("document.getElementById('myinput').nodeName")
+    self.assertEqual(v, "INPUT")
+
+
+if __name__ == '__main__':
+  pyauto_functional.Main()
diff --git a/chrome/test/pyautolib/pyauto.py b/chrome/test/pyautolib/pyauto.py
index 89b3c288dcaf1..bca01d27c5dfa 100644
--- a/chrome/test/pyautolib/pyauto.py
+++ b/chrome/test/pyautolib/pyauto.py
@@ -1447,8 +1447,12 @@ class Main(object):
     # TODO(nirnimesh): Figure out a way to control this from here on Win too.
     if PyUITest.IsPosix():
       chrome_flags += ' --enable-crash-reporter'
-    if chrome_flags:
-      suite_args.append('--extra-chrome-flags=%s' % chrome_flags)
+
+    # We add this so that pyauto can execute javascript in the renderer and
+    # read values back out.
+    chrome_flags += ' --dom-automation'
+
+    suite_args.append('--extra-chrome-flags=%s' % chrome_flags)
     pyauto_suite = PyUITestSuite(suite_args)
     loaded_tests = self._LoadTests(self._args)
     pyauto_suite.addTests(loaded_tests)
diff --git a/chrome/test/pyautolib/pyautolib.cc b/chrome/test/pyautolib/pyautolib.cc
index 76c32fe01793e..804c30a09cf35 100644
--- a/chrome/test/pyautolib/pyautolib.cc
+++ b/chrome/test/pyautolib/pyautolib.cc
@@ -297,6 +297,36 @@ std::string PyUITestBase::_SendJSONRequest(int window_index,
   return response;
 }
 
+std::wstring PyUITestBase::ExecuteJavascript(const std::wstring& script,
+                                             int window_index,
+                                             int tab_index,
+                                             const std::wstring& frame_xpath) {
+  scoped_refptr<BrowserProxy> browser_proxy =
+      automation()->GetBrowserWindow(window_index);
+  EXPECT_TRUE(browser_proxy.get());
+  std::wstring response;
+  if (!browser_proxy.get())
+    return response;
+  scoped_refptr<TabProxy> tab_proxy =
+      browser_proxy->GetTab(tab_index);
+  EXPECT_TRUE(tab_proxy.get());
+  if (!tab_proxy.get())
+    return response;
+
+  EXPECT_TRUE(tab_proxy->ExecuteAndExtractString(frame_xpath, script,
+                                                 &response));
+  return response;
+}
+
+std::wstring PyUITestBase::GetDOMValue(const std::wstring& expr,
+                                       int window_index,
+                                       int tab_index,
+                                       const std::wstring& frame_xpath) {
+  std::wstring script = std::wstring(L"window.domAutomationController.send(") +
+      expr + std::wstring(L")");
+  return ExecuteJavascript(script, window_index, tab_index, frame_xpath);
+}
+
 bool PyUITestBase::ResetToDefaultTheme() {
   return automation()->ResetToDefaultTheme();
 }
diff --git a/chrome/test/pyautolib/pyautolib.h b/chrome/test/pyautolib/pyautolib.h
index 2901fed7d89dc..e3c4c5c950221 100644
--- a/chrome/test/pyautolib/pyautolib.h
+++ b/chrome/test/pyautolib/pyautolib.h
@@ -148,6 +148,25 @@ class PyUITestBase : public UITestBase {
   // automation proxy additions.  Returns response as JSON dict.
   std::string _SendJSONRequest(int window_index, std::string& request);
 
+  // Execute javascript in a given tab, and return the response. This is
+  // 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
+  // window.domAutomationController.send(), passing in the intended return
+  // value.
+  std::wstring ExecuteJavascript(const std::wstring& script,
+                                 int window_index = 0,
+                                 int tab_index = 0,
+                                 const std::wstring& frame_xpath = L"");
+
+  // Evaluate a Javascript expression and return the result as a string. This
+  // method is intended largely to read values out of the frame DOM.
+  std::wstring GetDOMValue(const std::wstring& expr,
+                           int window_index = 0,
+                           int tab_index = 0,
+                           const std::wstring& frame_xpath = L"");
+
   // Resets to the default theme. Returns true on success.
   bool ResetToDefaultTheme();
 
diff --git a/chrome/test/pyautolib/pyautolib.i b/chrome/test/pyautolib/pyautolib.i
index a1c4d64568f38..b5fd1a555e1ee 100644
--- a/chrome/test/pyautolib/pyautolib.i
+++ b/chrome/test/pyautolib/pyautolib.i
@@ -154,6 +154,7 @@ class TabProxy {
   %feature("docstring", "Cancel authentication to a login prompt. ")
       CancelAuth;
   bool CancelAuth();
+
 };
 
 class PyUITestSuiteBase {
@@ -347,6 +348,22 @@ class PyUITestBase {
       _SendJSONRequest;
   std::string _SendJSONRequest(int window_index, std::string request);
 
+  %feature("docstring", "Execute a string of javascript in the specified "
+           "(window, tab, frame) and return a string.") ExecuteJavascript;
+  std::wstring ExecuteJavascript(const std::wstring& script,
+                                 int window_index=0,
+                                 int tab_index=0,
+                                 const std::wstring& frame_xpath="");
+
+  %feature("docstring", "Evaluate a javascript expression in the specified "
+           "(window, tab, frame) and return the specified DOM value "
+           "as a string. This is a wrapper around "
+           "window.domAutomationController.send().") GetDOMValue;
+  std::wstring GetDOMValue(const std::wstring& expr, 
+                           int window_index=0,
+                           int tab_index=0,
+                           const std::wstring& frame_xpath="");
+
   %feature("docstring", "Resets to the default theme. "
            "Returns true on success.") ResetToDefaultTheme;
   bool ResetToDefaultTheme();
-- 
GitLab