diff --git a/packages/vitest/src/integrations/chai/jest-expect.ts b/packages/vitest/src/integrations/chai/jest-expect.ts index df1bd4c35b4a..96a3291cff0c 100644 --- a/packages/vitest/src/integrations/chai/jest-expect.ts +++ b/packages/vitest/src/integrations/chai/jest-expect.ts @@ -2,6 +2,7 @@ import c from 'picocolors' import type { EnhancedSpy } from '../spy' import { isMockFunction } from '../spy' import { addSerializer } from '../snapshot/port/plugins' +import { toString } from '../utils' import type { Constructable, Test } from '../../types' import { assertTypes } from '../../utils' import { unifiedDiff } from '../../node/diff' @@ -550,6 +551,10 @@ export const JestChaiExpect: ChaiPlugin = (chai, utils) => { utils.flag(this, 'promise', 'resolves') utils.flag(this, 'error', new Error('resolves')) const obj = utils.flag(this, 'object') + + if (typeof obj?.then !== 'function') + throw new TypeError(`You must provide a Promise to expect() when using .resolves, not '${typeof obj}'.`) + const proxy: any = new Proxy(this, { get: (target, key, receiver) => { const result = Reflect.get(target, key, receiver) @@ -564,7 +569,7 @@ export const JestChaiExpect: ChaiPlugin = (chai, utils) => { return result.call(this, ...args) }, (err: any) => { - throw new Error(`promise rejected "${err}" instead of resolving`) + throw new Error(`promise rejected "${toString(err)}" instead of resolving`) }, ) } @@ -579,6 +584,10 @@ export const JestChaiExpect: ChaiPlugin = (chai, utils) => { utils.flag(this, 'error', new Error('rejects')) const obj = utils.flag(this, 'object') const wrapper = typeof obj === 'function' ? obj() : obj // for jest compat + + if (typeof wrapper?.then !== 'function') + throw new TypeError(`You must provide a Promise to expect() when using .rejects, not '${typeof wrapper}'.`) + const proxy: any = new Proxy(this, { get: (target, key, receiver) => { const result = Reflect.get(target, key, receiver) @@ -589,7 +598,7 @@ export const JestChaiExpect: ChaiPlugin = (chai, utils) => { return async (...args: any[]) => { return wrapper.then( (value: any) => { - throw new Error(`promise resolved "${value}" instead of rejecting`) + throw new Error(`promise resolved "${toString(value)}" instead of rejecting`) }, (err: any) => { utils.flag(this, 'object', err) diff --git a/packages/vitest/src/integrations/utils.ts b/packages/vitest/src/integrations/utils.ts index cc9da21c0dca..dbf0ee9f1f93 100644 --- a/packages/vitest/src/integrations/utils.ts +++ b/packages/vitest/src/integrations/utils.ts @@ -5,3 +5,12 @@ export function getRunningMode() { export function isWatchMode() { return getRunningMode() === 'watch' } + +export function toString(value: any) { + try { + return `${value}` + } + catch (_error) { + return 'unknown' + } +} diff --git a/test/core/test/jest-expect.test.ts b/test/core/test/jest-expect.test.ts index bcd0cca4a0ef..9d22d1d964a6 100644 --- a/test/core/test/jest-expect.test.ts +++ b/test/core/test/jest-expect.test.ts @@ -437,6 +437,19 @@ describe('async expect', () => { await expect((async () => 'true')()).resolves.not.toBe('true22') }) + it('throws an error on .resolves when the argument is not a promise', () => { + expect.assertions(2) + + const expectedError = new TypeError('You must provide a Promise to expect() when using .resolves, not \'number\'.') + + try { + expect(1).resolves.toEqual(2) + } + catch (error) { + expect(error).toEqual(expectedError) + } + }) + it.fails('failed to resolve', async () => { await expect((async () => { throw new Error('err') @@ -471,6 +484,26 @@ describe('async expect', () => { it.fails('failed to reject', async () => { await expect((async () => 'test')()).rejects.toBe('test') }) + + it('throws an error on .rejects when the argument (or function result) is not a promise', () => { + expect.assertions(4) + + const expectedError = new TypeError('You must provide a Promise to expect() when using .rejects, not \'number\'.') + + try { + expect(1).rejects.toEqual(2) + } + catch (error) { + expect(error).toEqual(expectedError) + } + + try { + expect(() => 1).rejects.toEqual(2) + } + catch (error) { + expect(error).toEqual(expectedError) + } + }) }) it('timeout', () => new Promise(resolve => setTimeout(resolve, 500)))