1import React, { PropsWithChildren } from 'react';
2import { renderHook } from '@testing-library/react-hooks';
3import { useStatelessReducer, useDispatch, DispatchContext, combineReducers } from './useStatelessReducer';
4
5describe('useStatelessReducer Hook', () => {
6  it('When dispatch is called, it should call the provided reducer with the correct action and state', () => {
7    const action = { type: 'SOME ACTION' };
8    const reducer = jest.fn();
9    const state = { someProp: 'some state' };
10
11    const { result } = renderHook(() => useStatelessReducer(() => {}, state, reducer));
12
13    result.current(action);
14
15    expect(reducer).toHaveBeenCalledWith(state, action);
16  });
17
18  it('When an action is dispatched, it should call the provided onChange callback with the result from the reducer', () => {
19    const action = { type: 'SOME ACTION' };
20    const state = { propA: 'A', propB: 'B' };
21    const expectedState = { ...state, propB: 'Changed' };
22    const reducer = () => expectedState;
23    const onChange = jest.fn();
24
25    const { result } = renderHook(() => useStatelessReducer(onChange, state, reducer));
26
27    result.current(action);
28
29    expect(onChange).toHaveBeenLastCalledWith(expectedState);
30  });
31});
32
33describe('useDispatch Hook', () => {
34  it('Should throw when used outside of DispatchContext', () => {
35    const { result } = renderHook(() => useDispatch());
36
37    expect(result.error).toBeTruthy();
38  });
39
40  it('Should return a dispatch function', () => {
41    const dispatch = jest.fn();
42    const wrapper = ({ children }: PropsWithChildren<{}>) => (
43      <DispatchContext.Provider value={dispatch}>{children}</DispatchContext.Provider>
44    );
45
46    const { result } = renderHook(() => useDispatch(), {
47      wrapper,
48    });
49
50    expect(result.current).toBe(dispatch);
51  });
52});
53
54describe('combineReducers', () => {
55  it('Should correctly combine reducers', () => {
56    const reducerA = jest.fn();
57    const reducerB = jest.fn();
58
59    const combinedReducer = combineReducers({ reducerA, reducerB });
60
61    const action = { type: 'SOME ACTION' };
62    const initialState = { reducerA: 'A', reducerB: 'B' };
63
64    combinedReducer(initialState, action);
65
66    expect(reducerA).toHaveBeenCalledWith(initialState.reducerA, action);
67    expect(reducerB).toHaveBeenCalledWith(initialState.reducerB, action);
68  });
69});
70