import React from 'react'; import { render, fireEvent } from '@testing-library/react'; import { act, renderHook } from '@testing-library/react-hooks'; import createReducerContext from '../src/factory/createReducerContext'; type Action = 'increment' | 'decrement'; const reducer = (state: number, action: Action) => { switch (action) { case 'increment': return state + 1; case 'decrement': return state - 1; default: throw new Error(); } }; it('should create a hook and a provider', () => { const [useSharedNumber, SharedNumberProvider] = createReducerContext(reducer, 0); expect(useSharedNumber).toBeInstanceOf(Function); expect(SharedNumberProvider).toBeInstanceOf(Function); }); describe('when using created hook', () => { it('should throw out of a provider', () => { const [useSharedNumber] = createReducerContext(reducer, 0); const { result } = renderHook(() => useSharedNumber()); expect(result.error).toEqual( new Error('useReducerContext must be used inside a ReducerProvider.') ); }); const setUp = () => { const [useSharedNumber, SharedNumberProvider] = createReducerContext(reducer, 0); const wrapper: React.FC = ({ children }) => ( {children} ); return renderHook(() => useSharedNumber(), { wrapper }); }; it('should init state and updater', () => { const { result } = setUp(); const [sharedNumber, updateSharedNumber] = result.current; expect(sharedNumber).toEqual(0); expect(updateSharedNumber).toBeInstanceOf(Function); }); it('should update the state', () => { const { result } = setUp(); const [, updateSharedNumber] = result.current; act(() => updateSharedNumber('increment')); const [sharedNumber] = result.current; expect(sharedNumber).toEqual(1); }); }); describe('when using among multiple components', () => { const [useSharedNumber, SharedNumberProvider] = createReducerContext(reducer, 0); const DisplayComponent = () => { const [sharedNumber] = useSharedNumber(); return

{sharedNumber}

; }; const UpdateComponent = () => { const [, updateSharedNumber] = useSharedNumber(); return ( ); }; it('should be in sync when under the same provider', () => { const { baseElement, getByText } = render( ); expect(baseElement.innerHTML).toBe( '

0

0

' ); fireEvent.click(getByText('INCREMENT')); expect(baseElement.innerHTML).toBe( '

1

1

' ); }); it('should be in update independently when under different providers', () => { const { baseElement, getByText } = render( <> ); expect(baseElement.innerHTML).toBe( '

0

0

' ); fireEvent.click(getByText('INCREMENT')); expect(baseElement.innerHTML).toBe( '

0

1

' ); }); it('should not update component that do not use the state context', () => { let renderCount = 0; const StaticComponent = () => { renderCount++; return

static

; }; const { baseElement, getByText } = render( <> ); expect(baseElement.innerHTML).toBe( '

static

0

' ); fireEvent.click(getByText('INCREMENT')); expect(baseElement.innerHTML).toBe( '

static

1

' ); expect(renderCount).toBe(1); }); it('should override initialValue', () => { const { baseElement } = render( <> ); expect(baseElement.innerHTML).toBe('

0

15

'); }); });