WebIDL WebExtensions API Bindings ================================= While on ``manifest_version: 2`` all the extension globals (extension pages and content scripts) that lives on the main thread and the WebExtensions API bindings can be injected into the extension global from the JS privileged code part of the WebExtensions internals (`See Schemas.inject defined in Schemas.sys.mjs `_), in ``manifest_version: 3`` the extension will be able to declare a background service worker instead of a background page, and the existing WebExtensions API bindings can't be injected into this new extension global, because it lives off of the main thread. To expose WebExtensions API bindings to the WebExtensions ``background.service_worker`` global we are in the process of generating new WebIDL bindings for the WebExtensions API. .. warning:: For more general in depth details about WebIDL in Gecko: - :doc:`/dom/bindings/webidl/index` - :doc:`/dom/webIdlBindings/index` Review process on changes to webidl definitions ----------------------------------------------- .. note:: When new webidl definitions are being introduced for a WebExtensions API, or existing ones need to be updated to stay in sync with changes applied to the JSONSchema definitions of the same WebExtensions API, the resulting patch will include a **new or changed WebIDL located at dom/webidl** and that part of the patch **will require a mandatory review and sign-off from a peer part of the** webidl_ **phabricator review group**. This section includes a brief description about the special setup of the webidl files related to WebExtensions and other notes useful to the WebIDL peers that will be reviewing and signing off these webidl files. .. _webidl: https://phabricator.services.mozilla.com/tag/webidl/ How/Where are these webidl interfaces restricted to the extensions background service workers? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ All the webidl interfaces related to the extensions API are only visible in specific extension globals: the WebExtensions background service worker (a service worker declared in the extension ``manifest.json`` file, through the ``background.service_worker`` manifest field). All webidl interfaces related to the WebExtensions API interfaces are exposed through the ``ExtensionBrowser`` interface, which gets exposed into the ``ServiceWorkerGlobalScope`` through the ``ExtensionGlobalsMixin`` interface and restricted to the WebExtensions background service worker through the ``mozilla::extensions::ExtensionAPIAllowed`` helper function. See ``ExtensionBrowser`` and ``ExtensionGlobalsMixin`` interfaces defined from ExtensionBrowser.webidl_ and ``mozilla::extensions::ExtensionAPIAllowed`` defined in ExtensionBrowser.cpp_. .. _ExtensionBrowser.webidl: https://searchfox.org/mozilla-central/source/dom/webidl/ExtensionBrowser.webidl .. _ExtensionBrowser.cpp: https://searchfox.org/mozilla-central/source/toolkit/components/extensions/webidl-api/ExtensionBrowser.cpp Why do all the webidl interfaces for WebExtensions API use LegacyNoInterfaceObject? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The existing WebExtensions API bindings are not exposing any constructor in the globals where they are available (e.g. the webidl bindings for the ``browser.alarms`` API namespace is defined by the ``ExtensionAlarms`` webidl interface, but there shouldn't be any ``ExtensionAlarms`` constructor available as a global to extension code running in the background service worker). A previous attempt to create W3C specs for the WebExtensions APIs described in WebIDL syntaxes (https://browserext.github.io/browserext) was also using the same ``NoInterfaceObject`` WebIDL attribute on the definitions of the API namespace with the same motivations (eg. see ``BrowserExtBrowserRuntime`` as defined here: https://browserext.github.io/browserext/#webidl-definition-4). Bug 1713877_ is tracking a followup to determine a long term replacement for the ``LegacyNoInterfaceObject`` attribute currently being used. .. _1713877: https://bugzilla.mozilla.org/1713877 Background Service Workers API Request Handling ----------------------------------------------- .. figure:: webidl_bindings_backgroundWorker_apiRequestHandling.drawio.svg :alt: High Level Diagram of the Background Service Worker API Request Handling .. This svg diagram has been created using https://app.diagrams.net, the svg file also includes the source in the drawio format and so it can be edited more easily by loading it back into app.diagrams.net and then re-export from there (and include the updated drawio format content into the exported svg file). Generating WebIDL definitions from WebExtensions API JSONSchema --------------------------------------------------------------- WebIDL definitions for the extension APIs are being generated based on the WebExtensions API JSONSchema data (the same metadata used to generate the "privilged JS"-based API bindings). Most of the API methods in generated WebIDL are meant to be implemented using stub methods shared between all WebExtensions API classes, a ``WebExtensionStub`` webidl extended attribute specify which shared stub method should be used when the related API method is called. For more in depth details about how to generate or update webidl definition for an Extension API given its API namespace: .. toctree:: :maxdepth: 2 generate_webidl_from_jsonschema Wiring up new WebExtensions WebIDL files into mozilla-central ------------------------------------------------------------- After a new WebIDL definition has been generated, there are a few more steps to ensure that the new WebIDL binding is wired up into mozilla-central build system and to be able to complete successfully a full Gecko build that include the new bindings. For more in depth details about these next steps: .. toctree:: :maxdepth: 2 wiring_up_new_webidl_bindings Testing WebExtensions WebIDL bindings ------------------------------------- Once the WebIDL definition for an WebExtensions API namespace has been implemented and wired up, the following testing strategies are available to cover them as part of the WebExtensions testing suites: ``toolkit/components/extensions/test/xpcshell/webidl-api`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The xpcshell tests added to this group of xpcshell tests are meant to provide testing coverage related to lower level components and behaviors (e.g. when making changes to the shared C++ helpers defined in ``toolkit/components/extensions/webidl-api``, or adding new ones). These tests will often mock part of the internals and use a ``browser.mockExtensionAPI`` API namespace which is only available in tests and not mapped to any actual API implementation (instead it is being mocked in the test cases to recreate the scenario that the test case is meant to cover). And so **they are not meant to provide any guarantees in terms of consistency of the behavior of the two different bindings implementations** (the new WebIDL bindings vs. the current implemented bindings), instead the other test suites listed in the sections below should be used for that purpose. All tests in this directory are skipped in builds where the WebExtensions WebIDL API bindings are being disabled at build time (e.g. beta and release builds, where otherwise the test would permafail while riding the train once got on those builds). ``toolkit/components/extensions/test/xpcshell/xpcshell-serviceworker.ini`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ When a new or existing xpcshell tests added to this xpcshell-test manifest, all test extensions will be generated with a background service worker instead of a background page. .. warning:: **Unless the background page or scripts are declared as part of the test extension manifest**, the test file added to this manifest should be explicitly reviewed to make sure all tests are going to provide the expected test coverage in all modes. .. note:: In a background script that runs in both a background page and a background service worker it may be necessary to run different code for part of the test, ``self !== self.window`` is a simple check that can be used to detect if the script is being executed as a background service worker. Test tasks that should be skipped when running in "background service worker mode", but temporarily until a followup fixes the underlying issue can use the ``ExtensionTestUtils.isInBackgroundServiceWorkerTests()`` in the optional ``add_task``'s ``skip_if`` parameter: .. code-block:: js add_task( { // TODO(Bug TBF): remove this once ... skip_if: () => ExtensionTestUtils.isInBackgroundServiceWorkerTests(), }, async function test_someapi_under_scenario() { ... } ); On the contrary if the test tasks is covering a scenario that is specific to a background page, and it would need to be permanently skipped while the background script is running as a service worker, it may be more appropriate to split out those tests in a separate test file not included in this manifest. .. warning:: Make sure that all tests running in multiple modes (in-process, remote, and "background service worker mode") do not assume that the WebIDL bindings and Background Service Worker are enabled and to skip them when appropriate, otherwise the test will become a permafailure once it gets to a channel where the "Extensions WebIDL API bindings" are disabled by default at build time (currently on **beta** and **release**). While running the test files locally they will be executed once for each manifest file where they are included, to restrict the run to just the "background service workers mode" specify the ``sw-webextensions`` tag: .. code-block:: bash mach xpcshell-test --tag sw-webextensions path/to/test/file.js ``toolkit/components/extensions/test/mochitest/mochitest-serviceworker.ini`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Same as the xpcshell-serviceworker.ini manifest but for the mochitest-plain tests. .. warning:: The same warnings described in the xpcshell-serviceworker.ini subsection do also apply to this manifest file. Test tasks that should be skipped when not running in "background service worker mode" can be split into separate test file or skipped inside the ``add_task`` body, but mochitests' ``add_task`` does not support a ``skip_if`` option and so that needs to be done manually (and it may be good to also log a message to make it visible when a test is skipped): .. code-block:: js add_task(async function test_someapi_in_background_service_worker() { if (!ExtensionTestUtils.isInBackgroundServiceWorkerTests()) { is( ExtensionTestUtils.getBackgroundServiceWorkerEnabled(), false, "This test should only be skipped with background service worker disabled" ) info("Test intentionally skipped on 'extensions.backgroundServiceWorker.enabled=false'"); return; } ... }); While executing the test files locally they will run once for each manifest file where they are included, to restrict the run to just the "background service workers mode" specify the ``sw-webextensions`` tag: .. code-block:: bash mach mochitest --tag sw-webextensions path/to/test/file.js