Bug 1027734 - Convert mozPay to WebIDL. r=bzbarsky.
authorPeter Van der Beken <peterv@propagandism.org>
Tue, 26 Jan 2016 18:38:03 +0100
changeset 305564 1f5aaf208c71c7cdb53d20e71f96292a2794d496
parent 305563 650c2be3cbf3c9edbab182f07b5e1aeb28c83f48
child 305565 216059cd4bcac664edef88b2d3af5d9c403e1b54
push id9214
push userraliiev@mozilla.com
push dateMon, 07 Mar 2016 14:25:21 +0000
treeherdermozilla-aurora@8849dd1a4a79 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky
bugs1027734
milestone47.0a1
Bug 1027734 - Convert mozPay to WebIDL. r=bzbarsky.
dom/base/Navigator.cpp
dom/base/Navigator.h
dom/payment/Payment.js
dom/payment/Payment.manifest
dom/payment/interfaces/moz.build
dom/payment/interfaces/nsINavigatorPayment.idl
dom/payment/interfaces/nsIPaymentContentHelperService.idl
dom/payment/tests/mochitest/MockPaymentsUIChromeScript.js
dom/payment/tests/mochitest/mochitest.ini
dom/payment/tests/mochitest/test_mozpay_callbacks.html
dom/webidl/Navigator.webidl
testing/marionette/jar.mn
testing/specialpowers/content/MockPaymentsUIGlue.jsm
testing/specialpowers/content/specialpowersAPI.js
testing/specialpowers/jar.mn
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -123,16 +123,21 @@
 #include "mozilla/EMEUtils.h"
 #include "mozilla/DetailedPromise.h"
 #endif
 
 #ifdef MOZ_WIDGET_GONK
 #include <cutils/properties.h>
 #endif
 
+#ifdef MOZ_PAY
+#include "nsIPaymentContentHelperService.h"
+#include "mozilla/dom/DOMRequest.h"
+#endif
+
 namespace mozilla {
 namespace dom {
 
 static bool sDoNotTrackEnabled = false;
 static bool sVibratorEnabled   = false;
 static uint32_t sMaxVibrateMS  = 0;
 static uint32_t sMaxVibrateListLen = 0;
 
@@ -2667,16 +2672,46 @@ Navigator::IsE10sEnabled(JSContext* aCx,
 
 bool
 Navigator::MozE10sEnabled()
 {
   // This will only be called if IsE10sEnabled() is true.
   return true;
 }
 
+#ifdef MOZ_PAY
+already_AddRefed<DOMRequest>
+Navigator::MozPay(JSContext* aCx,
+                  JS::Handle<JS::Value> aJwts,
+                  ErrorResult& aRv)
+{
+  if (!mWindow || !mWindow->GetDocShell()) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return nullptr;
+  }
+
+  nsresult rv;
+  nsCOMPtr<nsIPaymentContentHelperService> service =
+    do_GetService("@mozilla.org/payment/content-helper-service;1", &rv);
+  if (!service) {
+    aRv.Throw(rv);
+    return nullptr;
+  }
+
+  RefPtr<nsIDOMDOMRequest> request;
+  rv = service->Pay(mWindow, aJwts, getter_AddRefs(request));
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+    return nullptr;
+  }
+
+  return request.forget().downcast<DOMRequest>();
+}
+#endif // MOZ_PAY
+
 /* static */
 already_AddRefed<nsPIDOMWindowInner>
 Navigator::GetWindowFromGlobal(JSObject* aGlobal)
 {
   nsCOMPtr<nsPIDOMWindowInner> win =
     do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(aGlobal));
   MOZ_ASSERT(!win || win->IsInnerWindow());
   return win.forget();
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -37,16 +37,17 @@ namespace dom {
 class Geolocation;
 class systemMessageCallback;
 class MediaDevices;
 struct MediaStreamConstraints;
 class WakeLock;
 class ArrayBufferViewOrBlobOrStringOrFormData;
 struct MobileIdOptions;
 class ServiceWorkerContainer;
+class DOMRequest;
 } // namespace dom
 } // namespace mozilla
 
 //*****************************************************************************
 // Navigator: Script "navigator" object
 //*****************************************************************************
 
 namespace mozilla {
@@ -310,16 +311,22 @@ public:
   // If in doubt, return true.
   static bool MayResolve(jsid aId);
   void GetOwnPropertyNames(JSContext* aCx, nsTArray<nsString>& aNames,
                            ErrorResult& aRv);
   void GetLanguages(nsTArray<nsString>& aLanguages);
 
   bool MozE10sEnabled();
 
+#ifdef MOZ_PAY
+  already_AddRefed<DOMRequest> MozPay(JSContext* aCx,
+                                      JS::Handle<JS::Value> aJwts,
+                                      ErrorResult& aRv);
+#endif // MOZ_PAY
+
   static void GetAcceptLanguages(nsTArray<nsString>& aLanguages);
 
   // WebIDL helper methods
   static bool HasWakeLockSupport(JSContext* /* unused*/, JSObject* /*unused */);
   static bool HasCameraSupport(JSContext* /* unused */,
                                JSObject* aGlobal);
   static bool HasWifiManagerSupport(JSContext* /* unused */,
                                   JSObject* aGlobal);
--- a/dom/payment/Payment.js
+++ b/dom/payment/Payment.js
@@ -5,61 +5,101 @@
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
 
-const PAYMENTCONTENTHELPER_CID =
-  Components.ID("{a920adc0-c36e-4fd0-8de0-aac1ac6ebbd0}");
-
 const PAYMENT_IPC_MSG_NAMES = ["Payment:Success",
                                "Payment:Failed"];
 
 const PREF_DEBUG = "dom.payment.debug";
 
 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
                                    "@mozilla.org/childprocessmessagemanager;1",
                                    "nsIMessageSender");
 
