Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
RocketChat
Rocket.Chat.Fuselage
Commits
c43294fe
Unverified
Commit
c43294fe
authored
Mar 07, 2020
by
Tasso Evangelista
Committed by
GitHub
Mar 07, 2020
Browse files
feat: useMutableCallback (#156)
* Add useMutableCallback hook * Apply lint on tests * Replace testHook with runHooks
parent
d1343560
Changes
14
Hide whitespace changes
Inline
Side-by-side
packages/fuselage-hooks/.jest/helpers.js
View file @
c43294fe
import
React
from
'
react
'
;
import
ReactDOM
from
'
react-dom
'
;
import
React
,
{
useReducer
,
Component
,
createElement
}
from
'
react
'
;
import
ReactDOM
,
{
render
,
unmountComponentAtNode
}
from
'
react-dom
'
;
import
{
act
}
from
'
react-dom/test-utils
'
;
export
const
test
Hook
=
(
callback
,
...
acts
)
=>
{
export
const
run
Hook
s
=
(
fn
,
mutations
=
[]
)
=>
{
let
returnedValue
;
let
forceUpdate
;
function
FunctionalComponent
()
{
[,
forceUpdate
]
=
useReducer
((
state
)
=>
!
state
,
false
);
returnedValue
=
fn
();
return
null
;
}
let
errorThrown
;
class
ErrorBoundary
extends
React
.
Component
{
class
ComponentWith
ErrorBoundary
extends
Component
{
state
=
{
errored
:
false
}
static
getDerivedStateFromError
=
()
=>
({
errored
:
true
})
...
...
@@ -15,29 +23,35 @@ export const testHook = (callback, ...acts) => {
errorThrown
=
error
;
}
render
=
()
=>
(
this
.
state
.
errored
?
null
:
<>
{
this
.
props
.
children
}
<
/>
)
}
function
TestComponent
()
{
returnedValue
=
callback
();
return
null
;
render
=
()
=>
(
this
.
state
.
errored
?
null
:
createElement
(
FunctionalComponent
))
}
const
spy
=
jest
.
spyOn
(
console
,
'
error
'
);
spy
.
mockImplementation
(()
=>
{});
const
div
=
document
.
createElement
(
'
div
'
);
ReactDOM
.
render
(
<
ErrorBoundary
>
<
TestComponent
/>
<
/ErrorBoundary>, div
)
;
render
(
createElement
(
ComponentWithErrorBoundary
),
div
);
const
values
=
[
returnedValue
];
for
(
const
mutation
of
mutations
)
{
act
(()
=>
{
forceUpdate
();
acts
.
forEach
((
fn
)
=>
act
(
fn
.
bind
(
null
,
returnedValue
)));
if
(
mutation
===
true
)
{
return
;
}
mutation
(
returnedValue
);
});
values
.
push
(
returnedValue
);
}
ReactDOM
.
unmountComponentAtNode
(
div
);
unmountComponentAtNode
(
div
);
if
(
errorThrown
)
{
throw
errorThrown
;
}
return
returnedV
alue
;
return
v
alue
s
;
};
packages/fuselage-hooks/README.md
View file @
c43294fe
...
...
@@ -43,8 +43,10 @@ yarn test
-
[
Parameters
](
#parameters-6
)
-
[
useMergedRefs
](
#usemergedrefs
)
-
[
Parameters
](
#parameters-7
)
-
[
use
Toggle
](
#usetoggle
)
-
[
use
MutableCallback
](
#usemutablecallback
)
-
[
Parameters
](
#parameters-8
)
-
[
useToggle
](
#usetoggle
)
-
[
Parameters
](
#parameters-9
)
### useClassName
...
...
@@ -141,6 +143,16 @@ while receiving a forwared ref.
Returns
**any**
a merged callback ref
### useMutableCallback
Hook to create a stable callback from a mutable one.
#### Parameters
-
`fn`
**function (): any**
the mutable callback
Returns
**any**
a stable callback
### useToggle
Hook to create a toggleable boolean state.
...
...
packages/fuselage-hooks/package.json
View file @
c43294fe
...
...
@@ -29,7 +29,7 @@
"start"
:
"rollup -c -w"
,
"build"
:
"rollup -c"
,
"test"
:
"jest"
,
"lint"
:
"eslint src"
,
"lint"
:
"eslint src
tests
"
,
"lint-staged"
:
"lint-staged"
,
"docs"
:
"documentation readme src/index.js --section='API Reference' --readme-file README.md"
},
...
...
packages/fuselage-hooks/src/index.js
View file @
c43294fe
...
...
@@ -6,5 +6,6 @@ export * from './useDebouncedCallback';
export
*
from
'
./useExclusiveBooleanProps
'
;
export
*
from
'
./useMediaQuery
'
;
export
*
from
'
./useMergedRefs
'
;
export
*
from
'
./useMutableCallback
'
;
export
*
from
'
./useToggle
'
;
export
*
from
'
./useUniqueId
'
;
packages/fuselage-hooks/src/useMutableCallback.js
0 → 100644
View file @
c43294fe
// @flow
import
{
useCallback
,
useRef
}
from
'
react
'
;
/**
* Hook to create a stable callback from a mutable one.
*
* @param fn the mutable callback
* @return a stable callback
*/
export
const
useMutableCallback
=
(
fn
:
(...
args
:
any
[])
=>
any
)
=>
{
const
fnRef
=
useRef
(
fn
);
fnRef
.
current
=
fn
;
return
useCallback
((...
args
:
any
[])
=>
fnRef
.
current
&&
(
0
,
fnRef
.
current
)(...
args
),
[]);
};
packages/fuselage-hooks/tests/useClassName.spec.js
View file @
c43294fe
import
{
test
Hook
}
from
'
../.jest/helpers
'
;
import
{
run
Hook
s
}
from
'
../.jest/helpers
'
;
import
{
useClassName
}
from
'
../src
'
;
describe
(
'
useClassName hook
'
,
()
=>
{
const
componentClassName
=
'
component
'
;
it
(
'
accepts only the component className
'
,
()
=>
{
const
newClassName
=
test
Hook
(()
=>
useClassName
(
componentClassName
));
const
[
newClassName
]
=
run
Hook
s
(()
=>
useClassName
(
componentClassName
));
expect
(
newClassName
).
toEqual
(
componentClassName
);
});
it
(
'
composes with a true-valued boolean modifier
'
,
()
=>
{
const
newClassName
=
test
Hook
(()
=>
useClassName
(
componentClassName
,
{
a
:
true
}));
const
[
newClassName
]
=
run
Hook
s
(()
=>
useClassName
(
componentClassName
,
{
a
:
true
}));
expect
(
newClassName
).
toEqual
(
`
${
componentClassName
}
${
componentClassName
}
--a`
);
});
it
(
'
does not compose with a false-valued boolean modifier
'
,
()
=>
{
const
newClassName
=
test
Hook
(()
=>
useClassName
(
componentClassName
,
{
a
:
false
}));
const
[
newClassName
]
=
run
Hook
s
(()
=>
useClassName
(
componentClassName
,
{
a
:
false
}));
expect
(
newClassName
).
toEqual
(
componentClassName
);
});
it
(
'
composes with a non-boolean modifier
'
,
()
=>
{
const
newClassName
=
test
Hook
(()
=>
useClassName
(
componentClassName
,
{
a
:
'
b
'
}));
const
[
newClassName
]
=
run
Hook
s
(()
=>
useClassName
(
componentClassName
,
{
a
:
'
b
'
}));
expect
(
newClassName
).
toEqual
(
`
${
componentClassName
}
${
componentClassName
}
--a-b`
);
});
it
(
'
appends an arbitrary amount of additional classNames
'
,
()
=>
{
const
classNames
=
new
Array
(
5
).
fill
(
undefined
).
map
((
i
)
=>
`class-
${
i
}
`
);
const
newClassName
=
test
Hook
(()
=>
useClassName
(
componentClassName
,
{},
...
classNames
));
const
[
newClassName
]
=
run
Hook
s
(()
=>
useClassName
(
componentClassName
,
{},
...
classNames
));
expect
(
newClassName
).
toEqual
(
`
${
componentClassName
}
${
classNames
.
join
(
'
'
)
}
`
);
});
it
(
'
formats a modifier name from camelCase to kebab-case
'
,
()
=>
{
const
newClassName
=
test
Hook
(()
=>
useClassName
(
componentClassName
,
{
camelCaseModifier
:
true
}));
const
[
newClassName
]
=
run
Hook
s
(()
=>
useClassName
(
componentClassName
,
{
camelCaseModifier
:
true
}));
expect
(
newClassName
).
toEqual
(
`
${
componentClassName
}
${
componentClassName
}
--camel-case-modifier`
);
});
it
(
'
formats a modifier value from camelCase to kebab-case
'
,
()
=>
{
const
newClassName
=
test
Hook
(()
=>
useClassName
(
componentClassName
,
{
a
:
'
camelCaseValue
'
}));
const
[
newClassName
]
=
run
Hook
s
(()
=>
useClassName
(
componentClassName
,
{
a
:
'
camelCaseValue
'
}));
expect
(
newClassName
).
toEqual
(
`
${
componentClassName
}
${
componentClassName
}
--a-camel-case-value`
);
});
});
packages/fuselage-hooks/tests/useDebouncedCallback.spec.js
View file @
c43294fe
import
{
useState
}
from
'
react
'
;
import
{
testHook
}
from
'
../.jest/helpers
'
;
import
{
runHooks
}
from
'
../.jest/helpers
'
;
import
{
useDebouncedCallback
}
from
'
../src
'
;
describe
(
'
useDebouncedCallback hook
'
,
()
=>
{
...
...
@@ -13,7 +11,7 @@ describe('useDebouncedCallback hook', () => {
});
it
(
'
returns a debounced callback
'
,
()
=>
{
const
debouncedCallback
=
test
Hook
(()
=>
useDebouncedCallback
(
fn
,
delay
));
const
[
debouncedCallback
]
=
run
Hook
s
(()
=>
useDebouncedCallback
(
fn
,
delay
));
expect
(
debouncedCallback
).
toBeInstanceOf
(
Function
);
expect
(
debouncedCallback
.
flush
).
toBeInstanceOf
(
Function
);
expect
(
debouncedCallback
.
cancel
).
toBeInstanceOf
(
Function
);
...
...
@@ -24,69 +22,30 @@ describe('useDebouncedCallback hook', () => {
});
it
(
'
returns the same callback if deps don
\'
t change
'
,
()
=>
{
let
callbackA
;
let
callbackB
;
let
setDummy
;
testHook
(
()
=>
{
[,
setDummy
]
=
useState
(
0
);
return
useDebouncedCallback
(
fn
,
delay
,
[]);
},
(
returnedValue
)
=>
{
callbackA
=
returnedValue
;
setDummy
((
dep
)
=>
dep
+
1
);
},
(
returnedValue
)
=>
{
callbackB
=
returnedValue
;
}
);
const
[
callbackA
,
callbackB
]
=
runHooks
(()
=>
useDebouncedCallback
(
fn
,
delay
,
[]),
[
true
]);
expect
(
callbackA
).
toBe
(
callbackB
);
});
it
(
'
returns another callback if deps change
'
,
()
=>
{
let
callbackA
;
let
callbackB
;
let
dep
;
let
setDep
;
let
dep
=
Symbol
();
testHook
(
const
[
callbackA
,
,
callbackB
]
=
runHooks
(()
=>
useDebouncedCallback
(
fn
,
delay
,
[
dep
]),
[
()
=>
{
[
dep
,
setDep
]
=
useState
(
0
);
return
useDebouncedCallback
(
fn
,
delay
,
[
dep
]);
dep
=
Symbol
();
},
(
returnedValue
)
=>
{
callbackA
=
returnedValue
;
setDep
((
dep
)
=>
dep
+
1
);
},
(
returnedValue
)
=>
{
callbackB
=
returnedValue
;
}
);
]);
expect
(
callbackA
).
not
.
toBe
(
callbackB
);
});
it
(
'
returns another callback if delay change
'
,
()
=>
{
let
callbackA
;
let
callbackB
;
let
delay
;
let
setDelay
;
let
delay
=
0
;
testHook
(
const
[
callbackA
,
callbackB
]
=
runHooks
(()
=>
useDebouncedCallback
(
fn
,
delay
,
[]),
[
()
=>
{
[
delay
,
setDelay
]
=
useState
(
0
);
return
useDebouncedCallback
(
fn
,
delay
,
[]);
},
(
returnedValue
)
=>
{
callbackA
=
returnedValue
;
setDelay
((
delay
)
=>
delay
+
1
);
delay
=
1
;
},
(
returnedValue
)
=>
{
callbackB
=
returnedValue
;
}
);
]);
expect
(
callbackA
).
not
.
toBe
(
callbackB
);
});
...
...
packages/fuselage-hooks/tests/useDebouncedUpdates.spec.js
View file @
c43294fe
import
{
useState
}
from
'
react
'
;
import
{
test
Hook
}
from
'
../.jest/helpers
'
;
import
{
run
Hook
s
}
from
'
../.jest/helpers
'
;
import
{
useDebouncedUpdates
,
useDebouncedReducer
,
useDebouncedState
}
from
'
../src
'
;
describe
(
'
useDebouncedUpdates hook
'
,
()
=>
{
...
...
@@ -11,23 +11,10 @@ describe('useDebouncedUpdates hook', () => {
});
it
(
'
returns a debounced state updater
'
,
()
=>
{
let
valueA
;
let
valueB
;
let
valueC
;
const
[,
debouncedSetValue
]
=
testHook
(
()
=>
useDebouncedUpdates
(
useState
(
0
),
delay
),
([
value
,
debouncedSetValue
])
=>
{
valueA
=
value
;
debouncedSetValue
((
value
)
=>
value
+
1
);
},
([
value
])
=>
{
valueB
=
value
;
jest
.
runAllTimers
();
},
([
value
])
=>
{
valueC
=
value
;
}
);
const
[[
valueA
,
debouncedSetValue
],
[
valueB
],
[
valueC
]]
=
runHooks
(()
=>
useDebouncedUpdates
(
useState
(
0
),
delay
),
[
([,
setValue
])
=>
setValue
((
value
)
=>
value
+
1
),
()
=>
jest
.
runAllTimers
(),
]);
expect
(
debouncedSetValue
).
toBeInstanceOf
(
Function
);
expect
(
debouncedSetValue
.
flush
).
toBeInstanceOf
(
Function
);
...
...
@@ -39,55 +26,46 @@ describe('useDebouncedUpdates hook', () => {
describe
(
'
useDebouncedReducer hook
'
,
()
=>
{
it
(
'
is a debounced state updater
'
,
()
=>
{
const
initialState
=
{}
;
const
newState
=
{}
;
const
initialState
=
Symbol
()
;
const
newState
=
Symbol
()
;
const
reducer
=
jest
.
fn
(()
=>
newState
);
const
initializerArg
=
initialState
;
const
initializer
=
jest
.
fn
((
state
)
=>
state
);
let
stateA
;
let
stateB
;
testHook
(
()
=>
useDebouncedReducer
(
reducer
,
initializerArg
,
initializer
,
delay
),
([,
dispatch
])
=>
{
dispatch
();
},
([
state
])
=>
{
stateA
=
state
;
jest
.
runAllTimers
();
},
([
state
])
=>
{
stateB
=
state
;
}
);
const
[
[
stateA
],
[
stateB
],
[
stateC
],
]
=
runHooks
(()
=>
useDebouncedReducer
(
reducer
,
initializerArg
,
initializer
,
delay
),
[
([,
dispatch
])
=>
dispatch
(),
()
=>
jest
.
runAllTimers
(),
]);
expect
(
reducer
).
toHaveBeenCalledWith
(
initialState
,
undefined
);
expect
(
initializer
).
toHaveBeenCalledWith
(
initializerArg
);
expect
(
stateA
).
toBe
(
initialState
);
expect
(
stateB
).
toBe
(
newState
);
expect
(
stateB
).
toBe
(
initialState
);
expect
(
stateC
).
toBe
(
newState
);
});
});
describe
(
'
useDebouncedState hook
'
,
()
=>
{
it
(
'
is a debounced state updater
'
,
()
=>
{
const
initialValue
=
{}
;
const
newValue
=
{}
;
let
valueA
;
let
valueB
;
testHook
(
()
=>
useDebouncedState
(
initialValue
,
delay
),
const
initialValue
=
Symbol
()
;
const
newValue
=
Symbol
()
;
const
[
[
valueA
],
[
valueB
],
[
valueC
],
]
=
runHooks
(
()
=>
useDebouncedState
(
initialValue
,
delay
),
[
([,
setValue
])
=>
{
setValue
(
newValue
);
},
([
state
])
=>
{
valueA
=
state
;
()
=>
{
jest
.
runAllTimers
();
},
([
state
])
=>
{
valueB
=
state
;
}
);
]);
expect
(
valueA
).
toBe
(
initialValue
);
expect
(
valueB
).
toBe
(
newValue
);
expect
(
valueB
).
toBe
(
initialValue
);
expect
(
valueC
).
toBe
(
newValue
);
});
});
});
packages/fuselage-hooks/tests/useExclusiveBooleanProps.spec.js
View file @
c43294fe
import
{
test
Hook
}
from
'
../.jest/helpers
'
;
import
{
run
Hook
s
}
from
'
../.jest/helpers
'
;
import
{
useExclusiveBooleanProps
}
from
'
../src
'
;
describe
(
'
useExclusiveBooleanProps hook
'
,
()
=>
{
it
(
'
allows an empty set of props
'
,
()
=>
{
test
Hook
(()
=>
useExclusiveBooleanProps
({}));
run
Hook
s
(()
=>
useExclusiveBooleanProps
({}));
});
it
(
'
allows only false-valued props
'
,
()
=>
{
test
Hook
(()
=>
useExclusiveBooleanProps
({
a
:
false
,
b
:
false
,
c
:
false
}));
run
Hook
s
(()
=>
useExclusiveBooleanProps
({
a
:
false
,
b
:
false
,
c
:
false
}));
});
it
(
'
allows one true-valued prop
'
,
()
=>
{
test
Hook
(()
=>
useExclusiveBooleanProps
({
a
:
true
}));
run
Hook
s
(()
=>
useExclusiveBooleanProps
({
a
:
true
}));
});
it
(
'
allows one true-valued prop among false-valued ones
'
,
()
=>
{
test
Hook
(()
=>
useExclusiveBooleanProps
({
a
:
true
,
b
:
false
,
c
:
false
}));
run
Hook
s
(()
=>
useExclusiveBooleanProps
({
a
:
true
,
b
:
false
,
c
:
false
}));
});
it
(
'
denies two true-valued props
'
,
()
=>
{
expect
(()
=>
{
test
Hook
(()
=>
useExclusiveBooleanProps
({
a
:
true
,
b
:
true
}));
run
Hook
s
(()
=>
useExclusiveBooleanProps
({
a
:
true
,
b
:
true
}));
}).
toThrow
();
});
});
packages/fuselage-hooks/tests/useMediaQuery.spec.js
View file @
c43294fe
import
{
test
Hook
}
from
'
../.jest/helpers
'
;
import
{
run
Hook
s
}
from
'
../.jest/helpers
'
;
import
{
useMediaQuery
}
from
'
../src
'
;
describe
(
'
useMediaQuery hook
'
,
()
=>
{
...
...
@@ -23,44 +23,40 @@ describe('useMediaQuery hook', () => {
});
it
(
'
does not register a undefined media query
'
,
()
=>
{
test
Hook
(()
=>
useMediaQuery
());
run
Hook
s
(()
=>
useMediaQuery
());
expect
(
window
.
matchMedia
).
not
.
toHaveBeenCalled
();
});
it
(
'
does register a defined media query
'
,
()
=>
{
test
Hook
(()
=>
useMediaQuery
(
'
(max-width: 1024)
'
));
run
Hook
s
(()
=>
useMediaQuery
(
'
(max-width: 1024)
'
));
expect
(
window
.
matchMedia
).
toHaveBeenCalledWith
(
'
(max-width: 1024)
'
);
});
it
(
'
returns false if no query is given
'
,
()
=>
{
const
value
=
test
Hook
(()
=>
useMediaQuery
());
const
[
value
]
=
run
Hook
s
(()
=>
useMediaQuery
());
expect
(
value
).
toBe
(
false
);
});
it
(
'
returns false if the media query does not match
'
,
()
=>
{
const
value
=
test
Hook
(()
=>
useMediaQuery
(
'
(max-width: 1024)
'
));
const
[
value
]
=
run
Hook
s
(()
=>
useMediaQuery
(
'
(max-width: 1024)
'
));
expect
(
value
).
toBe
(
false
);
});
it
(
'
returns true if the media query does match
'
,
()
=>
{
mql
.
matches
=
true
;
const
value
=
test
Hook
(()
=>
useMediaQuery
(
'
(max-width: 1024)
'
));
const
[
value
]
=
run
Hook
s
(()
=>
useMediaQuery
(
'
(max-width: 1024)
'
));
expect
(
value
).
toBe
(
true
);
});
it
(
'
mutates its value to true if the media query matches
'
,
()
=>
{
testHook
(
()
=>
useMediaQuery
(
'
(max-width: 1024)
'
),
(
matches
)
=>
{
expect
(
matches
).
toBe
(
false
);
},
const
[
matchesA
,
matchesB
]
=
runHooks
(()
=>
useMediaQuery
(
'
(max-width: 1024)
'
),
[
()
=>
{
mql
.
matches
=
true
;
mql
.
onchange
();
},
(
matches
)
=>
{
expect
(
matches
).
toBe
(
true
);
}
);
]);
expect
(
matchesA
).
toBe
(
false
);
expect
(
matchesB
).
toBe
(
true
);
});
});
packages/fuselage-hooks/tests/useMergedRefs.spec.js
View file @
c43294fe
import
React
from
'
react
'
;
import
{
test
Hook
}
from
'
../.jest/helpers
'
;
import
{
run
Hook
s
}
from
'
../.jest/helpers
'
;
import
{
useMergedRefs
}
from
'
../src
'
;
describe
(
'
useMergedRefs hook
'
,
()
=>
{
it
(
'
returns a callback ref
'
,
()
=>
{
const
mergedRef
=
test
Hook
(()
=>
useMergedRefs
());
const
[
mergedRef
]
=
run
Hook
s
(()
=>
useMergedRefs
());
expect
(
mergedRef
).
toStrictEqual
(
expect
.
any
(
Function
));
});
it
(
'
works without any arguments
'
,
()
=>
{
const
value
=
{};
const
mergedRef
=
testHook
(
()
=>
jest
.
fn
(
useMergedRefs
()),
(
mergedRef
)
=>
{
mergedRef
(
value
);
},
);
const
[
mergedRef
]
=
runHooks
(()
=>
jest
.
fn
(
useMergedRefs
()));
const
value
=
Symbol
();
mergedRef
(
value
);
expect
(
mergedRef
).
toHaveBeenCalledWith
(
value
);
});
it
(
'
works with one ref
'
,
()
=>
{
const
ref
=
React
.
createRef
();
const
value
=
{};
testHook
(
()
=>
useMergedRefs
(
ref
),
(
mergedRef
)
=>
{
mergedRef
(
value
);
},
);
const
[
mergedRef
]
=
runHooks
(()
=>
useMergedRefs
(
ref
));
const
value
=
Symbol
();
mergedRef
(
value
);
expect
(
ref
.
current
).
toBe
(
value
);
});
it
(
'
works with many refs
'
,
()
=>
{
const
refs
=
new
Array
(
10
).
fill
(
undefined
).
map
(()
=>
React
.
createRef
());
const
value
=
{};
testHook
(
()
=>
useMergedRefs
(...
refs
),
(
mergedRef
)
=>
{
mergedRef
(
value
);
},
);
const
[
mergedRef
]
=
runHooks
(()
=>
useMergedRefs
(...
refs
));
const
value
=
Symbol
();
mergedRef
(
value
);
refs
.
forEach
((
ref
)
=>
expect
(
ref
.
current
).
toBe
(
value
));
});
it
(
'
works with callback ref
'
,
()
=>
{
const
callbackRef
=
jest
.
fn
();
const
value
=
{};
testHook
(
()
=>
useMergedRefs
(
callbackRef
),
(
mergedRef
)
=>
{
mergedRef
(
value
);
},
);
const
[
mergedRef
]
=
runHooks
(()
=>
useMergedRefs
(
callbackRef
));
const
value
=
Symbol
();
mergedRef
(
value
);
expect
(
callbackRef
).
toHaveBeenCalledWith
(
value
);
});
it
(
'
works with refs and callback refs
'
,
()
=>
{
const
refs
=
new
Array
(
5
).
fill
(
undefined
).
map
(()
=>
React
.
createRef
());
const
callbackRefs
=
new
Array
(
5
).
fill
(
undefined
).
map
(()
=>
jest
.
fn
());
const
[
mergedRef
]
=
runHooks
(()
=>
useMergedRefs
(...
refs
,
...
callbackRefs
));
const
value
=
{};
testHook
(
()
=>
useMergedRefs
(...
refs
,
...
callbackRefs
),
(
mergedRef
)
=>
{
mergedRef
(
value
);
},
);
const
value
=
Symbol
();