Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions docs/api/vi.md
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,33 @@ expect(spy).toHaveBeenCalled()
expect(spy).toHaveReturnedWith(1)
```

If the spying method is a class definition, the mock implementations have to use the `function` or the `class` keyword:

```ts {12-14,16-20}
const cart = {
Apples: class Apples {
getApples() {
return 42
}
}
}

const spy = vi.spyOn(cart, 'Apples')
.mockImplementation(() => ({ getApples: () => 0 })) // [!code --]
// with a function keyword
.mockImplementation(function () {
this.getApples = () => 0
})
// with a custom class
.mockImplementation(class MockApples {
getApples() {
return 0
}
})
```

If you provide an arrow function, you will get [`<anonymous> is not a constructor` error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Not_a_constructor) when the mock is called.

::: tip
In environments that support [Explicit Resource Management](https://github.com/tc39/proposal-explicit-resource-management), you can use `using` instead of `const` to automatically call `mockRestore` on any mocked function when the containing block is exited. This is especially useful for spied methods:

Expand Down
31 changes: 31 additions & 0 deletions docs/guide/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,37 @@ See also new guides:
- [Including and excluding files from coverage report](/guide/coverage.html#including-and-excluding-files-from-coverage-report) for examples
- [Profiling Test Performance | Code coverage](/guide/profiling-test-performance.html#code-coverage) for tips about debugging coverage generation

### `spyOn` Supports Constructors

Previously, if you tried to spy on a constructor with `vi.spyOn`, you would get an error like `Constructor <name> requires 'new'`. Since Vitest 4, all mocks called with a `new` keyword construct the instance instead of callying `mock.apply`. This means that the mock implementation has to use either the `function` or the `class` keyword in these cases:

```ts {12-14,16-20}
const cart = {
Apples: class Apples {
getApples() {
return 42
}
}
}

const Spy = vi.spyOn(cart, 'Apples')
.mockImplementation(() => ({ getApples: () => 0 })) // [!code --]
// with a function keyword
.mockImplementation(function () {
this.getApples = () => 0
})
// with a custom class
.mockImplementation(class MockApples {
getApples() {
return 0
}
})

const mock = new Spy()
```

Note that now if you provide an arrow function, you will get [`<anonymous> is not a constructor` error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Not_a_constructor) when the mock is called.

### Deprecated APIs are Removed

Vitest 4.0 removes some deprecated APIs, including:
Expand Down
32 changes: 30 additions & 2 deletions docs/guide/mocking.md
Original file line number Diff line number Diff line change
Expand Up @@ -764,6 +764,10 @@ import * as exports from './example.js'
vi.spyOn(exports, 'getter', 'get').mockReturnValue('mocked')
```

::: warning
This will not work in the Browser Mode. For a workaround, see [Limitations](/guide/browser/#spying-on-module-exports).
:::

### Mock an exported function

1. Example with `vi.mock`:
Expand All @@ -790,9 +794,29 @@ import * as exports from './example.js'
vi.spyOn(exports, 'method').mockImplementation(() => {})
```

::: warning
`vi.spyOn` example will not work in the Browser Mode. For a workaround, see [Limitations](/guide/browser/#spying-on-module-exports).
:::

### Mock an exported class implementation

1. Example with `vi.mock` and `.prototype`:
1. Example with a fake `class`:
```ts [example.js]
export class SomeClass {}
```
```ts
import { SomeClass } from './example.js'

vi.mock(import('./example.js'), () => {
const SomeClass = vi.fn(class FakeClass {
someMethod = vi.fn()
})
return { SomeClass }
})
// SomeClass.mock.instances will have SomeClass
```

2. Example with `vi.mock` and `.prototype`:
```ts [example.js]
export class SomeClass {}
```
Expand All @@ -807,7 +831,7 @@ vi.mock(import('./example.js'), () => {
// SomeClass.mock.instances will have SomeClass
```

2. Example with `vi.spyOn`:
3. Example with `vi.spyOn`:

```ts
import * as mod from './example.js'
Expand All @@ -818,6 +842,10 @@ SomeClass.prototype.someMethod = vi.fn()
vi.spyOn(mod, 'SomeClass').mockImplementation(SomeClass)
```

::: warning
`vi.spyOn` example will not work in the Browser Mode. For a workaround, see [Limitations](/guide/browser/#spying-on-module-exports).
:::

### Spy on an object returned from a function

1. Example using cache:
Expand Down
Loading