WebIDL WebExtensions API 绑定¶
在 manifest_version: 2
中,所有位于主线程上的扩展全局变量(扩展页面和内容脚本),以及 WebExtensions API 绑定,都可以从 WebExtensions 内部机制的 JS 特权代码部分注入到扩展全局变量中(参见 Schemas.sys.mjs 中定义的 Schemas.inject)。而在 manifest_version: 3
中,扩展可以声明一个后台服务工作线程来代替后台页面,而现有的 WebExtensions API 绑定无法注入到这个新的扩展全局变量中,因为它位于主线程之外。
为了将 WebExtensions API 绑定公开给 WebExtensions 的 background.service_worker
全局变量,我们正在生成 WebExtensions API 的新的 WebIDL 绑定。
WebIDL 定义变更审查流程¶
注意
当为 WebExtensions API 引入新的 WebIDL 定义,或需要更新现有的 WebIDL 定义以与应用于同一 WebExtensions API 的 JSONSchema 定义的更改保持同步时,生成的补丁将包括 **位于 dom/webidl 的新的或更改的 WebIDL**,并且补丁的这部分 **需要来自** webidl **Phabricator 审查组的同行强制审查和签核**。
本节简要介绍了与 WebExtensions 相关的 WebIDL 文件的特殊设置,以及对将审查和签核这些 WebIDL 文件的 WebIDL 同行有用的其他说明。
这些 WebIDL 接口如何/在哪里限制在扩展的后台服务工作线程中?¶
所有与扩展 API 相关的 WebIDL 接口仅在特定的扩展全局变量中可见:WebExtensions 后台服务工作线程(在扩展的 manifest.json
文件中,通过 background.service_worker
清单字段声明的服务工作线程)。
所有与 WebExtensions API 接口相关的 WebIDL 接口都通过 ExtensionBrowser
接口公开,该接口通过 ExtensionGlobalsMixin
接口公开到 ServiceWorkerGlobalScope
中,并通过 mozilla::extensions::ExtensionAPIAllowed
辅助函数限制在 WebExtensions 后台服务工作线程中。
请参阅 ExtensionBrowser.webidl 中定义的 ExtensionBrowser
和 ExtensionGlobalsMixin
接口,以及 ExtensionBrowser.cpp 中定义的 mozilla::extensions::ExtensionAPIAllowed
。
为什么 WebExtensions API 的所有 WebIDL 接口都使用 LegacyNoInterfaceObject?¶
现有的 WebExtensions API 绑定不会在可用的全局变量中公开任何构造函数(例如,browser.alarms
API 命名空间的 WebIDL 绑定由 ExtensionAlarms
WebIDL 接口定义,但作为全局变量,不应该有任何 ExtensionAlarms
构造函数可供在后台服务工作线程中运行的扩展代码使用)。
之前尝试使用 WebIDL 语法创建 WebExtensions API 的 W3C 规范(https://browserext.github.io/browserext)也对 API 命名空间的定义使用了相同的 NoInterfaceObject
WebIDL 属性,其动机相同(例如,参见此处定义的 BrowserExtBrowserRuntime
:https://browserext.github.io/browserext/#webidl-definition-4)。
Bug 1713877 正在跟踪后续操作,以确定当前使用的 LegacyNoInterfaceObject
属性的长期替代方案。
后台服务工作线程 API 请求处理¶
从 WebExtensions API JSONSchema 生成 WebIDL 定义¶
扩展 API 的 WebIDL 定义是根据 WebExtensions API JSONSchema 数据生成的(与用于生成基于“特权 JS”的 API 绑定的元数据相同)。
生成 WebIDL 中的大多数 API 方法都旨在使用所有 WebExtensions API 类共享的存根方法实现,WebExtensionStub
WebIDL 扩展属性指定在调用相关 API 方法时应使用哪个共享存根方法。
有关如何为扩展 API 生成或更新 WebIDL 定义(给定其 API 命名空间)的更多详细信息
将新的 WebExtensions WebIDL 文件连接到 mozilla-central¶
生成新的 WebIDL 定义后,还需要执行几个步骤来确保新的 WebIDL 绑定连接到 mozilla-central 构建系统,并能够成功完成包含新绑定的完整 Gecko 构建。
有关这些后续步骤的更多详细信息
测试 WebExtensions WebIDL 绑定¶
一旦 WebExtensions API 命名空间的 WebIDL 定义已实现并连接,以下测试策略可用于将其作为 WebExtensions 测试套件的一部分进行覆盖
toolkit/components/extensions/test/xpcshell/webidl-api
¶
添加到此组 xpcshell 测试中的 xpcshell 测试旨在提供与较低级别组件和行为相关的测试覆盖范围(例如,在更改 toolkit/components/extensions/webidl-api
中定义的共享 C++ 辅助函数或添加新的辅助函数时)。
这些测试通常会模拟部分内部机制并使用 browser.mockExtensionAPI
API 命名空间,该命名空间仅在测试中可用,并且不会映射到任何实际的 API 实现(而是它在测试用例中被模拟以重新创建测试用例旨在覆盖的场景)。
因此,**它们并非旨在在两种不同的绑定实现(新的 WebIDL 绑定与当前实现的绑定)的行为一致性方面提供任何保证**,而应使用下面各节中列出的其他测试套件来实现此目的。
在构建时禁用 WebExtensions WebIDL API 绑定的构建中,此目录中的所有测试都将被跳过(例如,Beta 和发布版本,否则测试将在搭乘列车时永久失败,一旦搭乘了这些版本)。
toolkit/components/extensions/test/xpcshell/xpcshell-serviceworker.ini
¶
当将新的或现有的 xpcshell 测试添加到此 xpcshell 测试清单时,所有测试扩展都将使用后台服务工作线程而不是后台页面生成。
警告
**除非后台页面或脚本作为测试扩展清单的一部分声明**,否则应明确审查添加到此清单中的测试文件,以确保所有测试都将在所有模式下提供预期的测试覆盖范围。
注意
在后台脚本中,该脚本在后台页面和后台服务工作线程中运行,可能需要为测试的一部分运行不同的代码,self !== self.window
是一个简单的检查,可用于检测脚本是否作为后台服务工作线程执行。
在运行“后台服务工作线程模式”时,应该跳过测试任务,但暂时(直到后续修复底层问题)可以在可选的add_task
的skip_if
参数中使用ExtensionTestUtils.isInBackgroundServiceWorkerTests()
。
add_task(
{
// TODO(Bug TBF): remove this once ...
skip_if: () => ExtensionTestUtils.isInBackgroundServiceWorkerTests(),
},
async function test_someapi_under_scenario() {
...
}
);
相反,如果测试任务涵盖了特定于后台页面的场景,并且需要在后台脚本作为服务工作线程运行时永久跳过,则将其拆分到此清单中未包含的单独测试文件中可能更合适。
警告
确保所有在多种模式(进程内、远程和“后台服务工作线程模式”)下运行的测试都不假设 WebIDL 绑定和后台服务工作线程已启用,并在适当的时候跳过它们,否则一旦测试到达在构建时默认禁用“扩展 WebIDL API 绑定”的通道(目前在 **beta** 和 **release** 上),测试将变成永久失败。
在本地运行测试文件时,它们将在包含它们的每个清单文件中执行一次,要将运行限制为仅“后台服务工作线程模式”,请指定sw-webextensions
标签。
mach xpcshell-test --tag sw-webextensions path/to/test/file.js
toolkit/components/extensions/test/mochitest/mochitest-serviceworker.ini
¶
与 xpcshell-serviceworker.ini 清单相同,但适用于 mochitest-plain 测试。
警告
xpcshell-serviceworker.ini 小节中描述的相同警告也适用于此清单文件。
不运行“后台服务工作线程模式”时应跳过的测试任务可以拆分到单独的测试文件,或者在add_task
主体中跳过,但是 mochitests 的add_task
不支持skip_if
选项,因此需要手动执行(并且最好也记录一条消息,以便在跳过测试时可见)。
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;
}
...
});
在本地执行测试文件时,它们将在包含它们的每个清单文件中运行一次,要将运行限制为仅“后台服务工作线程模式”,请指定sw-webextensions
标签。
mach mochitest --tag sw-webextensions path/to/test/file.js