-function PaymentContentHelper() {
+var _debug;
+try {
+  _debug = Services.prefs.getPrefType(PREF_DEBUG) == Ci.nsIPrefBranch.PREF_BOOL
+           && Services.prefs.getBoolPref(PREF_DEBUG);
+} catch(e) {
+  _debug = false;
+}
+
+function LOG(s) {
+  if (!_debug) {
+    return;
+  }
+  dump("-*- PaymentContentHelper: " + s + "\n");
+}
+
+function PaymentContentHelper(aWindow) {
+  this.initDOMRequestHelper(aWindow, PAYMENT_IPC_MSG_NAMES);
 };
 
 PaymentContentHelper.prototype = {
   __proto__: DOMRequestIpcHelper.prototype,
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsINavigatorPayment,
-                                         Ci.nsIDOMGlobalPropertyInitializer,
-                                         Ci.nsISupportsWeakReference,
-                                         Ci.nsIObserver]),
-  classID:        PAYMENTCONTENTHELPER_CID,
-  classInfo:      XPCOMUtils.generateCI({
-    classID: PAYMENTCONTENTHELPER_CID,
-    contractID: "@mozilla.org/payment/content-helper;1",
-    classDescription: "Payment Content Helper",
-    flags: Ci.nsIClassInfo.DOM_OBJECT,
-    interfaces: [Ci.nsINavigatorPayment]
-  }),
+  receiveMessage: function receiveMessage(aMessage) {
+    let name = aMessage.name;
+    let msg = aMessage.json;
+    if (_debug) {
+      LOG("Received message '" + name + "': " + JSON.stringify(msg));
+    }
+    let requestId = msg.requestId;
+    let request = this.takeRequest(requestId);
+    if (!request) {
+      return;
+    }
+    switch (name) {
+      case "Payment:Success":
+        Services.DOMRequest.fireSuccess(request, msg.result);
+        break;
+      case "Payment:Failed":
+        Services.DOMRequest.fireError(request, msg.errorMsg);
+        break;
+    }
+  },
+};
+
+function PaymentContentHelperService() {
+};
+
+PaymentContentHelperService.prototype = {
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPaymentContentHelperService]),
+  classID: Components.ID("{80035846-6732-4fcc-961b-f336b65218f4}"),
+  contractID: "@mozilla.org/payment/content-helper-service;1",
+
+  _xpcom_factory: XPCOMUtils.generateSingletonFactory(PaymentContentHelperService),
+
+  // keys are windows and values are PaymentContentHelpers
+  helpers: new WeakMap(),
 
   // nsINavigatorPayment
