Bug 1050749 - Expose BatteryManager via getBattery() returning a Promise r=bz,baku
☠☠ backed out by 5392300058b6 ☠ ☠
authorWei-Cheng Pan <wpan@mozilla.com>
Thu, 20 Aug 2015 15:39:47 +0800
changeset 291368 c6f579ae99a69318270ecb3f18dd3b9dcdeb594c
parent 291367 f51c32dbea005ffa0b97518074f937ed25baa4b1
child 291369 8e4ca69ff980b055495a80a40991d42d8244e93f
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz, baku
bugs1050749
milestone43.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1050749 - Expose BatteryManager via getBattery() returning a Promise r=bz,baku
dom/base/Navigator.cpp
dom/base/Navigator.h
dom/battery/BatteryManager.cpp
dom/battery/BatteryManager.h
dom/battery/test/marionette/manifest.ini
dom/battery/test/marionette/test_battery_level.js
dom/battery/test/marionette/test_battery_status_charging.js
dom/battery/test/marionette/test_battery_status_discharging.js
dom/battery/test/marionette/test_battery_status_full.js
dom/battery/test/marionette/test_battery_status_not_charging.js
dom/battery/test/marionette/test_battery_status_unknown.js
dom/battery/test/marionette/test_deprecated_battery_level.js
dom/battery/test/marionette/test_deprecated_battery_status_charging.js
dom/battery/test/marionette/test_deprecated_battery_status_discharging.js
dom/battery/test/marionette/test_deprecated_battery_status_full.js
dom/battery/test/marionette/test_deprecated_battery_status_not_charging.js
dom/battery/test/marionette/test_deprecated_battery_unknown.js
dom/battery/test/mochitest.ini
dom/battery/test/test_battery_basics.html
dom/battery/test/test_battery_charging.html
dom/battery/test/test_battery_discharging.html
dom/battery/test/test_deprecated_battery_basics.html
dom/webidl/Navigator.webidl
toolkit/modules/Battery.jsm
toolkit/modules/tests/browser/browser_Battery.js
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -180,16 +180,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMimeTypes)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlugins)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPermissions)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGeolocation)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNotification)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryManager)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryPromise)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPowerManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCellBroadcast)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIccManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileMessageManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTelephony)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVoicemail)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTVManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInputPortManager)
@@ -247,16 +248,18 @@ Navigator::Invalidate()
     mNotification = nullptr;
   }
 
   if (mBatteryManager) {
     mBatteryManager->Shutdown();
     mBatteryManager = nullptr;
   }
 
+  mBatteryPromise = nullptr;
+
 #ifdef MOZ_B2G_FM
   if (mFMRadio) {
     mFMRadio->Shutdown();
     mFMRadio = nullptr;
   }
 #endif
 
   if (mPowerManager) {
@@ -1450,18 +1453,47 @@ Navigator::GetMozFMRadio(ErrorResult& aR
 }
 
 #endif  // MOZ_B2G_FM
 
 //*****************************************************************************
 //    Navigator::nsINavigatorBattery
 //*****************************************************************************
 
+Promise*
+Navigator::GetBattery(ErrorResult& aRv)
+{
+  if (mBatteryPromise) {
+    return mBatteryPromise;
+  }
+
+  if (!mWindow || !mWindow->GetDocShell()) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return nullptr;
+  }
+
+  nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(mWindow);
+  nsRefPtr<Promise> batteryPromise = Promise::Create(go, aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
+  }
+  mBatteryPromise = batteryPromise;
+
+  if (!mBatteryManager) {
+    mBatteryManager = new battery::BatteryManager(mWindow);
+    mBatteryManager->Init();
+  }
+
+  mBatteryPromise->MaybeResolve(mBatteryManager);
+
+  return mBatteryPromise;
+}
+
 battery::BatteryManager*
-Navigator::GetBattery(ErrorResult& aRv)
+Navigator::GetDeprecatedBattery(ErrorResult& aRv)
 {
   if (!mBatteryManager) {
     if (!mWindow) {
       aRv.Throw(NS_ERROR_UNEXPECTED);
       return nullptr;
     }
     NS_ENSURE_TRUE(mWindow->GetDocShell(), nullptr);
 
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -155,17 +155,18 @@ public:
                                const nsAString& aTitle, ErrorResult& aRv);
   void RegisterContentHandler(const nsAString& aMIMEType, const nsAString& aURL,
                               const nsAString& aTitle, ErrorResult& aRv);
   nsMimeTypeArray* GetMimeTypes(ErrorResult& aRv);
   nsPluginArray* GetPlugins(ErrorResult& aRv);
   Permissions* GetPermissions(ErrorResult& aRv);
   // The XPCOM GetDoNotTrack is ok
   Geolocation* GetGeolocation(ErrorResult& aRv);
-  battery::BatteryManager* GetBattery(ErrorResult& aRv);
+  Promise* GetBattery(ErrorResult& aRv);
+  battery::BatteryManager* GetDeprecatedBattery(ErrorResult& aRv);
 
   static already_AddRefed<Promise> GetDataStores(nsPIDOMWindow* aWindow,
                                                  const nsAString& aName,
                                                  const nsAString& aOwner,
                                                  ErrorResult& aRv);
 
   static void AppName(nsAString& aAppName, bool aUsePrefOverriddenValue);
 
@@ -366,16 +367,17 @@ private:
                                                          const nsAString& aType);
 
   nsRefPtr<nsMimeTypeArray> mMimeTypes;
   nsRefPtr<nsPluginArray> mPlugins;
   nsRefPtr<Permissions> mPermissions;
   nsRefPtr<Geolocation> mGeolocation;
   nsRefPtr<DesktopNotificationCenter> mNotification;
   nsRefPtr<battery::BatteryManager> mBatteryManager;
