Web 测试辅助工具

概述

在 “@odoo/hoot” 模块之后,测试文件中最常使用的第二个模块应该是 "@web/../tests/web_test_helpers"。

该模块包含所有辅助工具,它们将 Hoot 提供的底层辅助工具与 Odoo 测试中最常用的功能结合起来。

这类辅助工具数量众多,本节文档只重点介绍其中最常用的部分,以及它们彼此交互的方式。

如需查看可用辅助工具的完整列表,请参阅 web_test_helpers 文件。

模拟环境

makeMockEnv 辅助工具是能创建 env 的最底层辅助工具。

它会负责以下事项:

  • 创建 env 对象本身,并预先配置好 Web 组件正常运行所需的所有属性,例如 getTemplate 或 translateFn;

  • 如果该测试尚未创建过,则创建 MockServer;

  • 启动所有已注册的 服务,并等待它们全部就绪;

  • 初始化其他不依附于服务的功能,例如 Web router;

  • 确保在测试结束时清理其设置中涉及的所有功能。

该方法非常适合测试底层功能,例如不依附于 Component 的 服务:

// Can be further configured, but is already packed with all the necessary stuff
const env = await makeMockEnv();

expect(env.isSmall).toBe(false);

注解

与 makeMockServer 一样,每个测试只能有一个活动的 env。无需手动调用 makeMockEnv 来获取当前环境实例;可以改为调用 getMockEnv 辅助工具。

挂载组件

通过 mountWithCleanup 辅助工具,实例化 组件 并将其追加到 DOM 中应当是一件轻松的事。它会在内部准备 env,如果尚不存在则创建,进而确保 MockServer 正在运行。

它的第一个参数是一个 Component 类,第二个参数是 可选 的参数,用于指定 props 或自定义的 target:

await mountWithCleanup(Checkbox, {
    props: {
        value: false
    },
});

该辅助工具将返回活动的 Component 实例。

重要

通常 不建议 获取 Component 实例来直接与其交互,或对其内部变量执行断言。唯一“可接受”的用例是 Component 在 DOM 中显示难以获取的信息时,例如 canvas 中的图表。大多数情况下,强烈建议从 DOM 中查询派生信息。

挂载视图

挂载视图只需使用 mountWithCleanup 配合 View 组件和正确的属性即可。

为此,Web 测试辅助工具导出了 mountView 辅助工具,它接收一个参数对象,用于确定视图的 type、resModel 以及其他可选属性,例如 XML arch:

// Resolves when the view is fully ready
await mountView({
    type: "list",
    resModel: "res.partner",
    arch: /* xml */ `
        <list>
            <field name="display_name" />
        </list>
    `,
});

与 mountView 所基于的前述辅助工具一样,它会确保当前测试同时运行 env 和 MockServer。

注解

与 mountWithCleanup 一样,不建议 获取返回的 View 组件实例。但在某些情况下仍可这样做,例如 图表视图。

与组件交互

Hoot 提供了与 DOM 交互的辅助工具(例如 click、press 等)。然而,在与较复杂的组件交互时,这些辅助工具有 2 个问题:

  1. 辅助工具会尝试立即交互,而有时元素尚未被追加到文档中(所需时间也无法确定);

  2. 辅助工具对每个派发的事件只等待一个微任务周期,而大多数基于 Owl 的 UI 至少需要一个完整的动画帧才能完成更新。

// Edit record name
await click(".o_field_widget[name=name]");
await edit("Gaston Lagaffe");

// Potential error 1: button may not be in the DOM yet
await click(".btn:contains(Save)");

// Potential error 2: view is not yet updated
expect(".o_field_widget[name=name]").toHaveText("Gaston Lagaffe");

考虑到这些限制,Web 测试辅助工具提供了 contains 辅助工具:

// Combines 'click' + 'edit' + 'animationFrame' calls
await contains(".o_field_widget[name=name]").edit("Gaston Lagaffe");
// Waits for (at least) a full animation frame after the click
await contains(".btn:contains(Save)").click();
expect(".o_field_widget[name=name]").toHaveText("Gaston Lagaffe");

这种方法虽然看似离“单元测试”的概念稍远一些,但仍然是测试更复杂单元的一种不错且便捷的方式,例如 视图、WebClient,或 服务 与组件之间的成对交互。

但它不应成为所有交互的默认做法,因为其中一些交互仍需在给定的时间范围内 精确 发生,而这是 contains 完全忽略的概念。

注解

Hoot 中的大多数辅助工具都可以作为 contains 实例的方法使用,其形式与 API 通常相同。