Skip to content

Commit

Permalink
feat!: add promise-based return assertions, do not auto-resolve retur…
Browse files Browse the repository at this point in the history
…ned promises (#5749)
  • Loading branch information
sheremet-va committed May 31, 2024
1 parent 48c502f commit 5f71018
Show file tree
Hide file tree
Showing 11 changed files with 446 additions and 102 deletions.
119 changes: 117 additions & 2 deletions docs/api/expect.md
Original file line number Diff line number Diff line change
Expand Up @@ -954,7 +954,7 @@ test('spy function returned a value', () => {

- **Type**: `(amount: number) => Awaitable<void>`

This assertion checks if a function has successfully returned a value exact amount of times (i.e., did not throw an error). Requires a spy function to be passed to `expect`.
This assertion checks if a function has successfully returned a value an exact amount of times (i.e., did not throw an error). Requires a spy function to be passed to `expect`.

```ts twoslash
import { expect, test, vi } from 'vitest'
Expand Down Expand Up @@ -991,7 +991,7 @@ test('spy function returns a product', () => {

- **Type**: `(returnValue: any) => Awaitable<void>`

You can call this assertion to check if a function has successfully returned a value with certain parameters on its last invoking. Requires a spy function to be passed to `expect`.
You can call this assertion to check if a function has successfully returned a certain value when it was last invoked. Requires a spy function to be passed to `expect`.

```ts twoslash
import { expect, test, vi } from 'vitest'
Expand Down Expand Up @@ -1025,6 +1025,121 @@ test('spy function returns bananas on second call', () => {
})
```

## toHaveResolved

- **Type**: `() => Awaitable<void>`

This assertion checks if a function has successfully resolved a value at least once (i.e., did not reject). Requires a spy function to be passed to `expect`.

If the function returned a promise, but it was not resolved yet, this will fail.

```ts twoslash
// @filename: db/apples.js
/** @type {any} */
const db = {}
export default db
// @filename: test.ts
// ---cut---
import { expect, test, vi } from 'vitest'
import db from './db/apples.js'

async function getApplesPrice(amount: number) {
return amount * await db.get('price')
}

test('spy function resolved a value', async () => {
const getPriceSpy = vi.fn(getApplesPrice)

const price = await getPriceSpy(10)

expect(price).toBe(100)
expect(getPriceSpy).toHaveResolved()
})
```

## toHaveResolvedTimes

- **Type**: `(amount: number) => Awaitable<void>`

This assertion checks if a function has successfully resolved a value an exact amount of times (i.e., did not reject). Requires a spy function to be passed to `expect`.

This will only count resolved promises. If the function returned a promise, but it was not resolved yet, it will not be counted.

```ts twoslash
import { expect, test, vi } from 'vitest'

test('spy function resolved a value two times', async () => {
const sell = vi.fn((product: string) => Promise.resolve({ product }))

await sell('apples')
await sell('bananas')

expect(sell).toHaveResolvedTimes(2)
})
```

## toHaveResolvedWith

- **Type**: `(returnValue: any) => Awaitable<void>`

You can call this assertion to check if a function has successfully resolved a certain value at least once. Requires a spy function to be passed to `expect`.

If the function returned a promise, but it was not resolved yet, this will fail.

```ts twoslash
import { expect, test, vi } from 'vitest'

test('spy function resolved a product', async () => {
const sell = vi.fn((product: string) => Promise.resolve({ product }))

await sell('apples')

expect(sell).toHaveResolvedWith({ product: 'apples' })
})
```

## toHaveLastResolvedWith

- **Type**: `(returnValue: any) => Awaitable<void>`

You can call this assertion to check if a function has successfully resolved a certain value when it was last invoked. Requires a spy function to be passed to `expect`.

If the function returned a promise, but it was not resolved yet, this will fail.

```ts twoslash
import { expect, test, vi } from 'vitest'

test('spy function resolves bananas on a last call', async () => {
const sell = vi.fn((product: string) => Promise.resolve({ product }))

await sell('apples')
await sell('bananas')

expect(sell).toHaveLastResolvedWith({ product: 'bananas' })
})
```

## toHaveNthResolvedWith

- **Type**: `(time: number, returnValue: any) => Awaitable<void>`

You can call this assertion to check if a function has successfully resolved a certain value on a specific invokation. Requires a spy function to be passed to `expect`.

If the function returned a promise, but it was not resolved yet, this will fail.

```ts twoslash
import { expect, test, vi } from 'vitest'

test('spy function returns bananas on second call', async () => {
const sell = vi.fn((product: string) => Promise.resolve({ product }))

await sell('apples')
await sell('bananas')

expect(sell).toHaveNthResolvedWith(2, { product: 'bananas' })
})
```

## toSatisfy

- **Type:** `(predicate: (value: any) => boolean) => Awaitable<void>`
Expand Down
25 changes: 24 additions & 1 deletion docs/api/mock.md
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ This is an array containing all values that were `returned` from the function. O
- `'return'` - function returned without throwing.
- `'throw'` - function threw a value.

The `value` property contains the returned value or thrown error. If the function returned a promise, the `value` will be the _resolved_ value, not the actual `Promise`, unless it was never resolved.
The `value` property contains the returned value or thrown error. If the function returned a `Promise`, then `result` will always be `'return'` even if the promise was rejected.

```js
const fn = vi.fn()
Expand Down Expand Up @@ -332,6 +332,29 @@ fn.mock.results === [
]
```

## mock.settledResults

An array containing all values that were `resolved` or `rejected` from the function.

This array will be empty if the function was never resolved or rejected.

```js
const fn = vi.fn().mockResolvedValueOnce('result')

const result = fn()

fn.mock.settledResults === []

await result

fn.mock.settledResults === [
{
type: 'fulfilled',
value: 'result',
},
]
```

## mock.invocationCallOrder

The order of mock's execution. This returns an array of numbers that are shared between all defined mocks.
Expand Down
1 change: 1 addition & 0 deletions docs/guide/cli-table.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
| `--browser.provider <name>` | Provider used to run browser tests. Some browsers are only available for specific providers. Can be "webdriverio", "playwright", or the path to a custom provider. Visit [`browser.provider`](https://vitest.dev/config/#browser-provider) for more information (default: `"webdriverio"`) |
| `--browser.providerOptions <options>` | Options that are passed down to a browser provider. Visit [`browser.providerOptions`](https://vitest.dev/config/#browser-provideroptions) for more information |
| `--browser.isolate` | Run every browser test file in isolation. To disable isolation, use `--browser.isolate=false` (default: `true`) |
| `--browser.ui` | Show Vitest UI when running tests (default: `!process.env.CI`) |
| `--pool <pool>` | Specify pool, if not running in the browser (default: `threads`) |
| `--poolOptions.threads.isolate` | Isolate tests in threads pool (default: `true`) |
| `--poolOptions.threads.singleThread` | Run tests inside a single thread (default: `false`) |
Expand Down
Loading

0 comments on commit 5f71018

Please sign in to comment.