+  nsRefPtr<Promise> mBatteryPromise;
 #ifdef MOZ_B2G_FM
   nsRefPtr<FMRadio> mFMRadio;
 #endif
   nsRefPtr<PowerManager> mPowerManager;
   nsRefPtr<CellBroadcast> mCellBroadcast;
   nsRefPtr<IccManager> mIccManager;
   nsRefPtr<MobileMessageManager> mMobileMessageManager;
   nsRefPtr<Telephony> mTelephony;
--- a/dom/battery/BatteryManager.cpp
+++ b/dom/battery/BatteryManager.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <limits>
 #include "BatteryManager.h"
 #include "Constants.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/Hal.h"
 #include "mozilla/dom/BatteryManagerBinding.h"
+#include "mozilla/Preferences.h"
 #include "nsIDOMClassInfo.h"
 
 /**
  * We have to use macros here because our leak analysis tool things we are
  * leaking strings when we have |static const nsString|. Sad :(
  */
 #define LEVELCHANGE_EVENT_NAME           NS_LITERAL_STRING("levelchange")
 #define CHARGINGCHANGE_EVENT_NAME        NS_LITERAL_STRING("chargingchange")
@@ -51,36 +52,84 @@ BatteryManager::Shutdown()
 }
 
 JSObject*
 BatteryManager::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return BatteryManagerBinding::Wrap(aCx, this, aGivenProto);
 }
 
