Upgrade to Pro — share decks privately, control downloads, hide ads and more …

React Hooks勉強会 vol.5

React Hooks勉強会 vol.5

社内勉強会の資料です。
https://water-cell.connpass.com/event/178647/

yukikayuki

June 18, 2020
Tweet

More Decks by yukikayuki

Other Decks in Programming

Transcript

  1. React Hooks ษڧձ vol.5 Hooksͷςετ 2020.6.18 @_yukikayuki

  2. ࣗݾ঺հ • State • Kaneda Takayuki • Web Application Developer

    • झຯ • Splatoon2, ᲔΛ৯΂Δ @_yukikayuki
  3. Scope • o Custom Hooksͷςετ • x React Componentͷςετ •

    x E2Eςετ
  4. Agenda • Hooksͷ͓͞Β͍ • react-hooks-testing-libraryΛ࢖ͬͯςετ • useCounter

  5. Hooksͷ͓͞Β͍

  6. ✌ ϑοΫͷϧʔϧ • ϑοΫ͸ؔ਺ͷτοϓϨϕϧͷΈͰݺͼग़ͯ͠ ͍ͩ͘͞ɻϧʔϓ΍৚݅෼ذ΍ωετͨؔ͠਺ ͷதͰϑοΫΛݺͼग़͞ͳ͍Ͱ͍ͩ͘͞ɻ • ϑοΫ͸ React ͷؔ਺ίϯϙʔωϯτͷ಺෦ͷ

    ΈͰݺͼग़͍ͯͩ͘͠͞ɻ௨ৗͷ JavaScript ؔ ਺಺Ͱ͸ݺͼग़͞ͳ͍Ͱ͍ͩ͘͞ɻ https://ja.reactjs.org/docs/hooks-overview.html#rules-of-hooks
  7. Hooks͸ React Componentͷ֎Ͱ͸ ׆ಈͰ͖ͳ͍

  8. ϧʔϧΛഁΔͱͲ͏ͳΔ͔

  9. useCounter.js import {useState, useCallback} from 'react' export default function useCounter(initialValue

    = 0) { const [count, setCount] = useState(initialValue) const increment = useCallback(() => setCount((x) => x + 1), []) const reset = useCallback(() => setCount(initialValue), [initialValue]) return {count, increment, reset} }
  10. useCount.test.js import useCounter from "./useCounter"; test('should use counter', () =>

    { const {count} = useCounter() expect(count).toBe(0) })
  11. jest useContainer.test.js Error: Invalid hook call. Hooks can only be

    called inside of the body of a function component. This could happen for one of the following reasons: 1. You might have mismatching versions of React and the renderer (such as React DOM) 2. You might be breaking the Rules of Hooks 3. You might have more than one copy of React in the same app See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.
  12. react-hooks-testing-library

  13. ͲͷϥΠϒϥϦΛ࢖͏΂͖͔ • ௐ΂ͨݶΓReact Componentͷςετ͸Enzyme ͱReact Testing Libraryͷ2ڧͬΆ͍ • testing-libraryϑΝϛϦʔʁͷreact-hooks-testing- library͕Hooks୯ମͰςετͰ͖Δ

    • react-useͰ΋࢖ͬͯΔΆ͍͠ɺͦΕ͕͍͍Μ͡Ό ͳ͍͔
  14. ؀ڥߏங • yarn create react-app my-app • cd my-app •

    yarn add -D @testing-library/react-hooks react-testing-renderer
  15. useCounter.js import {useState, useCallback} from 'react' export default function useCounter(initialValue

    = 0) { const [count, setCount] = useState(initialValue) const increment = useCallback(() => setCount((x) => x + 1), []) const reset = useCallback(() => setCount(initialValue), [initialValue]) return {count, increment, reset} }
  16. Rendering import {renderHook} from "@testing-library/react-hooks"; import useCounter from "./useCounter"; test('should

    use counter', () => { const {result} = renderHook(() => useCounter()) expect(result.current.count).toBe(0) expect(typeof result.current.increment).toBe('function') expect(typeof result.current.reset).toBe('function') })
  17. Updates import {act, renderHook} from "@testing-library/react-hooks"; import useCounter from "./useCounter";

    test('should increment counter', () => { const {result} = renderHook(() => useCounter()) act(() => { result.current.increment() }) expect(result.current.count).toBe(1) })
  18. act() • ϨϯμʔɾϢʔβΠϕϯτɾσʔλͷऔಘͳͲ ͷλεΫʹؔ࿈͢Δߋ৽ॲཧ͕͢΂ͯॲཧ͞ ΕɺDOMʹ൓ө͞Ε͍ͯΔ͜ͱΛอূ͢Δ • ࣮ࡍͷϢʔβ͕ΞϓϦέʔγϣϯΛ࢖͏࣌ʹ ମݧ͢Δͷͱ͍ۙঢ়گͰ࣮ߦ͞ΕΔΑ͏ʹͳ Δ

  19. jest noAct.test.js import {renderHook} from "@testing-library/react-hooks"; import useCounter from "./useCounter";

    test('should increment counter', () => { const {result} = renderHook(() => useCounter()) result.current.increment() expect(result.current.count).toBe(1) })
  20. act()ແ͠ͷWarning Warning: An update to TestHook inside a test was

    not wrapped in act(...). When testing, code that causes React state updates should be wrapped into act(...): act(() => { /* fire events that update state */ }); /* assert on the output */ This ensures that you're testing the behavior the user would see in the browser. Learn more at https://fb.me/react-wrap-tests-with-act in TestHook in Suspense
  21. Providing Props 1 import {act, renderHook} from "@testing-library/react-hooks"; import useCounter

    from "./useCounter"; test('should increment counter from custom initial value', () => { const {result} = renderHook(() => useCounter(9000)) act(() => { result.current.increment() }) expect(result.current.count).toBe(9001) })
  22. Providing Props 2 import {act, renderHook} from "@testing-library/react-hooks"; import useCounter

    from "./useCounter"; test('should reset counter to updated initial value 1', () => { let initialValue = 0 const {result, rerender} = renderHook(() => useCounter(initialValue)) initialValue = 10 rerender() act(() => { result.current.reset() }) expect(result.current.count).toBe(10) })
  23. Providing Props 3 import {act, renderHook} from "@testing-library/react-hooks"; import useCounter

    from "./useCounter"; test('should reset counter to updated initial value 2', () => { const {result, rerender} = renderHook(({initialValue}) => useCounter(initialValue), { initialProps: {initialValue: 0}, }) rerender({initialValue: 10}) act(() => { result.current.reset() }) expect(result.current.count).toBe(10) })
  24. ·ͱΊ

  25. Hooks୯ମͷςετ͸ຊྲྀͰ͸ͳ͍ • Hooks୯ମͷςετʹ͍ͭͯ͸ެࣜυΩϡϝ ϯτʹॻ͍ͯͳ͍ • Componentͷςετʹ͍ͭͯ͸ެࣜυΩϡϝ ϯτ > Testingʹॻ͍ͯ͋Δ •

    Componentͱͯ͠Hooks΋ςετ͍ͯ͠Δ
  26. react-hooks-testing-libraryʹ ॏཁͳ͜ͱ͕ॻ͔Ε͍ͯΔ NOTE it is not recommended to test single-use

    custom hooks in isolation from the components where it's being used. It's better to test the component that's using the hook rather than the hook itself. The React Hooks Testing Library is intended to be used for reusable hooks/libraries. ஫ɿ࢖͍ࣺͯͷΧελϜϑοΫΛɺͦΕ͕࢖༻͞Ε͍ͯΔίϯϙʔ ωϯτ͔Β੾Γ཭ͯ͠ςετ͢Δ͜ͱ͸͓קΊ͠·ͤΜɻϑοΫࣗ ମͰ͸ͳ͘ɺϑοΫΛ࢖༻͍ͯ͠ΔίϯϙʔωϯτΛςετ͢Δ͜ ͱΛ͓קΊ͠·͢ɻReact Hooks Testing Library ࠶ར༻Մೳͳϑο Ϋ/ϥΠϒϥϦͷͨΊʹ࢖༻͞ΕΔ͜ͱΛҙਤ͍ͯ͠·͢ɻ https://github.com/testing-library/react-testing-library#hooks
  27. ࣍ͷֶशύε • react-hooks-testing-libraryͷAdvanced HooksΛ΍ͬͯΈΔ • YoutubeͰ’ How To Test Custom

    Effect Hook - Custom Hooks Mini Course Part 5’ΛݟΔ • react-useͷςετίʔυΛ؍࡯͢Δ
  28. ྑ͍ςετϥΠϑΛ