Skip to content

Commit 391860f

Browse files
hi-ogawasheremet-vaspamshaker
authoredNov 13, 2024··
feat: support inline diff options and support printBasicPrototype (#6740)
Co-authored-by: Vladimir <sleuths.slews0s@icloud.com> Co-authored-by: Michał Grzegorzewski <4864089+spamshaker@users.noreply.github.com>
1 parent 32f23b9 commit 391860f

File tree

16 files changed

+295
-20
lines changed

16 files changed

+295
-20
lines changed
 

‎docs/config/index.md

+48-10
Original file line numberDiff line numberDiff line change
@@ -2284,22 +2284,32 @@ export default defineConfig({
22842284
### diff
22852285

22862286
- **Type:** `string`
2287-
- **CLI:** `--diff=<value>`
2287+
- **CLI:** `--diff=<path>`
22882288

2289-
Path to a diff config that will be used to generate diff interface. Useful if you want to customize diff display.
2289+
`DiffOptions` object or a path to a module which exports `DiffOptions`. Useful if you want to customize diff display.
2290+
2291+
For example, as a config object:
22902292

22912293
:::code-group
2292-
```ts [vitest.diff.ts]
2293-
import type { DiffOptions } from 'vitest'
2294-
import c from 'tinyrainbow'
2294+
```ts [vitest.config.js]
2295+
import { defineConfig } from 'vitest/config'
2296+
import c from 'picocolors'
22952297

2296-
export default {
2297-
aIndicator: c.bold('--'),
2298-
bIndicator: c.bold('++'),
2299-
omitAnnotationLines: true,
2300-
} satisfies DiffOptions
2298+
export default defineConfig({
2299+
test: {
2300+
diff: {
2301+
aIndicator: c.bold('--'),
2302+
bIndicator: c.bold('++'),
2303+
omitAnnotationLines: true,
2304+
}
2305+
}
2306+
})
23012307
```
2308+
:::
23022309

2310+
Or as a module:
2311+
2312+
:::code-group
23032313
```ts [vitest.config.js]
23042314
import { defineConfig } from 'vitest/config'
23052315

@@ -2309,12 +2319,32 @@ export default defineConfig({
23092319
}
23102320
})
23112321
```
2322+
2323+
```ts [vitest.diff.ts]
2324+
import type { DiffOptions } from 'vitest'
2325+
import c from 'picocolors'
2326+
2327+
export default {
2328+
aIndicator: c.bold('--'),
2329+
bIndicator: c.bold('++'),
2330+
omitAnnotationLines: true,
2331+
} satisfies DiffOptions
2332+
```
23122333
:::
23132334

2335+
#### diff.expand
2336+
2337+
- **Type**: `boolean`
2338+
- **Default**: `true`
2339+
- **CLI:** `--diff.expand=false`
2340+
2341+
Expand all common lines.
2342+
23142343
#### diff.truncateThreshold
23152344

23162345
- **Type**: `number`
23172346
- **Default**: `0`
2347+
- **CLI:** `--diff.truncateThreshold=<path>`
23182348

23192349
The maximum length of diff result to be displayed. Diffs above this threshold will be truncated.
23202350
Truncation won't take effect with default value 0.
@@ -2323,6 +2353,7 @@ Truncation won't take effect with default value 0.
23232353

23242354
- **Type**: `string`
23252355
- **Default**: `'... Diff result is truncated'`
2356+
- **CLI:** `--diff.truncateAnnotation=<annotation>`
23262357

23272358
Annotation that is output at the end of diff result if it's truncated.
23282359

@@ -2333,6 +2364,13 @@ Annotation that is output at the end of diff result if it's truncated.
23332364

23342365
Color of truncate annotation, default is output with no color.
23352366

2367+
#### diff.printBasicPrototype
2368+
2369+
- **Type**: `boolean`
2370+
- **Default**: `true`
2371+
2372+
Print basic prototype `Object` and `Array` in diff output
2373+
23362374
### fakeTimers
23372375

23382376
- **Type:** `FakeTimerInstallOpts`

‎packages/browser/src/node/plugin.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ export default (browserServer: BrowserServer, base = '/'): Plugin[] => {
230230
'msw/browser',
231231
]
232232

233-
if (project.config.diff) {
233+
if (typeof project.config.diff === 'string') {
234234
entries.push(project.config.diff)
235235
}
236236

‎packages/utils/src/diff/index.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import { getType } from './getType'
2323
import { normalizeDiffOptions } from './normalizeDiffOptions'
2424
import { diffStringsRaw, diffStringsUnified } from './printDiffs'
2525

26-
export type { DiffOptions, DiffOptionsColor } from './types'
26+
export type { DiffOptions, DiffOptionsColor, SerializedDiffOptions } from './types'
2727

2828
export { diffLinesRaw, diffLinesUnified, diffLinesUnified2 }
2929
export { diffStringsRaw, diffStringsUnified }
@@ -180,11 +180,12 @@ function getFormatOptions(
180180
formatOptions: PrettyFormatOptions,
181181
options?: DiffOptions,
182182
): PrettyFormatOptions {
183-
const { compareKeys } = normalizeDiffOptions(options)
183+
const { compareKeys, printBasicPrototype } = normalizeDiffOptions(options)
184184

185185
return {
186186
...formatOptions,
187187
compareKeys,
188+
printBasicPrototype,
188189
}
189190
}
190191

‎packages/utils/src/diff/normalizeDiffOptions.ts

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ function getDefaultOptions(): DiffOptionsNormalized {
3434
includeChangeCounts: false,
3535
omitAnnotationLines: false,
3636
patchColor: c.yellow,
37+
printBasicPrototype: true,
3738
truncateThreshold: DIFF_TRUNCATE_THRESHOLD_DEFAULT,
3839
truncateAnnotation: '... Diff result is truncated',
3940
truncateAnnotationColor: noColor,

‎packages/utils/src/diff/types.ts

+18
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,29 @@ export interface DiffOptions {
2626
includeChangeCounts?: boolean
2727
omitAnnotationLines?: boolean
2828
patchColor?: DiffOptionsColor
29+
printBasicPrototype?: boolean
2930
compareKeys?: CompareKeys
3031
truncateThreshold?: number
3132
truncateAnnotation?: string
3233
truncateAnnotationColor?: DiffOptionsColor
3334
}
3435

36+
export interface SerializedDiffOptions {
37+
aAnnotation?: string
38+
aIndicator?: string
39+
bAnnotation?: string
40+
bIndicator?: string
41+
commonIndicator?: string
42+
contextLines?: number
43+
emptyFirstOrLastLinePlaceholder?: string
44+
expand?: boolean
45+
includeChangeCounts?: boolean
46+
omitAnnotationLines?: boolean
47+
printBasicPrototype?: boolean
48+
truncateThreshold?: number
49+
truncateAnnotation?: string
50+
}
51+
3552
export interface DiffOptionsNormalized {
3653
aAnnotation: string
3754
aColor: DiffOptionsColor
@@ -51,6 +68,7 @@ export interface DiffOptionsNormalized {
5168
includeChangeCounts: boolean
5269
omitAnnotationLines: boolean
5370
patchColor: DiffOptionsColor
71+
printBasicPrototype: boolean
5472
truncateThreshold: number
5573
truncateAnnotation: string
5674
truncateAnnotationColor: DiffOptionsColor

‎packages/vitest/src/node/cli/cli-config.ts

+51-2
Original file line numberDiff line numberDiff line change
@@ -599,9 +599,58 @@ export const cliOptionsConfig: VitestCLIOptions = {
599599
},
600600
diff: {
601601
description:
602-
'Path to a diff config that will be used to generate diff interface',
602+
'DiffOptions object or a path to a module which exports DiffOptions object',
603603
argument: '<path>',
604-
normalize: true,
604+
subcommands: {
605+
aAnnotation: {
606+
description: 'Annotation for expected lines (default: `Expected`)',
607+
argument: '<annotation>',
608+
},
609+
aIndicator: {
610+
description: 'Indicator for expected lines (default: `-`)',
611+
argument: '<indicator>',
612+
},
613+
bAnnotation: {
614+
description: 'Annotation for received lines (default: `Received`)',
615+
argument: '<annotation>',
616+
},
617+
bIndicator: {
618+
description: 'Indicator for received lines (default: `+`)',
619+
argument: '<indicator>',
620+
},
621+
commonIndicator: {
622+
description: 'Indicator for common lines (default: ` `)',
623+
argument: '<indicator>',
624+
},
625+
contextLines: {
626+
description: 'Number of lines of context to show around each change (default: `5`)',
627+
argument: '<lines>',
628+
},
629+
emptyFirstOrLastLinePlaceholder: {
630+
description: 'Placeholder for an empty first or last line (default: `""`)',
631+
argument: '<placeholder>',
632+
},
633+
expand: {
634+
description: 'Expand all common lines (default: `true`)',
635+
},
636+
includeChangeCounts: {
637+
description: 'Include comparison counts in diff output (default: `false`)',
638+
},
639+
omitAnnotationLines: {
640+
description: 'Omit annotation lines from the output (default: `false`)',
641+
},
642+
printBasicPrototype: {
643+
description: 'Print basic prototype Object and Array (default: `true`)',
644+
},
645+
truncateThreshold: {
646+
description: 'Number of lines to show before and after each change (default: `0`)',
647+
argument: '<threshold>',
648+
},
649+
truncateAnnotation: {
650+
description: 'Annotation for truncated lines (default: `... Diff result is truncated`)',
651+
argument: '<annotation>',
652+
},
653+
},
605654
},
606655
exclude: {
607656
description: 'Additional file globs to be excluded from test',

‎packages/vitest/src/node/config/resolveConfig.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -578,7 +578,7 @@ export function resolveConfig(
578578
}
579579
}
580580

581-
if (resolved.diff) {
581+
if (typeof resolved.diff === 'string') {
582582
resolved.diff = resolvePath(resolved.diff, resolved.root)
583583
resolved.forceRerunTriggers.push(resolved.diff)
584584
}

‎packages/vitest/src/node/config/serializeConfig.ts

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export function serializeConfig(
3737
pool: config.pool,
3838
expect: config.expect,
3939
snapshotSerializers: config.snapshotSerializers,
40+
// TODO: non serializable function?
4041
diff: config.diff,
4142
retry: config.retry,
4243
disableConsoleIntercept: config.disableConsoleIntercept,

‎packages/vitest/src/node/types/config.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { FakeTimerInstallOpts } from '@sinonjs/fake-timers'
22
import type { PrettyFormatOptions } from '@vitest/pretty-format'
33
import type { SequenceHooks, SequenceSetupFiles } from '@vitest/runner'
44
import type { SnapshotStateOptions } from '@vitest/snapshot'
5+
import type { SerializedDiffOptions } from '@vitest/utils/diff'
56
import type { AliasOptions, ConfigEnv, DepOptimizationConfig, ServerOptions, UserConfig as ViteUserConfig } from 'vite'
67
import type { ViteNodeServerOptions } from 'vite-node'
78
import type { ChaiConfig } from '../../integrations/chai/config'
@@ -563,7 +564,7 @@ export interface InlineConfig {
563564
/**
564565
* Path to a module which has a default export of diff config.
565566
*/
566-
diff?: string
567+
diff?: string | SerializedDiffOptions
567568

568569
/**
569570
* Paths to snapshot serializer modules.
@@ -979,7 +980,7 @@ export interface ResolvedConfig
979980
mode: VitestRunMode
980981

981982
base?: string
982-
diff?: string
983+
diff?: string | SerializedDiffOptions
983984
bail?: number
984985

985986
setupFiles: string[]

‎packages/vitest/src/runtime/config.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { PrettyFormatOptions } from '@vitest/pretty-format'
33
import type { SequenceHooks, SequenceSetupFiles } from '@vitest/runner'
44
import type { SnapshotUpdateState } from '@vitest/snapshot'
55
import type { SnapshotEnvironment } from '@vitest/snapshot/environment'
6+
import type { SerializedDiffOptions } from '@vitest/utils/diff'
67

78
/**
89
* Config that tests have access to.
@@ -98,7 +99,7 @@ export interface SerializedConfig {
9899
showDiff?: boolean
99100
truncateThreshold?: number
100101
} | undefined
101-
diff: string | undefined
102+
diff: string | SerializedDiffOptions | undefined
102103
retry: number
103104
includeTaskLocation: boolean | undefined
104105
inspect: boolean | string | undefined

‎packages/vitest/src/runtime/setup-common.ts

+3
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ export async function loadDiffConfig(
4747
config: SerializedConfig,
4848
executor: VitestExecutor,
4949
) {
50+
if (typeof config.diff === 'object') {
51+
return config.diff
52+
}
5053
if (typeof config.diff !== 'string') {
5154
return
5255
}
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { expect, test } from 'vitest'
2+
3+
test('large diff', () => {
4+
const x = [...Array(30)].map((_, i) => i);
5+
const y = [...x];
6+
y[0] = 1000;
7+
y[15] = 2000;
8+
y[29] = 3000;
9+
expect(x).toEqual(y)
10+
})
11+
12+
test("printBasicPrototype", () => {
13+
expect({
14+
obj: { k: "foo" },
15+
arr: [1, 2]
16+
}).toEqual({
17+
obj: { k: "bar" },
18+
arr: [1, 3]
19+
});
20+
})
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import {defineConfig} from 'vitest/config'
2+
3+
export default defineConfig({
4+
test: {
5+
diff: {
6+
// expand: false,
7+
// printBasicPrototype: false,
8+
}
9+
}
10+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2+
3+
exports[`inline diff options: { expand: false, printBasicPrototype: false } 1`] = `
4+
[
5+
"- Expected
6+
+ Received
7+
8+
@@ -1,7 +1,7 @@
9+
[
10+
- 1000,
11+
+ 0,
12+
1,
13+
2,
14+
3,
15+
4,
16+
5,
17+
@@ -12,11 +12,11 @@
18+
10,
19+
11,
20+
12,
21+
13,
22+
14,
23+
- 2000,
24+
+ 15,
25+
16,
26+
17,
27+
18,
28+
19,
29+
20,
30+
@@ -26,7 +26,7 @@
31+
24,
32+
25,
33+
26,
34+
27,
35+
28,
36+
- 3000,
37+
+ 29,
38+
]",
39+
"- Expected
40+
+ Received
41+
42+
{
43+
"arr": [
44+
1,
45+
- 3,
46+
+ 2,
47+
],
48+
"obj": {
49+
- "k": "bar",
50+
+ "k": "foo",
51+
},
52+
}",
53+
]
54+
`;
55+
56+
exports[`inline diff options: undefined 1`] = `
57+
[
58+
"- Expected
59+
+ Received
60+
61+
Array [
62+
- 1000,
63+
+ 0,
64+
1,
65+
2,
66+
3,
67+
4,
68+
5,
69+
6,
70+
7,
71+
8,
72+
9,
73+
10,
74+
11,
75+
12,
76+
13,
77+
14,
78+
- 2000,
79+
+ 15,
80+
16,
81+
17,
82+
18,
83+
19,
84+
20,
85+
21,
86+
22,
87+
23,
88+
24,
89+
25,
90+
26,
91+
27,
92+
28,
93+
- 3000,
94+
+ 29,
95+
]",
96+
"- Expected
97+
+ Received
98+
99+
Object {
100+
"arr": Array [
101+
1,
102+
- 3,
103+
+ 2,
104+
],
105+
"obj": Object {
106+
- "k": "bar",
107+
+ "k": "foo",
108+
},
109+
}",
110+
]
111+
`;

‎test/config/test/diff.test.ts

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { stripVTControlCharacters } from 'node:util'
2+
import { expect, test } from 'vitest'
3+
import { runVitest } from '../../test-utils'
4+
5+
test.for([
6+
[undefined],
7+
[{ expand: false, printBasicPrototype: false }],
8+
])(`inline diff options: %o`, async ([options]) => {
9+
const { ctx } = await runVitest({
10+
root: './fixtures/diff',
11+
diff: options,
12+
})
13+
const errors = ctx!.state.getFiles().flatMap(f =>
14+
f.tasks.flatMap(t => t.result?.errors ?? []),
15+
)
16+
expect(
17+
errors.map(e => e.diff && stripVTControlCharacters(e.diff)),
18+
).matchSnapshot()
19+
})

‎test/config/test/failures.test.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,9 @@ test('coverage.autoUpdate cannot update thresholds when configuration file doesn
247247
})
248248

249249
test('boolean flag 100 should not crash CLI', async () => {
250-
const { stderr } = await runVitestCli('--coverage.enabled', '--coverage.thresholds.100')
250+
let { stderr } = await runVitestCli('--coverage.enabled', '--coverage.thresholds.100')
251+
// non-zero coverage shows up, which is non-deterministic, so strip it.
252+
stderr = stderr.replace(/\([0-9.]+%\) does/g, '(0%) does')
251253

252254
expect(stderr).toMatch('ERROR: Coverage for lines (0%) does not meet global threshold (100%)')
253255
expect(stderr).toMatch('ERROR: Coverage for functions (0%) does not meet global threshold (100%)')

0 commit comments

Comments
 (0)
Please sign in to comment.