@@ -363,6 +363,33 @@ describe('jest mock compat layer', () => {
363363 expect ( obj . property ) . toBe ( true )
364364 } )
365365
366+ it ( 'respyin on a spy resets the counter' , ( ) => {
367+ const obj = {
368+ method ( ) {
369+ return 'original'
370+ } ,
371+ }
372+ vi . spyOn ( obj , 'method' )
373+ obj . method ( )
374+ expect ( obj . method ) . toHaveBeenCalledTimes ( 1 )
375+ vi . spyOn ( obj , 'method' )
376+ obj . method ( )
377+ expect ( obj . method ) . toHaveBeenCalledTimes ( 1 )
378+ } )
379+
380+ it ( 'spyOn on the getter multiple times' , ( ) => {
381+ const obj = {
382+ get getter ( ) {
383+ return 'original'
384+ } ,
385+ }
386+
387+ vi . spyOn ( obj , 'getter' , 'get' ) . mockImplementation ( ( ) => 'mocked' )
388+ vi . spyOn ( obj , 'getter' , 'get' )
389+
390+ expect ( obj . getter ) . toBe ( 'mocked' )
391+ } )
392+
366393 it ( 'spyOn multiple times' , ( ) => {
367394 const obj = {
368395 method ( ) {
@@ -383,9 +410,9 @@ describe('jest mock compat layer', () => {
383410
384411 spy2 . mockRestore ( )
385412
386- expect ( obj . method ( ) ) . toBe ( 'mocked ' )
387- expect ( vi . isMockFunction ( obj . method ) ) . toBe ( true )
388- expect ( obj . method ) . toBe ( spy1 )
413+ expect ( obj . method ( ) ) . toBe ( 'original ' )
414+ expect ( vi . isMockFunction ( obj . method ) ) . toBe ( false )
415+ expect ( obj . method ) . not . toBe ( spy1 )
389416
390417 spy1 . mockRestore ( )
391418 expect ( vi . isMockFunction ( obj . method ) ) . toBe ( false )
@@ -560,11 +587,104 @@ describe('jest mock compat layer', () => {
560587 expect ( fn . getMockImplementation ( ) ) . toBe ( temporaryMockImplementation )
561588 } )
562589
590+ it ( 'keeps the descriptor the same as the original one when restoring' , ( ) => {
591+ class Foo {
592+ f ( ) {
593+ return 'original'
594+ }
595+ }
596+
597+ // initially there's no own properties
598+ const foo = new Foo ( )
599+ expect ( foo . f ( ) ) . toMatchInlineSnapshot ( `"original"` )
600+ expect ( Object . getOwnPropertyDescriptors ( foo ) ) . toMatchInlineSnapshot ( `{}` )
601+
602+ // mocked function in own property
603+ const spy = vi . spyOn ( foo , 'f' ) . mockImplementation ( ( ) => 'mocked' )
604+ expect ( foo . f ( ) ) . toMatchInlineSnapshot ( `"mocked"` )
605+ expect ( Object . getOwnPropertyDescriptors ( foo ) ) . toMatchInlineSnapshot ( `
606+ {
607+ "f": {
608+ "configurable": true,
609+ "enumerable": false,
610+ "value": [MockFunction f] {
611+ "calls": [
612+ [],
613+ ],
614+ "results": [
615+ {
616+ "type": "return",
617+ "value": "mocked",
618+ },
619+ ],
620+ },
621+ "writable": true,
622+ },
623+ }
624+ ` )
625+
626+ // probably original prototype method is not moved to own property
627+ spy . mockRestore ( )
628+ expect ( foo . f ( ) ) . toMatchInlineSnapshot ( `"original"` )
629+ expect ( Object . getOwnPropertyDescriptors ( foo ) ) . toMatchInlineSnapshot ( `{}` )
630+ } )
631+
632+ it ( 'mocks inherited methods' , ( ) => {
633+ class Bar {
634+ _bar = 'bar'
635+ get bar ( ) : string {
636+ return this . _bar
637+ }
638+
639+ set bar ( bar : string ) {
640+ this . _bar = bar
641+ }
642+ }
643+ class Foo extends Bar { }
644+ const foo = new Foo ( )
645+ vi . spyOn ( foo , 'bar' , 'get' ) . mockImplementation ( ( ) => 'foo' )
646+ expect ( foo . bar ) . toEqual ( 'foo' )
647+ // foo.bar setter is inherited from Bar, so we can set it
648+ expect ( ( ) => {
649+ foo . bar = 'baz'
650+ } ) . not . toThrowError ( )
651+ expect ( foo . bar ) . toEqual ( 'foo' )
652+ } )
653+
654+ it ( 'mocks inherited overridden methods' , ( ) => {
655+ class Bar {
656+ _bar = 'bar'
657+ get bar ( ) : string {
658+ return this . _bar
659+ }
660+
661+ set bar ( bar : string ) {
662+ this . _bar = bar
663+ }
664+ }
665+ class Foo extends Bar {
666+ get bar ( ) : string {
667+ return `${ super . bar } -foo`
668+ }
669+ }
670+ const foo = new Foo ( )
671+ expect ( foo . bar ) . toEqual ( 'bar-foo' )
672+ vi . spyOn ( foo , 'bar' , 'get' ) . mockImplementation ( ( ) => 'foo' )
673+ expect ( foo . bar ) . toEqual ( 'foo' )
674+ // foo.bar setter is not inherited from Bar
675+ expect ( ( ) => {
676+ // @ts -expect-error bar is readonly
677+ foo . bar = 'baz'
678+ } ) . toThrowError ( )
679+ expect ( foo . bar ) . toEqual ( 'foo' )
680+ } )
681+
563682 describe ( 'is disposable' , ( ) => {
564683 describe . runIf ( Symbol . dispose ) ( 'in environments supporting it' , ( ) => {
565684 it ( 'has dispose property' , ( ) => {
566685 expect ( vi . fn ( ) [ Symbol . dispose ] ) . toBeTypeOf ( 'function' )
567686 } )
687+
568688 it ( 'calls mockRestore when disposing' , ( ) => {
569689 const fn = vi . fn ( )
570690 const restoreSpy = vi . spyOn ( fn , 'mockRestore' )
@@ -573,10 +693,12 @@ describe('jest mock compat layer', () => {
573693 }
574694 expect ( restoreSpy ) . toHaveBeenCalled ( )
575695 } )
696+
576697 it ( 'allows disposal when using mockImplementation' , ( ) => {
577698 expect ( vi . fn ( ) . mockImplementation ( ( ) => { } ) [ Symbol . dispose ] ) . toBeTypeOf ( 'function' )
578699 } )
579700 } )
701+
580702 describe . skipIf ( Symbol . dispose ) ( 'in environments not supporting it' , ( ) => {
581703 it ( 'does not have dispose property' , ( ) => {
582704 expect ( vi . fn ( ) [ Symbol . dispose ] ) . toBeUndefined ( )
0 commit comments