From f55e165d5e57bd38a9a709bf602173ff9e27febf Mon Sep 17 00:00:00 2001 From: yoho Date: Thu, 1 Dec 2022 15:13:53 +0800 Subject: [PATCH 01/11] feat: custom format test.each named --- packages/vitest/src/runtime/suite.ts | 23 +++++++++++++++++------ packages/vitest/src/types/tasks.ts | 8 ++++---- test/core/test/each.test.ts | 12 ++++++++++++ 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/packages/vitest/src/runtime/suite.ts b/packages/vitest/src/runtime/suite.ts index db07a6902559..1752671d9bb8 100644 --- a/packages/vitest/src/runtime/suite.ts +++ b/packages/vitest/src/runtime/suite.ts @@ -186,13 +186,18 @@ function createSuite() { if (Array.isArray(cases) && args.length) cases = formatTemplateString(cases, args) - return (name: string, fn: (...args: T[]) => void, options?: number | TestOptions) => { + return (name: string | ((...args: T[]) => string), fn: (...args: T[]) => void, options?: number | TestOptions) => { const arrayOnlyCases = cases.every(Array.isArray) cases.forEach((i, idx) => { const items = Array.isArray(i) ? i : [i] + let formatNamed!: string + if (typeof name === 'string') + formatNamed = formatTitle(name, items, idx) + else + formatNamed = arrayOnlyCases ? name(...items) : name(i) arrayOnlyCases - ? suite(formatTitle(name, items, idx), () => fn(...items), options) - : suite(formatTitle(name, items, idx), () => fn(i), options) + ? suite(formatNamed, () => fn(...items), options) + : suite(formatNamed, () => fn(i), options) }) } } @@ -222,13 +227,19 @@ function createTest(fn: ( if (Array.isArray(cases) && args.length) cases = formatTemplateString(cases, args) - return (name: string, fn: (...args: T[]) => void, options?: number | TestOptions) => { + return (name: string | ((...args: T[]) => string), fn: (...args: T[]) => void, options?: number | TestOptions) => { const arrayOnlyCases = cases.every(Array.isArray) cases.forEach((i, idx) => { const items = Array.isArray(i) ? i : [i] + let formatNamed!: string + if (typeof name === 'string') + formatNamed = formatTitle(name, items, idx) + else + formatNamed = arrayOnlyCases ? name(...items) : name(i) + arrayOnlyCases - ? test(formatTitle(name, items, idx), () => fn(...items), options) - : test(formatTitle(name, items, idx), () => fn(i), options) + ? test(formatNamed, () => fn(...items), options) + : test(formatNamed, () => fn(i), options) }) } } diff --git a/packages/vitest/src/types/tasks.ts b/packages/vitest/src/types/tasks.ts index 21480be3b34c..80ddecc6631d 100644 --- a/packages/vitest/src/types/tasks.ts +++ b/packages/vitest/src/types/tasks.ts @@ -116,22 +116,22 @@ interface SuiteEachFunction { interface TestEachFunction { (cases: ReadonlyArray): ( - name: string, + name: string | ((...args: T) => string), fn: (...args: T) => Awaitable, options?: number | TestOptions, ) => void >(cases: ReadonlyArray): ( - name: string, + name: string | ((...args: ExtractEachCallbackArgs) => string), fn: (...args: ExtractEachCallbackArgs) => Awaitable, options?: number | TestOptions, ) => void (cases: ReadonlyArray): ( - name: string, + name: string | ((...args: T[]) => string), fn: (...args: T[]) => Awaitable, options?: number | TestOptions, ) => void (...args: [TemplateStringsArray, ...any]): ( - name: string, + name: string | ((...args: any[]) => string), fn: (...args: any[]) => Awaitable, options?: number | TestOptions, ) => void diff --git a/test/core/test/each.test.ts b/test/core/test/each.test.ts index a54ba8ac4ded..707351018b72 100644 --- a/test/core/test/each.test.ts +++ b/test/core/test/each.test.ts @@ -194,6 +194,18 @@ ${{ asd: 1 }} | ${'b'} | ${'[object Object]b'} expect(a + b).toBe(expected) }) +test.each` +a | b | expected +${1} | ${1} | ${2} +${'a'} | ${'b'} | ${'ab'} +${[]} | ${'b'} | ${'b'} +${{}} | ${'b'} | ${'[object Object]b'} +${{ asd: 1 }} | ${'b'} | ${'[object Object]b'} +`( + (a, b, expected) => `fmt returns ${JSON.stringify(expected)} when ${JSON.stringify(a)} is added ${JSON.stringify(b)}`, + ({ a, b, expected }) => expect(a + b).toBe(expected), +) + test.each` a | b | expected ${true} | ${true} | ${true} From 623293f594743bc885ca1a03ea7f90546d4546f7 Mon Sep 17 00:00:00 2001 From: yoho Date: Thu, 1 Dec 2022 15:33:09 +0800 Subject: [PATCH 02/11] docs: format title --- docs/api/index.md | 49 +++++++++++++++++++++++++++++++++++++ test/core/test/each.test.ts | 18 ++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/docs/api/index.md b/docs/api/index.md index d9683428c1d4..0a9ee830b229 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -244,6 +244,39 @@ You cannot use this syntax, when using Vitest as [type checker](/guide/testing-t // ✓ add(2, 1) -> 3 ``` + You can also access function to custom format the test title: + + ```ts + test.each([ + [1, 1, 2], + [1, 2, 3], + [2, 1, 3], + ])( + (a, b, expected) => `${a} + ${b} = ${expected}`, + (a, b, expected) => expect(a + b).toBe(expected), + ) + + // this will return + // ✓ 1 + 1 = 2 + // ✓ 1 + 2 = 3 + // ✓ 2 + 1 = 3 + ``` + + ```ts + test.each([ + { a: 1, b: 1, expected: 2 }, + { a: 1, b: 2, expected: 3 }, + { a: 2, b: 1, expected: 3 }, + ])( + ({ a, b, expected }) => `${a} + ${b} = ${expected}`, + ({ a, b, expected }) => expect(a + b).toBe(expected), + ) + + // this will return + // ✓ 1 + 1 = 2 + // ✓ 1 + 2 = 3 + // ✓ 2 + 1 = 3 + ``` Starting from Vitest 0.25.3, you can also use template string table. @@ -263,6 +296,22 @@ You cannot use this syntax, when using Vitest as [type checker](/guide/testing-t }) ``` + You can also use custom format function to format the test title. + + ```ts + test.each` + a | b | expected + ${1} | ${1} | ${2} + ${'a'} | ${'b'} | ${'ab'} + ${[]} | ${'b'} | ${'b'} + ${{}} | ${'b'} | ${'[object Object]b'} + ${{ asd: 1 }} | ${'b'} | ${'[object Object]b'} + `( + (a, b, expected) => `fmt returns ${JSON.stringify(expected)} when ${JSON.stringify(a)} is added ${JSON.stringify(b)}`, + ({ a, b, expected }) => expect(a + b).toBe(expected), + ) + ``` + If you want to have access to `TestContext`, use `describe.each` with a single test. ::: warning diff --git a/test/core/test/each.test.ts b/test/core/test/each.test.ts index 707351018b72..7ec14477e476 100644 --- a/test/core/test/each.test.ts +++ b/test/core/test/each.test.ts @@ -8,6 +8,24 @@ test.each([ expect(a + b).toBe(expected) }) +test.each([ + [1, 1, 2], + [1, 2, 3], + [2, 1, 3], +])( + (a, b, expected) => `${a} + ${b} = ${expected}`, + (a, b, expected) => expect(a + b).toBe(expected), +) + +test.each([ + { a: 1, b: 1, expected: 2 }, + { a: 1, b: 2, expected: 3 }, + { a: 2, b: 1, expected: 3 }, +])( + ({ a, b, expected }) => `${a} + ${b} = ${expected}`, + ({ a, b, expected }) => expect(a + b).toBe(expected), +) + test.each([ ['string', true], ['string', false], From 54efae3f01a26b0fabf9f1b57aca5feb73c45cf1 Mon Sep 17 00:00:00 2001 From: yoho Date: Thu, 1 Dec 2022 16:44:40 +0800 Subject: [PATCH 03/11] chore: update --- docs/api/index.md | 50 +++++++++------------------- packages/vitest/src/runtime/suite.ts | 9 +++-- test/core/test/each.test.ts | 18 ---------- 3 files changed, 23 insertions(+), 54 deletions(-) diff --git a/docs/api/index.md b/docs/api/index.md index 0a9ee830b229..70ac9835ef20 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -244,40 +244,6 @@ You cannot use this syntax, when using Vitest as [type checker](/guide/testing-t // ✓ add(2, 1) -> 3 ``` - You can also access function to custom format the test title: - - ```ts - test.each([ - [1, 1, 2], - [1, 2, 3], - [2, 1, 3], - ])( - (a, b, expected) => `${a} + ${b} = ${expected}`, - (a, b, expected) => expect(a + b).toBe(expected), - ) - - // this will return - // ✓ 1 + 1 = 2 - // ✓ 1 + 2 = 3 - // ✓ 2 + 1 = 3 - ``` - - ```ts - test.each([ - { a: 1, b: 1, expected: 2 }, - { a: 1, b: 2, expected: 3 }, - { a: 2, b: 1, expected: 3 }, - ])( - ({ a, b, expected }) => `${a} + ${b} = ${expected}`, - ({ a, b, expected }) => expect(a + b).toBe(expected), - ) - - // this will return - // ✓ 1 + 1 = 2 - // ✓ 1 + 2 = 3 - // ✓ 2 + 1 = 3 - ``` - Starting from Vitest 0.25.3, you can also use template string table. * First row should be column names, separated by `|`; @@ -312,6 +278,22 @@ You cannot use this syntax, when using Vitest as [type checker](/guide/testing-t ) ``` + You can also custom title formatter. + + ```ts + test.each` + a | b | expected + ${1} | ${1} | ${2} + ${'a'} | ${'b'} | ${'ab'} + ${[]} | ${'b'} | ${'b'} + ${{}} | ${'b'} | ${'[object Object]b'} + ${{ asd: 1 }} | ${'b'} | ${'[object Object]b'} + `( + (a, b, expected) => `fmt returns ${JSON.stringify(expected)} when ${JSON.stringify(a)} is added ${JSON.stringify(b)}`, + ({ a, b, expected }) => expect(a + b).toBe(expected), + ) + ``` + If you want to have access to `TestContext`, use `describe.each` with a single test. ::: warning diff --git a/packages/vitest/src/runtime/suite.ts b/packages/vitest/src/runtime/suite.ts index 1752671d9bb8..210fc26d7d8d 100644 --- a/packages/vitest/src/runtime/suite.ts +++ b/packages/vitest/src/runtime/suite.ts @@ -193,8 +193,11 @@ function createSuite() { let formatNamed!: string if (typeof name === 'string') formatNamed = formatTitle(name, items, idx) - else + else if (Array.isArray(cases) && args.length) formatNamed = arrayOnlyCases ? name(...items) : name(i) + else + throw new Error('only apply with string template') + arrayOnlyCases ? suite(formatNamed, () => fn(...items), options) : suite(formatNamed, () => fn(i), options) @@ -234,8 +237,10 @@ function createTest(fn: ( let formatNamed!: string if (typeof name === 'string') formatNamed = formatTitle(name, items, idx) - else + else if (Array.isArray(cases) && args.length) formatNamed = arrayOnlyCases ? name(...items) : name(i) + else + throw new Error('only apply with string template') arrayOnlyCases ? test(formatNamed, () => fn(...items), options) diff --git a/test/core/test/each.test.ts b/test/core/test/each.test.ts index 7ec14477e476..707351018b72 100644 --- a/test/core/test/each.test.ts +++ b/test/core/test/each.test.ts @@ -8,24 +8,6 @@ test.each([ expect(a + b).toBe(expected) }) -test.each([ - [1, 1, 2], - [1, 2, 3], - [2, 1, 3], -])( - (a, b, expected) => `${a} + ${b} = ${expected}`, - (a, b, expected) => expect(a + b).toBe(expected), -) - -test.each([ - { a: 1, b: 1, expected: 2 }, - { a: 1, b: 2, expected: 3 }, - { a: 2, b: 1, expected: 3 }, -])( - ({ a, b, expected }) => `${a} + ${b} = ${expected}`, - ({ a, b, expected }) => expect(a + b).toBe(expected), -) - test.each([ ['string', true], ['string', false], From bd67a2f2ece64d0737cc6f2ce16030ea00118e12 Mon Sep 17 00:00:00 2001 From: yoho Date: Thu, 1 Dec 2022 16:45:58 +0800 Subject: [PATCH 04/11] chore: update --- docs/api/index.md | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/docs/api/index.md b/docs/api/index.md index 70ac9835ef20..f209586208aa 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -278,22 +278,6 @@ You cannot use this syntax, when using Vitest as [type checker](/guide/testing-t ) ``` - You can also custom title formatter. - - ```ts - test.each` - a | b | expected - ${1} | ${1} | ${2} - ${'a'} | ${'b'} | ${'ab'} - ${[]} | ${'b'} | ${'b'} - ${{}} | ${'b'} | ${'[object Object]b'} - ${{ asd: 1 }} | ${'b'} | ${'[object Object]b'} - `( - (a, b, expected) => `fmt returns ${JSON.stringify(expected)} when ${JSON.stringify(a)} is added ${JSON.stringify(b)}`, - ({ a, b, expected }) => expect(a + b).toBe(expected), - ) - ``` - If you want to have access to `TestContext`, use `describe.each` with a single test. ::: warning From 3cf511b09dcdb2d5771214c9dbdc473bc0bd02ad Mon Sep 17 00:00:00 2001 From: yoho Date: Thu, 1 Dec 2022 16:47:16 +0800 Subject: [PATCH 05/11] chore: update --- packages/vitest/src/types/tasks.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/vitest/src/types/tasks.ts b/packages/vitest/src/types/tasks.ts index 80ddecc6631d..259d43b7e089 100644 --- a/packages/vitest/src/types/tasks.ts +++ b/packages/vitest/src/types/tasks.ts @@ -116,17 +116,17 @@ interface SuiteEachFunction { interface TestEachFunction { (cases: ReadonlyArray): ( - name: string | ((...args: T) => string), + name: string, fn: (...args: T) => Awaitable, options?: number | TestOptions, ) => void >(cases: ReadonlyArray): ( - name: string | ((...args: ExtractEachCallbackArgs) => string), + name: string, fn: (...args: ExtractEachCallbackArgs) => Awaitable, options?: number | TestOptions, ) => void (cases: ReadonlyArray): ( - name: string | ((...args: T[]) => string), + name: string, fn: (...args: T[]) => Awaitable, options?: number | TestOptions, ) => void From 366bf156946eee6d83783f6ff52c82309875941c Mon Sep 17 00:00:00 2001 From: yoho Date: Thu, 1 Dec 2022 16:48:05 +0800 Subject: [PATCH 06/11] chore: upadte --- docs/api/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/api/index.md b/docs/api/index.md index f209586208aa..8fe75a772fd9 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -244,6 +244,7 @@ You cannot use this syntax, when using Vitest as [type checker](/guide/testing-t // ✓ add(2, 1) -> 3 ``` + Starting from Vitest 0.25.3, you can also use template string table. * First row should be column names, separated by `|`; From f635364ccfbf6b17d42d8bf14cda2354f93159d5 Mon Sep 17 00:00:00 2001 From: yoho Date: Fri, 2 Dec 2022 15:27:19 +0800 Subject: [PATCH 07/11] docs: update --- docs/api/index.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/api/index.md b/docs/api/index.md index 8fe75a772fd9..0ecf9a1d0dab 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -279,6 +279,10 @@ You cannot use this syntax, when using Vitest as [type checker](/guide/testing-t ) ``` + ::: tip + This syntax can only use in the string template `test.each` and `describe.each` format. + ::: + If you want to have access to `TestContext`, use `describe.each` with a single test. ::: warning From 56ecd8dadd24848995fe7c6f22e19a61435c45be Mon Sep 17 00:00:00 2001 From: yoho Date: Sat, 3 Dec 2022 10:41:50 +0800 Subject: [PATCH 08/11] chore: revert --- docs/api/index.md | 20 -------------------- packages/vitest/src/runtime/suite.ts | 28 ++++++---------------------- packages/vitest/src/types/tasks.ts | 2 +- 3 files changed, 7 insertions(+), 43 deletions(-) diff --git a/docs/api/index.md b/docs/api/index.md index 0ecf9a1d0dab..d9683428c1d4 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -263,26 +263,6 @@ You cannot use this syntax, when using Vitest as [type checker](/guide/testing-t }) ``` - You can also use custom format function to format the test title. - - ```ts - test.each` - a | b | expected - ${1} | ${1} | ${2} - ${'a'} | ${'b'} | ${'ab'} - ${[]} | ${'b'} | ${'b'} - ${{}} | ${'b'} | ${'[object Object]b'} - ${{ asd: 1 }} | ${'b'} | ${'[object Object]b'} - `( - (a, b, expected) => `fmt returns ${JSON.stringify(expected)} when ${JSON.stringify(a)} is added ${JSON.stringify(b)}`, - ({ a, b, expected }) => expect(a + b).toBe(expected), - ) - ``` - - ::: tip - This syntax can only use in the string template `test.each` and `describe.each` format. - ::: - If you want to have access to `TestContext`, use `describe.each` with a single test. ::: warning diff --git a/packages/vitest/src/runtime/suite.ts b/packages/vitest/src/runtime/suite.ts index 210fc26d7d8d..36b184ebb8e2 100644 --- a/packages/vitest/src/runtime/suite.ts +++ b/packages/vitest/src/runtime/suite.ts @@ -186,21 +186,13 @@ function createSuite() { if (Array.isArray(cases) && args.length) cases = formatTemplateString(cases, args) - return (name: string | ((...args: T[]) => string), fn: (...args: T[]) => void, options?: number | TestOptions) => { + return (name: string, fn: (...args: T[]) => void, options?: number | TestOptions) => { const arrayOnlyCases = cases.every(Array.isArray) cases.forEach((i, idx) => { const items = Array.isArray(i) ? i : [i] - let formatNamed!: string - if (typeof name === 'string') - formatNamed = formatTitle(name, items, idx) - else if (Array.isArray(cases) && args.length) - formatNamed = arrayOnlyCases ? name(...items) : name(i) - else - throw new Error('only apply with string template') - arrayOnlyCases - ? suite(formatNamed, () => fn(...items), options) - : suite(formatNamed, () => fn(i), options) + ? suite(formatTitle(name, items, idx), () => fn(...items), options) + : suite(formatTitle(name, items, idx), () => fn(i), options) }) } } @@ -230,21 +222,14 @@ function createTest(fn: ( if (Array.isArray(cases) && args.length) cases = formatTemplateString(cases, args) - return (name: string | ((...args: T[]) => string), fn: (...args: T[]) => void, options?: number | TestOptions) => { + return (name: string, fn: (...args: T[]) => void, options?: number | TestOptions) => { const arrayOnlyCases = cases.every(Array.isArray) cases.forEach((i, idx) => { const items = Array.isArray(i) ? i : [i] - let formatNamed!: string - if (typeof name === 'string') - formatNamed = formatTitle(name, items, idx) - else if (Array.isArray(cases) && args.length) - formatNamed = arrayOnlyCases ? name(...items) : name(i) - else - throw new Error('only apply with string template') arrayOnlyCases - ? test(formatNamed, () => fn(...items), options) - : test(formatNamed, () => fn(i), options) + ? test(formatTitle(name, items, idx), () => fn(...items), options) + : test(formatTitle(name, items, idx), () => fn(i), options) }) } } @@ -285,7 +270,6 @@ function formatTitle(template: string, items: any[], idx: number) { .replace(/%#/g, `${idx}`) .replace(/__vitest_escaped_%__/g, '%%') } - const count = template.split('%').length - 1 let formatted = util.format(template, ...items.slice(0, count)) if (isObject(items[0])) { diff --git a/packages/vitest/src/types/tasks.ts b/packages/vitest/src/types/tasks.ts index 259d43b7e089..21480be3b34c 100644 --- a/packages/vitest/src/types/tasks.ts +++ b/packages/vitest/src/types/tasks.ts @@ -131,7 +131,7 @@ interface TestEachFunction { options?: number | TestOptions, ) => void (...args: [TemplateStringsArray, ...any]): ( - name: string | ((...args: any[]) => string), + name: string, fn: (...args: any[]) => Awaitable, options?: number | TestOptions, ) => void From fa66bf4cfd7ea3012f201d7b7b9f43dd0abc78db Mon Sep 17 00:00:00 2001 From: yoho Date: Sat, 3 Dec 2022 16:19:21 +0800 Subject: [PATCH 09/11] chore: update --- test/core/test/each.test.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/test/core/test/each.test.ts b/test/core/test/each.test.ts index 707351018b72..a54ba8ac4ded 100644 --- a/test/core/test/each.test.ts +++ b/test/core/test/each.test.ts @@ -194,18 +194,6 @@ ${{ asd: 1 }} | ${'b'} | ${'[object Object]b'} expect(a + b).toBe(expected) }) -test.each` -a | b | expected -${1} | ${1} | ${2} -${'a'} | ${'b'} | ${'ab'} -${[]} | ${'b'} | ${'b'} -${{}} | ${'b'} | ${'[object Object]b'} -${{ asd: 1 }} | ${'b'} | ${'[object Object]b'} -`( - (a, b, expected) => `fmt returns ${JSON.stringify(expected)} when ${JSON.stringify(a)} is added ${JSON.stringify(b)}`, - ({ a, b, expected }) => expect(a + b).toBe(expected), -) - test.each` a | b | expected ${true} | ${true} | ${true} From 9ef5e1a75b9222029b5a02e32f1610ccd361388b Mon Sep 17 00:00:00 2001 From: yoho Date: Sat, 3 Dec 2022 16:33:08 +0800 Subject: [PATCH 10/11] feat: object attr getter --- packages/vitest/src/runtime/suite.ts | 6 +++--- packages/vitest/src/utils/index.ts | 12 ++++++++++++ test/core/test/each.test.ts | 9 +++++++++ 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/packages/vitest/src/runtime/suite.ts b/packages/vitest/src/runtime/suite.ts index 36b184ebb8e2..1f217fbdc3d2 100644 --- a/packages/vitest/src/runtime/suite.ts +++ b/packages/vitest/src/runtime/suite.ts @@ -1,6 +1,6 @@ import util from 'util' import type { BenchFunction, BenchOptions, Benchmark, BenchmarkAPI, File, RunMode, Suite, SuiteAPI, SuiteCollector, SuiteFactory, SuiteHooks, Task, Test, TestAPI, TestFunction, TestOptions } from '../types' -import { getWorkerState, isObject, isRunningInBenchmark, isRunningInTest, noop } from '../utils' +import { getWorkerState, isObject, isRunningInBenchmark, isRunningInTest, noop, objectAttr } from '../utils' import { createChainable } from './chain' import { collectTask, collectorContext, createTestContext, runWithSuite, withTimeout } from './context' import { getHooks, setBenchOptions, setFn, setHooks } from './map' @@ -273,8 +273,8 @@ function formatTitle(template: string, items: any[], idx: number) { const count = template.split('%').length - 1 let formatted = util.format(template, ...items.slice(0, count)) if (isObject(items[0])) { - formatted = formatted.replace(/\$([$\w_]+)/g, (_, key) => { - return items[0][key] + formatted = formatted.replace(/\$([$\w_.]+)/g, (_, key) => { + return objectAttr(items[0], key) }) } return formatted diff --git a/packages/vitest/src/utils/index.ts b/packages/vitest/src/utils/index.ts index 15eb87b1b799..7db9215e170b 100644 --- a/packages/vitest/src/utils/index.ts +++ b/packages/vitest/src/utils/index.ts @@ -180,3 +180,15 @@ export function createDefer(): DeferPromise { p.reject = reject! return p } + +export function objectAttr(source: any, path: string, defaultValue = undefined) { + // a[3].b -> a.3.b + const paths = path.replace(/\[(\d+)\]/g, '.$1').split('.') + let result = source + for (const p of paths) { + result = Object(result)[p] + if (result === undefined) + return defaultValue + } + return result +} diff --git a/test/core/test/each.test.ts b/test/core/test/each.test.ts index a54ba8ac4ded..6f61dbf4bbed 100644 --- a/test/core/test/each.test.ts +++ b/test/core/test/each.test.ts @@ -194,6 +194,15 @@ ${{ asd: 1 }} | ${'b'} | ${'[object Object]b'} expect(a + b).toBe(expected) }) +test.each` +a | b | expected +${{ val: 1 }} | ${'b'} | ${'1b'} +${{ val: 2 }} | ${'b'} | ${'2b'} +${{ val: 3 }} | ${'b'} | ${'3b'} +`('returns $expected when $a.val is added $b', ({ a, b, expected }) => { + expect(a.val + b).toBe(expected) +}) + test.each` a | b | expected ${true} | ${true} | ${true} From 937d2bfad0c4616e3f3adcf4130210396d50441f Mon Sep 17 00:00:00 2001 From: yoho Date: Sat, 3 Dec 2022 16:37:45 +0800 Subject: [PATCH 11/11] docs: object getter --- docs/api/index.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/api/index.md b/docs/api/index.md index d9683428c1d4..706bfd8d0fdf 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -244,6 +244,24 @@ You cannot use this syntax, when using Vitest as [type checker](/guide/testing-t // ✓ add(2, 1) -> 3 ``` + You can also access Object attributes with `.`, if you are using objects as arguments: + + ```ts + test.each` + a | b | expected + ${{ val: 1 }} | ${'b'} | ${'1b'} + ${{ val: 2 }} | ${'b'} | ${'2b'} + ${{ val: 3 }} | ${'b'} | ${'3b'} + `('add($a.val, $b) -> $expected', ({ a, b, expected }) => { + expect(a.val + b).toBe(expected) + }) + + // this will return + // ✓ add(1, b) -> 1b + // ✓ add(2, b) -> 2b + // ✓ add(3, b) -> 3b + ``` + Starting from Vitest 0.25.3, you can also use template string table.