Web test helpers¶
概述¶
继 “@odoo/hoot” 模块之后,测试文件中第二个最常用的模块应为 "@web/../tests/web_test_helpers"。
该模块包含所有辅助函数,这些辅助函数将 Hoot 提供的底层辅助函数与 Odoo 测试中最常用的特性结合起来。
这些辅助函数很多,本节文档仅重点介绍最常用的辅助函数及其相互交互方式。
完整的可用辅助函数列表请参见 web_test_helpers file。
Mock environment¶
makeMockEnv 是最底层的辅助函数,能够生成一个 env。
It will take care of
创建
env对象本身,并预配置好 Web 部件正常运行所需的所有属性,如getTemplate或translateFn;生成一个
MockServer(若该测试尚未有一个);启动所有已注册的 services,并等待它们全部就绪;
初始化其他不与某个服务绑定的特性,如 Web
router(路由器);保证在测试结束时拆卸其设置中的所有特性。
该方法非常适合测试底层特性,如未与 Component 绑定的 services:
// 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 辅助函数代替。
Example
Mounting components¶
借助 mountWithCleanup 辅助函数,实例化 components 并将其追加到 DOM 应当很简单。它会在内部准备好 env (若尚不存在),进而确保有一个 MockServer 在运行。
它接收一个 Component 类作为第一个参数,以及一个 可选 的第二参数用于指定 props 或自定义 target:
await mountWithCleanup(Checkbox, {
props: {
value: false
},
});
该辅助函数将返回处于活跃状态的 Component 实例。
重要
通常 不建议 获取 Component 实例来直接与其交互或对内部变量进行断言。唯一”可接受”的用例是 Component 在 DOM 中显示难以获取的信息时,例如 canvas 中的图表。大多数情况下,更推荐查询 DOM 中的派生信息。
Example
Mounting views¶
挂载视图只需使用 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 部件实例。不过像 Graph view 这样的用例是可以的。
与部件交互¶
Hoot 提供了与 DOM 交互的辅助函数(如 click、press 等)。不过,当与更复杂的部件交互时,这些辅助函数存在 2 个问题:
辅助函数尝试立即交互,而有时元素尚未被追加到文档中(时间未知);
辅助函数对每个派发的事件只等待一个微任务(micro-task)节拍,而大多数基于 Owl 的 UI 至少需要一个完整的动画帧(animation frame)才能更新。
// 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");
这种方式虽然看起来略偏离”单元测试”的概念,但仍然是测试更复杂单元(如 views、WebClient)或成对的 services 与部件之间交互的一种简洁便捷的方法。
不过它不应成为所有交互的默认做法,因为有些交互仍需在给定的时间框架内 精确 发生,而 contains 完全忽略了这一概念。
注解
Hoot 中的大多数辅助函数也可作为 contains 实例的方法使用,其(通常)形态和 API 相同。