编写新的浏览器 mochitests

创建新的空测试文件后,您将获得一个空的add_task,您可以在其中编写测试。

一般指南

测试可以使用okisisnot,以及所有常规的CommonJS 标准断言来进行测试断言。

测试可以使用info将字符串记录到测试输出中。console.log适用于单个测试的本地运行,但通常不用于签入的测试。

测试将在浏览器窗口内的单独作用域中运行。gBrowsergURLBardocument以及其他各种全局变量因此可以像在同一窗口中非测试代码一样访问。但是,在测试文件中声明的变量在其生命周期结束后将不会存在。

测试架构

各个测试有责任将其找到的浏览器保持原样。如果测试更改了首选项、打开了选项卡、自定义了 UI 或进行了其他更改,则在完成时应将其恢复。

为了帮助做到这一点,提供了一些有用的基本功能

  • add_setup允许您添加在任何add_task任务之前运行的设置任务。

  • SpecialPowers.pushPrefEnv见下文)允许您设置首选项,这些首选项将在测试文件运行结束后自动恢复。

  • BrowserTestUtils.withNewTab允许您轻松运行与您打开的选项卡进行交互的异步代码,并在完成后关闭它。

  • registerCleanupFunction接受一个异步回调函数,您可以使用它来执行测试可能需要的任何其他清理工作。

常见操作

打开新的选项卡和新窗口,以及关闭它们

应使用BrowserTestUtils中的相关方法(无需任何额外工作即可使用)。

典型情况如下

add_task(async function() {
  await BrowserTestUtils.withNewTab("https://example.com/mypage", async (browser) {
    // `browser` will have finished loading the passed URL when this code runs.
    // Do stuff with `browser` in here. When the async function exits,
    // the test framework will clean up the tab.
  });
});

在与选项卡或其子框架关联的内容进程中执行代码

应使用SpecialPowers.spawn

let result = await SpecialPowers.spawn(browser, [42, 100], async (val, val2) => {
  // Replaces the document body with '42':
  content.document.body.textContent = val;
  // Optionally, return a result. Has to be serializable to make it back to
  // the parent process (so DOM nodes or similar won't work!).
  return Promise.resolve(val2 * 2);
});

您可以传递 BrowsingContext 引用而不是browser以直接在子框架中执行代码。

在传递给SpecialPowers.spawn的函数参数内,content指的是该浏览器/BrowsingContext 中 Web 内容的window

对于某些操作,例如鼠标点击,BrowserTestUtils上提供了便捷助手

await BrowserTestUtils.synthesizeMouseAtCenter("#my.css.selector", {accelKey: true}, browser);

更改首选项

使用SpecialPowers.pushPrefEnv

await SpecialPowers.pushPrefEnv({
  set: [["accessibility.tabfocus", 7]]
});

此示例设置允许按钮和其他控件接收选项卡焦点的首选项 - 这是 Windows 和 Linux 上的默认设置,但在 macOS 上不是,因此如果您的测试在 macOS 上使用键盘焦点,则可能需要它才能可靠地通过。

等待观察者服务通知主题或 DOM 事件

分别使用TestUtils上的实用程序

await TestUtils.topicObserved("sync-pane-loaded");

BrowserTestUtils

await BrowserTestUtils.waitForEvent(domElement, "click");

等待某些 DOM 更新。

使用BrowserTestUtils.waitForMutationCondition。**不要**使用waitForCondition,它使用超时循环,并且经常导致间歇性故障。

模拟未经测试的代码

提供了Sinon 模拟框架。您可以使用类似以下内容导入它

const { sinon } = ChromeUtils.importESModule("resource://testing-common/Sinon.sys.mjs");

Sinon 网站上提供了有关如何进行模拟的更多详细信息。

其他文件

您可以通过使用browser.toml文件将其添加到support-files属性来使用额外文件(例如要加载的网页)

["browser_foo.js"]
support-files = [
  "bar.html",
  "baz.js",
]

在测试之间重用代码

对于特定测试集通用的操作,您可以使用head.js文件来共享 JS 代码。

如果代码需要跨测试的各个目录使用,您应该考虑它是否足够通用以至于需要包含在BrowserTestUtils.sys.mjs中,或者如果没有,则设置一个单独的jsm模块,其中包含您的测试帮助程序。您可以将这些添加到moz.build中的TESTING_JS_MODULES中,以避免将它们与 Firefox 打包在一起。它们将在resource://testing-common/中对所有测试可用。