diff --git a/docs/advanced/runner.md b/docs/advanced/runner.md index 0e4e2be53..9ff366a94 100644 --- a/docs/advanced/runner.md +++ b/docs/advanced/runner.md @@ -209,7 +209,7 @@ interface Test extends TaskBase { */ file: File /** - * Whether the task was skipped by calling `t.skip()`. + * Whether the task was skipped by calling `context.skip()`. */ pending?: boolean /** diff --git a/docs/api/index.md b/docs/api/index.md index e9dfc47d7..cd34e03a9 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -1279,16 +1279,6 @@ test('performs an organization query', async () => { ::: tip This hook is always called in reverse order and is not affected by [`sequence.hooks`](/config/#sequence-hooks) option. - - -Note that this hook is not called if test was skipped with a dynamic `ctx.skip()` call: - -```ts{2} -test('skipped dynamically', (t) => { - onTestFinished(() => {}) // not called - t.skip() -}) -``` ::: ### onTestFailed diff --git a/docs/guide/cli-generated.md b/docs/guide/cli-generated.md index f0572dc3c..172c980c7 100644 --- a/docs/guide/cli-generated.md +++ b/docs/guide/cli-generated.md @@ -761,6 +761,13 @@ Omit annotation lines from the output (default: `false`) Print basic prototype Object and Array (default: `true`) +### diff.maxDepth + +- **CLI:** `--diff.maxDepth ` +- **Config:** [diff.maxDepth](/config/#diff-maxdepth) + +Limit the depth to recurse when printing nested objects (default: `20`) + ### diff.truncateThreshold - **CLI:** `--diff.truncateThreshold ` diff --git a/docs/guide/test-context.md b/docs/guide/test-context.md index de171f9bd..ba2c3be45 100644 --- a/docs/guide/test-context.md +++ b/docs/guide/test-context.md @@ -14,19 +14,19 @@ The first argument for each test callback is a test context. ```ts import { it } from 'vitest' -it('should work', (ctx) => { +it('should work', ({ task }) => { // prints name of the test - console.log(ctx.task.name) + console.log(task.name) }) ``` ## Built-in Test Context -#### `context.task` +#### `task` A readonly object containing metadata about the test. -#### `context.expect` +#### `expect` The `expect` API bound to the current test: @@ -52,7 +52,12 @@ it.concurrent('math is hard', ({ expect }) => { }) ``` -#### `context.skip` +#### `skip` + +```ts +function skip(note?: string): never +function skip(condition: boolean, note?: string): void +``` Skips subsequent test execution and marks test as skipped: @@ -65,6 +70,23 @@ it('math is hard', ({ skip }) => { }) ``` +Since Vitest 3.1, it accepts a boolean parameter to skip the test conditionally: + +```ts +it('math is hard', ({ skip, mind }) => { + skip(mind === 'foggy') + expect(2 + 2).toBe(5) +}) +``` + +#### `onTestFailed` + +The [`onTestFailed`](/api/#ontestfailed) hook bound to the current test. This API is useful if you are running tests concurrently and need to have a special handling only for this specific test. + +#### `onTestFinished` + +The [`onTestFinished`](/api/#ontestfailed) hook bound to the current test. This API is useful if you are running tests concurrently and need to have a special handling only for this specific test. + ## Extend Test Context Vitest provides two different ways to help you extend the test context. @@ -73,15 +95,15 @@ Vitest provides two different ways to help you extend the test context. Like [Playwright](https://playwright.dev/docs/api/class-test#test-extend), you can use this method to define your own `test` API with custom fixtures and reuse it anywhere. -For example, we first create `myTest` with two fixtures, `todos` and `archive`. +For example, we first create the `test` collector with two fixtures: `todos` and `archive`. ```ts [my-test.ts] -import { test } from 'vitest' +import { test as baseTest } from 'vitest' const todos = [] const archive = [] -export const myTest = test.extend({ +export const test = baseTest.extend({ todos: async ({}, use) => { // setup the fixture before each test function todos.push(1, 2, 3) @@ -100,16 +122,16 @@ Then we can import and use it. ```ts [my-test.test.ts] import { expect } from 'vitest' -import { myTest } from './my-test.js' +import { test } from './my-test.js' -myTest('add items to todos', ({ todos }) => { +test('add items to todos', ({ todos }) => { expect(todos.length).toBe(3) todos.push(4) expect(todos.length).toBe(4) }) -myTest('move items from todos to archive', ({ todos, archive }) => { +test('move items from todos to archive', ({ todos, archive }) => { expect(todos.length).toBe(3) expect(archive.length).toBe(0) @@ -119,10 +141,12 @@ myTest('move items from todos to archive', ({ todos, archive }) => { }) ``` -We can also add more fixtures or override existing fixtures by extending `myTest`. +We can also add more fixtures or override existing fixtures by extending our `test`. ```ts -export const myTest2 = myTest.extend({ +import { test as todosTest } from './my-test.js' + +export const test = todosTest.extend({ settings: { // ... } @@ -134,34 +158,35 @@ export const myTest2 = myTest.extend({ Vitest runner will smartly initialize your fixtures and inject them into the test context based on usage. ```ts -import { test } from 'vitest' +import { test as baseTest } from 'vitest' -async function todosFn({ task }, use) { - await use([1, 2, 3]) -} - -const myTest = test.extend({ - todos: todosFn, +const test = baseTest.extend<{ + todos: number[] + archive: number[] +}>({ + todos: async ({ task }, use) => { + await use([1, 2, 3]) + }, archive: [] }) -// todosFn will not run -myTest('', () => {}) -myTest('', ({ archive }) => {}) +// todos will not run +test('skip', () => {}) +test('skip', ({ archive }) => {}) -// todosFn will run -myTest('', ({ todos }) => {}) +// todos will run +test('run', ({ todos }) => {}) ``` ::: warning When using `test.extend()` with fixtures, you should always use the object destructuring pattern `{ todos }` to access context both in fixture function and test function. ```ts -myTest('context must be destructured', (context) => { // [!code --] +test('context must be destructured', (context) => { // [!code --] expect(context.todos.length).toBe(2) }) -myTest('context must be destructured', ({ todos }) => { // [!code ++] +test('context must be destructured', ({ todos }) => { // [!code ++] expect(todos.length).toBe(2) }) ``` @@ -316,19 +341,46 @@ interface MyFixtures { archive: number[] } -const myTest = test.extend({ +const test = baseTest.extend({ todos: [], archive: [] }) -myTest('types are defined correctly', ({ todos, archive }) => { +test('types are defined correctly', ({ todos, archive }) => { expectTypeOf(todos).toEqualTypeOf() expectTypeOf(archive).toEqualTypeOf() }) ``` +::: info Type Infering +Note that Vitest doesn't support infering the types when the `use` function is called. It is always preferable to pass down the whole context type as the generic type when `test.extend` is called: + +```ts +import { test as baseTest } from 'vitest' + +const test = baseTest.extend<{ + todos: number[] + schema: string +}>({ + todos: ({ schema }, use) => use([]), + schema: 'test' +}) + +test('types are correct', ({ + todos, // number[] + schema, // string +}) => { + // ... +}) +``` +::: + ### `beforeEach` and `afterEach` +::: danger Deprecated +This is an outdated way of extending context and it will not work when the `test` is extended with `test.extend`. +::: + The contexts are different for each test. You can access and extend them within the `beforeEach` and `afterEach` hooks. ```ts @@ -346,7 +398,7 @@ it('should work', ({ foo }) => { #### TypeScript -To provide property types for all your custom contexts, you can aggregate the `TestContext` type by adding +To provide property types for all your custom contexts, you can augment the `TestContext` type by adding ```ts declare module 'vitest' { diff --git a/packages/runner/src/types/tasks.ts b/packages/runner/src/types/tasks.ts index 47847d394..c7a871d7c 100644 --- a/packages/runner/src/types/tasks.ts +++ b/packages/runner/src/types/tasks.ts @@ -149,7 +149,7 @@ export interface TaskResult { /** @private */ note?: string /** - * Whether the task was skipped by calling `t.skip()`. + * Whether the task was skipped by calling `context.skip()`. * @internal */ pending?: boolean diff --git a/test/cli/fixtures/fails/skip-conditional.test.ts b/test/cli/fixtures/fails/skip-conditional.test.ts index 6431f6c4f..6d90afb92 100644 --- a/test/cli/fixtures/fails/skip-conditional.test.ts +++ b/test/cli/fixtures/fails/skip-conditional.test.ts @@ -1,11 +1,11 @@ import { expect, it } from 'vitest'; -it('skips correctly', (t) => { - t.skip(true) +it('skips correctly', ({ skip }) => { + skip(true) expect.unreachable() }) -it('doesnt skip correctly', (t) => { - t.skip(false) +it('doesnt skip correctly', ({ skip }) => { + skip(false) throw new Error('doesnt skip') }) diff --git a/test/core/test/on-finished.test.ts b/test/core/test/on-finished.test.ts index b7ac84fc4..e0667fa09 100644 --- a/test/core/test/on-finished.test.ts +++ b/test/core/test/on-finished.test.ts @@ -11,9 +11,9 @@ it('on-finished regular', () => { collected.push(2) }) -it('on-finished context', (t) => { +it('on-finished context', ({ onTestFinished }) => { collected.push(4) - t.onTestFinished(() => { + onTestFinished(() => { collected.push(6) }) collected.push(5) @@ -29,9 +29,9 @@ it.fails('failed finish', () => { collected.push(null) }) -it.fails('failed finish context', (t) => { +it.fails('failed finish context', ({ onTestFinished }) => { collected.push(10) - t.onTestFinished(() => { + onTestFinished(() => { collected.push(12) }) collected.push(11) diff --git a/test/reporters/fixtures/default/a.test.ts b/test/reporters/fixtures/default/a.test.ts index 8f60d69ae..a517625fb 100644 --- a/test/reporters/fixtures/default/a.test.ts +++ b/test/reporters/fixtures/default/a.test.ts @@ -26,15 +26,15 @@ describe('a failed', () => { }) describe('a skipped', () => { - test('skipped with note', (t) => { - t.skip('reason') + test('skipped with note', ({ skip }) => { + skip('reason') }) - test('condition', (t) => { - t.skip(true) + test('condition', ({ skip }) => { + skip(true) }) - test('condition with note', (t) => { - t.skip(true, 'note') + test('condition with note', ({ skip }) => { + skip(true, 'note') }) })