+  pay: function pay(aWindow, aJwts) {
+    let requestHelper = this.helpers.get(aWindow);
+    if (!requestHelper) {
+      requestHelper = new PaymentContentHelper(aWindow);
+      this.helpers.set(aWindow, requestHelper);
+    }
+    let request = requestHelper.createRequest();
+    let requestId = requestHelper.getRequestId(request);
 
-  pay: function pay(aJwts) {
-    let request = this.createRequest();
-    let requestId = this.getRequestId(request);
-
-    let docShell = this._window.QueryInterface(Ci.nsIInterfaceRequestor)
+    let docShell = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                    .getInterface(Ci.nsIWebNavigation)
                    .QueryInterface(Ci.nsIDocShell);
     if (!docShell.isActive) {
-      if (this._debug) {
-        this.LOG("The caller application is a background app. No request " +
-                  "will be sent");
+      if (_debug) {
+        LOG("The caller application is a background app. No request will be " +
+            "sent");
       }
+
       let runnable = {
         run: function run() {
           Services.DOMRequest.fireError(request, "BACKGROUND_APP");
         }
       }
       Services.tm.currentThread.dispatch(runnable,
                                          Ci.nsIThread.DISPATCH_NORMAL);
       return request;
@@ -70,66 +110,11 @@ PaymentContentHelper.prototype = {
     }
 
     cpmm.sendAsyncMessage("Payment:Pay", {
       jwts: aJwts,
       requestId: requestId
     });
     return request;
   },
-
-  // nsIDOMGlobalPropertyInitializer
-
-  init: function(aWindow) {
-    try {
-      if (!Services.prefs.getBoolPref("dom.mozPay.enabled")) {
-        return null;
-      }
-    } catch (e) {
-      return null;
-    }
-
-    this._window = aWindow;
-    this.initDOMRequestHelper(aWindow, PAYMENT_IPC_MSG_NAMES);
-
-    try {
-      this._debug =
-        Services.prefs.getPrefType(PREF_DEBUG) == Ci.nsIPrefBranch.PREF_BOOL
-        && Services.prefs.getBoolPref(PREF_DEBUG);
-    } catch(e) {
-      this._debug = false;
-    }
-
-    return Cu.exportFunction(this.pay.bind(this), aWindow);
-  },
-
-  // nsIFrameMessageListener
-
-  receiveMessage: function receiveMessage(aMessage) {
-    let name = aMessage.name;
-    let msg = aMessage.json;
-    if (this._debug) {
-      this.LOG("Received message '" + name + "': " + JSON.stringify(msg));
-    }
-    let requestId = msg.requestId;
-    let request = this.takeRequest(requestId);
-    if (!request) {
-      return;
-    }
-    switch (name) {
-      case "Payment:Success":
-        Services.DOMRequest.fireSuccess(request, msg.result);
-        break;
-      case "Payment:Failed":
-        Services.DOMRequest.fireError(request, msg.errorMsg);
-        break;
-    }
-  },
-
-  LOG: function LOG(s) {
-    if (!this._debug) {
-      return;
-    }
-    dump("-*- PaymentContentHelper: " + s + "\n");
-  }
 };
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PaymentContentHelper]);
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PaymentContentHelperService]);
--- a/dom/payment/Payment.manifest
+++ b/dom/payment/Payment.manifest
@@ -1,9 +1,8 @@
-component {a920adc0-c36e-4fd0-8de0-aac1ac6ebbd0} Payment.js
-contract @mozilla.org/payment/content-helper;1 {a920adc0-c36e-4fd0-8de0-aac1ac6ebbd0}
-category JavaScript-navigator-property mozPay @mozilla.org/payment/content-helper;1
+component {80035846-6732-4fcc-961b-f336b65218f4} Payment.js
+contract @mozilla.org/payment/content-helper-service;1 {80035846-6732-4fcc-961b-f336b65218f4}
 
 component {b8bce4e7-fbf0-4719-a634-b1bf9018657c} PaymentFlowInfo.js
 contract @mozilla.org/payment/flow-info;1 {b8bce4e7-fbf0-4719-a634-b1bf9018657c}
 
 component {82144756-72ab-45b7-8621-f3dad431dd2f} PaymentProvider.js
 contract @mozilla.org/payment/provider;1 {82144756-72ab-45b7-8621-f3dad431dd2f}
