Skip to content

Commit 98b087e

Browse files
authored
Merge pull request #988 from vitest-dev/sync-95a42b87-1
docs(en): merge docs-cn/sync-docs into docs-cn/dev @ 95a42b8
2 parents 1216d23 + f399b31 commit 98b087e

23 files changed

Lines changed: 775 additions & 322 deletions

.vitepress/config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,10 @@ export default ({ mode }: { mode: string }) => {
902902
text: '类型测试',
903903
link: '/guide/testing-types',
904904
},
905+
{
906+
text: 'Benchmarking',
907+
link: '/guide/benchmarking',
908+
},
905909
{
906910
text: '内联测试',
907911
link: '/guide/in-source',

.vitepress/sponsors.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,6 @@ export const sponsors: SponsorTier[] = [
4343
url: 'https://vital.io/',
4444
img: '/vital.svg',
4545
},
46-
{
47-
name: 'OOMOL',
48-
url: 'https://oomol.com/',
49-
img: '/oomol.svg',
50-
},
5146
{
5247
name: 'Mailmeteor',
5348
url: 'https://mailmeteor.com/',
@@ -58,6 +53,11 @@ export const sponsors: SponsorTier[] = [
5853
url: 'https://www.liminity.se/',
5954
img: '/liminity.svg',
6055
},
56+
{
57+
name: 'Kraken Tech',
58+
url: 'https://kraken.tech/',
59+
img: '/kraken.svg',
60+
},
6161
{
6262
name: 'Aerius Ventilation',
6363
url: 'https://aerius.se/',

api/advanced/vitest.md

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,35 +5,9 @@ title: Vitest API
55

66
# Vitest
77

8-
Vitest 实例需要当前的测试模式。它可以是以下之一:
9-
10-
- `test`:运行运行时测试时
11-
- `benchmark`:运行基准测试时 <Experimental />
12-
13-
::: details New in Vitest 4
14-
Vitest 4 新增了多个 API(它们都标记有 "4.0.0+" 徽章),并移除了已弃用的 API:
15-
16-
- `invalidates`
17-
- `changedTests`(使用 [`onFilterWatchedSpecification`](#onfilterwatchedspecification) 代替)
18-
- `server`(使用 [`vite`](#vite) 代替)
19-
- `getProjectsByTestFile`(使用 [`getModuleSpecifications`](#getmodulespecifications) 代替)
20-
- `getFileWorkspaceSpecs`(使用 [`getModuleSpecifications`](#getmodulespecifications) 代替)
21-
- `getModuleProjects`(自行通过 [`this.projects`](#projects) 过滤)
22-
- `updateLastChanged`(重命名为 [`invalidateFile`](#invalidatefile)
23-
- `globTestSpecs`(使用 [`globTestSpecifications`](#globtestspecifications) 代替)
24-
- `globTestFiles`(使用 [`globTestSpecifications`](#globtestspecifications) 代替)
25-
- `listFile`(使用 [`getRelevantTestSpecifications`](#getrelevanttestspecifications) 代替)
26-
:::
27-
28-
## mode
29-
30-
### test
31-
32-
测试模式只会调用 `test``it` 中的函数,并在遇到 `bench` 时抛出错误。此模式使用配置中的 `include``exclude` 选项来查找测试文件。
33-
34-
### benchmark <Experimental /> {#benchmark}
8+
## mode <Deprecated /> {#mode}
359

36-
基准测试模式调用 `bench` 函数,并在遇到 `test``it` 时抛出错误。此模式使用配置中的 `benchmark.include``benchmark.exclude` 选项来查找基准测试文件。
10+
Since Vitest 5, this property is always `'test'`.
3711

3812
## config
3913

api/browser/assertions.md

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ test('error banner is rendered', async () => {
3434
// 它会反复检查该元素是否存在于 DOM 中,并且
3535
// `element.textContent` 的内容等于 "Error!"
3636
// 直到所有条件都满足为止
37-
await expect.element(banner).toHaveTextContent('Error!')
37+
await expect.element(banner).toMatchTextContent('Error!')
3838
})
3939
```
4040

@@ -56,11 +56,11 @@ interface ExpectPollOptions {
5656
::: tip
5757
Like [`expect.poll`](/api/expect#poll), `expect.element` retries DOM assertions until they pass or the timeout is reached. When it receives a locator, Vitest resolves it with [`locator.findElement()`](/api/browser/locators#findelement) before running the DOM assertion. The `timeout` option applies to the whole retry operation. The `interval` option controls how often failed DOM assertions are retried, but locator resolution uses `findElement`'s own increasing retry intervals.
5858

59-
`toHaveTextContent` 以及其他所有断言在常规的 `expect` 中仍然可用,但没有内置的重试机制:
59+
`toMatchTextContent` 以及其他所有断言在常规的 `expect` 中仍然可用,但没有内置的重试机制:
6060

6161
```ts
6262
// 如果 .textContent 不是 `'Error!'`,则会立即失败。
63-
expect(banner).toHaveTextContent('Error!')
63+
expect(banner).toMatchTextContent('Error!')
6464
```
6565
:::
6666

@@ -696,7 +696,32 @@ await expect.element(button).not.toHaveStyle({
696696

697697
```ts
698698
function toHaveTextContent(
699-
text: string | RegExp,
699+
text: string | number,
700+
options?: { normalizeWhitespace: boolean }
701+
): Promise<void>
702+
```
703+
<!-- TODO: translation -->
704+
This matcher allows you to validate that an element's text matches provided string exactly. This
705+
supports elements, but also text nodes and fragments.
706+
707+
If you wish to perform a partial check or do a case-sensitive match, use [`toMatchTextContent`](#tomatchtextcontent) instead.
708+
709+
```html
710+
<span data-testid="text-content">Text Content</span>
711+
```
712+
713+
```ts
714+
const element = getByTestId('text-content')
715+
716+
await expect.element(element).toHaveTextContent('Text Content')
717+
await expect.element(element).not.toHaveTextContent('Content')
718+
```
719+
720+
## toMatchTextContent
721+
722+
```ts
723+
function toMatchTextContent(
724+
text: string | number | RegExp,
700725
options?: { normalizeWhitespace: boolean }
701726
): Promise<void>
702727
```
@@ -707,7 +732,7 @@ function toHaveTextContent(
707732

708733
若要进行不区分大小写的匹配,可以使用带有 `/i` 修饰符的 `RegExp`
709734

710-
如果你想匹配整段内容,可以使用 `RegExp` 来实现。
735+
如果你想匹配整段内容,可以使用 `RegExp` 或 [`toHaveTextContent`](#tohavetextcontent) 来实现。
711736

712737
```html
713738
<span data-testid="text-content">Text Content</span>
@@ -716,12 +741,12 @@ function toHaveTextContent(
716741
```ts
717742
const element = getByTestId('text-content')
718743
719-
await expect.element(element).toHaveTextContent('Content')
744+
await expect.element(element).toMatchTextContent('Content')
720745
// 匹配整段内容
721-
await expect.element(element).toHaveTextContent(/^Text Content$/)
746+
await expect.element(element).toMatchTextContent(/^Text Content$/)
722747
// 不区分大小写匹配
723-
await expect.element(element).toHaveTextContent(/content$/i)
724-
await expect.element(element).not.toHaveTextContent('content')
748+
await expect.element(element).toMatchTextContent(/content$/i)
749+
await expect.element(element).not.toMatchTextContent('content')
725750
```
726751

727752
## toHaveValue

api/browser/commands.md

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,11 @@ outline: deep
1414
在浏览器测试中,可借助 `readFile``writeFile``removeFile` 三个 API 完成文件操作。自 Vitest 3.2 起,所有路径均以 [project](/guide/projects) 根目录为基准解析(根目录默认为 `process.cwd()`,可手动重写);旧版本则以当前测试文件所在目录为基准。
1515

1616
默认情况下,Vitest 使用 `utf-8` 编码,但你可以使用选项覆盖它。
17-
17+
<!-- TODO: translation -->
1818
::: tip
19-
此 API 遵循 [`server.fs`](https://vitejs.dev/config/server-options.html#server-fs-allow) 出于安全原因的限制。
19+
The built-in file commands follow Vite's [`server.fs`](https://vitejs.dev/config/server-options.html#server-fs-allow) restrictions for security reasons.
2020

21-
<!-- TODO: translation -->
22-
If [`browser.api.allowWrite`](/config/browser/api) or [`api.allowWrite`](/config/api#api-allowwrite) are disabled, `writeFile` and `removeFile` functions won't do anything.
21+
`writeFile` and `removeFile` also require write access through [`browser.api.allowWrite`](/config/browser/api) and [`api.allowWrite`](/config/api#api-allowwrite).
2322
:::
2423

2524
```ts
@@ -59,7 +58,9 @@ expect(input).toHaveValue('a')
5958
```
6059

6160
::: warning
62-
CDP session仅适用于 `playwright` provider,并且仅在使用 `chromium` 浏览器时有效。有关详细信息,请参阅 playwright 的 [`CDPSession`](https://playwright.dev/docs/api/class-cdpsession)文档。
61+
CDP session 仅适用于 `playwright` provider,并且仅在使用 `chromium` 浏览器时有效。有关详细信息,请参阅 playwright 的 [`CDPSession`](https://playwright.dev/docs/api/class-cdpsession) 文档。
62+
63+
CDP is a privileged debugging API. It is available only when browser API write and exec operations are enabled through [`browser.api.allowWrite`](/config/browser/api#api-allowwrite), [`browser.api.allowExec`](/config/browser/api#api-allowexec), [`api.allowWrite`](/config/api#api-allowwrite), and [`api.allowExec`](/config/api#api-allowexec).
6364
:::
6465

6566
## 自定义命令 {#custom-commands}
@@ -125,7 +126,55 @@ declare module 'vitest/browser' {
125126
::: warning
126127
如果自定义命令具有相同的名称,则它们将覆盖内置命令。
127128
:::
128-
<!-- TODO: translation -->
129+
130+
::: warning Security
131+
Custom commands run in the Vitest Node process and are callable from browser test code through Vitest's browser RPC connection. They can access local files, environment variables, network services, databases, shell commands, and other Node APIs.
132+
133+
Vitest's built-in file commands validate paths against Vite's [`server.fs`](https://vite.dev/config/server-options#server-fs-allow) restrictions and separately check whether writes are allowed. Custom commands do not automatically inherit these protections. If a custom command accepts browser-provided input and uses it to read, write, delete, execute, or expose local resources, validate that input before using it.
134+
135+
For file reads or fixture loading, use `isFileLoadingAllowed` from `vitest/node` or an explicit allowlist. For writes and deletes, also require an explicit mutation policy, such as [`browser.api.allowWrite`](/config/browser/api#api-allowwrite), [`api.allowWrite`](/config/api#api-allowwrite), and a command-specific allowed directory. For commands that execute code, shell commands, or project scripts, also check [`browser.api.allowExec`](/config/browser/api#api-allowexec) and [`api.allowExec`](/config/api#api-allowexec).
136+
137+
For example, if you create your own file-writing command instead of using Vitest's built-in `writeFile`, apply the same checks:
138+
139+
```ts
140+
import { mkdir, writeFile } from 'node:fs/promises'
141+
import { dirname, resolve } from 'node:path'
142+
import { normalizePath } from 'vite'
143+
import { isFileLoadingAllowed } from 'vitest/node'
144+
import type { BrowserCommand } from 'vitest/node'
145+
146+
function assertFileAccess(path: string, project: any) {
147+
if (
148+
!isFileLoadingAllowed(project.vite.config, path)
149+
&& !isFileLoadingAllowed(project.vitest.vite.config, path)
150+
) {
151+
throw new Error(`Access denied to "${path}".`)
152+
}
153+
}
154+
155+
function assertWrite(project: any) {
156+
if (!project.config.browser.api.allowWrite || !project.vitest.config.api.allowWrite) {
157+
throw new Error('Writing files is disabled.')
158+
}
159+
}
160+
161+
export const myWriteFileCommand: BrowserCommand<[path: string, content: string]> = async (
162+
{ project },
163+
path,
164+
content,
165+
) => {
166+
assertWrite(project)
167+
168+
const file = resolve(project.config.root, path)
169+
assertFileAccess(normalizePath(file), project)
170+
171+
await mkdir(dirname(file), { recursive: true })
172+
await writeFile(file, content)
173+
}
174+
```
175+
176+
:::
177+
129178
### Recording trace markers
130179

131180
Custom commands can record [trace markers](/api/browser/context#mark) for the test that triggered them through `context.mark`. This is the server-side equivalent of `page.mark` and helps annotate the [trace view](/guide/browser/trace-view) with custom actions performed inside a command.

api/browser/context.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,8 @@ At the moment, the `frameLocator` method is only supported by the `playwright` p
206206

207207
::: warning
208208
CDP 会话仅适用于 `playwright` provider,并且仅在使用 `chromium` 浏览器时有效。有关详细信息,请参阅 playwright 的 [`CDPSession`](https://playwright.dev/docs/api/class-cdpsession)文档。
209+
<!-- TODO: translation -->
210+
CDP is a privileged debugging API. It is available only when browser API write and exec operations are enabled through [`browser.api.allowWrite`](/config/browser/api#api-allowwrite), [`browser.api.allowExec`](/config/browser/api#api-allowexec), [`api.allowWrite`](/config/api#api-allowwrite), and [`api.allowExec`](/config/api#api-allowexec).
209211
:::
210212

211213
```ts

0 commit comments

Comments
 (0)