Skip to content
This repository was archived by the owner on May 5, 2025. It is now read-only.

Commit 2732e8f

Browse files
committed
add: implement tests for Redux hooks, rootReducer, and store to verify initial state and action handling
1 parent 5536cdc commit 2732e8f

File tree

3 files changed

+195
-0
lines changed

3 files changed

+195
-0
lines changed

tests/redux/hooks.test.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { renderHook } from '@testing-library/react-hooks';
2+
import { Provider } from 'react-redux';
3+
import configureMockStore from 'redux-mock-store';
4+
import * as React from 'react';
5+
import { AnyAction } from 'redux';
6+
7+
import { useAppDispatch, useAppSelector } from '@/redux/hooks';
8+
9+
// Mock the store
10+
const mockStore = configureMockStore();
11+
const initialState = {
12+
gifts: {
13+
gifts: [],
14+
loading: false,
15+
error: null
16+
},
17+
recipients: {
18+
recipients: [],
19+
loading: false,
20+
error: null
21+
}
22+
};
23+
const store = mockStore(initialState);
24+
25+
// Use a custom wrapper function that correctly types the Provider props
26+
const wrapper = ({ children }: { children: React.ReactNode }) => {
27+
// Make TypeScript happy by properly typing the Provider props
28+
return React.createElement(
29+
Provider as React.ComponentType<{ store: typeof store; children?: React.ReactNode }>,
30+
{ store },
31+
children
32+
);
33+
};
34+
35+
describe('Redux hooks', () => {
36+
describe('useAppDispatch', () => {
37+
it('should return a dispatch function', () => {
38+
const { result } = renderHook(() => useAppDispatch(), { wrapper });
39+
expect(typeof result.current).toBe('function');
40+
});
41+
42+
it('should dispatch an action correctly', () => {
43+
const { result } = renderHook(() => useAppDispatch(), { wrapper });
44+
result.current({ type: 'TEST_ACTION' });
45+
46+
const actions = store.getActions();
47+
expect(actions).toContainEqual({ type: 'TEST_ACTION' });
48+
});
49+
});
50+
51+
describe('useAppSelector', () => {
52+
it('should select data from the store state', () => {
53+
const { result } = renderHook(
54+
() => useAppSelector((state) => state.gifts.gifts),
55+
{ wrapper }
56+
);
57+
58+
expect(result.current).toEqual([]);
59+
});
60+
});
61+
});

tests/redux/rootReducer.test.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import rootReducer from '@/redux/rootReducer';
2+
3+
describe('rootReducer', () => {
4+
it('should return the initial state', () => {
5+
const state = rootReducer(undefined, { type: 'UNKNOWN_ACTION' });
6+
7+
// Check that the root state has the expected structure with both reducers
8+
expect(state).toHaveProperty('gifts');
9+
expect(state).toHaveProperty('recipients');
10+
});
11+
12+
it('should handle actions for the gifts slice', () => {
13+
// Initial state that would be provided by the store
14+
const initialState = {
15+
gifts: {
16+
gifts: [],
17+
loading: false,
18+
error: null
19+
},
20+
recipients: {
21+
recipients: [],
22+
loading: false,
23+
error: null
24+
}
25+
};
26+
27+
// Dispatch a gifts-specific action
28+
const state = rootReducer(initialState, {
29+
type: 'gifts/addGift/fulfilled',
30+
payload: {
31+
id: '1',
32+
title: 'Test Gift',
33+
image: 'test.jpg',
34+
price: 50,
35+
recipient: '1',
36+
selectedDate: '2025-05-01'
37+
}
38+
});
39+
40+
// The gifts slice should have updated
41+
expect(state.gifts.gifts).toHaveLength(1);
42+
expect(state.gifts.gifts[0].title).toBe('Test Gift');
43+
44+
// The recipients slice should remain unchanged
45+
expect(state.recipients).toEqual(initialState.recipients);
46+
});
47+
48+
it('should handle actions for the recipients slice', () => {
49+
// Initial state
50+
const initialState = {
51+
gifts: {
52+
gifts: [],
53+
loading: false,
54+
error: null
55+
},
56+
recipients: {
57+
recipients: [],
58+
loading: false,
59+
error: null
60+
}
61+
};
62+
63+
// Dispatch a recipients-specific action
64+
const state = rootReducer(initialState, {
65+
type: 'recipients/addRecipient/fulfilled',
66+
payload: {
67+
id: '1',
68+
name: 'Test Recipient',
69+
image: 'test.jpg',
70+
budget: 100,
71+
spent: 0
72+
}
73+
});
74+
75+
// The recipients slice should have updated
76+
expect(state.recipients.recipients).toHaveLength(1);
77+
expect(state.recipients.recipients[0].name).toBe('Test Recipient');
78+
79+
// The gifts slice should remain unchanged
80+
expect(state.gifts).toEqual(initialState.gifts);
81+
});
82+
});

tests/redux/store.test.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import store from '@/redux/store';
2+
3+
describe('Redux store', () => {
4+
it('should have the correct initial state', () => {
5+
const state = store.getState();
6+
7+
// Check that the store contains the expected slices
8+
expect(state).toHaveProperty('gifts');
9+
expect(state).toHaveProperty('recipients');
10+
11+
// Check that gifts slice has the expected initial state
12+
expect(state.gifts).toEqual({
13+
gifts: [],
14+
loading: false,
15+
error: null,
16+
});
17+
18+
// Check that recipients slice has the expected initial state
19+
expect(state.recipients).toEqual({
20+
recipients: [],
21+
loading: false,
22+
error: null,
23+
});
24+
});
25+
26+
it('should handle dispatched actions', () => {
27+
// Dispatch a test action
28+
store.dispatch({
29+
type: 'gifts/fetchGifts/pending',
30+
});
31+
32+
// Check that the state was updated correctly
33+
const state = store.getState();
34+
expect(state.gifts.loading).toBe(true);
35+
36+
// Reset store to avoid affecting other tests
37+
store.dispatch({ type: 'UNKNOWN_ACTION' });
38+
});
39+
40+
it('should have thunk middleware available', () => {
41+
// Dispatch an async thunk action (mock)
42+
const asyncAction = () => (dispatch: any) => {
43+
dispatch({ type: 'TEST_ASYNC_ACTION' });
44+
};
45+
46+
// This will throw if thunk middleware isn't available
47+
store.dispatch(asyncAction() as any);
48+
49+
// Reset store to avoid affecting other tests
50+
store.dispatch({ type: 'UNKNOWN_ACTION' });
51+
});
52+
});

0 commit comments

Comments
 (0)