命令 API
命令是一种特殊函数,它在服务器端被调用,执行特定操作后将结果返回给浏览器端。Vitest 提供了多种内置命令,你可以在浏览器测试中使用它们。
内置命令
文件处理
你可以在浏览器测试中使用 readFile
、writeFile
和 removeFile
API 来处理文件。自 Vitest 3.2 版本起,所有路径都相对于 项目 根目录解析(默认情况下为 process.cwd()
,除非手动指定)。在此之前,路径是相对于测试文件解析的。
默认情况下,Vitest 使用 utf-8
编码,但你可以通过选项覆盖此设置。
TIP
出于安全考虑,此 API 遵循 server.fs
限制。
import { server } from '@vitest/browser/context';
const { readFile, writeFile, removeFile } = server.commands;
it('handles files', async () => {
const file = './test.txt';
await writeFile(file, 'hello world');
const content = await readFile(file);
expect(content).toBe('hello world');
await removeFile(file);
});
CDP 会话
Vitest 通过从 @vitest/browser/context
导出的 cdp
方法,提供了对 Chrome Devtools Protocol (CDP) 的直接访问。这主要对库作者有用,以便在此基础上构建更高级的工具。
import { cdp } from '@vitest/browser/context';
const input = document.createElement('input');
document.body.appendChild(input);
input.focus();
await cdp().send('Input.dispatchKeyEvent', {
type: 'keyDown',
text: 'a',
});
expect(input).toHaveValue('a');
WARNING
CDP 会话仅适用于 playwright
提供者,并且仅在使用 chromium
浏览器时可用。详情请参阅 Playwright 的 CDPSession
文档。
自定义命令
你还可以通过 browser.commands
配置选项添加自己的命令。如果你正在开发一个库,可以通过插件中的 config
钩子来提供这些命令:
import type { Plugin } from 'vitest/config';
import type { BrowserCommand } from 'vitest/node';
const myCustomCommand: BrowserCommand<[arg1: string, arg2: string]> = (
{ testPath, provider },
arg1,
arg2
) => {
if (provider.name === 'playwright') {
console.log(testPath, arg1, arg2);
return { someValue: true };
}
throw new Error(`provider ${provider.name} is not supported`);
};
export default function BrowserCommands(): Plugin {
return {
name: 'vitest:custom-commands',
config() {
return {
test: {
browser: {
commands: {
myCustomCommand,
},
},
},
};
},
};
}
然后,你可以从 @vitest/browser/context
导入该命令,并在测试中调用它:
import { commands } from '@vitest/browser/context';
import { expect, test } from 'vitest';
test('custom command works correctly', async () => {
const result = await commands.myCustomCommand('test1', 'test2');
expect(result).toEqual({ someValue: true });
});
// if you are using TypeScript, you can augment the module
declare module '@vitest/browser/context' {
interface BrowserCommands {
myCustomCommand: (
arg1: string,
arg2: string
) => Promise<{
someValue: true;
}>;
}
}
WARNING
如果自定义函数与内置函数同名,它们将覆盖内置函数。
自定义 playwright
命令
Vitest 在命令上下文中暴露了几个 playwright
特定的属性。
page
引用包含测试 iframe 的完整页面。这是编排器 HTML,通常不应直接操作它,以免造成功能失效。frame
是一个异步方法,它会解析出测试器的Frame
对象。它与page
有类似的 API,但不支持某些方法。如果你需要查询元素,应该更推荐使用context.iframe
,因为它更稳定、更快。iframe
是一个FrameLocator
,应该用于查询页面上的其他元素。context
引用唯一的 BrowserContext。
import { BrowserCommand } from 'vitest/node';
export const myCommand: BrowserCommand<[string, number]> = async (
ctx,
arg1: string,
arg2: number
) => {
if (ctx.provider.name === 'playwright') {
const element = await ctx.iframe.findByRole('alert');
const screenshot = await element.screenshot();
// do something with the screenshot
return difference;
}
};
TIP
若使用 TypeScript,不要忘记在你的 setup file 或 config file 中引用 @vitest/browser/providers/playwright
,以便在配置和 userEvent
及 page
选项中实现自动补全:
/// <reference types="@vitest/browser/providers/playwright" />
自定义 webdriverio
命令
Vitest 在上下文对象上暴露了一些 webdriverio
特定的属性。
browser
是WebdriverIO.Browser
API。
Vitest 会在命令调用之前,通过调用 browser.switchToFrame
自动将 webdriver
上下文切换到测试 iframe。因此,$
和 $$
方法引用的是 iframe 内部的元素,而不是编排器中的元素,但非 webdriver API 仍将引用父框架上下文。
TIP
若使用 TypeScript,不要忘记在你的 setup file 或 config file 中引用 @vitest/browser/providers/webdriverio
,以便获得自动补全:
/// <reference types="@vitest/browser/providers/webdriverio" />