--- a/dom/payment/interfaces/moz.build
+++ b/dom/payment/interfaces/moz.build
@@ -1,15 +1,15 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 XPIDL_SOURCES += [
-    'nsINavigatorPayment.idl',
+    'nsIPaymentContentHelperService.idl',
     'nsIPaymentFlowInfo.idl',
     'nsIPaymentProviderStrategy.idl',
     'nsIPaymentUIGlue.idl',
 ]
 
 XPIDL_MODULE = 'dom_payment'
 
rename from dom/payment/interfaces/nsINavigatorPayment.idl
rename to dom/payment/interfaces/nsIPaymentContentHelperService.idl
--- a/dom/payment/interfaces/nsINavigatorPayment.idl
+++ b/dom/payment/interfaces/nsIPaymentContentHelperService.idl
@@ -1,17 +1,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "domstubs.idl"
 
 interface nsIDOMDOMRequest;
+interface mozIDOMWindow;
 
-[scriptable, uuid(44fb7308-7d7b-4975-8a27-e01fe9623bdb)]
-interface nsINavigatorPayment : nsISupports
+[scriptable, uuid(80035846-6732-4fcc-961b-f336b65218f4)]
+interface nsIPaymentContentHelperService : nsISupports
 {
   // The 'jwts' parameter can be either a single DOMString or an array of
   // DOMStrings. In both cases, it represents the base64url encoded and
   // digitally signed payment information. Each payment provider should
   // define its supported JWT format.
-  nsIDOMDOMRequest pay(in jsval jwts);
+  nsIDOMDOMRequest pay(in mozIDOMWindow window, in jsval jwts);
 };
rename from testing/specialpowers/content/MockPaymentsUIGlue.jsm
rename to dom/payment/tests/mochitest/MockPaymentsUIChromeScript.js
--- a/testing/specialpowers/content/MockPaymentsUIGlue.jsm
+++ b/dom/payment/tests/mochitest/MockPaymentsUIChromeScript.js
@@ -1,110 +1,91 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-this.EXPORTED_SYMBOLS = ["MockPaymentsUIGlue"];
-
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cm = Components.manager;
 const Cu = Components.utils;
 
 const CONTRACT_ID = "@mozilla.org/payment/ui-glue;1";
 
-Cu.import("resource://gre/modules/FileUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
-var classID;
-var oldFactory;
-var newFactory = function(window) {
-  return {
-    createInstance: function(aOuter, aIID) {
-      if (aOuter) {
-        throw Components.results.NS_ERROR_NO_AGGREGATION;
-      }
-      return new MockPaymentsUIGlueInstance(window).QueryInterface(aIID);
-    },
-    lockFactory: function(aLock) {
-      throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
-    },
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory])
-  };
+var oldClassID, oldFactory;
+var newClassID = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator).generateUUID();
+var newFactory = {
+  createInstance: function(aOuter, aIID) {
+    if (aOuter) {
+      throw Components.results.NS_ERROR_NO_AGGREGATION;
+    }
+    return new MockPaymentsUIGlueInstance().QueryInterface(aIID);
+  },
+  lockFactory: function(aLock) {
+    throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
+  },
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory])
 };
 
