Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(expect): support expect.unreachable #3556

Merged
merged 9 commits into from Jun 16, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
47 changes: 45 additions & 2 deletions docs/api/expect.md
Expand Up @@ -42,7 +42,7 @@ type Awaitable<T> = T | PromiseLike<T>
})
// 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.

```ts
Expand All @@ -54,7 +54,7 @@ type Awaitable<T> = T | PromiseLike<T>
expect.soft(1 + 2).toBe(4) // do not run
})
```

::: warning
`expect.soft` can only be used inside the [`test`](/api/#test) function.
:::
Expand Down Expand Up @@ -1136,6 +1136,49 @@ If the value in the error message is too truncated, you can increase [chaiConfig
})
```

## expect.unreachable

- **Type:** `(message?: string) => never`

This method is used to asserting that a line should never be reached.

For example, if we want to test that `build()` throws due to receiving directories having no `src` folder, and also handle each error separately, we could do this:

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

async function build(dir) {
if (dir.includes('no-src'))
throw new Error(`${dir}/src does not exist`)
}

const errorDirs = [
'no-src-folder',
// ...
]

test.each(errorDirs)('build fails with "%s"', async (dir) => {
try {
await build(dir)
expect.unreachable('Should not pass build')
}
catch (err: any) {
expect(err).toBeInstanceOf(Error)
expect(err.stack).toContain('build')

switch (dir) {
case 'no-src-folder':
expect(err.message).toBe(`${dir}/src does not exist`)
break
default:
// to exhaust all error tests
expect.unreachable('All error test must be handled')
break
}
}
})
```

<!-- asymmetric matchers -->

## expect.anything
Expand Down
1 change: 1 addition & 0 deletions packages/expect/src/types.ts
Expand Up @@ -80,6 +80,7 @@ export type MatchersObject<T extends MatcherState = MatcherState> = Record<strin

export interface ExpectStatic extends Chai.ExpectStatic, AsymmetricMatchersContaining {
<T>(actual: T, message?: string): Assertion<T>
unreachable(message?: string): never
soft<T>(actual: T, message?: string): Assertion<T>
extend(expects: MatchersObject): void
assertions(expected: number): void
Expand Down
4 changes: 4 additions & 0 deletions packages/vitest/src/integrations/chai/index.ts
Expand Up @@ -53,6 +53,10 @@ export function createExpect(test?: Test) {
return assert
}

expect.unreachable = (message?: string) => {
chai.assert.fail(`expected${message ? ` "${message}" ` : ' '}not to be reached`)
}

function assertions(expected: number) {
const errorGen = () => new Error(`expected number of assertions to be ${expected}, but got ${expect.getState().assertionCalls}`)
if (Error.captureStackTrace)
Expand Down
5 changes: 5 additions & 0 deletions test/fails/fixtures/expect-unreachable.test.ts
@@ -0,0 +1,5 @@
import { expect, test } from 'vitest'

test('', () => {
expect.unreachable('hi')
})
2 changes: 2 additions & 0 deletions test/fails/test/__snapshots__/runner.test.ts.snap
Expand Up @@ -10,6 +10,8 @@ exports[`should fail expect.test.ts > expect.test.ts 1`] = `"AssertionError: exp

exports[`should fail expect-soft.test.ts > expect-soft.test.ts 1`] = `"Error: expect.soft() can only be used inside a test"`;

exports[`should fail expect-unreachable.test.ts > expect-unreachable.test.ts 1`] = `"AssertionError: expected \\"hi\\" not to be reached"`;

exports[`should fail hook-timeout.test.ts > hook-timeout.test.ts 1`] = `"Error: Hook timed out in 10ms."`;

exports[`should fail hooks-called.test.ts > hooks-called.test.ts 1`] = `
Expand Down