Bug 1459299 - 1. Add evaluateChromeJS for chrome privilege code; r?snorp draft
authorJim Chen <nchen@mozilla.com>
Fri, 11 May 2018 10:25:03 -0400
changeset 794193 71d9d15d1baea29016b602b0a3506f318c294bf5
parent 793719 17db33b6a124422d43a9f518bea1bc62a698126b
child 794194 059c596960b890623d63414aa8459aceeb895bf5
push id109606
push userbmo:nchen@mozilla.com
push dateFri, 11 May 2018 14:25:53 +0000
reviewerssnorp
bugs1459299
milestone62.0a1
Bug 1459299 - 1. Add evaluateChromeJS for chrome privilege code; r?snorp Add GeckoSessionTestRule.evaluateChromeJS for JS code that requires chrome privileges, such as setting prefs. MozReview-Commit-ID: G7NUKukWTT8
mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/BaseSessionTest.kt
mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/GeckoSessionTestRuleTest.kt
mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/rdp/RDPConnection.java
mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/rule/GeckoSessionTestRule.java
--- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/BaseSessionTest.kt
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/BaseSessionTest.kt
@@ -96,17 +96,17 @@ open class BaseSessionTest(noErrorCollec
             sessionRule.delegateUntilTestEnd(this, callback)
 
     fun GeckoSession.delegateDuringNextWait(callback: Any) =
             sessionRule.delegateDuringNextWait(this, callback)
 
     fun GeckoSession.synthesizeTap(x: Int, y: Int) =
             sessionRule.synthesizeTap(this, x, y)
 
-    fun GeckoSession.evaluateJS(js: String) =
+    fun GeckoSession.evaluateJS(js: String): Any? =
             sessionRule.evaluateJS(this, js)
 
     infix fun Any?.dot(prop: Any): Any? =
             if (prop is Int) this.asJSList<Any>()[prop] else this.asJSMap<Any>()[prop]
 
     @Suppress("UNCHECKED_CAST")
     fun <T> Any?.asJSMap(): Map<String, T> = this as Map<String, T>
 
--- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/GeckoSessionTestRuleTest.kt
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/GeckoSessionTestRuleTest.kt
@@ -1263,9 +1263,26 @@ class GeckoSessionTestRuleTest : BaseSes
         sessionRule.session.evaluateJS("throw Error()")
     }
 
     @WithDevToolsAPI
     @Test(expected = RuntimeException::class)
     fun evaluateJS_throwOnSyntaxError() {
         sessionRule.session.evaluateJS("<{[")
     }
+
+    @WithDevToolsAPI
+    @Test(expected = RuntimeException::class)
+    fun evaluateJS_throwOnChromeAccess() {
+        sessionRule.session.evaluateJS("ChromeUtils")
+    }
+
+    @WithDevToolsAPI
+    @Test fun evaluateChromeJS() {
+        assertThat("Should be able to access ChromeUtils",
+                   sessionRule.evaluateChromeJS("ChromeUtils"), notNullValue())
+    }
+
+    @Test(expected = AssertionError::class)
+    fun evaluateChromeJS_throwOnNotWithDevTools() {
+        sessionRule.evaluateChromeJS("0")
+    }
 }
--- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/rdp/RDPConnection.java
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/rdp/RDPConnection.java
@@ -198,9 +198,22 @@ public final class RDPConnection impleme
      * @return Tab actor.
      */
     public Tab getMostRecentTab() {
         final JSONObject reply = mRoot.sendPacket("{\"type\":\"getTab\"}", "tab")
                                       .optJSONObject("tab");
         final Actor actor = getActor(reply);
         return (actor != null) ? (Tab) actor : new Tab(this, reply);
     }
+
+    /**
+     * Get the actor for the chrome process. The returned Tab object acts like a tab but has
+     * chrome privileges.
+     *
+     * @return Tab actor representing the process.
+     */
+    public Tab getChromeProcess() {
+        final JSONObject reply = mRoot.sendPacket("{\"type\":\"getProcess\"}", "form")
+                                      .optJSONObject("form");
+        final Actor actor = getActor(reply);
+        return (actor != null) ? (Tab) actor : new Tab(this, reply);
+    }
 }
--- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/rule/GeckoSessionTestRule.java
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/rule/GeckoSessionTestRule.java
@@ -602,16 +602,17 @@ public class GeckoSessionTestRule extend
     protected long mTimeoutMillis;
     protected Point mDisplaySize;
     protected SurfaceTexture mDisplayTexture;
     protected Surface mDisplaySurface;
     protected GeckoDisplay mDisplay;
     protected boolean mClosedSession;
     protected boolean mWithDevTools;
     protected Map<GeckoSession, Tab> mRDPTabs;
+    protected Tab mRDPChromeProcess;
 
     public GeckoSessionTestRule() {
         mDefaultSettings = new GeckoSessionSettings();
         mDefaultSettings.setBoolean(GeckoSessionSettings.USE_MULTIPROCESS, env.isMultiprocess());
     }
 
     /**
      * Set an ErrorCollector for assertion errors, or null to not use one.
@@ -988,16 +989,17 @@ public class GeckoSessionTestRule extend
         mNullDelegates = null;
         mCallRecords = null;
         mWaitScopeDelegates = null;
         mTestScopeDelegates = null;
         mLastWaitStart = 0;
         mLastWaitEnd = 0;
         mTimeoutMillis = 0;
         mRDPTabs = null;
+        mRDPChromeProcess = null;
     }
 
     @Override
     public Statement apply(final Statement base, final Description description) {
         return super.apply(new Statement() {
             @Override
             public void evaluate() throws Throwable {
                 try {
@@ -1623,17 +1625,41 @@ public class GeckoSessionTestRule extend
      * Evaluate a JavaScript expression in the context of the target page and return the result.
      * RDP must be enabled first using the {@link WithDevToolsAPI} annotation. String, number, and
      * boolean results are converted to Java values. Undefined and null results are returned as
      * null. Objects are returned as Map instances. Arrays are returned as Object[] instances.
      *
      * @param session Session containing the target page.
      * @param js JavaScript expression.
      * @return Result of evaluating the expression.
+     * @see #evaluateChromeJS
      */
     public Object evaluateJS(final @NonNull GeckoSession session, final @NonNull String js) {
-        assertThat("Must enable RDP using @WithDevToolsAPI", mRDPTabs, notNullValue());
+        assertThat("Must enable RDP using @WithDevToolsAPI",
+                   mWithDevTools, equalTo(true));
 
         final Tab tab = mRDPTabs.get(session);
         assertThat("Session should have tab object", tab, notNullValue());
         return tab.getConsole().evaluateJS(js);
     }
+
+    /**
+     * Evaluate a JavaScript expression in the context of a chrome window and return the result.
+     * RDP must be enabled first using the {@link WithDevToolsAPI} annotation. Results are
+     * converted the same way as {@link #evaluateJS}.
+     *
+     * @param js JavaScript expression.
+     * @return Result of evaluating the expression.
+     * @see #evaluateJS
+     */
+    public Object evaluateChromeJS(final @NonNull String js) {
+        assertThat("Must enable RDP using @WithDevToolsAPI",
+                   mWithDevTools, equalTo(true));
+
+        if (mRDPChromeProcess == null) {
+            mRDPChromeProcess = sRDPConnection.getChromeProcess();
+            assertThat("Should have chrome process object",
+                       mRDPChromeProcess, notNullValue());
+            mRDPChromeProcess.attach();
+        }
+        return mRDPChromeProcess.getConsole().evaluateJS(js);
+    }
 }