diff --git a/.vitepress/components/HomePage.vue b/.vitepress/components/HomePage.vue index f8578495..48882618 100644 --- a/.vitepress/components/HomePage.vue +++ b/.vitepress/components/HomePage.vue @@ -1,85 +1,80 @@ + + diff --git a/.vitepress/components/ListItem.vue b/.vitepress/components/ListItem.vue index 4e046b2a..4a8b2fbe 100644 --- a/.vitepress/components/ListItem.vue +++ b/.vitepress/components/ListItem.vue @@ -16,7 +16,7 @@ function reset() { const color = computed(() => { return { - '--vp-c-brand': state.value === 1 + '--vp-c-brand-1': state.value === 1 ? '#66ba1c' : state.value === 2 ? 'rgba(248, 113, 113)' @@ -50,12 +50,12 @@ onMounted(async () => {
-
-
-
+
+
+
@@ -63,8 +63,3 @@ onMounted(async () => { - diff --git a/.vitepress/contributors.ts b/.vitepress/contributors.ts index 56e8b51c..9e6314fb 100644 --- a/.vitepress/contributors.ts +++ b/.vitepress/contributors.ts @@ -53,6 +53,16 @@ function createLinks(tm: CoreTeam): CoreTeam { } const plainTeamMembers: CoreTeam[] = [ + { + avatar: contributorsAvatars['sheremet-va'], + name: 'Vladimir', + github: 'sheremet-va', + mastodon: 'https://elk.zone/m.webtoo.ls/@sheremet_va', + twitter: 'sheremet_va', + sponsor: 'https://github.com/sponsors/sheremet-va', + title: '全栈开源开发者', + desc: 'Vitest 的核心团队成员', + }, { avatar: contributorsAvatars.antfu, name: 'Anthony Fu', @@ -67,16 +77,6 @@ const plainTeamMembers: CoreTeam[] = [ orgLink: 'https://nuxtlabs.com/', desc: 'Vite 和 Vue 的核心团队成员', }, - { - avatar: contributorsAvatars['sheremet-va'], - name: 'Vladimir', - github: 'sheremet-va', - mastodon: 'https://elk.zone/m.webtoo.ls/@sheremet_va', - twitter: 'sheremet_va', - sponsor: 'https://github.com/sponsors/sheremet-va', - title: '全栈开源开发者', - desc: 'Vitest 的核心团队成员', - }, { avatar: contributorsAvatars.AriPerkkio, name: 'Ari Perkkiö', diff --git a/.vitepress/scripts/pwa.ts b/.vitepress/scripts/pwa.ts index fdca7e50..53bb4ee3 100644 --- a/.vitepress/scripts/pwa.ts +++ b/.vitepress/scripts/pwa.ts @@ -68,6 +68,8 @@ export const pwa: PwaOptions = { // warning: sponsors/antfu.svg is 2.51 MB, and won't be precached maximumFileSizeToCacheInBytes: 3 * 1024 * 1024, // <== 3MB globPatterns: ['**/*.{css,js,html,png,svg,ico,txt,woff2,json}'], + // Rollup 4 change the layout: don't calculate revision (hash) + dontCacheBustURLsMatching: /^assets\//, runtimeCaching: [ { urlPattern: pwaFontsRegex, diff --git a/.vitepress/sponsors.ts b/.vitepress/sponsors.ts new file mode 100644 index 00000000..13835a9b --- /dev/null +++ b/.vitepress/sponsors.ts @@ -0,0 +1,62 @@ +interface Sponsor { + name: string + img: string + url: string +} + +const vitestSponsors = { + special: [ + { + name: 'Vite', + url: 'https://vitejs.dev', + img: '/vite.svg', + }, + { + name: 'NuxtLabs', + url: 'https://nuxtlabs.com', + img: '/nuxtlabs.svg', + }, + { + name: 'Stackblitz', + url: 'https://stackblitz.com', + img: '/stackblitz.svg', + }, + { + name: 'Zammad', + url: 'https://zammad.com', + img: '/zammad.svg', + }, + ], + platinum: [ + { + name: 'Bit', + url: 'https://bit.dev', + img: '/bit.svg', + }, + ], + gold: [ + { + name: 'InfoSupport', + url: 'https://www.infosupport.com/open-source/', + img: '/infosupport.svg', + }, + ], +} satisfies Record + +export const sponsors = [ + { + tier: 'Special Sponsors', + size: 'big', + items: vitestSponsors.special, + }, + { + tier: 'Platinum Sponsors', + size: 'big', + items: vitestSponsors.platinum, + }, + { + tier: 'Gold Sponsors', + size: 'medium', + items: vitestSponsors.gold, + }, +] diff --git a/.vitepress/style/main.css b/.vitepress/style/main.css index 7b57691c..b76a1c0f 100644 --- a/.vitepress/style/main.css +++ b/.vitepress/style/main.css @@ -8,6 +8,28 @@ html:not(.dark) [img-dark] { /* Overrides */ +.vp-doc ul.features-list { + padding: 0; +} +.vp-doc ul.features-list li { + list-style: none; + display: flex; + gap: 0.4rem; + margin: 0; +} +.vp-doc ul.features-list li div:first-of-type { + position: relative; +} +.vp-doc ul.features-list li div:first-of-type div { + position: absolute; +} +.vp-doc ul.features-list li div:first-of-type div.flip { + transform: rotateY(90deg); +} +.vp-doc ul.features-list li div:first-of-type div div { + position: unset; +} + .sp .sp-link.link:hover, .sp .sp-link.link:focus { background-color: var(--vitest-c-sponsor-hover) !important; diff --git a/api/expect.md b/api/expect.md index 8c4c66b4..3f87909c 100644 --- a/api/expect.md +++ b/api/expect.md @@ -1,14 +1,14 @@ # expect -The following types are used in the type signatures below +以下类型在下面的类型签名中被使用。 ```ts type Awaitable = T | PromiseLike ``` -`expect` is used to create assertions. In this context `assertions` are functions that can be called to assert a statement. Vitest provides `chai` assertions by default and also `Jest` compatible assertions build on top of `chai`. +`expect` 用于创建断言。 在这种情况下, `assertions` 是可以调用来断言语句的函数。 Vitest 默认提供 `chai` 断言,并且还在 `chai` 之上构建了与 `Jest` 兼容的断言。 -For example, this code asserts that an `input` value is equal to `2`. If it's not, the assertion will throw an error, and the test will fail. +例如,此代码断言 `input` 值等于 `2`。 如果不是,assertions 将抛出错误,并且测试将失败。 ```ts import { expect } from 'vitest' @@ -19,19 +19,19 @@ expect(input).to.equal(2) // chai API expect(input).toBe(2) // jest API ``` -Technically this example doesn't use [`test`](/api/#test) function, so in the console you will see Nodejs error instead of Vitest output. To learn more about `test`, please read [Test API Reference](/api/). +从技术上讲,这个示例没有使用 [`test`](/api/#test) 函数,因此在控制台中你将看到 Nodejs 错误而不是 Vitest 输出。 要了解更多关于 `test` 的信息,请阅读[测试 API 参考](/api/)。 -Also, `expect` can be used statically to access matchers functions, described later, and more. +此外,`expect` 可以静态地使用来访问匹配器函数,稍后将会介绍。 ::: warning -`expect` has no effect on testing types, if the expression doesn't have a type error. If you want to use Vitest as [type checker](/guide/testing-types), use [`expectTypeOf`](/api/expect-typeof) or [`assertType`](/api/assert-type). +如果表达式没有类型错误,则 `expect` 对测试类型没有影响。 如果您想使用 Vitest 作为[类型检查器](/guide/testing-types),请使用 [`expectTypeOf`](/api/expect-typeof) 或 [`assertType`](/api/assert-type) 。 ::: ## soft -- **Type:** `ExpectStatic & (actual: any) => Assertions` +- **类型:** `ExpectStatic & (actual: any) => Assertions` -`expect.soft` functions similarly to `expect`, but instead of terminating the test execution upon a failed assertion, it continues running and marks the failure as a test failure. All errors encountered during the test will be displayed until the test is completed. +`expect.soft` 的功能与 `expect` 类似,但它不会在断言失败时终止测试执行,而是继续运行并将失败标记为测试失败。 测试过程中遇到的所有错误都会显示出来,直到测试完成。 ```ts import { expect, test } from 'vitest' @@ -43,7 +43,7 @@ test('expect.soft test', () => { // At the end of the test, the above errors will be output. ``` -It can also be used with `expect`. if `expect` assertion fails, the test will be terminated and all errors will be displayed. +它也可以与 `expect` 一起使用。 如果 `expect` 断言失败,测试将终止并显示所有错误。 ```ts import { expect, test } from 'vitest' @@ -56,12 +56,12 @@ test('expect.soft test', () => { ``` ::: warning -`expect.soft` can only be used inside the [`test`](/api/#test) function. +`expect.soft` 只能在 [`test`](/api/#test) 函数的内部使用。 ::: ## not -Using `not` will negate the assertion. For example, this code asserts that an `input` value is not equal to `2`. If it's equal, the assertion will throw an error, and the test will fail. +使用 `not` 将否定该断言。 例如,此代码断言 `input` 值不等于 `2`。 如果相等,断言将抛出错误,测试将失败。 ```ts import { expect, test } from 'vitest' @@ -74,11 +74,11 @@ expect(input).not.toBe(2) // jest API ## toBe -- **Type:** `(value: any) => Awaitable` +- **类型:** `(value: any) => Awaitable` -`toBe` can be used to assert if primitives are equal or that objects share the same reference. It is equivalent of calling `expect(Object.is(3, 3)).toBe(true)`. If the objects are not the same, but you want to check if their structures are identical, you can use [`toEqual`](#toequal). +`toBe` 可用于断言基元是否相等或对象共享相同的引用。 它相当于调用 `expect(Object.is(3, 3)).toBe(true)` 。 如果对象不相同,但你想检查它们的结构是否相同,可以使用 [`toEqual`](#toequal)。 -For example, the code below checks if the trader has 13 apples. +例如,下面的代码检查交易者是否有 13 个苹果。 ```ts import { expect, test } from 'vitest' @@ -100,7 +100,7 @@ test('stocks are the same', () => { }) ``` -Try not to use `toBe` with floating-point numbers. Since JavaScript rounds them, `0.1 + 0.2` is not strictly `0.3`. To reliably assert floating-point numbers, use [`toBeCloseTo`](#tobecloseto) assertion. +尽量不要将 `toBe` 与浮点数一起使用。 由于 JavaScript 对它们进行四舍五入,因此 `0.1 + 0.2` 并不严格是 `0.3` 。 要可靠地断言浮点数,请使用 [`toBeCloseTo`](#tobecloseto) 断言。 ## toBeCloseTo @@ -422,7 +422,7 @@ test('structurally the same, but semantically different', () => { - **Type:** `(received: string) => Awaitable` -`toContain` asserts if the actual value is in an array. `toContain` can also check whether a string is a substring of another string. +`toContain` asserts if the actual value is in an array. `toContain` can also check whether a string is a substring of another string. Since Vitest 1.0, if you are running tests in a browser-like environment, this assertion can also check if class is contained in a `classList`, or an element is inside another one. ```ts import { expect, test } from 'vitest' @@ -430,6 +430,12 @@ import { getAllFruits } from './stocks.js' test('the fruit list contains orange', () => { expect(getAllFruits()).toContain('orange') + + const element = document.querySelector('#el') + // element has a class + expect(element.classList).toContain('flex') + // element is inside another one + expect(document.querySelector('#wrapper')).toContain(element) }) ``` diff --git a/api/index.md b/api/index.md index 7120f975..149dfe46 100644 --- a/api/index.md +++ b/api/index.md @@ -230,6 +230,30 @@ test.concurrent('test 2', async ({ expect }) => { You cannot use this syntax, when using Vitest as [type checker](/guide/testing-types). ::: +### test.sequential + +- **Type:** `(name: string | Function, fn: TestFunction, timeout?: number) => void` + +`test.sequential` marks a test as sequential. This is useful if you want to run tests in sequence within `describe.concurrent` or with the `--sequence.concurrent` command option. + +```ts +// with config option { sequence: { concurrent: true } } +test('concurrent test 1', async () => { /* ... */ }) +test('concurrent test 2', async () => { /* ... */ }) + +test.sequential('sequential test 1', async () => { /* ... */ }) +test.sequential('sequential test 2', async () => { /* ... */ }) + +// within concurrent suite +describe.concurrent('suite', () => { + test('concurrent test 1', async () => { /* ... */ }) + test('concurrent test 2', async () => { /* ... */ }) + + test.sequential('sequential test 1', async () => { /* ... */ }) + test.sequential('sequential test 2', async () => { /* ... */ }) +}) +``` + ### test.todo - **Type:** `(name: string | Function) => void` @@ -674,7 +698,7 @@ You cannot use this syntax, when using Vitest as [type checker](/guide/testing-t - **Type:** `(name: string | Function, fn: TestFunction, options?: number | TestOptions) => void` -`describe.sequential` in a suite marks every test as sequential. This is useful if you want to run tests in sequential within `describe.concurrent` or with the `--sequence.concurrent` command option. +`describe.sequential` in a suite marks every test as sequential. This is useful if you want to run tests in sequence within `describe.concurrent` or with the `--sequence.concurrent` command option. ```ts describe.concurrent('suite', () => { diff --git a/config/index.md b/config/index.md index a39dd07f..357b1c1a 100644 --- a/config/index.md +++ b/config/index.md @@ -27,7 +27,7 @@ export default defineConfig({ }) ``` -使用 `vitest` 的 `defineConfig` 可以参考下面的格式: +使用 `vitest/config` 中的 `defineConfig` 可以参考下面的格式: ```ts import { defineConfig } from 'vitest/config' @@ -1115,7 +1115,7 @@ npx vitest --coverage.enabled --coverage.provider=istanbul --coverage.all #### coverage.clean -- **Type:** `boolean` +- **类型:** `boolean` - **默认值:** `true` - **可用的测试提供者:** `'v8' | 'istanbul'` - **命令行终端:** `--coverage.clean`, `--coverage.clean=false` @@ -1195,9 +1195,9 @@ npx vitest --coverage.enabled --coverage.provider=istanbul --coverage.all #### coverage.allowExternal -- **Type:** `boolean` -- **Default:** `false` -- **Available for providers:** `'v8' | 'istanbul'` +- **类型:** `boolean` +- **默认值:** `false` +- **可用的测试提供者:** `'v8' | 'istanbul'` - **CLI:** `--coverage.allowExternal`, `--coverage.allowExternal=false` Collect coverage of files outside the [project `root`](https://vitest.dev/config/#root). @@ -1211,93 +1211,109 @@ Collect coverage of files outside the [project `root`](https://vitest.dev/config 是否显示具有 100% 语句、分支和函数的测试覆盖率的文件。 -#### coverage.perFile - -- **类型:** `boolean` -- **默认值:** `false` -- **可用的测试提供者:** `'v8' | 'istanbul'` -- **命令行终端:** `--coverage.perFile`, `--coverage.perFile=false` +#### coverage.thresholds -检查每个文件的阈值。 -有关实际阈值,请参见 `lines`, `functions`, `branches` and `statements` 。 +覆盖范围阈值选项 -#### coverage.thresholdAutoUpdate +##### coverage.thresholds.lines -- **类型:** `boolean` -- **默认值:** `false` +- **类型:** `number` - **可用的测试提供者:** `'v8' | 'istanbul'` -- **命令行终端:** `--coverage.thresholdAutoUpdate=` +- **命令行终端:** `--coverage.thresholds.lines=` -当前覆盖率高于配置的阈值时,将阈值 `lines`、 `functions`、`branches` 和 `statements` 更新到配置文件。 -此选项有助于在提高覆盖率时维持阈值。 +lines 的全局阈值。 +更多信息请查看 [istanbul documentation](https://github.com/istanbuljs/nyc#coverage-thresholds)。 -#### coverage.lines +##### coverage.thresholds.functions - **类型:** `number` - **可用的测试提供者:** `'v8' | 'istanbul'` -- **命令行终端:** `--coverage.lines=` +- **命令行终端:** `--coverage.thresholds.functions=` -行的阈值。参考 [istanbul 文档](https://github.com/istanbuljs/nyc#coverage-thresholds) 来了解详情。 +functions 的全局阈值。 +更多信息请查看 [istanbul documentation](https://github.com/istanbuljs/nyc#coverage-thresholds)。 -#### coverage.functions +##### coverage.thresholds.branches - **类型:** `number` - **可用的测试提供者:** `'v8' | 'istanbul'` -- **命令行终端:** `--coverage.functions=` +- **命令行终端:** `--coverage.thresholds.branches=` -函数的阈值。参考 [istanbul 文档](https://github.com/istanbuljs/nyc#coverage-thresholds) 来了解详情。 +branches 的全局阈值。 +更多信息请查看 [istanbul documentation](https://github.com/istanbuljs/nyc#coverage-thresholds)。 -#### coverage.branches +##### coverage.thresholds.statements - **类型:** `number` - **可用的测试提供者:** `'v8' | 'istanbul'` -- **命令行终端:** `--coverage.branches=` +- **命令行终端:** `--coverage.thresholds.statements=` -分支的阈值。参考 [istanbul 文档](https://github.com/istanbuljs/nyc#coverage-thresholds) 来了解详情。 +statements 的全局阈值。 +更多信息请查看 [istanbul documentation](https://github.com/istanbuljs/nyc#coverage-thresholds)。 -#### coverage.statements +##### coverage.thresholds.perFile -- **类型:** `number` +- **类型:** `boolean` +- **默认值:** `false` - **可用的测试提供者:** `'v8' | 'istanbul'` -- **命令行终端:** `--coverage.statements=` +- **命令行终端:** `--coverage.thresholds.perFile`, `--coverage.thresholds.perFile=false` -语句的阈值。参考 [istanbul 文档](https://github.com/istanbuljs/nyc#coverage-thresholds) 来了解详情。 +检查每个文件的阈值。 -#### coverage.allowExternal +##### coverage.thresholds.autoUpdate - **类型:** `boolean` - **默认值:** `false` -- **可用的测试提供者:** `'v8'` -- **命令行终端:** `--coverage.allowExternal`, `--coverage.allowExternal=false` +- **可用的测试提供者:** `'v8' | 'istanbul'` +- **命令行终端:** `--coverage.thresholds.autoUpdate=` -是否允许来自 cwd 外部的文件。 +如果当前覆盖率高于配置的阈值时,将所有阈值 `lines` 、`functions` 、`branches` 和 `statements` 更新到配置文件中。 +此选项有助于在覆盖率提高时保持阈值不变。 -#### coverage.excludeNodeModules +##### coverage.thresholds.100 - **类型:** `boolean` -- **默认值:** `true` -- **可用的测试提供者:** `'v8'` -- **命令行终端:** `--coverage.excludeNodeModules`, `--coverage.excludeNodeModules=false` - -排除 `/node_modules/` 下的覆盖范围。 +- **默认值:** `false` +- **可用的测试提供者:** `'v8' | 'istanbul'` +- **命令行终端:** `--coverage.thresholds.100`, `--coverage.thresholds.100=false` -#### coverage.src +将全局阈值设置为 100。 +这是 `--coverage.thresholds.lines 100 --coverage.thresholds.functions 100 --coverage.thresholds.branches 100 --coverage.thresholds.statements 100` 的快捷方式。 -- **类型:** `string[]` -- **默认值:** `process.cwd()` -- **可用的测试提供者:** `'v8'` -- **命令行终端:** `--coverage.src=` +##### coverage.thresholds[glob-pattern] -指定启用 `--all` 时使用的目录。 +- **类型:** `{ statements?: number functions?: number branches?: number lines?: number }` +- **默认值:** `undefined` +- **可用的测试提供者:** `'v8' | 'istanbul'` -#### coverage.100 +设置与 glob 模式匹配的文件的阈值。 -- **类型:** `boolean` -- **默认值:** `false` -- **可用的测试提供者:** `'v8' | 'istanbul'` -- **命令行终端:** `--coverage.100`, `--coverage.100=false` + +```ts +{ + coverage: { + thresholds: { + // Thresholds for all files + functions: 95, + branches: 70, + + // Thresholds for matching glob pattern + 'src/utils/**.ts': { + statements: 95, + functions: 90, + branches: 85, + lines: 80, + }, -为 `--coverage.lines 100 --coverage.functions 100 --coverage.branches 100 --coverage.statements 100` 设置的快捷方式。 + // Files matching this pattern will only have lines thresholds set. + // Global thresholds are not inherited. + '**/math.ts': { + lines: 100, + } + } + } +} +``` #### coverage.ignoreClassMethods diff --git a/guide/mocking.md b/guide/mocking.md index a06ed59c..11c4bec9 100644 --- a/guide/mocking.md +++ b/guide/mocking.md @@ -278,7 +278,7 @@ Mock Service Worker (MSW) 通过拦截测试发出的请求进行工作,允许 ```js import { afterAll, afterEach, beforeAll } from 'vitest' import { setupServer } from 'msw/node' -import { graphql, rest } from 'msw' +import { HttpResponse, graphql, rest } from 'msw' const posts = [ { @@ -291,18 +291,19 @@ const posts = [ ] export const restHandlers = [ - rest.get('https://rest-endpoint.example/path/to/posts', (req, res, ctx) => { - return res(ctx.status(200), ctx.json(posts)) + http.get('https://rest-endpoint.example/path/to/posts', () => { + return HttpResponse.json(posts) }), ] const graphqlHandlers = [ - graphql.query( - 'https://graphql-endpoint.example/api/v1/posts', - (req, res, ctx) => { - return res(ctx.data(posts)) - } - ), + graphql.query('https://graphql-endpoint.example/api/v1/posts', () => { + return HttpResponse.json( + { + data: { posts }, + }, + ) + }), ] const server = setupServer(...restHandlers, ...graphqlHandlers) diff --git a/public/bit.svg b/public/bit.svg new file mode 100644 index 00000000..8750e3ef --- /dev/null +++ b/public/bit.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/public/infosupport.svg b/public/infosupport.svg new file mode 100644 index 00000000..e541b37b --- /dev/null +++ b/public/infosupport.svg @@ -0,0 +1,49 @@ + + + + Group 58 + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/nuxtlabs.svg b/public/nuxtlabs.svg new file mode 100644 index 00000000..d2935645 --- /dev/null +++ b/public/nuxtlabs.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/stackblitz.svg b/public/stackblitz.svg new file mode 100644 index 00000000..a16fcd92 --- /dev/null +++ b/public/stackblitz.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/vite.svg b/public/vite.svg new file mode 100644 index 00000000..de4aeddc --- /dev/null +++ b/public/vite.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/public/zammad.svg b/public/zammad.svg new file mode 100644 index 00000000..0685eb75 --- /dev/null +++ b/public/zammad.svg @@ -0,0 +1,30 @@ + + + + logo + Created with Sketch. + + + + + \ No newline at end of file