Skip to content

Commit f75ab65

Browse files
authoredMay 30, 2023
fix: assertion diff message now handle non writable property correctly (#3422)
1 parent 306b233 commit f75ab65

File tree

4 files changed

+58
-8
lines changed

4 files changed

+58
-8
lines changed
 

‎packages/runner/src/utils/error.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,8 @@ export function processError(err: any, options: DiffOptions = {}) {
9797
if (err.name)
9898
err.nameStr = String(err.name)
9999

100-
const clonedActual = deepClone(err.actual)
101-
const clonedExpected = deepClone(err.expected)
100+
const clonedActual = deepClone(err.actual, { forceWritable: true })
101+
const clonedExpected = deepClone(err.expected, { forceWritable: true })
102102

103103
const { replacedActual, replacedExpected } = replaceAsymmetricMatcher(clonedActual, clonedExpected)
104104

‎packages/utils/src/helpers.ts

+19-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import type { Arrayable, Nullable } from './types'
22

3+
interface CloneOptions {
4+
forceWritable?: boolean
5+
}
6+
37
export function notNullish<T>(v: T | null | undefined): v is NonNullable<T> {
48
return v != null
59
}
@@ -72,20 +76,28 @@ export function getOwnProperties(obj: any) {
7276
return Array.from(ownProps)
7377
}
7478

75-
export function deepClone<T>(val: T): T {
79+
const defaultCloneOptions: CloneOptions = { forceWritable: false }
80+
81+
export function deepClone<T>(
82+
val: T,
83+
options: CloneOptions = defaultCloneOptions,
84+
): T {
7685
const seen = new WeakMap()
77-
return clone(val, seen)
86+
return clone(val, seen, options)
7887
}
7988

80-
export function clone<T>(val: T, seen: WeakMap<any, any>): T {
89+
export function clone<T>(
90+
val: T,
91+
seen: WeakMap<any, any>,
92+
options: CloneOptions = defaultCloneOptions,
93+
): T {
8194
let k: any, out: any
8295
if (seen.has(val))
8396
return seen.get(val)
8497
if (Array.isArray(val)) {
85-
out = Array(k = val.length)
98+
out = Array((k = val.length))
8699
seen.set(val, out)
87-
while (k--)
88-
out[k] = clone(val[k], seen)
100+
while (k--) out[k] = clone(val[k], seen)
89101
return out as any
90102
}
91103

@@ -110,6 +122,7 @@ export function clone<T>(val: T, seen: WeakMap<any, any>): T {
110122
else {
111123
Object.defineProperty(out, k, {
112124
...descriptor,
125+
writable: options.forceWritable ? true : descriptor.writable,
113126
value: cloned,
114127
})
115128
}

‎test/core/test/error.test.ts

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { processError } from '@vitest/runner/utils'
2+
import { expect, test } from 'vitest'
3+
4+
test('Can correctly process error where actual and expected contains non writable properties', () => {
5+
const actual = {}
6+
const expected = {}
7+
Object.defineProperty(actual, 'root', {
8+
value: { foo: 'bar' },
9+
writable: false,
10+
enumerable: true,
11+
})
12+
Object.defineProperty(expected, 'root', {
13+
value: { foo: 'NOT BAR' },
14+
writable: false,
15+
enumerable: true,
16+
})
17+
18+
const err = {
19+
actual,
20+
expected,
21+
}
22+
23+
expect(() => processError(err)).not.toThrow(TypeError)
24+
})

‎test/core/test/utils.spec.ts

+13
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,20 @@ describe('deepClone', () => {
142142
value: 1,
143143
writable: false,
144144
})
145+
Object.defineProperty(objB, 'writableValue', {
146+
configurable: false,
147+
enumerable: false,
148+
value: 1,
149+
writable: true,
150+
})
145151
expect(deepClone(objB).value).toEqual(objB.value)
152+
expect(Object.getOwnPropertyDescriptor(deepClone(objB), 'value')?.writable).toEqual(false)
153+
expect(
154+
Object.getOwnPropertyDescriptor(deepClone(objB), 'writableValue')?.writable,
155+
).toEqual(true)
156+
expect(
157+
Object.getOwnPropertyDescriptor(deepClone(objB, { forceWritable: true }), 'value')?.writable,
158+
).toEqual(true)
146159
const objC = Object.create(objB)
147160
expect(deepClone(objC).value).toEqual(objC.value)
148161
const objD: any = { name: 'd', ref: null }

0 commit comments

Comments
 (0)
Please sign in to comment.