diff --git a/src/__tests__/createMemo.test.ts b/src/__tests__/createMemo.test.ts index 8056ed14..2acb5d94 100644 --- a/src/__tests__/createMemo.test.ts +++ b/src/__tests__/createMemo.test.ts @@ -3,13 +3,13 @@ import createMemo from '../createMemo'; const getDouble = jest.fn((n: number): number => n * 2); -it('should init memoized hook', () => { +it('should init memo hook', () => { const useMemoGetDouble = createMemo(getDouble); expect(useMemoGetDouble).toBeInstanceOf(Function); }); -describe('created memo hook', () => { +describe('when using created memo hook', () => { let useMemoGetDouble; beforeEach(() => { diff --git a/src/__tests__/createReducer.test.ts b/src/__tests__/createReducer.test.ts new file mode 100644 index 00000000..42ae47c6 --- /dev/null +++ b/src/__tests__/createReducer.test.ts @@ -0,0 +1,112 @@ +import { act, renderHook } from '@testing-library/react-hooks'; +import createReducer from '../createReducer'; +import logger from 'redux-logger'; +import thunk from 'redux-thunk'; + +it('should init reducer hook function', () => { + const useSomeReducer = createReducer(); + expect(useSomeReducer).toBeInstanceOf(Function); +}); + +/** + * This test suite implements the special demo in storybook that creates a + * reducer with thunk and logger for using a simple counter + */ +describe('when using created reducer hook', () => { + const initialCount = 1; + let originalLog; + let originalGroup; + const mockLog = jest.fn(); + const mockGroup = jest.fn(); + + function reducer(state, action) { + switch (action.type) { + case 'increment': + return { count: state.count + 1 }; + case 'decrement': + return { count: state.count - 1 }; + case 'reset': + return { count: action.payload }; + default: + throw new Error(); + } + } + + // Action creator to increment count, wait a second and then reset + const addAndReset = () => { + return dispatch => { + dispatch({ type: 'increment' }); + + setTimeout(() => { + dispatch({ type: 'reset', payload: initialCount }); + }, 1000); + }; + }; + + const setUp = () => { + const useThunkReducer = createReducer(thunk, logger); + return renderHook(() => useThunkReducer(reducer, { count: initialCount })); + }; + + beforeAll(() => { + originalLog = console.log; + originalGroup = console.group; + console.log = mockLog; + console.group = mockGroup; + }); + + beforeEach(() => { + jest.useFakeTimers(); + }); + + afterAll(() => { + console.log = originalLog; + console.group = originalGroup; + }); + + it('should init state and dispatcher', () => { + const { result } = setUp(); + const [state, dispatch] = result.current; + + expect(state).toEqual({ count: 1 }); + expect(dispatch).toBeInstanceOf(Function); + }); + + it.each` + actionType | expectedCount | payload + ${'increment'} | ${2} | ${undefined} + ${'decrement'} | ${0} | ${undefined} + ${'reset'} | ${1} | ${1} + `('should handle "$actionType" action', ({ actionType, expectedCount, payload }) => { + const { result } = setUp(); + const [, dispatch] = result.current; + expect(mockLog).not.toHaveBeenCalled(); + + act(() => { + dispatch({ type: actionType, payload }); + }); + + expect(result.current[0]).toEqual({ count: expectedCount }); + expect(mockLog).toHaveBeenCalled(); + }); + + it('should handle async action with several middlewares', () => { + const { result } = setUp(); + const [, dispatch] = result.current; + expect(mockLog).not.toHaveBeenCalled(); + + act(() => { + dispatch(addAndReset()); + }); + + expect(result.current[0]).toEqual({ count: 2 }); + expect(mockLog).toHaveBeenCalled(); + + // fast-forward until all timers have been executed + act(() => { + jest.runAllTimers(); + }); + + expect(result.current[0]).toEqual({ count: 1 }); + }); +});