+bool
+BatteryManager::Charging() const
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  // For testing, unable to report the battery status information
+  if (Preferences::GetBool("dom.battery.test.default", false)) {
+    return true;
+  }
+  if (Preferences::GetBool("dom.battery.test.charging", false)) {
+    return true;
+  }
+  if (Preferences::GetBool("dom.battery.test.discharging", false)) {
+    return false;
+  }
+
+  return mCharging;
+}
+
 double
 BatteryManager::DischargingTime() const
 {
-  if (mCharging || mRemainingTime == kUnknownRemainingTime) {
+  MOZ_ASSERT(NS_IsMainThread());
+  // For testing, unable to report the battery status information
+  if (Preferences::GetBool("dom.battery.test.default", false)) {
+    return std::numeric_limits<double>::infinity();
+  }
+  if (Preferences::GetBool("dom.battery.test.discharging", false)) {
+    return 42.0;
+  }
+
+  if (Charging() || mRemainingTime == kUnknownRemainingTime) {
     return std::numeric_limits<double>::infinity();
   }
 
   return mRemainingTime;
 }
 
 double
 BatteryManager::ChargingTime() const
 {
-  if (!mCharging || mRemainingTime == kUnknownRemainingTime) {
+  MOZ_ASSERT(NS_IsMainThread());
+  // For testing, unable to report the battery status information
+  if (Preferences::GetBool("dom.battery.test.default", false)) {
+    return 0.0;
+  }
+  if (Preferences::GetBool("dom.battery.test.charging", false)) {
+    return 42.0;
+  }
+
+  if (!Charging() || mRemainingTime == kUnknownRemainingTime) {
     return std::numeric_limits<double>::infinity();
   }
 
   return mRemainingTime;
 }
 
+double
+BatteryManager::Level() const
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  // For testing, unable to report the battery status information
+  if (Preferences::GetBool("dom.battery.test.default")) {
+    return 1.0;
+  }
+
+  return mLevel;
+}
+
 void
 BatteryManager::UpdateFromBatteryInfo(const hal::BatteryInformation& aBatteryInfo)
 {
   mLevel = aBatteryInfo.level();
   mCharging = aBatteryInfo.charging();
   mRemainingTime = aBatteryInfo.remainingTime();
 
   // Add some guards to make sure the values are coherent.
--- a/dom/battery/BatteryManager.h
+++ b/dom/battery/BatteryManager.h
@@ -41,29 +41,23 @@ public:
 
   nsPIDOMWindow* GetParentObject() const
   {
      return GetOwner();
   }
 
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
-  bool Charging() const
-  {
-    return mCharging;
-  }
+  bool Charging() const;
 
   double ChargingTime() const;
 
   double DischargingTime() const;
 
-  double Level() const
-  {
-    return mLevel;
-  }
+  double Level() const;
 
   IMPL_EVENT_HANDLER(chargingchange)
   IMPL_EVENT_HANDLER(chargingtimechange)
   IMPL_EVENT_HANDLER(dischargingtimechange)
   IMPL_EVENT_HANDLER(levelchange)
 
 private:
   /**
--- a/dom/battery/test/marionette/manifest.ini
+++ b/dom/battery/test/marionette/manifest.ini
@@ -4,8 +4,14 @@ browser = false
 qemu = true
 
 [test_battery_level.js]
 [test_battery_status_charging.js]
 [test_battery_status_discharging.js]
 [test_battery_status_full.js]
 [test_battery_status_not_charging.js]
 [test_battery_status_unknown.js]
+[test_deprecated_battery_level.js]
+[test_deprecated_battery_status_charging.js]
+[test_deprecated_battery_status_discharging.js]
+[test_deprecated_battery_status_full.js]
+[test_deprecated_battery_status_not_charging.js]
+[test_deprecated_battery_status_unknown.js]
--- a/dom/battery/test/marionette/test_battery_level.js
+++ b/dom/battery/test/marionette/test_battery_level.js
@@ -1,22 +1,25 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 MARIONETTE_TIMEOUT = 10000;
 
-let battery = window.navigator.battery;
+let battery = null;
 
 function verifyInitialState() {
-  ok(battery, "battery");
-  is(battery.level, 0.5, "battery.level");
-  runEmulatorCmd("power display", function (result) {
-    is(result.pop(), "OK", "power display successful");
-    ok(result.indexOf("capacity: 50") !== -1, "power capacity");
-    setUp();
+  window.navigator.getBattery().then(function (b) {
+    battery = b;
+    ok(battery, "battery");
+    is(battery.level, 0.5, "battery.level");
+    runEmulatorCmd("power display", function (result) {
+      is(result.pop(), "OK", "power display successful");
+      ok(result.indexOf("capacity: 50") !== -1, "power capacity");
+      setUp();
+    });
   });
 }
 
 function unexpectedEvent(event) {
   ok(false, "Unexpected " + event.type + " event");
 }
 
 function setUp() {
@@ -24,20 +27,20 @@ function setUp() {
   battery.onlevelchange = unexpectedEvent;
   levelUp();
 }
 
 function changeCapacity(capacity, changeExpected, nextFunction) {
   log("Changing power capacity to " + capacity);
   if (changeExpected) {
     battery.onlevelchange = function (event) {
-     battery.onlevelchange = unexpectedEvent;
-     is(event.type, "levelchange", "event.type");
-     is(battery.level, capacity / 100, "battery.level");
-     nextFunction();
+      battery.onlevelchange = unexpectedEvent;
+      is(event.type, "levelchange", "event.type");
+      is(battery.level, capacity / 100, "battery.level");
+      nextFunction();
     };
     runEmulatorCmd("power capacity " + capacity);
   }
   else {
     runEmulatorCmd("power capacity " + capacity, function () {
       is(battery.level, capacity / 100, "battery.level");
       nextFunction();
     });
--- a/dom/battery/test/marionette/test_battery_status_charging.js
+++ b/dom/battery/test/marionette/test_battery_status_charging.js
@@ -1,24 +1,27 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 MARIONETTE_TIMEOUT = 10000;
 
-let battery = window.navigator.battery;
+let battery = null;
 let fromStatus = "charging";
 let fromCharging = true;
 
 function verifyInitialState() {
-  ok(battery, "battery");
-  ok(battery.charging, "battery.charging");
-  runEmulatorCmd("power display", function (result) {
-    is(result.pop(), "OK", "power display successful");
-    ok(result.indexOf("status: Charging") !== -1, "power status charging");
-    setUp();
+  window.navigator.getBattery().then(function (b) {
+    battery = b;
+    ok(battery, "battery");
+    ok(battery.charging, "battery.charging");
+    runEmulatorCmd("power display", function (result) {
+      is(result.pop(), "OK", "power display successful");
+      ok(result.indexOf("status: Charging") !== -1, "power status charging");
+      setUp();
+    });
   });
 }
 
 function unexpectedEvent(event) {
   ok(false, "Unexpected " + event.type + " event");
 }
 
 function setUp() {
--- a/dom/battery/test/marionette/test_battery_status_discharging.js
+++ b/dom/battery/test/marionette/test_battery_status_discharging.js
@@ -1,24 +1,27 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 MARIONETTE_TIMEOUT = 10000;
 
-let battery = window.navigator.battery;
+let battery = null;
 let fromStatus = "discharging";
 let fromCharging = false;
 
 function verifyInitialState() {
-  ok(battery, "battery");
-  ok(battery.charging, "battery.charging");
-  runEmulatorCmd("power display", function (result) {
-    is(result.pop(), "OK", "power display successful");
-    ok(result.indexOf("status: Charging") !== -1, "power status charging");
-    setUp();
+  window.navigator.getBattery().then(function (b) {
+    battery = b;
+    ok(battery, "battery");
+    ok(battery.charging, "battery.charging");
+    runEmulatorCmd("power display", function (result) {
+      is(result.pop(), "OK", "power display successful");
+      ok(result.indexOf("status: Charging") !== -1, "power status charging");
+      setUp();
+    });
   });
 }
 
 function unexpectedEvent(event) {
   ok(false, "Unexpected " + event.type + " event");
 }
 
 function setUp() {
--- a/dom/battery/test/marionette/test_battery_status_full.js
+++ b/dom/battery/test/marionette/test_battery_status_full.js
@@ -3,22 +3,25 @@
 
 MARIONETTE_TIMEOUT = 10000;
 
 let battery = window.navigator.battery;
 let fromStatus = "full";
 let fromCharging = true;
 
 function verifyInitialState() {
-  ok(battery, "battery");
-  ok(battery.charging, "battery.charging");
-  runEmulatorCmd("power display", function (result) {
-    is(result.pop(), "OK", "power display successful");
-    ok(result.indexOf("status: Charging") !== -1, "power status charging");
-    setUp();
+  window.navigator.getBattery().then(function (b) {
+    battery = b;
+    ok(battery, "battery");
+    ok(battery.charging, "battery.charging");
+    runEmulatorCmd("power display", function (result) {
+      is(result.pop(), "OK", "power display successful");
+      ok(result.indexOf("status: Charging") !== -1, "power status charging");
+      setUp();
+    });
   });
 }
 
 function unexpectedEvent(event) {
   ok(false, "Unexpected " + event.type + " event");
 }
 
 function setUp() {
--- a/dom/battery/test/marionette/test_battery_status_not_charging.js
+++ b/dom/battery/test/marionette/test_battery_status_not_charging.js
@@ -3,22 +3,25 @@
 
 MARIONETTE_TIMEOUT = 10000;
 
 let battery = window.navigator.battery;
 let fromStatus = "not-charging";
 let fromCharging = false;
 
 function verifyInitialState() {
-  ok(battery, "battery");
-  ok(battery.charging, "battery.charging");
-  runEmulatorCmd("power display", function (result) {
-    is(result.pop(), "OK", "power display successful");
-    ok(result.indexOf("status: Charging") !== -1, "power status charging");
-    setUp();
+  window.navigator.getBattery().then(function (b) {
+    battery = b;
+    ok(battery, "battery");
+    ok(battery.charging, "battery.charging");
+    runEmulatorCmd("power display", function (result) {
+      is(result.pop(), "OK", "power display successful");
+      ok(result.indexOf("status: Charging") !== -1, "power status charging");
+      setUp();
+    });
   });
 }
 
 function unexpectedEvent(event) {
   ok(false, "Unexpected " + event.type + " event");
 }
 
 function setUp() {
--- a/dom/battery/test/marionette/test_battery_status_unknown.js
+++ b/dom/battery/test/marionette/test_battery_status_unknown.js
@@ -3,22 +3,25 @@
 
 MARIONETTE_TIMEOUT = 10000;
 
 let battery = window.navigator.battery;
 let fromStatus = "unknown";
 let fromCharging = false;
 
 function verifyInitialState() {
-  ok(battery, "battery");
-  ok(battery.charging, "battery.charging");
-  runEmulatorCmd("power display", function (result) {
-    is(result.pop(), "OK", "power display successful");
-    ok(result.indexOf("status: Charging") !== -1, "power status charging");
-    setUp();
+  window.navigator.getBattery().then(function (b) {
+    battery = b;
+    ok(battery, "battery");
+    ok(battery.charging, "battery.charging");
+    runEmulatorCmd("power display", function (result) {
+      is(result.pop(), "OK", "power display successful");
+      ok(result.indexOf("status: Charging") !== -1, "power status charging");
+      setUp();
+    });
   });
 }
 
 function unexpectedEvent(event) {
   ok(false, "Unexpected " + event.type + " event");
 }
 
 function setUp() {
new file mode 100644
--- /dev/null
+++ b/dom/battery/test/marionette/test_deprecated_battery_level.js
@@ -0,0 +1,68 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 10000;
+
+let battery = window.navigator.battery;
+
+function verifyInitialState() {
+  ok(battery, "battery");
+  is(battery.level, 0.5, "battery.level");
+  runEmulatorCmd("power display", function (result) {
+    is(result.pop(), "OK", "power display successful");
+    ok(result.indexOf("capacity: 50") !== -1, "power capacity");
+    setUp();
+  });
+}
+
+function unexpectedEvent(event) {
+  ok(false, "Unexpected " + event.type + " event");
+}
+
+function setUp() {
+  battery.onchargingchange = unexpectedEvent;
+  battery.onlevelchange = unexpectedEvent;
+  levelUp();
+}
+
+function changeCapacity(capacity, changeExpected, nextFunction) {
+  log("Changing power capacity to " + capacity);
+  if (changeExpected) {
+    battery.onlevelchange = function (event) {
+     battery.onlevelchange = unexpectedEvent;
+     is(event.type, "levelchange", "event.type");
+     is(battery.level, capacity / 100, "battery.level");
+     nextFunction();
+    };
+    runEmulatorCmd("power capacity " + capacity);
+  }
+  else {
+    runEmulatorCmd("power capacity " + capacity, function () {
+      is(battery.level, capacity / 100, "battery.level");
+      nextFunction();
+    });
+  }
+}
+
+function levelUp() {
+  changeCapacity("90", true, levelDown);
+}
+
+function levelDown() {
+  changeCapacity("10", true, levelSame);
+}
+
+function levelSame() {
+  changeCapacity("10", false, cleanUp);
+}
+
+function cleanUp() {
+  battery.onchargingchange = null;
+  battery.onlevelchange = function () {
+    battery.onlevelchange = null;
+    finish();
+  };
+  runEmulatorCmd("power capacity 50");
+}
+
+verifyInitialState();
new file mode 100644
--- /dev/null
+++ b/dom/battery/test/marionette/test_deprecated_battery_status_charging.js
@@ -0,0 +1,85 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 10000;
+
+let battery = window.navigator.battery;
+let fromStatus = "charging";
+let fromCharging = true;
+
+function verifyInitialState() {
+  ok(battery, "battery");
+  ok(battery.charging, "battery.charging");
+  runEmulatorCmd("power display", function (result) {
+    is(result.pop(), "OK", "power display successful");
+    ok(result.indexOf("status: Charging") !== -1, "power status charging");
+    setUp();
+  });
+}
+
+function unexpectedEvent(event) {
+  ok(false, "Unexpected " + event.type + " event");
+}
+
+function setUp() {
+  battery.onchargingchange = unexpectedEvent;
+  battery.onlevelchange = unexpectedEvent;
+  toDischarging();
+}
+
+function resetStatus(charging, nextFunction) {
+  log("Resetting power status to " + fromStatus);
+  if (charging !== fromCharging) {
+    battery.onchargingchange = function () {
+      battery.onchargingchange = unexpectedEvent;
+      nextFunction();
+    };
+    runEmulatorCmd("power status " + fromStatus);
+  }
+  else {
+    runEmulatorCmd("power status " + fromStatus, nextFunction);
+  }
+}
+
+function changeStatus(toStatus, toCharging, nextFunction) {
+  log("Changing power status to " + toStatus);
+  if (fromCharging !== toCharging) {
+    battery.onchargingchange = function (event) {
+      battery.onchargingchange = unexpectedEvent;
+      is(event.type, "chargingchange", "event type");
+      is(battery.charging, toCharging, "battery.charging");
+      resetStatus(toCharging, nextFunction);
+    };
+    runEmulatorCmd("power status " + toStatus);
+  }
+  else {
+    runEmulatorCmd("power status " + toStatus, function () {
+      is(battery.charging, toCharging, "battery.charging");
+      resetStatus(toCharging, nextFunction);
+    });
+  }
+}
+
+function toDischarging() {
+  changeStatus("discharging", false, toFull);
+}
+
+function toFull() {
+  changeStatus("full", true, toNotCharging);
+}
+
+function toNotCharging() {
+  changeStatus("not-charging", false, toUnknown);
+}
+
+function toUnknown() {
+  changeStatus("unknown", false, cleanUp);
+}
+
+function cleanUp() {
+  battery.onchargingchange = null;
+  battery.onlevelchange = null;
+  finish();
+}
+
+verifyInitialState();
new file mode 100644
--- /dev/null
+++ b/dom/battery/test/marionette/test_deprecated_battery_status_discharging.js
@@ -0,0 +1,93 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 10000;
+
+let battery = window.navigator.battery;
+let fromStatus = "discharging";
+let fromCharging = false;
+
+function verifyInitialState() {
+  ok(battery, "battery");
+  ok(battery.charging, "battery.charging");
+  runEmulatorCmd("power display", function (result) {
+    is(result.pop(), "OK", "power display successful");
+    ok(result.indexOf("status: Charging") !== -1, "power status charging");
+    setUp();
+  });
+}
+
+function unexpectedEvent(event) {
+  ok(false, "Unexpected " + event.type + " event");
+}
+
+function setUp() {
+  battery.onchargingchange = function () {
+    battery.onchargingchange = unexpectedEvent;
+    toCharging();
+  };
+  battery.onlevelchange = unexpectedEvent;
+  log("Changing power status to " + fromStatus);
+  runEmulatorCmd("power status " + fromStatus);
+}
+
+function resetStatus(charging, nextFunction) {
+  log("Resetting power status to " + fromStatus);
+  if (charging !== fromCharging) {
+    battery.onchargingchange = function () {
+      battery.onchargingchange = unexpectedEvent;
+      nextFunction();
+    };
+    runEmulatorCmd("power status " + fromStatus);
+  }
+  else {
+    runEmulatorCmd("power status " + fromStatus, nextFunction);
+  }
+}
+
+function changeStatus(toStatus, toCharging, nextFunction) {
+  log("Changing power status to " + toStatus);
+  if (fromCharging !== toCharging) {
+    battery.onchargingchange = function (event) {
+      battery.onchargingchange = unexpectedEvent;
+      is(event.type, "chargingchange", "event type");
+      is(battery.charging, toCharging, "battery.charging");
+      resetStatus(toCharging, nextFunction);
+    };
+    runEmulatorCmd("power status " + toStatus);
+  }
+  else {
+    runEmulatorCmd("power status " + toStatus, function () {
+      is(battery.charging, toCharging, "battery.charging");
+      resetStatus(toCharging, nextFunction);
+    });
+  }
+}
+
+function toCharging() {
+  changeStatus("charging", true, toFull);
+}
+
+function toFull() {
+  changeStatus("full", true, toNotCharging);
+}
+
+function toNotCharging() {
+  changeStatus("not-charging", false, toUnknown);
+}
+
+function toUnknown() {
+  changeStatus("unknown", false, cleanUp);
+}
+
+function cleanUp() {
+  battery.onchargingchange = function () {
+    battery.onchargingchange = null;
+    finish();
+  };
+  battery.onlevelchange = null;
+  log("Resetting power status to charging");
+  runEmulatorCmd("power status charging");
+}
+
+verifyInitialState();
new file mode 100644
--- /dev/null
+++ b/dom/battery/test/marionette/test_deprecated_battery_status_full.js
@@ -0,0 +1,87 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 10000;
+
+let battery = window.navigator.battery;
+let fromStatus = "full";
+let fromCharging = true;
+
+function verifyInitialState() {
+  ok(battery, "battery");
+  ok(battery.charging, "battery.charging");
+  runEmulatorCmd("power display", function (result) {
+    is(result.pop(), "OK", "power display successful");
+    ok(result.indexOf("status: Charging") !== -1, "power status charging");
+    setUp();
+  });
+}
+
+function unexpectedEvent(event) {
+  ok(false, "Unexpected " + event.type + " event");
+}
+
+function setUp() {
+  battery.onchargingchange = unexpectedEvent;
+  battery.onlevelchange = unexpectedEvent;
+  log("Changing power status to " + fromStatus);
+  runEmulatorCmd("power status " + fromStatus, toCharging);
+}
+
+function resetStatus(charging, nextFunction) {
+  log("Resetting power status to " + fromStatus);
+  if (charging !== fromCharging) {
+    battery.onchargingchange = function () {
+      battery.onchargingchange = unexpectedEvent;
+      nextFunction();
+    };
+    runEmulatorCmd("power status " + fromStatus);
+  }
+  else {
+    runEmulatorCmd("power status " + fromStatus, nextFunction);
+  }
+}
+
+function changeStatus(toStatus, toCharging, nextFunction) {
+  log("Changing power status to " + toStatus);
+  if (fromCharging !== toCharging) {
+    battery.onchargingchange = function (event) {
+      battery.onchargingchange = unexpectedEvent;
+      is(event.type, "chargingchange", "event type");
+      is(battery.charging, toCharging, "battery.charging");
+      resetStatus(toCharging, nextFunction);
+    };
+    runEmulatorCmd("power status " + toStatus);
+  }
+  else {
+    runEmulatorCmd("power status " + toStatus, function () {
+      is(battery.charging, toCharging, "battery.charging");
+      resetStatus(toCharging, nextFunction);
+    });
+  }
+}
+
+function toCharging() {
+  changeStatus("charging", true, toDischarging);
+}
+
+function toDischarging() {
+  changeStatus("discharging", false, toNotCharging);
+}
+
+function toNotCharging() {
+  changeStatus("not-charging", false, toUnknown);
+}
+
+function toUnknown() {
+  changeStatus("unknown", false, cleanUp);
+}
+
+function cleanUp() {
+  battery.onchargingchange = null;
+  battery.onlevelchange = null;
+  log("Resetting power status to charging");
+  runEmulatorCmd("power status charging", finish);
+}
+
+verifyInitialState();
new file mode 100644
--- /dev/null
+++ b/dom/battery/test/marionette/test_deprecated_battery_status_not_charging.js
@@ -0,0 +1,93 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 10000;
+
+let battery = window.navigator.battery;
+let fromStatus = "not-charging";
+let fromCharging = false;
+
+function verifyInitialState() {
+  ok(battery, "battery");
+  ok(battery.charging, "battery.charging");
+  runEmulatorCmd("power display", function (result) {
+    is(result.pop(), "OK", "power display successful");
+    ok(result.indexOf("status: Charging") !== -1, "power status charging");
+    setUp();
+  });
+}
+
+function unexpectedEvent(event) {
+  ok(false, "Unexpected " + event.type + " event");
+}
+
+function setUp() {
+  battery.onchargingchange = function () {
+    battery.onchargingchange = unexpectedEvent;
+    toCharging();
+  };
+  battery.onlevelchange = unexpectedEvent;
+  log("Changing power status to " + fromStatus);
+  runEmulatorCmd("power status " + fromStatus);
+}
+
+function resetStatus(charging, nextFunction) {
+  log("Resetting power status to " + fromStatus);
+  if (charging !== fromCharging) {
+    battery.onchargingchange = function () {
+      battery.onchargingchange = unexpectedEvent;
+      nextFunction();
+    };
+    runEmulatorCmd("power status " + fromStatus);
+  }
+  else {
+    runEmulatorCmd("power status " + fromStatus, nextFunction);
+  }
+}
+
+function changeStatus(toStatus, toCharging, nextFunction) {
+  log("Changing power status to " + toStatus);
+  if (fromCharging !== toCharging) {
+    battery.onchargingchange = function (event) {
+      battery.onchargingchange = unexpectedEvent;
+      is(event.type, "chargingchange", "event type");
+      is(battery.charging, toCharging, "battery.charging");
+      resetStatus(toCharging, nextFunction);
+    };
+    runEmulatorCmd("power status " + toStatus);
+  }
+  else {
+    runEmulatorCmd("power status " + toStatus, function () {
+      is(battery.charging, toCharging, "battery.charging");
+      resetStatus(toCharging, nextFunction);
+    });
+  }
+}
+
+function toCharging() {
+  changeStatus("charging", true, toDischarging);
+}
+
+function toDischarging() {
+  changeStatus("discharging", false, toFull);
+}
+
+function toFull() {
+  changeStatus("full", true, toUnknown);
+}
+
+function toUnknown() {
+  changeStatus("unknown", false, cleanUp);
+}
+
+function cleanUp() {
+  battery.onchargingchange = function () {
+    battery.onchargingchange = null;
+    finish();
+  };
+  battery.onlevelchange = null;
+  log("Resetting power status to charging");
+  runEmulatorCmd("power status charging");
+}
+
+verifyInitialState();
new file mode 100644
--- /dev/null
+++ b/dom/battery/test/marionette/test_deprecated_battery_unknown.js
@@ -0,0 +1,93 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 10000;
+
+let battery = window.navigator.battery;
+let fromStatus = "unknown";
+let fromCharging = false;
+
+function verifyInitialState() {
+  ok(battery, "battery");
+  ok(battery.charging, "battery.charging");
+  runEmulatorCmd("power display", function (result) {
+    is(result.pop(), "OK", "power display successful");
+    ok(result.indexOf("status: Charging") !== -1, "power status charging");
+    setUp();
+  });
+}
+
+function unexpectedEvent(event) {
+  ok(false, "Unexpected " + event.type + " event");
+}
+
+function setUp() {
+  battery.onchargingchange = function () {
+    battery.onchargingchange = unexpectedEvent;
+    toCharging();
+  };
+  battery.onlevelchange = unexpectedEvent;
+  log("Changing power status to " + fromStatus);
+  runEmulatorCmd("power status " + fromStatus);
+}
+
+function resetStatus(charging, nextFunction) {
+  log("Resetting power status to " + fromStatus);
+  if (charging !== fromCharging) {
+    battery.onchargingchange = function () {
+      battery.onchargingchange = unexpectedEvent;
+      nextFunction();
+    };
+    runEmulatorCmd("power status " + fromStatus);
+  }
+  else {
+    runEmulatorCmd("power status " + fromStatus, nextFunction);
+  }
+}
+
+function changeStatus(toStatus, toCharging, nextFunction) {
+  log("Changing power status to " + toStatus);
+  if (fromCharging !== toCharging) {
+    battery.onchargingchange = function (event) {
+      battery.onchargingchange = unexpectedEvent;
+      is(event.type, "chargingchange", "event type");
+      is(battery.charging, toCharging, "battery.charging");
+      resetStatus(toCharging, nextFunction);
+    };
+    runEmulatorCmd("power status " + toStatus);
+  }
+  else {
+    runEmulatorCmd("power status " + toStatus, function () {
+      is(battery.charging, toCharging, "battery.charging");
+      resetStatus(toCharging, nextFunction);
+    });
+  }
+}
+
+function toCharging() {
+  changeStatus("charging", true, toDischarging);
+}
+
+function toDischarging() {
+  changeStatus("discharging", false, toFull);
+}
+
+function toFull() {
+  changeStatus("full", true, toNotCharging);
+}
+
+function toNotCharging() {
+  changeStatus("not-charging", false, cleanUp);
+}
+
+function cleanUp() {
+  battery.onchargingchange = function () {
+    battery.onchargingchange = null;
+    finish();
+  };
+  battery.onlevelchange = null;
+  log("Resetting power status to charging");
+  runEmulatorCmd("power status charging");
+}
+
+verifyInitialState();
--- a/dom/battery/test/mochitest.ini
+++ b/dom/battery/test/mochitest.ini
@@ -1,2 +1,8 @@
 [test_battery_basics.html]
 skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug))
+[test_battery_charging.html]
+skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug))
+[test_battery_discharging.html]
+skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug))
+[test_deprecated_battery_basics.html]
+skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug))
--- a/dom/battery/test/test_battery_basics.html
+++ b/dom/battery/test/test_battery_basics.html
@@ -7,27 +7,30 @@
 </head>
 <body>
 <p id="display"></p>
 <div id="content" style="display: none">
 </div>
 <pre id="test">
 <script type="application/javascript">
 
-/** Test for Battery API **/
+SimpleTest.waitForExplicitFinish();
 
-ok('battery' in navigator, "navigator.battery should exist");
+/** Test for Battery API **/
+ok("getBattery" in navigator, "navigator.getBattery should exist");
 
-var battery = navigator.battery;
-ok(battery.level >= 0.0 && battery.level <= 1.0, "Battery level " + battery.level + " should be in the range [0.0, 1.0]");
+navigator.getBattery().then(function (battery) {
+  ok(battery.level >= 0.0 && battery.level <= 1.0, "Battery level " + battery.level + " should be in the range [0.0, 1.0]");
 
-if (battery.charging) {
-  ok(battery.chargingTime >= 0, "Battery chargingTime " + battery.chargingTime + " should be nonnegative when charging");
-  is(battery.dischargingTime, Infinity, "Battery dischargingTime should be Infinity when charging");
-} else {
-  is(battery.chargingTime, Infinity, "Battery chargingTime should be Infinity when discharging");
-  ok(battery.dischargingTime > 0, "Battery dischargingTime " + battery.dischargingTime + " should be positive when discharging");
-}
+  SpecialPowers.pushPrefEnv({"set": [["dom.battery.test.default", true]]}, function () {
+    ok(battery.charging, "Battery should be charging by default");
+    is(battery.chargingTime, 0, "Battery chargingTime " + battery.chargingTime + " should be zero by default");
+    is(battery.dischargingTime, Infinity, "Battery dischargingTime should be Infinity by default");
+    is(battery.level, 1.0, "Battery level " + battery.level + " should be 1.0 by default");
+
+    SimpleTest.finish();
+  });
+});
 
 </script>
 </pre>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/dom/battery/test/test_battery_charging.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for Battery API</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+/** Test for Battery API **/
+navigator.getBattery().then(function (battery) {
+  ok(battery.level >= 0.0 && battery.level <= 1.0, "Battery level " + battery.level + " should be in the range [0.0, 1.0]");
+
+  SpecialPowers.pushPrefEnv({"set": [["dom.battery.test.charging", true]]}, function () {
+    is(battery.charging, true, "Battery should be charging");
+    ok(battery.chargingTime >= 0, "Battery chargingTime " + battery.chargingTime + " should be nonnegative when charging");
+    is(battery.dischargingTime, Infinity, "Battery dischargingTime should be Infinity when charging");
+
+    SimpleTest.finish();
+  });
+});
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/battery/test/test_battery_discharging.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for Battery API</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+/** Test for Battery API **/
+navigator.getBattery().then(function (battery) {
+  ok(battery.level >= 0.0 && battery.level <= 1.0, "Battery level " + battery.level + " should be in the range [0.0, 1.0]");
+
+  SpecialPowers.pushPrefEnv({"set": [["dom.battery.test.discharging", true]]}, function () {
+    is(battery.charging, false, "Battery should be discharging");
+    is(battery.chargingTime, Infinity, "Battery chargingTime should be Infinity when discharging");
+    ok(battery.dischargingTime > 0, "Battery dischargingTime " + battery.dischargingTime + " should be positive when discharging");
+
+    SimpleTest.finish();
+  });
+});
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/battery/test/test_deprecated_battery_basics.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for Battery API</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Battery API **/
+ok("battery" in navigator, "navigator.battery should exist");
+
+var battery = navigator.battery;
+ok(battery.level >= 0.0 && battery.level <= 1.0, "Battery level " + battery.level + " should be in the range [0.0, 1.0]");
+
+if (battery.charging) {
+  ok(battery.chargingTime >= 0, "Battery chargingTime " + battery.chargingTime + " should be nonnegative when charging");
+  is(battery.dischargingTime, Infinity, "Battery dischargingTime should be Infinity when charging");
+} else {
+  is(battery.chargingTime, Infinity, "Battery chargingTime should be Infinity when discharging");
+  ok(battery.dischargingTime > 0, "Battery dischargingTime " + battery.dischargingTime + " should be positive when discharging");
+}
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/webidl/Navigator.webidl
+++ b/dom/webidl/Navigator.webidl
@@ -120,24 +120,25 @@ partial interface Navigator {
 [NoInterfaceObject]
 interface NavigatorGeolocation {
   [Throws, Pref="geo.enabled"]
   readonly attribute Geolocation geolocation;
 };
 Navigator implements NavigatorGeolocation;
 
 // http://www.w3.org/TR/battery-status/#navigatorbattery-interface
-[NoInterfaceObject]
-interface NavigatorBattery {
-    // XXXbz Per spec this should be non-nullable, but we return null in
-    // torn-down windows.  See bug 884925.
-    [Throws, Pref="dom.battery.enabled"]
-    readonly attribute BatteryManager? battery;
+partial interface Navigator {
+  [Throws, Pref="dom.battery.enabled"]
+  Promise<BatteryManager> getBattery();
+  // Deprecated. Use getBattery() instead.
+  // XXXbz Per spec this should be non-nullable, but we return null in
+  // torn-down windows.  See bug 884925.
+  [Throws, Pref="dom.battery.enabled", BinaryName="deprecatedBattery"]
+  readonly attribute BatteryManager? battery;
 };
-Navigator implements NavigatorBattery;
 
 // https://wiki.mozilla.org/WebAPI/DataStore
 [NoInterfaceObject,
  Exposed=(Window,Worker)]
 interface NavigatorDataStore {
     [NewObject, Func="Navigator::HasDataStoreSupport"]
     Promise<sequence<DataStore>> getDataStores(DOMString name,
                                                optional DOMString? owner = null);
--- a/toolkit/modules/Battery.jsm
+++ b/toolkit/modules/Battery.jsm
@@ -1,21 +1,21 @@
 // -*- Mode: javascript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 // 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/.
 
 "use strict";
 
-/** This module wraps around navigator.battery (https://developer.mozilla.org/en-US/docs/Web/API/Navigator.battery).
+/** This module wraps around navigator.getBattery (https://developer.mozilla.org/en-US/docs/Web/API/Navigator.getBattery).
   * and provides a framework for spoofing battery values in test code.
   * To spoof the battery values, set `Debugging.fake = true` after exporting this with a BackstagePass,
-  * after which you can spoof a property yb setting the relevant property of the Battery object.
+  * after which you can spoof a property yb setting the relevant property of the BatteryManager object.
   */
-this.EXPORTED_SYMBOLS = ["Battery"];
+this.EXPORTED_SYMBOLS = ["GetBattery", "Battery"];
 
 const Ci = Components.interfaces;
 const Cc = Components.classes;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
 
 // Load Services, for the BatteryManager API
@@ -35,28 +35,39 @@ this.Debugging = {
   /**
    * If `false`, use the DOM Battery implementation.
    * Set it to `true` if you need to fake battery values
    * for testing or debugging purposes.
    */
   fake: false
 }
 
+this.GetBattery = function () {
+  return new Services.appShell.hiddenDOMWindow.Promise(function (resolve, reject) {
+    // Return fake values if spoofing is enabled, otherwise fetch the real values from the BatteryManager API
+    if (Debugging.fake) {
+      resolve(gFakeBattery);
+      return;
+    }
+    Services.appShell.hiddenDOMWindow.navigator.getBattery().then(resolve, reject);
+  });
+};
+
 this.Battery = {};
 
 for (let k of ["charging", "chargingTime", "dischargingTime", "level"]) {
   let prop = k;
   Object.defineProperty(this.Battery, prop, {
     get: function() {
       // Return fake value if spoofing is enabled, otherwise fetch the real value from the BatteryManager API
       if (Debugging.fake) {
         return gFakeBattery[prop];
       }
       return Services.appShell.hiddenDOMWindow.navigator.battery[prop];
     },
     set: function(fakeSetting) {
       if (!Debugging.fake) {
-          throw new Error("Tried to set fake battery value when battery spoofing was disabled");
+        throw new Error("Tried to set fake battery value when battery spoofing was disabled");
       }
       gFakeBattery[prop] = fakeSetting;
     }
   })
-}
\ No newline at end of file
+}
--- a/toolkit/modules/tests/browser/browser_Battery.js
+++ b/toolkit/modules/tests/browser/browser_Battery.js
@@ -1,18 +1,21 @@
 /* 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/. */
 
 let imported = Components.utils.import("resource://gre/modules/Battery.jsm", this);
 Cu.import("resource://gre/modules/Services.jsm", this);
 
 function test() {
+  waitForExplicitFinish();
+
   is(imported.Debugging.fake, false, "Battery spoofing is initially false")
 
+  // begin deprecated battery API testing
   for (let k of ["charging", "chargingTime", "dischargingTime", "level"]) {
     Assert.throws(() => Battery[k] = 10, "Setting battery " + k + "preference without spoofing enabled should throw");
     ok(Battery[k] == Services.appShell.hiddenDOMWindow.navigator.battery[k], "Battery "+ k + " is correctly set");
   }
   imported.Debugging.fake = true;
 
   Battery.charging = true;
   Battery.chargingTime = 100;
@@ -22,9 +25,41 @@ function test() {
   is(Battery.level, 0.5, "Test for level setter");
 
   Battery.charging = false;
   Battery.dischargingTime = 50;
   Battery.level = 0.7;
   ok(!Battery.charging, "Test for charging setter");
   is(Battery.dischargingTime, 50, "Test for dischargingTime setter");
   is(Battery.level, 0.7, "Test for level setter");
-}
\ No newline at end of file
+
+  imported.Debugging.fake = false;
+  // end deprecated battery API testing
+
+  GetBattery().then(function (battery) {
+    for (let k of ["charging", "chargingTime", "dischargingTime", "level"]) {
+      let backup = battery[k];
+      battery[k] = "__magic__";
+      is(battery[k], backup, "Setting battery " + k + "preference without spoofing enabled should fail");
+    }
+
+    imported.Debugging.fake = true;
+
+    // reload again to get the fake one
+    GetBattery().then(function (battery) {
+      battery.charging = true;
+      battery.chargingTime = 100;
+      battery.level = 0.5;
+      ok(battery.charging, "Test for charging setter");
+      is(battery.chargingTime, 100, "Test for chargingTime setter");
+      is(battery.level, 0.5, "Test for level setter");
+
+      battery.charging = false;
+      battery.dischargingTime = 50;
+      battery.level = 0.7;
+      ok(!battery.charging, "Test for charging setter");
+      is(battery.dischargingTime, 50, "Test for dischargingTime setter");
+      is(battery.level, 0.7, "Test for level setter");
+
+      finish();
+    });
+  });
+}