[READ-ONLY] Mirror of https://github.com/vitest-dev/vitest. Next generation testing framework powered by Vite. vitest.dev
test testing-tools vite
12

Configure Feed

Select the types of activity you want to include in your feed.

fix: print value shape when .resolves and .rejects fails (#4137)

authored by

Vladimir and committed by
GitHub
(Sep 18, 2023, 1:25 PM +0200) e649d78f a084ceaf

+66 -28
+1 -1
examples/mocks/test/factory.test.ts
··· 75 75 expect((example as any).then).toBe('a then export') 76 76 expect((example as any).mocked).toBe(true) 77 77 expect(example.square(2, 3)).toBe(5) 78 - expect(example.asyncSquare(2, 3)).resolves.toBe(5) 78 + await expect(example.asyncSquare(2, 3)).resolves.toBe(5) 79 79 }) 80 80 81 81 test('successfully with actual', () => {
+25 -24
packages/expect/src/jest-expect.ts
··· 1 - import { AssertionError } from 'chai' 2 1 import { assertTypes, getColors } from '@vitest/utils' 3 2 import type { Constructable } from '@vitest/utils' 4 3 import type { EnhancedSpy } from '@vitest/spy' ··· 13 12 14 13 // Jest Expect Compact 15 14 export const JestChaiExpect: ChaiPlugin = (chai, utils) => { 15 + const { AssertionError } = chai 16 16 const c = () => getColors() 17 17 18 18 function def(name: keyof Assertion | (keyof Assertion)[], fn: ((this: Chai.AssertionStatic & Assertion, ...args: any[]) => any)) { ··· 436 436 if (called && isNot) 437 437 msg = formatCalls(spy, msg) 438 438 439 - if ((called && isNot) || (!called && !isNot)) { 440 - const err = new Error(msg) 441 - err.name = 'AssertionError' 442 - throw err 443 - } 439 + if ((called && isNot) || (!called && !isNot)) 440 + throw new AssertionError(msg) 444 441 }) 445 442 def(['toHaveBeenCalledWith', 'toBeCalledWith'], function (...args) { 446 443 const spy = getSpy(this) ··· 448 445 const pass = spy.mock.calls.some(callArg => jestEquals(callArg, args, [iterableEquality])) 449 446 const isNot = utils.flag(this, 'negate') as boolean 450 447 451 - let msg = utils.getMessage( 448 + const msg = utils.getMessage( 452 449 this, 453 450 [ 454 451 pass, ··· 458 455 ], 459 456 ) 460 457 461 - if ((pass && isNot) || (!pass && !isNot)) { 462 - msg = formatCalls(spy, msg, args) 463 - const err = new Error(msg) 464 - err.name = 'AssertionError' 465 - throw err 466 - } 458 + if ((pass && isNot) || (!pass && !isNot)) 459 + throw new AssertionError(formatCalls(spy, msg, args)) 467 460 }) 468 461 def(['toHaveBeenNthCalledWith', 'nthCalledWith'], function (times: number, ...args: any[]) { 469 462 const spy = getSpy(this) ··· 595 588 const pass = spy.mock.results.some(({ type, value: result }) => type === 'return' && jestEquals(value, result)) 596 589 const isNot = utils.flag(this, 'negate') as boolean 597 590 598 - let msg = utils.getMessage( 591 + const msg = utils.getMessage( 599 592 this, 600 593 [ 601 594 pass, ··· 605 598 ], 606 599 ) 607 600 608 - if ((pass && isNot) || (!pass && !isNot)) { 609 - msg = formatReturns(spy, msg, value) 610 - const err = new Error(msg) 611 - err.name = 'AssertionError' 612 - throw err 613 - } 601 + if ((pass && isNot) || (!pass && !isNot)) 602 + throw new AssertionError(formatReturns(spy, msg, value)) 614 603 }) 615 604 def(['toHaveLastReturnedWith', 'lastReturnedWith'], function (value: any) { 616 605 const spy = getSpy(this) ··· 650 639 }) 651 640 652 641 utils.addProperty(chai.Assertion.prototype, 'resolves', function __VITEST_RESOLVES__(this: any) { 642 + const error = new Error('resolves') 653 643 utils.flag(this, 'promise', 'resolves') 654 - utils.flag(this, 'error', new Error('resolves')) 644 + utils.flag(this, 'error', error) 655 645 const test: Test = utils.flag(this, 'vitest-test') 656 646 const obj = utils.flag(this, 'object') 657 647 ··· 672 662 return result.call(this, ...args) 673 663 }, 674 664 (err: any) => { 675 - throw new Error(`promise rejected "${String(err)}" instead of resolving`) 665 + const _error = new AssertionError( 666 + `promise rejected "${utils.inspect(err)}" instead of resolving`, 667 + { showDiff: false }, 668 + ) 669 + _error.stack = (error.stack as string).replace(error.message, _error.message) 670 + throw _error 676 671 }, 677 672 ) 678 673 ··· 685 680 }) 686 681 687 682 utils.addProperty(chai.Assertion.prototype, 'rejects', function __VITEST_REJECTS__(this: any) { 683 + const error = new Error('rejects') 688 684 utils.flag(this, 'promise', 'rejects') 689 - utils.flag(this, 'error', new Error('rejects')) 685 + utils.flag(this, 'error', error) 690 686 const test: Test = utils.flag(this, 'vitest-test') 691 687 const obj = utils.flag(this, 'object') 692 688 const wrapper = typeof obj === 'function' ? obj() : obj // for jest compat ··· 704 700 return async (...args: any[]) => { 705 701 const promise = wrapper.then( 706 702 (value: any) => { 707 - throw new Error(`promise resolved "${String(value)}" instead of rejecting`) 703 + const _error = new AssertionError( 704 + `promise resolved "${utils.inspect(value)}" instead of rejecting`, 705 + { showDiff: false }, 706 + ) 707 + _error.stack = (error.stack as string).replace(error.message, _error.message) 708 + throw _error 708 709 }, 709 710 (err: any) => { 710 711 utils.flag(this, 'object', err)
+40 -3
test/core/test/jest-expect.test.ts
··· 1 1 /* eslint-disable no-sparse-arrays */ 2 2 import { AssertionError } from 'node:assert' 3 + import { fileURLToPath } from 'node:url' 4 + import { resolve } from 'node:path' 3 5 import { describe, expect, it, vi } from 'vitest' 4 6 import { generateToBeMessage, setupColors } from '@vitest/expect' 5 7 import { processError } from '@vitest/utils/error' ··· 604 606 605 607 try { 606 608 expect(1).resolves.toEqual(2) 609 + expect.unreachable() 607 610 } 608 611 catch (error) { 609 612 expect(error).toEqual(expectedError) ··· 658 661 659 662 try { 660 663 expect(1).rejects.toEqual(2) 664 + expect.unreachable() 661 665 } 662 666 catch (error) { 663 667 expect(error).toEqual(expectedError) ··· 665 669 666 670 try { 667 671 expect(() => 1).rejects.toEqual(2) 672 + expect.unreachable() 668 673 } 669 674 catch (error) { 670 675 expect(error).toEqual(expectedError) ··· 686 691 const toStrictEqualError1 = generatedToBeMessage('toStrictEqual', '{ key: \'value\' }', '{ key: \'value\' }') 687 692 try { 688 693 expect(actual).toBe({ ...actual }) 694 + expect.unreachable() 689 695 } 690 696 catch (error: any) { 691 697 expect(error.message).toBe(toStrictEqualError1.message) ··· 694 700 const toStrictEqualError2 = generatedToBeMessage('toStrictEqual', 'FakeClass{}', 'FakeClass{}') 695 701 try { 696 702 expect(new FakeClass()).toBe(new FakeClass()) 703 + expect.unreachable() 697 704 } 698 705 catch (error: any) { 699 706 expect(error.message).toBe(toStrictEqualError2.message) ··· 702 709 const toEqualError1 = generatedToBeMessage('toEqual', '{}', 'FakeClass{}') 703 710 try { 704 711 expect({}).toBe(new FakeClass()) 712 + expect.unreachable() 705 713 } 706 714 catch (error: any) { 707 715 expect(error.message).toBe(toEqualError1.message) 708 - // expect(error).toEqual('1234') 709 716 } 710 717 711 718 const toEqualError2 = generatedToBeMessage('toEqual', 'FakeClass{}', '{}') 712 719 try { 713 720 expect(new FakeClass()).toBe({}) 721 + expect.unreachable() 714 722 } 715 723 catch (error: any) { 716 724 expect(error.message).toBe(toEqualError2.message) ··· 742 750 }) 743 751 }) 744 752 753 + it('printing error message', async () => { 754 + const root = resolve(fileURLToPath(import.meta.url), '../../../../') 755 + // have "\" on windows, and "/" on unix 756 + const filename = fileURLToPath(import.meta.url).replace(root, '<root>') 757 + try { 758 + await expect(Promise.resolve({ foo: { bar: 42 } })).rejects.toThrow() 759 + expect.unreachable() 760 + } 761 + catch (err: any) { 762 + const stack = err.stack.replace(new RegExp(root, 'g'), '<root>') 763 + expect(err.message).toMatchInlineSnapshot('"promise resolved \\"{ foo: { bar: 42 } }\\" instead of rejecting"') 764 + expect(stack).toContain(`at ${filename}`) 765 + } 766 + 767 + try { 768 + const error = new Error('some error') 769 + Object.assign(error, { foo: { bar: 42 } }) 770 + await expect(Promise.reject(error)).resolves.toBe(1) 771 + expect.unreachable() 772 + } 773 + catch (err: any) { 774 + const stack = err.stack.replace(new RegExp(root, 'g'), '<root>') 775 + expect(err.message).toMatchInlineSnapshot('"promise rejected \\"Error: some error { foo: { bar: 42 } }\\" instead of resolving"') 776 + expect(stack).toContain(`at ${filename}`) 777 + } 778 + }) 779 + 745 780 it('handle thenable objects', async () => { 746 781 await expect({ then: (resolve: any) => resolve(0) }).resolves.toBe(0) 747 782 await expect({ then: (_: any, reject: any) => reject(0) }).rejects.toBe(0) 748 783 749 784 try { 750 785 await expect({ then: (resolve: any) => resolve(0) }).rejects.toBe(0) 786 + expect.unreachable() 751 787 } 752 788 catch (error) { 753 - expect(error).toEqual(new Error('promise resolved "0" instead of rejecting')) 789 + expect(error).toEqual(new Error('promise resolved "+0" instead of rejecting')) 754 790 } 755 791 756 792 try { 757 793 await expect({ then: (_: any, reject: any) => reject(0) }).resolves.toBe(0) 794 + expect.unreachable() 758 795 } 759 796 catch (error) { 760 - expect(error).toEqual(new Error('promise rejected "0" instead of resolving')) 797 + expect(error).toEqual(new Error('promise rejected "+0" instead of resolving')) 761 798 } 762 799 }) 763 800 })