Bug 1724183 - Add test.assertEq WebExtensions API implementation to ExtensionTest webidl bindings. r=baku,mixedpuppy
authorLuca Greco <lgreco@mozilla.com>
Tue, 12 Oct 2021 18:32:27 +0000
changeset 595557 211c00af6c724814c5028dd2dab509c3ece50d05
parent 595556 fd452367df8add8ae50b85f52baa5c5e2933b750
child 595558 1db9a2d4ac46e10ea2e91b75c307288116d034ea
push id38872
push usermalexandru@mozilla.com
push dateWed, 13 Oct 2021 03:44:20 +0000
treeherdermozilla-central@9b9f8bfe2625 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku, mixedpuppy
bugs1724183
milestone95.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 1724183 - Add test.assertEq WebExtensions API implementation to ExtensionTest webidl bindings. r=baku,mixedpuppy This patch introduce a new method to ExtensionTest.h/.cpp that implements the parts of browser.test.assertEq that needs to happen on the background service worker thread (because the first two parameters are expected to not be always of types that can be structure cloned). The C++ method is meant to follow closely enough what the current implementation is doing in privileged JS code (See https://searchfox.org/mozilla-central/rev/00977c4e37865a92f1c15572ae4aea90e934b25b/toolkit/components/extensions/child/ext-test.js#169-186) after that the C++ method calls the existing assertEq implementation, which will be actually be getting the first 2 parameters already converted as strings (which will be already different if `expected` and `actual` js values were different despite their stringified value may be looking the same, because the method will add " (different)" to the stringified `actual` value if the two parameter were not strictly equal). The existing test.assertEq implementation will also take care to send the result of the assertion to the parent process (which will make sure that the test case being executed will fail as expected), as it happens for all other test API methods that are just forwarding their parameters to the main thread through the pre-existing stub methods. Differential Revision: https://phabricator.services.mozilla.com/D121890
dom/webidl/ExtensionTest.webidl
toolkit/components/extensions/test/xpcshell/webidl-api/test_ext_webidl_api_request_handler.js
toolkit/components/extensions/webidl-api/ExtensionTest.cpp
toolkit/components/extensions/webidl-api/ExtensionTest.h
toolkit/components/extensions/webidl-api/ExtensionWebIDL.conf
--- a/dom/webidl/ExtensionTest.webidl
+++ b/dom/webidl/ExtensionTest.webidl
@@ -47,17 +47,17 @@ interface ExtensionTest {
   void succeed(optional any message);
 
   [Throws, WebExtensionStub="NoReturn"]
   void assertTrue(any... args);
 
   [Throws, WebExtensionStub="NoReturn"]
   void assertFalse(any... args);
 
-  [Throws, WebExtensionStub="NotImplementedNoReturn"]
+  [Throws, WebExtensionStub="AssertEq"]
   void assertEq(any... args);
 
   [Throws, WebExtensionStub="NotImplementedAsync"]
   any assertRejects(Promise<any> promise, any expectedError, optional DOMString message, optional Function callback);
 
   [Throws, WebExtensionStub="NotImplementedNoReturn"]
   void assertThrows(Function func, any expectedError, optional DOMString message);
 
--- a/toolkit/components/extensions/test/xpcshell/webidl-api/test_ext_webidl_api_request_handler.js
+++ b/toolkit/components/extensions/test/xpcshell/webidl-api/test_ext_webidl_api_request_handler.js
@@ -35,16 +35,25 @@ add_task(async function test_sw_api_requ
     },
     files: {
       "page.html": "<!DOCTYPE html><body></body>",
       "sw.js": async function() {
         browser.test.onMessage.addListener(msg => {
           browser.test.succeed("call to test.succeed");
           browser.test.assertTrue(true, "call to test.assertTrue");
           browser.test.assertFalse(false, "call to test.assertFalse");
+          // Smoke test assertEq (more complete coverage of the behavior expected
+          // by the test API will be introduced in test_ext_test.html as part of
+          // Bug 1723785).
+          const errorObject = new Error("fake_error_message");
+          browser.test.assertEq(
+            errorObject,
+            errorObject,
+            "call to test.assertEq"
+          );
           browser.test.notifyPass("test-completed");
         });
         browser.test.sendMessage("bgsw-ready");
       },
     },
   });
 
   await extension.startup();
--- a/toolkit/components/extensions/webidl-api/ExtensionTest.cpp
+++ b/toolkit/components/extensions/webidl-api/ExtensionTest.cpp
@@ -1,16 +1,17 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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 "ExtensionTest.h"
 #include "ExtensionEventManager.h"
 
