单元测试

概述

我们在活动流中的单元测试使用 mocha、chai 和 sinon 编写,并使用 karma 运行。它们包括内容代码(React 组件等)和 .sys.mjs 的单元测试。

您可以在 tests/unit 中找到单元测试。

执行

要运行一次单元测试,请执行 npm test

要持续运行单元测试(即在“测试驱动开发”模式下),您可以运行 npm run tddmc

调试

要调试测试,您应该使用 npm run tddmc 以持续模式运行它们。在打开的 Firefox 窗口中(它应该显示“Karma… - connected”),点击“debug”按钮并打开您的控制台以查看测试输出、设置断点等。

不幸的是,Firefox 中的测试源映射目前尚不可用。如果您需要查看行号,可以通过运行 npm install --save-dev karma-chrome-launcher && npm run tddmc -- --browsers Chrome 使用 Chrome 运行测试。

放置新测试的位置

如果您正在创建新的测试,请将其添加到 tests/unit 的子目录中,该子目录对应于您正在测试的文件。测试应以 .test.js.test.jsx 结尾,如果测试包含任何 jsx。

例如,如果您正在测试的文件是 lib/Foo.sys.mjs,则测试文件应为 test/unit/lib/Foo.test.js

Mocha 测试

我们所有的单元测试都是使用 mocha 编写的,它注入诸如 describeitbeforeEach 等全局变量。它可用于编写同步或异步测试。

describe("FooModule", () => {
  // A synchronous test
  it("should create an instance", () => {
    assert.instanceOf(new FooModule(), FooModule);
  });
  describe("#meaningOfLife", () => {
    // An asynchronous test
    it("should eventually get the meaning of life", async () => {
      const foo = new FooModule();
      const result = await foo.meaningOfLife();
      assert.equal(result, 42);
    });
  });
});

断言

要编写断言,请使用全局可用的 assert 对象(这是由 karma-chai 提供的,因此您无需 require 它)。

例如

assert.equal(foo, 3);
assert.propertyVal(someObj, "foo", 3);
assert.calledOnce(someStub);

您可以使用来自以下任何断言:

自定义断言

我们有一些自定义断言用于检查各种类型的操作。

.isUserEventAction(action)

断言给定的 action 是有效的用户事件,即它仅包含活动流中用户事件的预期/有效属性。

// This will pass
assert.isUserEventAction(ac.UserEvent({event: "CLICK"}));

// This will fail
assert.isUserEventAction({type: "FOO"});

// This will fail because BLOOP is not a valid event type
assert.isUserEventAction(ac.UserEvent({event: "BLOOP"}));

.sys.mjs 中覆盖全局变量

您将要测试的大多数 .sys.mjs 使用 Cu.importXPCOMUtils 来注入全局变量。为了为这些全局变量添加模拟/存根/伪造,您应该使用 test/unit/utils 中的 GlobalOverrider 实用程序。

const {GlobalOverrider} = require("test/unit/utils");
describe("MyModule", () => {
  let globals;
  let sandbox;
  beforeEach(() => {
    globals = new GlobalOverrider();
    sandbox = globals.sandbox; // this is a sinon sandbox
    // This will inject a "AboutNewTab" global before each test
    globals.set("AboutNewTab", {override: sandbox.stub()});
  });
  // globals.restore() clears any globals you added as well as the sinon sandbox
  afterEach(() => globals.restore());
});

测试 React 组件

您应该使用 enzyme 测试套件来测试活动流的 React 组件。

如果可能,请使用 浅渲染方法(这将避免不必要地渲染子组件)。

const React = require("react");
const {shallow} = require("enzyme");

describe("<Foo>", () => {
  it("should be hidden by default", () => {
    const wrapper = shallow(<Foo />);
    assert.isTrue(wrapper.find(".wrapper").props().hidden);
  });
});

如果需要,您也可以使用 enzyme 的 mount 实用程序进行 完整 DOM 渲染

const React = require("react");
const {mount} = require("enzyme");
...
const wrapper = mount(<Foo />);