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: add parameter for test name of each #1031

Merged
merged 5 commits into from Mar 26, 2022
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
43 changes: 27 additions & 16 deletions docs/api/index.md
Expand Up @@ -121,22 +121,33 @@ For compatibility with Jest, `TestFunction` can also be of type `(done: DoneCall
- **Type:** `(cases: ReadonlyArray<T>) => void`
- **Alias:** `it.each`

Use `test.each` when you need to run the same test with different variables.
You can use `%i` or `%s` in the test name in the order of the test function parameters.
```ts
test.each([
[1, 1, 2],
[1, 2, 3],
[2, 1, 3],
])('add(%i, %i) -> %i', (a, b, expected) => {
expect(a + b).toBe(expected)
})

// this will return
// √ add(1, 1) -> 2
// √ add(1, 2) -> 3
// √ add(2, 1) -> 3
```
Use `test.each` when you need to run the same test with different variables.
You can inject parameters with [printf formmatting](https://nodejs.org/api/util.html#util_util_format_format_args) in the test name in the order of the test function parameters.

- `%s`: string
- `%d`: number
- `%i`: integer
- `%f`: floating point value
- `%j`: json
- `$o`: object
- `%#`: index of the test case
- `%%`: single precent sign ('%')

```ts
test.each([
[1, 1, 2],
[1, 2, 3],
[2, 1, 3],
])('add(%i, %i) -> %i', (a, b, expected) => {
expect(a + b).toBe(expected)
})

// this will return
// √ add(1, 1) -> 2
// √ add(1, 2) -> 3
// √ add(2, 1) -> 3
```

## describe

When you use `test` in the top level of file, they are collected as part of the implicit suite for it. Using `describe` you can define a new suite in the current context, as a set of related tests and other nested suites. A suite lets you organize your tests so reports are more clear.
Expand Down
18 changes: 13 additions & 5 deletions packages/vitest/src/runtime/suite.ts
Expand Up @@ -14,7 +14,15 @@ export const test = createTest(
},
)

function formatTitle(template: string, items: any[]) {
function formatTitle(template: string, items: any[], idx: number) {
if (template.includes('%#')) {
// '%#' match index of the test case
template = template
.replace(/%%/g, '__vitest_escaped_%__')
.replace(/%#/g, `${idx}`)
.replace(/__vitest_escaped_%__/g, '%%')
}

const count = template.split('%').length - 1
let formatted = format(template, ...items.slice(0, count))
if (isObject(items[0])) {
Expand Down Expand Up @@ -146,9 +154,9 @@ function createSuite() {

suite.each = <T>(cases: ReadonlyArray<T>) => {
return (name: string, fn: (...args: T[]) => void) => {
cases.forEach((i) => {
cases.forEach((i, idx) => {
const items = toArray(i) as any
suite(formatTitle(name, items), () => fn(...items))
suite(formatTitle(name, items, idx), () => fn(...items))
})
}
}
Expand All @@ -164,9 +172,9 @@ function createTest(fn: ((this: Record<'concurrent'| 'skip'| 'only'| 'todo'| 'fa

test.each = <T>(cases: ReadonlyArray<T>) => {
return (name: string, fn: (...args: T[]) => void) => {
cases.forEach((i) => {
cases.forEach((i, idx) => {
const items = toArray(i) as any
test(formatTitle(name, items), () => fn(...items))
test(formatTitle(name, items, idx), () => fn(...items))
})
}
}
Expand Down
8 changes: 8 additions & 0 deletions test/core/test/each.test.ts
Expand Up @@ -75,3 +75,11 @@ describe.each([1, 2, 0])('%s (describe.each 1d)', (num) => {
expect(typeof num).toEqual('number')
})
})

test.each([
[1, 1, 2],
[1, 2, 3],
[2, 1, 3],
])('the index of the test case is %#', (a, b, expected) => {
expect(a + b).toBe(expected)
})