+#include "js/Equality.h"  // JS::StrictlyEqual
 #include "mozilla/dom/ExtensionTestBinding.h"
 #include "nsIGlobalObject.h"
 
 namespace mozilla {
 namespace extensions {
 
 bool IsInAutomation(JSContext* aCx, JSObject* aGlobal) {
   return NS_IsMainThread()
@@ -47,16 +48,71 @@ bool ExtensionTest::IsAllowed(JSContext*
 
 JSObject* ExtensionTest::WrapObject(JSContext* aCx,
                                     JS::Handle<JSObject*> aGivenProto) {
   return dom::ExtensionTest_Binding::Wrap(aCx, this, aGivenProto);
 }
 
 nsIGlobalObject* ExtensionTest::GetParentObject() const { return mGlobal; }
 
+void ExtensionTest::CallWebExtMethodAssertEq(
+    JSContext* aCx, const nsAString& aApiMethod,
+    const dom::Sequence<JS::Value>& aArgs, ErrorResult& aRv) {
+  uint32_t argsCount = aArgs.Length();
+
+  JS::Rooted<JS::Value> expectedVal(
+      aCx, argsCount > 0 ? aArgs[0] : JS::UndefinedValue());
+  JS::Rooted<JS::Value> actualVal(
+      aCx, argsCount > 1 ? aArgs[1] : JS::UndefinedValue());
+  JS::Rooted<JS::Value> messageVal(
+      aCx, argsCount > 2 ? aArgs[2] : JS::UndefinedValue());
+
+  bool isEqual;
+  if (NS_WARN_IF(!JS::StrictlyEqual(aCx, actualVal, expectedVal, &isEqual))) {
+    ThrowUnexpectedError(aCx, aRv);
+    return;
+  }
+
+  JS::RootedString expectedJSString(aCx, JS::ToString(aCx, expectedVal));
+  JS::RootedString actualJSString(aCx, JS::ToString(aCx, actualVal));
+  JS::RootedString messageJSString(aCx, JS::ToString(aCx, messageVal));
+
+  nsString expected;
+  nsString actual;
+  nsString message;
+
+  if (NS_WARN_IF(!AssignJSString(aCx, expected, expectedJSString) ||
+                 !AssignJSString(aCx, actual, actualJSString) ||
+                 !AssignJSString(aCx, message, messageJSString))) {
+    ThrowUnexpectedError(aCx, aRv);
+    return;
+  }
+
+  if (!isEqual && actual.Equals(expected)) {
+    actual.AppendLiteral(" (different)");
+  }
+
+  if (NS_WARN_IF(!dom::ToJSValue(aCx, expected, &expectedVal) ||
+                 !dom::ToJSValue(aCx, actual, &actualVal) ||
+                 !dom::ToJSValue(aCx, message, &messageVal))) {
+    ThrowUnexpectedError(aCx, aRv);
+    return;
+  }
+
+  dom::Sequence<JS::Value> args;
+  if (NS_WARN_IF(!args.AppendElement(expectedVal, fallible) ||
+                 !args.AppendElement(actualVal, fallible) ||
+                 !args.AppendElement(messageVal, fallible))) {
+    ThrowUnexpectedError(aCx, aRv);
+    return;
+  }
+
+  CallWebExtMethodNoReturn(aCx, aApiMethod, args, aRv);
+}
+
 ExtensionEventManager* ExtensionTest::OnMessage() {
   if (!mOnMessageEventMgr) {
     mOnMessageEventMgr = CreateEventManager(u"onMessage"_ns);
   }
 
   return mOnMessageEventMgr;
 }
 
--- a/toolkit/components/extensions/webidl-api/ExtensionTest.h
+++ b/toolkit/components/extensions/webidl-api/ExtensionTest.h
@@ -53,16 +53,20 @@ class ExtensionTest final : public nsISu
   JSObject* WrapObject(JSContext* aCx,
                        JS::Handle<JSObject*> aGivenProto) override;
 
   // DOM bindings methods
   static bool IsAllowed(JSContext* aCx, JSObject* aGlobal);
 
   nsIGlobalObject* GetParentObject() const;
 
+  void CallWebExtMethodAssertEq(JSContext* aCx, const nsAString& aApiMethod,
+                                const dom::Sequence<JS::Value>& aArgs,
+                                ErrorResult& aRv);
+
   ExtensionEventManager* OnMessage();
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ExtensionTest)
 };
 
 }  // namespace extensions
 }  // namespace mozilla
--- a/toolkit/components/extensions/webidl-api/ExtensionWebIDL.conf
+++ b/toolkit/components/extensions/webidl-api/ExtensionWebIDL.conf
@@ -46,17 +46,17 @@ WEBEXT_TYPES_MAPPING = {
 #
 #     "namespace.methodName": "WebExtensionStubName",
 #
 # NOTE: Please keep this table in alphabetic order.
 WEBEXT_STUBS_MAPPING = {
     "runtime.connect": "ReturnsPort",
     "runtime.connectNative": "ReturnsPort",
     "runtime.getURL": "ReturnsString",
-    "test.assertEq": "NotImplementedNoReturn",
+    "test.assertEq": "AssertEq",
     "test.assertRejects": "NotImplementedAsync",
     "test.assertThrows": "NotImplementedNoReturn",
     "test.withHandlingUserInput": "NotImplementedNoReturn",
 }
 
 # Mapping table for the directories where the JSON API schema will be loaded
 # from.
 WEBEXT_SCHEMADIRS_MAPPING = {