-this.MockPaymentsUIGlue = {
-  init: function(aWindow) {
-    try {
-      classID = registrar.contractIDToCID(CONTRACT_ID);
-      oldFactory = Cm.getClassObject(Cc[CONTRACT_ID], Ci.nsIFactory);
-    } catch (ex) {
-      oldClassID = "";
-      oldFactory = null;
-      dump("TEST-INFO | can't get payments ui glue registered component, " +
-          "assuming there is none");
-    }
-    if (oldFactory) {
-      registrar.unregisterFactory(classID, oldFactory);
-    }
-    registrar.registerFactory(classID, "", CONTRACT_ID,
-                              new newFactory(aWindow));
-  },
+addMessageListener("MockPaymentsUIGlue.init", function (message) {
+  try {
+    oldClassID = registrar.contractIDToCID(CONTRACT_ID);
+    oldFactory = Cm.getClassObject(oldClassID, Ci.nsIFactory);
+  } catch (ex) {
+    oldClassID = "";
+    oldFactory = null;
+    dump("TEST-INFO | can't get payments ui glue registered component, " +
+         "assuming there is none\n");
+  }
+  if (oldFactory) {
+    registrar.unregisterFactory(oldClassID, oldFactory);
+  }
+  registrar.registerFactory(newClassID, "", CONTRACT_ID, newFactory);});
 
-  reset: function() {
-  },
+addMessageListener("MockPaymentsUIGlue.cleanup", function (message) {
+  if (oldClassID) {
+    registrar.registerFactory(oldClassID, "", CONTRACT_ID, null);
+  }
+});
 
-  cleanup: function() {
-    this.reset();
-    if (oldFactory) {
-      registrar.unregisterFactory(classID, newFactory);
-      registrar.registerFactory(classID, "", CONTRACT_ID, oldFactory);
-    }
-  }
-};
+var payments = new Map();
 
-function MockPaymentsUIGlueInstance(aWindow) {
-  this.window = aWindow;
+function MockPaymentsUIGlueInstance() {
 };
 
 MockPaymentsUIGlueInstance.prototype = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIPaymentUIGlue]),
 
   confirmPaymentRequest: function(aRequestId,
                                   aRequests,
                                   aSuccessCb,
                                   aErrorCb) {
     aSuccessCb.onresult(aRequestId, aRequests[0].type);
   },
 
   showPaymentFlow: function(aRequestId,
                             aPaymentFlowInfo,
                             aErrorCb) {
-    let document = this.window.document;
-    let frame = document.createElement("iframe");
-    frame.setAttribute("mozbrowser", true);
-    frame.setAttribute("remote", true);
-    document.body.appendChild(frame);
-    let docshell = frame.contentWindow
-                        .QueryInterface(Ci.nsIInterfaceRequestor)
-                        .getInterface(Ci.nsIWebNavigation)
-                        .QueryInterface(Ci.nsIDocShell);
+    let win = Services.ww.openWindow(null,
+                                     null,
+                                     "_blank",
+                                     "chrome,dialog=no,resizable,scrollbars,centerscreen",
+                                     null);
+
+    payments.set(aRequestId, win);
+    let docshell = win.QueryInterface(Ci.nsIInterfaceRequestor)
+                      .getInterface(Ci.nsIWebNavigation)
+                      .QueryInterface(Ci.nsIDocShell);
     docshell.paymentRequestId = aRequestId;
-    frame.src = aPaymentFlowInfo.uri + aPaymentFlowInfo.jwt;
+
+    win.document.location = aPaymentFlowInfo.uri + aPaymentFlowInfo.jwt;
   },
 
   closePaymentFlow: function(aRequestId) {
+    payments.get(aRequestId).close();
+    payments.delete(aRequestId);
+
     return Promise.resolve();
-  }
+  },
 };
