Last active
August 8, 2019 22:30
-
-
Save shuhei/302ca48e2972a8b7b9baa33379b56c52 to your computer and use it in GitHub Desktop.
An idea for testing custom React hooks
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const React = require("react"); | |
const { mount } = require("enzyme"); | |
// A custom hook to test | |
function useCounter(initial) { | |
const [count, setCount] = React.useState(initial); | |
const increment = React.useCallback(() => setCount(c => c + 1), []); | |
const reset = React.useCallback(() => setCount(initial), [initial]); | |
return { count, increment, reset }; | |
} | |
// A component for testing the hook | |
function CounterTest({ initial }) { | |
const { count, increment, reset } = useCounter(initial); | |
return ( | |
<div> | |
<div id="count">{count}</div> | |
<button id="increment" onClick={increment}>increment</button> | |
<button id="reset" onClick={reset}>reset</button> | |
</div> | |
); | |
} | |
test("counter", () => { | |
const wrapper = mount(<CounterTest initial={123} />); | |
expect(wrapper.find("#count").text()).toEqual("123"); | |
// `increment` should increment the count. | |
wrapper.find("#increment").simulate("click"); | |
expect(wrapper.find("#count").text()).toEqual("124"); | |
wrapper.find("#increment").simulate("click"); | |
expect(wrapper.find("#count").text()).toEqual("125"); | |
// `reset` should reset the count with the initial value. | |
wrapper.find("#reset").simulate("click"); | |
expect(wrapper.find("#count").text()).toEqual("123"); | |
// `reset` should use the latest initial value. | |
wrapper.setProps({ initial: 234 }); | |
expect(wrapper.find("#count").text()).toEqual("123"); | |
wrapper.find("#reset").simulate("click"); | |
expect(wrapper.find("#count").text()).toEqual("234"); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const React = require("react"); | |
const { mount } = require("enzyme"); | |
// A custom hook to test | |
function useCounter(initial) { | |
const [count, setCount] = React.useState(initial); | |
const increment = React.useCallback(() => setCount(c => c + 1), []); | |
const reset = React.useCallback(() => setCount(initial), [initial]); | |
return { count, increment, reset }; | |
} | |
// A component for testing the hook | |
function CounterTest({ initial }) { | |
const { count, increment, reset } = useCounter(initial); | |
return render({ count, increment, reset }); | |
} | |
test("counter", () => { | |
const wrapper = mount(<CounterTest initial={123} />); | |
expect(getValue(wrapper, "count")).toEqual(123); | |
// `increment` should increment the count. | |
callFunction(wrapper, "increment"); | |
expect(getValue(wrapper, "count")).toEqual(124); | |
callFunction(wrapper, "increment"); | |
expect(getValue(wrapper, "count")).toEqual(125); | |
// `reset` should reset the count with the initial value. | |
callFunction(wrapper, "reset"); | |
expect(getValue(wrapper, "count")).toEqual(123); | |
// `reset` should use the latest initial value. | |
wrapper.setProps({ initial: 234 }); | |
expect(getValue(wrapper, "count")).toEqual(123); | |
callFunction(wrapper, "reset"); | |
expect(getValue(wrapper, "count")).toEqual(234); | |
}); | |
// Helper functions | |
function render(fields) { | |
const items = Object.entries(fields).map(([name, value]) => { | |
if (typeof value === "function") { | |
const onClick = (args) => { | |
value.apply(null, args); | |
}; | |
return <button id={name} onClick={onClick}>{JSON.stringify(value)}</button>; | |
} | |
return <div id={name}>{value}</div>; | |
}); | |
return <div>{items}</div>; | |
} | |
function getValue(wrapper, name) { | |
return JSON.parse(wrapper.find(`#${name}`).text()); | |
} | |
function callFunction(wrapper, name, args = []) { | |
wrapper.find(`#${name}`).simulate('click', args); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const React = require("react"); | |
const { mount } = require("enzyme"); | |
// A custom hook to test | |
function useCounter(initial) { | |
const [count, setCount] = React.useState(initial); | |
const increment = React.useCallback(() => setCount(c => c + 1), []); | |
const reset = React.useCallback(() => setCount(initial), [initial]); | |
return { count, increment, reset }; | |
} | |
// A component for testing the hook | |
function CounterTest({ initial }) { | |
const { count, increment, reset } = useCounter(initial); | |
return render({ count, increment, reset }); | |
} | |
test("counter", () => { | |
const wrapper = mount(<CounterTest initial={123} />); | |
const hook = makeHook(wrapper); | |
expect(hook.count).toEqual(123); | |
// `increment` should increment the count. | |
hook.increment(); | |
expect(hook.count).toEqual(124); | |
hook.increment(); | |
expect(hook.count).toEqual(125); | |
// `reset` should reset the count with the initial value. | |
hook.reset(); | |
expect(hook.count).toEqual(123); | |
// `reset` should use the latest initial value. | |
wrapper.setProps({ initial: 234 }); | |
expect(hook.count).toEqual(123); | |
hook.reset(); | |
expect(hook.count).toEqual(234); | |
}); | |
// Helper functions | |
function render(fields) { | |
const items = Object.entries(fields).map(([name, value]) => { | |
if (typeof value === "function") { | |
const onClick = (args) => { | |
value.apply(null, args); | |
}; | |
return ( | |
<button | |
id={name} | |
key={name} | |
onClick={onClick} | |
>{JSON.stringify(value)}</button> | |
); | |
} | |
return ( | |
<div | |
id={name} | |
key={name} | |
>{value}</div> | |
); | |
}); | |
return <div>{items}</div>; | |
} | |
function makeHook(wrapper) { | |
return new Proxy({}, { | |
get(target, prop) { | |
const element = wrapper.find(`#${prop}`); | |
if (element.is('div')) { | |
return JSON.parse(element.text()); | |
} else { | |
return (args) => { | |
element.simulate('click', args); | |
}; | |
} | |
} | |
}); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const React = require("react"); | |
const { mount } = require("enzyme"); | |
// A custom hook to test | |
function useCounter(initial) { | |
const [count, setCount] = React.useState(initial); | |
const increment = React.useCallback(() => setCount(c => c + 1), []); | |
const reset = React.useCallback(() => setCount(initial), [initial]); | |
return { count, increment, reset }; | |
} | |
test("counter", () => { | |
const { hook, update, act } = makeHook(useCounter, 123); | |
expect(hook.count).toEqual(123); | |
// `increment` should increment the count. | |
hook.increment(); | |
expect(hook.count).toEqual(124); | |
hook.increment(); | |
expect(hook.count).toEqual(125); | |
// `reset` should reset the count with the initial value. | |
hook.reset(); | |
expect(hook.count).toEqual(123); | |
// `reset` should use the latest initial value. | |
update(234); | |
expect(hook.count).toEqual(123); | |
hook.reset(); | |
expect(hook.count).toEqual(234); | |
}); | |
function makeHook(useHook, ...args) { | |
let current; | |
function TestComponent({ args }) { | |
current = useHook(...args); | |
const callFunc = ({ func }) => { | |
func(); | |
}; | |
return ( | |
<button id="call-me" onClick={callFunc}>call me</button> | |
); | |
} | |
const wrapper = mount(<TestComponent args={args} />); | |
const update = (...args) => { | |
wrapper.setProps({ args }); | |
}; | |
const act = (func) => { | |
wrapper.find("#call-me").simulate("click", { func }); | |
}; | |
const hook = new Proxy({}, { | |
get(_target, prop) { | |
const value = current[prop]; | |
if (typeof value === "function") { | |
return (...args) => { | |
act(() => value(...args)); | |
}; | |
} else { | |
return value; | |
} | |
} | |
}); | |
return { | |
hook, | |
update, | |
act | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment