Skip to content

Commit

Permalink
feat: improve deep equality check failing message for toBe (#1383)
Browse files Browse the repository at this point in the history
  • Loading branch information
TommyDew42 committed Jun 6, 2022
1 parent 8452a7d commit 842e048
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 3 deletions.
38 changes: 35 additions & 3 deletions packages/vitest/src/integrations/chai/jest-expect.ts
Expand Up @@ -7,7 +7,7 @@ import type { Constructable, Test } from '../../types'
import { assertTypes } from '../../utils'
import { unifiedDiff } from '../../node/diff'
import type { ChaiPlugin, MatcherState } from '../../types/chai'
import { arrayBufferEquality, iterableEquality, equals as jestEquals, sparseArrayEquality, subsetEquality, typeEquality } from './jest-utils'
import { arrayBufferEquality, generateToBeMessage, iterableEquality, equals as jestEquals, sparseArrayEquality, subsetEquality, typeEquality } from './jest-utils'
import type { AsymmetricMatcher } from './jest-asymmetric-matchers'
import { stringify } from './jest-matcher-utils'

Expand Down Expand Up @@ -129,9 +129,41 @@ export const JestChaiExpect: ChaiPlugin = (chai, utils) => {
})
def('toBe', function (expected) {
const actual = this._obj
const pass = Object.is(actual, expected)

let deepEqualityName = ''

if (!pass) {
const toStrictEqualPass = jestEquals(
actual,
expected,
[
iterableEquality,
typeEquality,
sparseArrayEquality,
arrayBufferEquality,
],
true,
)

if (toStrictEqualPass) {
deepEqualityName = 'toStrictEqual'
}
else {
const toEqualPass = jestEquals(
actual,
expected,
[iterableEquality],
)

if (toEqualPass)
deepEqualityName = 'toEqual'
}
}

return this.assert(
Object.is(actual, expected),
'expected #{this} to be #{exp} // Object.is equality',
pass,
generateToBeMessage(deepEqualityName),
'expected #{this} not to be #{exp} // Object.is equality',
expected,
actual,
Expand Down
13 changes: 13 additions & 0 deletions packages/vitest/src/integrations/chai/jest-utils.ts
Expand Up @@ -508,3 +508,16 @@ export const sparseArrayEquality = (
equals(a, b, [iterableEquality, typeEquality], true) && equals(aKeys, bKeys)
)
}

export const generateToBeMessage = (
deepEqualityName: string,
expected = '#{this}',
actual = '#{exp}',
) => {
const toBeMessage = `expected ${expected} to be ${actual} // Object.is equality`

if (['toStrictEqual', 'toEqual'].includes(deepEqualityName))
return `${toBeMessage}\n\nIf it should pass with deep equality, replace "toBe" with "${deepEqualityName}"\n\nExpected: ${expected}\nReceived: serializes to the same string\n`

return toBeMessage
}
48 changes: 48 additions & 0 deletions test/core/test/jest-expect.test.ts
@@ -1,5 +1,7 @@
/* eslint-disable no-sparse-arrays */
import { AssertionError } from 'assert'
import { describe, expect, it, vi } from 'vitest'
import { generateToBeMessage } from 'vitest/src/integrations/chai/jest-utils'

class TestError extends Error {}

Expand Down Expand Up @@ -548,6 +550,52 @@ describe('async expect', () => {
expect(error).toEqual(expectedError)
}
})

it('reminds users to use deep equality checks if they are comparing objects', () => {
const generatedToBeMessage = (
deepEqualityName: string,
expected: string,
actual: string,
) => new AssertionError({
message: generateToBeMessage(deepEqualityName, expected, actual),
})

const actual = { key: 'value' }
class FakeClass {}

const toStrictEqualError1 = generatedToBeMessage('toStrictEqual', '{ key: \'value\' }', '{ key: \'value\' }')
try {
expect(actual).toBe({ ...actual })
}
catch (error) {
expect(error).toEqual(toStrictEqualError1)
}

const toStrictEqualError2 = generatedToBeMessage('toStrictEqual', 'FakeClass{}', 'FakeClass{}')
try {
expect(new FakeClass()).toBe(new FakeClass())
}
catch (error) {
expect(error).toEqual(toStrictEqualError2)
}

const toEqualError1 = generatedToBeMessage('toEqual', '{}', 'FakeClass{}')
try {
expect({}).toBe(new FakeClass())
}
catch (error) {
expect(error).toEqual(toEqualError1)
// expect(error).toEqual('1234')
}

const toEqualError2 = generatedToBeMessage('toEqual', 'FakeClass{}', '{}')
try {
expect(new FakeClass()).toBe({})
}
catch (error) {
expect(error).toEqual(toEqualError2)
}
})
})

it('timeout', () => new Promise(resolve => setTimeout(resolve, 500)))

0 comments on commit 842e048

Please sign in to comment.