From 3ec0f306890010506912ddec5a607106e8f99693 Mon Sep 17 00:00:00 2001 From: scarf Date: Sun, 4 Dec 2022 00:29:59 +0900 Subject: [PATCH 1/6] test: add test for objectAttr --- test/core/test/utils.spec.ts | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/test/core/test/utils.spec.ts b/test/core/test/utils.spec.ts index 5525adae7a3b..09704ce392ca 100644 --- a/test/core/test/utils.spec.ts +++ b/test/core/test/utils.spec.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from 'vitest' -import { assertTypes, deepClone, deepMerge, resetModules, toArray } from '../../../packages/vitest/src/utils' +import { assertTypes, deepClone, deepMerge, objectAttr, resetModules, toArray } from '../../../packages/vitest/src/utils' import { deepMergeSnapshot } from '../../../packages/vitest/src/integrations/snapshot/port/utils' import type { ModuleCacheMap } from '../../../packages/vite-node/src/types' @@ -182,3 +182,27 @@ describe('resetModules doesn\'t resets only user modules', () => { expect(moduleCache.size).toBe(2) }) }) + +describe('objectAttr', () => { + const arrow = (a: number) => a * 3 + const func = function (a: number) { + return a * 3 + } + + test.each` + value | path | expected + ${{ foo: 'bar' }} | ${'foo'} | ${'bar'} + ${{ foo: { bar: 'baz' } }} | ${'foo'} | ${{ bar: 'baz' }} + ${{ foo: { bar: 'baz' } }} | ${'foo.bar'} | ${'baz'} + ${{ foo: [{ bar: 'baz' }] }} | ${'foo.0.bar'} | ${'baz'} + ${{ foo: [1, 2, ['a']] }} | ${'foo'} | ${[1, 2, ['a']]} + ${{ foo: [1, 2, ['a']] }} | ${'foo.2'} | ${['a']} + ${{ foo: [1, 2, ['a']] }} | ${'foo.2.0'} | ${'a'} + ${{ foo: [[[1]]] }} | ${'foo.0.0.0'} | ${1} + ${{ foo: [[[[1]]]] }} | ${'foo.0.0.0.0'} | ${1} + ${{ foo: arrow }} | ${'foo'} | ${arrow} + ${{ foo: func }} | ${'foo'} | ${func} + `('objectAttr($value, $path) -> $expected', ({ value, path, expected }) => { + expect(objectAttr(value, path)).toEqual(expected) + }) +}) From 62761afc402db0c64e3337519013931e105278c1 Mon Sep 17 00:00:00 2001 From: scarf Date: Sun, 4 Dec 2022 00:30:34 +0900 Subject: [PATCH 2/6] feat: pretty print test title objects --- packages/vitest/src/runtime/suite.ts | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/packages/vitest/src/runtime/suite.ts b/packages/vitest/src/runtime/suite.ts index 1f217fbdc3d2..2be06c3ca277 100644 --- a/packages/vitest/src/runtime/suite.ts +++ b/packages/vitest/src/runtime/suite.ts @@ -1,4 +1,6 @@ import util from 'util' +import { serialize } from 'v8' +import { format as prettyFormat } from 'pretty-format' 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, objectAttr } from '../utils' import { createChainable } from './chain' @@ -273,13 +275,27 @@ 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 objectAttr(items[0], key) - }) + formatted = formatted.replace(/\$([$\w_.]+)/g, + (_, key) => formatObject(objectAttr(items[0], key)), + ) } return formatted } +function formatObject(value: unknown, maxDepth = 4) { + const formatFunctions = { + test: (val: unknown) => typeof val === 'function', + serialize: (val: Function) => val.toString(), + } + + return prettyFormat(value, { + plugins: [formatFunctions], + escapeRegex: true, + maxDepth, + min: true, + }) +} + function formatTemplateString(cases: any[], args: any[]): any[] { const header = cases.join('').trim().replace(/ /g, '').split('\n').map(i => i.split('|'))[0] const res: any[] = [] From a9fa2e1910f71814e1a9c23150248e6aa96aa9d2 Mon Sep 17 00:00:00 2001 From: scarf Date: Sun, 4 Dec 2022 00:41:23 +0900 Subject: [PATCH 3/6] style: apply lint --- packages/vitest/src/runtime/suite.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/vitest/src/runtime/suite.ts b/packages/vitest/src/runtime/suite.ts index 2be06c3ca277..1b590a3b8d74 100644 --- a/packages/vitest/src/runtime/suite.ts +++ b/packages/vitest/src/runtime/suite.ts @@ -1,5 +1,4 @@ import util from 'util' -import { serialize } from 'v8' import { format as prettyFormat } from 'pretty-format' 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, objectAttr } from '../utils' From 1500c58d847d1e8fb184beabb3ce2e6f1ea69bc7 Mon Sep 17 00:00:00 2001 From: scarf Date: Sun, 4 Dec 2022 07:07:25 +0900 Subject: [PATCH 4/6] refactor(dev): add return type for formatObject --- packages/vitest/src/runtime/suite.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vitest/src/runtime/suite.ts b/packages/vitest/src/runtime/suite.ts index 1b590a3b8d74..32c731c9ca68 100644 --- a/packages/vitest/src/runtime/suite.ts +++ b/packages/vitest/src/runtime/suite.ts @@ -281,7 +281,7 @@ function formatTitle(template: string, items: any[], idx: number) { return formatted } -function formatObject(value: unknown, maxDepth = 4) { +function formatObject(value: unknown, maxDepth = 4): string { const formatFunctions = { test: (val: unknown) => typeof val === 'function', serialize: (val: Function) => val.toString(), From d6dccab4ba87b2bc548b641876bb21e3d4dba19a Mon Sep 17 00:00:00 2001 From: scarf Date: Mon, 5 Dec 2022 17:13:28 +0900 Subject: [PATCH 5/6] feat(dev): use maxWidth specify maximum printed width for properties such as arrays and sets --- packages/vitest/src/runtime/suite.ts | 3 ++- test/core/test/utils.spec.ts | 25 +++++++++++++------------ 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/packages/vitest/src/runtime/suite.ts b/packages/vitest/src/runtime/suite.ts index 32c731c9ca68..a622949e6d6b 100644 --- a/packages/vitest/src/runtime/suite.ts +++ b/packages/vitest/src/runtime/suite.ts @@ -281,7 +281,7 @@ function formatTitle(template: string, items: any[], idx: number) { return formatted } -function formatObject(value: unknown, maxDepth = 4): string { +function formatObject(value: unknown, maxDepth = 3, maxWidth = 2): string { const formatFunctions = { test: (val: unknown) => typeof val === 'function', serialize: (val: Function) => val.toString(), @@ -291,6 +291,7 @@ function formatObject(value: unknown, maxDepth = 4): string { plugins: [formatFunctions], escapeRegex: true, maxDepth, + maxWidth, min: true, }) } diff --git a/test/core/test/utils.spec.ts b/test/core/test/utils.spec.ts index 09704ce392ca..7ebfda54a73d 100644 --- a/test/core/test/utils.spec.ts +++ b/test/core/test/utils.spec.ts @@ -190,18 +190,19 @@ describe('objectAttr', () => { } test.each` - value | path | expected - ${{ foo: 'bar' }} | ${'foo'} | ${'bar'} - ${{ foo: { bar: 'baz' } }} | ${'foo'} | ${{ bar: 'baz' }} - ${{ foo: { bar: 'baz' } }} | ${'foo.bar'} | ${'baz'} - ${{ foo: [{ bar: 'baz' }] }} | ${'foo.0.bar'} | ${'baz'} - ${{ foo: [1, 2, ['a']] }} | ${'foo'} | ${[1, 2, ['a']]} - ${{ foo: [1, 2, ['a']] }} | ${'foo.2'} | ${['a']} - ${{ foo: [1, 2, ['a']] }} | ${'foo.2.0'} | ${'a'} - ${{ foo: [[[1]]] }} | ${'foo.0.0.0'} | ${1} - ${{ foo: [[[[1]]]] }} | ${'foo.0.0.0.0'} | ${1} - ${{ foo: arrow }} | ${'foo'} | ${arrow} - ${{ foo: func }} | ${'foo'} | ${func} + value | path | expected + ${{ foo: 'bar' }} | ${'foo'} | ${'bar'} + ${{ foo: { bar: 'baz' } }} | ${'foo'} | ${{ bar: 'baz' }} + ${{ foo: { bar: 'baz' } }} | ${'foo.bar'} | ${'baz'} + ${{ foo: [{ bar: 'baz' }] }} | ${'foo.0.bar'} | ${'baz'} + ${{ foo: [1, 2, ['a']] }} | ${'foo'} | ${[1, 2, ['a']]} + ${{ foo: [1, 2, ['a']] }} | ${'foo.2'} | ${['a']} + ${{ foo: [1, 2, ['a']] }} | ${'foo.2.0'} | ${'a'} + ${{ foo: [[1]] }} | ${'foo.0.0'} | ${1} + ${{ deep: [[[1]]] }} | ${'deep.0.0.0'} | ${1} + ${{ a: 1, b: 2, c: 3, d: 4 }} | ${'a'} | ${1} + ${{ arrow }} | ${'arrow'} | ${arrow} + ${{ func }} | ${'func'} | ${func} `('objectAttr($value, $path) -> $expected', ({ value, path, expected }) => { expect(objectAttr(value, path)).toEqual(expected) }) From 6c60616dacbbc59ce0fe6f6ddaeecff16febb78d Mon Sep 17 00:00:00 2001 From: scarf Date: Mon, 5 Dec 2022 17:48:45 +0900 Subject: [PATCH 6/6] refactor: use `chaiUtil.objDisplay` instead --- packages/vitest/src/runtime/suite.ts | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/packages/vitest/src/runtime/suite.ts b/packages/vitest/src/runtime/suite.ts index a622949e6d6b..8a69f6bc05e1 100644 --- a/packages/vitest/src/runtime/suite.ts +++ b/packages/vitest/src/runtime/suite.ts @@ -1,5 +1,5 @@ import util from 'util' -import { format as prettyFormat } from 'pretty-format' +import { util as chaiUtil } from 'chai' 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, objectAttr } from '../utils' import { createChainable } from './chain' @@ -275,27 +275,13 @@ function formatTitle(template: string, items: any[], idx: number) { let formatted = util.format(template, ...items.slice(0, count)) if (isObject(items[0])) { formatted = formatted.replace(/\$([$\w_.]+)/g, - (_, key) => formatObject(objectAttr(items[0], key)), + (_, key) => chaiUtil.objDisplay(objectAttr(items[0], key)) as unknown as string, + // https://github.com/chaijs/chai/pull/1490 ) } return formatted } -function formatObject(value: unknown, maxDepth = 3, maxWidth = 2): string { - const formatFunctions = { - test: (val: unknown) => typeof val === 'function', - serialize: (val: Function) => val.toString(), - } - - return prettyFormat(value, { - plugins: [formatFunctions], - escapeRegex: true, - maxDepth, - maxWidth, - min: true, - }) -} - function formatTemplateString(cases: any[], args: any[]): any[] { const header = cases.join('').trim().replace(/ /g, '').split('\n').map(i => i.split('|'))[0] const res: any[] = []