Skip to content

Commit 8e385bb

Browse files
fenghan34sheremet-va
andauthoredJun 16, 2023
feat(expect): support expect.unreachable (#3556)
Co-authored-by: Vladimir <sleuths.slews0s@icloud.com>
1 parent 689855b commit 8e385bb

File tree

5 files changed

+57
-2
lines changed

5 files changed

+57
-2
lines changed
 

‎docs/api/expect.md

+45-2
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ type Awaitable<T> = T | PromiseLike<T>
4242
})
4343
// At the end of the test, the above errors will be output.
4444
```
45-
45+
4646
It can also be used with `expect`. if `expect` assertion fails, the test will be terminated and all errors will be displayed.
4747

4848
```ts
@@ -54,7 +54,7 @@ type Awaitable<T> = T | PromiseLike<T>
5454
expect.soft(1 + 2).toBe(4) // do not run
5555
})
5656
```
57-
57+
5858
::: warning
5959
`expect.soft` can only be used inside the [`test`](/api/#test) function.
6060
:::
@@ -1136,6 +1136,49 @@ If the value in the error message is too truncated, you can increase [chaiConfig
11361136
})
11371137
```
11381138

1139+
## expect.unreachable
1140+
1141+
- **Type:** `(message?: string) => never`
1142+
1143+
This method is used to asserting that a line should never be reached.
1144+
1145+
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:
1146+
1147+
```ts
1148+
import { expect, test } from 'vitest'
1149+
1150+
async function build(dir) {
1151+
if (dir.includes('no-src'))
1152+
throw new Error(`${dir}/src does not exist`)
1153+
}
1154+
1155+
const errorDirs = [
1156+
'no-src-folder',
1157+
// ...
1158+
]
1159+
1160+
test.each(errorDirs)('build fails with "%s"', async (dir) => {
1161+
try {
1162+
await build(dir)
1163+
expect.unreachable('Should not pass build')
1164+
}
1165+
catch (err: any) {
1166+
expect(err).toBeInstanceOf(Error)
1167+
expect(err.stack).toContain('build')
1168+
1169+
switch (dir) {
1170+
case 'no-src-folder':
1171+
expect(err.message).toBe(`${dir}/src does not exist`)
1172+
break
1173+
default:
1174+
// to exhaust all error tests
1175+
expect.unreachable('All error test must be handled')
1176+
break
1177+
}
1178+
}
1179+
})
1180+
```
1181+
11391182
<!-- asymmetric matchers -->
11401183

11411184
## expect.anything

‎packages/expect/src/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ export type MatchersObject<T extends MatcherState = MatcherState> = Record<strin
8080

8181
export interface ExpectStatic extends Chai.ExpectStatic, AsymmetricMatchersContaining {
8282
<T>(actual: T, message?: string): Assertion<T>
83+
unreachable(message?: string): never
8384
soft<T>(actual: T, message?: string): Assertion<T>
8485
extend(expects: MatchersObject): void
8586
assertions(expected: number): void

‎packages/vitest/src/integrations/chai/index.ts

+4
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ export function createExpect(test?: Test) {
5353
return assert
5454
}
5555

56+
expect.unreachable = (message?: string) => {
57+
chai.assert.fail(`expected${message ? ` "${message}" ` : ' '}not to be reached`)
58+
}
59+
5660
function assertions(expected: number) {
5761
const errorGen = () => new Error(`expected number of assertions to be ${expected}, but got ${expect.getState().assertionCalls}`)
5862
if (Error.captureStackTrace)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { expect, test } from 'vitest'
2+
3+
test('', () => {
4+
expect.unreachable('hi')
5+
})

‎test/fails/test/__snapshots__/runner.test.ts.snap

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ exports[`should fail expect.test.ts > expect.test.ts 1`] = `"AssertionError: exp
1010
1111
exports[`should fail expect-soft.test.ts > expect-soft.test.ts 1`] = `"Error: expect.soft() can only be used inside a test"`;
1212
13+
exports[`should fail expect-unreachable.test.ts > expect-unreachable.test.ts 1`] = `"AssertionError: expected \\"hi\\" not to be reached"`;
14+
1315
exports[`should fail hook-timeout.test.ts > hook-timeout.test.ts 1`] = `"Error: Hook timed out in 10ms."`;
1416
1517
exports[`should fail hooks-called.test.ts > hooks-called.test.ts 1`] = `

0 commit comments

Comments
 (0)
Please sign in to comment.