11import { act , renderHook } from '@testing-library/react-hooks' ;
22
3- import { useMotion , MotionOptions , MotionShorthand , getDefaultMotionState } from './useMotion' ;
3+ import { useMotion , MotionShorthand , MotionOptions , getDefaultMotionState } from './useMotion' ;
44
5- const defaultDuration = 100 ;
5+ const cssDuration = 100 ;
66const renderHookWithRef = (
77 initialMotion : MotionShorthand ,
88 initialOptions ?: MotionOptions ,
9- style : Record < string , string | undefined > = { 'transition-duration' : `${ defaultDuration } ms` } ,
9+ style : Record < string , string | undefined > = { 'transition-duration' : `${ cssDuration } ms` } ,
1010) => {
1111 const refEl = document . createElement ( 'div' ) ;
1212 const hook = renderHook ( ( { motion, options } ) => useMotion ( motion , options ) , {
@@ -45,7 +45,7 @@ const jumpAnimationFrame = () => {
4545 act ( ( ) => jest . advanceTimersToNextTimer ( ) ) ;
4646} ;
4747
48- const jumpAnimationTimeout = ( timeout : number = defaultDuration ) => {
48+ const jumpAnimationTimeout = ( timeout : number = cssDuration ) => {
4949 // timeout + requestAnimationFrame
5050 act ( ( ) => {
5151 jest . advanceTimersByTime ( timeout ) ;
@@ -54,16 +54,23 @@ const jumpAnimationTimeout = (timeout: number = defaultDuration) => {
5454} ;
5555
5656describe ( 'useMotion' , ( ) => {
57+ let computedStyleMock : jest . SpyInstance ;
58+
5759 beforeEach ( ( ) => {
5860 jest . useFakeTimers ( ) ;
61+ computedStyleMock = jest . spyOn ( window , 'getComputedStyle' ) . mockImplementation ( ( ) => {
62+ return {
63+ getPropertyValue : ( ) => `${ cssDuration } ms` ,
64+ } as unknown as CSSStyleDeclaration ;
65+ } ) ;
5966 } ) ;
6067
6168 afterEach ( ( ) => {
6269 jest . useRealTimers ( ) ;
6370 jest . resetAllMocks ( ) ;
6471 } ) ;
6572
66- describe ( 'when motion is received ' , ( ) => {
73+ describe ( 'when presence is boolean ' , ( ) => {
6774 it ( 'should sync presence value with canRender' , ( ) => {
6875 const { result, rerender } = renderHookWithRef ( false ) ;
6976
@@ -73,25 +80,6 @@ describe('useMotion', () => {
7380 expect ( result . current . canRender ) . toBe ( true ) ;
7481 } ) ;
7582
76- it ( 'should return default values when presence is false' , ( ) => {
77- const defaultState = getDefaultMotionState ( ) ;
78- const { result } = renderHookWithRef ( getDefaultMotionState ( ) ) ;
79-
80- expect ( result . current . type ) . toStrictEqual ( 'unmounted' ) ;
81- expect ( result . current . ref ) . toStrictEqual ( defaultState . ref ) ;
82- expect ( result . current . active ) . toStrictEqual ( false ) ;
83- } ) ;
84-
85- it ( 'should return default values when presence is true' , ( ) => {
86- const defaultState = getDefaultMotionState ( ) ;
87- const { result } = renderHookWithRef ( { ...getDefaultMotionState ( ) , active : true } ) ;
88-
89- expect ( result . current . ref ) . toStrictEqual ( defaultState . ref ) ;
90- expect ( result . current . active ) . toStrictEqual ( true ) ;
91- } ) ;
92- } ) ;
93-
94- describe ( 'when presence is false by default' , ( ) => {
9583 it ( 'should return default values when presence is false' , ( ) => {
9684 const { result } = renderHookWithRef ( false ) ;
9785
@@ -100,10 +88,8 @@ describe('useMotion', () => {
10088 expect ( result . current . active ) . toBe ( false ) ;
10189 expect ( result . current . canRender ) . toBe ( false ) ;
10290 } ) ;
103- } ) ;
10491
105- describe ( 'when presence is true by default' , ( ) => {
106- it ( 'should return default values' , ( ) => {
92+ it ( 'should return default values when presence is true' , ( ) => {
10793 const { result } = renderHookWithRef ( true ) ;
10894
10995 expect ( typeof result . current . ref ) . toBe ( 'function' ) ;
@@ -125,6 +111,54 @@ describe('useMotion', () => {
125111 } ) ;
126112 } ) ;
127113
114+ describe ( 'when duration is provided' , ( ) => {
115+ it ( 'should only call getComputedStyle when duration is not provided' , ( ) => {
116+ const { result, rerender } = renderHookWithRef ( false , { duration : 300 } ) ;
117+
118+ expect ( typeof result . current . ref ) . toBe ( 'function' ) ;
119+ expect ( result . current . type ) . toBe ( 'unmounted' ) ;
120+ expect ( result . current . active ) . toBe ( false ) ;
121+ expect ( result . current . canRender ) . toBe ( false ) ;
122+
123+ rerender ( true , { duration : 300 } ) ;
124+
125+ expect ( result . current . canRender ) . toBe ( true ) ;
126+ expect ( result . current . type ) . toBe ( 'entering' ) ;
127+ expect ( result . current . active ) . toBe ( false ) ;
128+
129+ jumpAnimationFrame ( ) ;
130+ jumpAnimationTimeout ( ) ;
131+
132+ expect ( computedStyleMock ) . not . toHaveBeenCalled ( ) ;
133+
134+ rerender ( false ) ;
135+
136+ jumpAnimationFrame ( ) ;
137+ jumpAnimationTimeout ( ) ;
138+
139+ expect ( computedStyleMock ) . toHaveBeenCalledTimes ( 1 ) ;
140+ } ) ;
141+ } ) ;
142+
143+ describe ( 'when presence is a MotionShorthand' , ( ) => {
144+ it ( 'should return default values when presence is false' , ( ) => {
145+ const defaultState = getDefaultMotionState ( ) ;
146+ const { result } = renderHookWithRef ( defaultState ) ;
147+
148+ expect ( result . current . type ) . toStrictEqual ( 'unmounted' ) ;
149+ expect ( result . current . ref ) . toStrictEqual ( defaultState . ref ) ;
150+ expect ( result . current . active ) . toStrictEqual ( false ) ;
151+ } ) ;
152+
153+ it ( 'should return default values when presence is true' , ( ) => {
154+ const defaultState = getDefaultMotionState ( ) ;
155+ const { result } = renderHookWithRef ( { ...defaultState , active : true } ) ;
156+
157+ expect ( result . current . ref ) . toStrictEqual ( defaultState . ref ) ;
158+ expect ( result . current . active ) . toStrictEqual ( true ) ;
159+ } ) ;
160+ } ) ;
161+
128162 describe ( 'when presence changes' , ( ) => {
129163 it ( 'should toggle values starting with false' , ( ) => {
130164 const { result, rerender } = renderHookWithRef ( false ) ;
@@ -252,6 +286,7 @@ describe('useMotion', () => {
252286 jumpAnimationFrame ( ) ;
253287 expect ( result . current . active ) . toBe ( true ) ;
254288
289+ jumpAnimationFrame ( ) ;
255290 jumpAnimationTimeout ( 0 ) ;
256291 expect ( result . current . type ) . toBe ( 'entered' ) ;
257292
@@ -265,6 +300,7 @@ describe('useMotion', () => {
265300 jumpAnimationFrame ( ) ;
266301 expect ( result . current . active ) . toBe ( false ) ;
267302
303+ jumpAnimationFrame ( ) ;
268304 jumpAnimationTimeout ( 0 ) ;
269305 expect ( result . current . type ) . toBe ( 'exited' ) ;
270306
0 commit comments