命令
命令是一种函数,它在服务器上调用另一个函数,并将结果返回给浏览器。Vitest 暴露了一些内置命令,你可以在浏览器测试中使用。
内置命令
文件处理
你可以使用 readFile
、writeFile
和 removeFile
API 在浏览器测试中处理文件。即使这些 API 在位于另一个文件中的辅助函数中被调用,所有路径也都是相对于测试文件解析的。
默认情况下,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 的访问。这主要对库作者在其基础上构建工具很有用。
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
。它的 API 与page
类似,但不支持某些方法。如果你需要查询元素,应该优先使用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,不要忘记将 @vitest/browser/providers/playwright
添加到你的 tsconfig
"compilerOptions.types" 字段中,以便在配置和 userEvent
以及 page
选项中获得自动补全:
{
"compilerOptions": {
"types": ["@vitest/browser/providers/playwright"]
}
}
自定义 webdriverio
命令
Vitest 在上下文对象上暴露了一些 webdriverio
特定的属性。
browser
是WebdriverIO.Browser
API。
Vitest 在调用命令之前会自动通过调用 browser.switchToFrame
将 webdriver
上下文切换到测试 iframe,因此 $
和 $$
方法引用的是 iframe 内的元素,而不是协调器中的元素,但非 Webdriver API 仍将引用父框架上下文。
TIP
如果你正在使用 TypeScript,不要忘记将 @vitest/browser/providers/webdriverio
添加到你的 tsconfig
"compilerOptions.types" 字段中,以便获得自动补全:
{
"compilerOptions": {
"types": ["@vitest/browser/providers/webdriverio"]
}
}