Skip to content

Commit

Permalink
fix: assertion diff message now handle non writable property correctly (
Browse files Browse the repository at this point in the history
  • Loading branch information
PCreations committed May 30, 2023
1 parent 306b233 commit f75ab65
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 8 deletions.
4 changes: 2 additions & 2 deletions packages/runner/src/utils/error.ts
Expand Up @@ -97,8 +97,8 @@ export function processError(err: any, options: DiffOptions = {}) {
if (err.name)
err.nameStr = String(err.name)

const clonedActual = deepClone(err.actual)
const clonedExpected = deepClone(err.expected)
const clonedActual = deepClone(err.actual, { forceWritable: true })
const clonedExpected = deepClone(err.expected, { forceWritable: true })

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

Expand Down
25 changes: 19 additions & 6 deletions packages/utils/src/helpers.ts
@@ -1,5 +1,9 @@
import type { Arrayable, Nullable } from './types'

interface CloneOptions {
forceWritable?: boolean
}

export function notNullish<T>(v: T | null | undefined): v is NonNullable<T> {
return v != null
}
Expand Down Expand Up @@ -72,20 +76,28 @@ export function getOwnProperties(obj: any) {
return Array.from(ownProps)
}

export function deepClone<T>(val: T): T {
const defaultCloneOptions: CloneOptions = { forceWritable: false }

export function deepClone<T>(
val: T,
options: CloneOptions = defaultCloneOptions,
): T {
const seen = new WeakMap()
return clone(val, seen)
return clone(val, seen, options)
}

export function clone<T>(val: T, seen: WeakMap<any, any>): T {
export function clone<T>(
val: T,
seen: WeakMap<any, any>,
options: CloneOptions = defaultCloneOptions,
): T {
let k: any, out: any
if (seen.has(val))
return seen.get(val)
if (Array.isArray(val)) {
out = Array(k = val.length)
out = Array((k = val.length))
seen.set(val, out)
while (k--)
out[k] = clone(val[k], seen)
while (k--) out[k] = clone(val[k], seen)
return out as any
}

Expand All @@ -110,6 +122,7 @@ export function clone<T>(val: T, seen: WeakMap<any, any>): T {
else {
Object.defineProperty(out, k, {
...descriptor,
writable: options.forceWritable ? true : descriptor.writable,
value: cloned,
})
}
Expand Down
24 changes: 24 additions & 0 deletions test/core/test/error.test.ts
@@ -0,0 +1,24 @@
import { processError } from '@vitest/runner/utils'
import { expect, test } from 'vitest'

test('Can correctly process error where actual and expected contains non writable properties', () => {
const actual = {}
const expected = {}
Object.defineProperty(actual, 'root', {
value: { foo: 'bar' },
writable: false,
enumerable: true,
})
Object.defineProperty(expected, 'root', {
value: { foo: 'NOT BAR' },
writable: false,
enumerable: true,
})

const err = {
actual,
expected,
}

expect(() => processError(err)).not.toThrow(TypeError)
})
13 changes: 13 additions & 0 deletions test/core/test/utils.spec.ts
Expand Up @@ -142,7 +142,20 @@ describe('deepClone', () => {
value: 1,
writable: false,
})
Object.defineProperty(objB, 'writableValue', {
configurable: false,
enumerable: false,
value: 1,
writable: true,
})
expect(deepClone(objB).value).toEqual(objB.value)
expect(Object.getOwnPropertyDescriptor(deepClone(objB), 'value')?.writable).toEqual(false)
expect(
Object.getOwnPropertyDescriptor(deepClone(objB), 'writableValue')?.writable,
).toEqual(true)
expect(
Object.getOwnPropertyDescriptor(deepClone(objB, { forceWritable: true }), 'value')?.writable,
).toEqual(true)
const objC = Object.create(objB)
expect(deepClone(objC).value).toEqual(objC.value)
const objD: any = { name: 'd', ref: null }
Expand Down

0 comments on commit f75ab65

Please sign in to comment.