-// Expose everything to content. We call reset() here so that all of the relevant
-// lazy expandos get added.
-MockPaymentsUIGlue.reset();
-function exposeAll(obj) {
-  var props = {};
-  for (var prop in obj)
-    props[prop] = 'rw';
-  obj.__exposedProps__ = props;
-}
-exposeAll(MockPaymentsUIGlue);
-exposeAll(MockPaymentsUIGlueInstance.prototype);
--- a/dom/payment/tests/mochitest/mochitest.ini
+++ b/dom/payment/tests/mochitest/mochitest.ini
@@ -1,12 +1,11 @@
 [DEFAULT]
-skip-if=true # This test uses MockPaymentsUIGlue which uses __exposedProps__
-             # we need to move this to a chrome test, but these are not
-             # available in b2g or android for now.
+skip-if=buildapp != 'b2g' && toolkit != 'android'
 
 support-files=
   file_mozpayproviderchecker.html
   file_payprovidersuccess.html
   file_payproviderfailure.html
+  MockPaymentsUIChromeScript.js
 
 [test_mozpaymentprovider.html]
 [test_mozpay_callbacks.html]
--- a/dom/payment/tests/mochitest/test_mozpay_callbacks.html
+++ b/dom/payment/tests/mochitest/test_mozpay_callbacks.html
@@ -74,32 +74,36 @@ function runTest() {
   if (!tests.length) {
     ok(true, "Done!");
     SimpleTest.finish();
     return;
   }
   tests.shift()();
 }
 
-SpecialPowers.MockPaymentsUIGlue.init(window);
+const uiGlue = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('MockPaymentsUIChromeScript.js'));
+SimpleTest.registerCleanupFunction(() => {
+ uiGlue.sendAsyncMessage("MockPaymentsUIGlue.cleanup", {});
+});
+uiGlue.sendAsyncMessage("MockPaymentsUIGlue.init", {});
 
 SpecialPowers.pushPrefEnv({
   "set": [
     ["dom.payment.skipHTTPSCheck", "true"],
     ["dom.payment.debug", "true"],
     ["dom.payment.provider.1.name", "SuccessProvider"],
     ["dom.payment.provider.1.description", ""],
     ["dom.payment.provider.1.uri",
-     "http://mochi.test:8888/tests/dom/payment/tests/mochitest/file_payprovidersuccess.html?req="],
+     "https://example.com:443/tests/dom/payment/tests/mochitest/file_payprovidersuccess.html?req="],
     ["dom.payment.provider.1.type", "mozilla/payments/test/success"],
     ["dom.payment.provider.1.requestMethod", "GET"],
     ["dom.payment.provider.2.name", "FailureProvider"],
     ["dom.payment.provider.2.description", ""],
     ["dom.payment.provider.2.uri",
-     "http://mochi.test:8888/tests/dom/payment/tests/mochitest/file_payproviderfailure.html?req="],
+     "https://example.com:443/tests/dom/payment/tests/mochitest/file_payproviderfailure.html?req="],
     ["dom.payment.provider.2.type", "mozilla/payments/test/failure"],
     ["dom.payment.provider.2.requestMethod", "GET"],
   ]
   }, () => {
     runTest();
   });
 
 </script>
--- a/dom/webidl/Navigator.webidl
+++ b/dom/webidl/Navigator.webidl
@@ -460,8 +460,19 @@ partial interface Navigator {
 #endif
 
 #ifdef NIGHTLY_BUILD
 partial interface Navigator {
   [Func="Navigator::IsE10sEnabled"]
   readonly attribute boolean mozE10sEnabled;
 };
 #endif
+
+#ifdef MOZ_PAY
+partial interface Navigator {
+  [Throws, NewObject, Pref="dom.mozPay.enabled"]
+  // The 'jwts' parameter can be either a single DOMString or an array of
+  // DOMStrings. In both cases, it represents the base64url encoded and
+  // digitally signed payment information. Each payment provider should
+  // define its supported JWT format.
+  DOMRequest mozPay(any jwts);
+};
+#endif
--- a/testing/marionette/jar.mn
+++ b/testing/marionette/jar.mn
@@ -37,10 +37,9 @@ marionette.jar:
   content/SpecialPowersObserver.jsm (../specialpowers/content/SpecialPowersObserver.jsm)
 * content/specialpowersAPI.js (../specialpowers/content/specialpowersAPI.js)
   content/SpecialPowersObserverAPI.js (../specialpowers/content/SpecialPowersObserverAPI.js)
   content/ChromePowers.js (../mochitest/tests/SimpleTest/ChromePowers.js)
   content/MozillaLogger.js (../specialpowers/content/MozillaLogger.js)
   content/MockFilePicker.jsm (../specialpowers/content/MockFilePicker.jsm)
   content/MockColorPicker.jsm (../specialpowers/content/MockColorPicker.jsm)
   content/MockPermissionPrompt.jsm (../specialpowers/content/MockPermissionPrompt.jsm)
-  content/MockPaymentsUIGlue.jsm (../specialpowers/content/MockPaymentsUIGlue.jsm)
   content/Assert.jsm (../modules/Assert.jsm)
--- a/testing/specialpowers/content/specialpowersAPI.js
+++ b/testing/specialpowers/content/specialpowersAPI.js
@@ -9,17 +9,16 @@
 
 var Ci = Components.interfaces;
 var Cc = Components.classes;
 var Cu = Components.utils;
 
 Cu.import("chrome://specialpowers/content/MockFilePicker.jsm");
 Cu.import("chrome://specialpowers/content/MockColorPicker.jsm");
 Cu.import("chrome://specialpowers/content/MockPermissionPrompt.jsm");
-Cu.import("chrome://specialpowers/content/MockPaymentsUIGlue.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 // We're loaded with "this" not set to the global in some cases, so we
 // have to play some games to get at the global object here.  Normally
 // we'd try "this" from a function called with undefined this value,
 // but this whole file is in strict mode.  So instead fall back on
@@ -456,20 +455,16 @@ SpecialPowersAPI.prototype = {
   get MockColorPicker() {
     return MockColorPicker;
   },
 
   get MockPermissionPrompt() {
     return MockPermissionPrompt;
   },
 
-  get MockPaymentsUIGlue() {
-    return MockPaymentsUIGlue;
-  },
-
   loadChromeScript: function (url) {
     // Create a unique id for this chrome script
     let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"]
                           .getService(Ci.nsIUUIDGenerator);
     let id = uuidGenerator.generateUUID().toString();
 
     // Tells chrome code to evaluate this chrome script
     this._sendSyncMessage("SPLoadChromeScript",
--- a/testing/specialpowers/jar.mn
+++ b/testing/specialpowers/jar.mn
@@ -3,10 +3,9 @@ specialpowers.jar:
   content/specialpowers.js (content/specialpowers.js)
 * content/specialpowersAPI.js (content/specialpowersAPI.js)
   content/SpecialPowersObserverAPI.js (content/SpecialPowersObserverAPI.js)
   content/SpecialPowersObserver.jsm (content/SpecialPowersObserver.jsm)
   content/MozillaLogger.js (content/MozillaLogger.js)
   content/MockFilePicker.jsm (content/MockFilePicker.jsm)
   content/MockColorPicker.jsm (content/MockColorPicker.jsm)
   content/MockPermissionPrompt.jsm (content/MockPermissionPrompt.jsm)
-  content/MockPaymentsUIGlue.jsm (content/MockPaymentsUIGlue.jsm)
   content/Assert.jsm (../modules/Assert.jsm)