Skip to content

Commit a60a1e6

Browse files
authored
Merge pull request #24 from atlp-rwanda/ft-order-management-#187900465
#187900465: A buyer and seller should be manage orders
2 parents ff6239d + 0ec37d6 commit a60a1e6

24 files changed

+1104
-29
lines changed

Diff for: .github/workflows/deploy.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
node-version: "20"
2727

2828
- name: Install dependencies
29-
run: npm install
29+
run: npm install --force
3030

3131
- name: Running test
3232
run: npm run test:coverage

Diff for: package-lock.json

+23-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: package.json

+2-3
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@
2828
"@radix-ui/react-navigation-menu": "^1.1.4",
2929
"@reduxjs/toolkit": "^2.2.5",
3030
"@tanstack/react-query": "^5.45.1",
31-
"@testing-library/jest-dom": "^6.4.6",
32-
"@testing-library/react": "^16.0.0",
3331
"@testing-library/user-event": "^14.5.2",
3432
"axios": "^1.7.2",
3533
"axios-mock-adapter": "^1.22.0",
@@ -41,6 +39,7 @@
4139
"jest-environment-jsdom": "^29.7.0",
4240
"jest-fetch-mock": "^3.0.3",
4341
"jest-mock-extended": "^3.0.7",
42+
"jwt-decode": "^4.0.0",
4443
"moment": "^2.30.1",
4544
"node-fetch": "^3.3.2",
4645
"npm": "^10.8.1",
@@ -52,6 +51,7 @@
5251
"react-icons": "^5.2.1",
5352
"react-jwt": "^1.2.1",
5453
"react-loading-skeleton": "^3.4.0",
54+
"react-number-format": "^5.4.0",
5555
"react-redux": "^9.1.2",
5656
"react-router-dom": "^6.23.1",
5757
"react-spinners": "^0.14.1",
@@ -69,7 +69,6 @@
6969
"@commitlint/cli": "^19.3.0",
7070
"@commitlint/config-conventional": "^19.2.2",
7171
"@testing-library/dom": "^10.2.0",
72-
"@testing-library/jest-dom": "^6.4.6",
7372
"@types/jest": "^29.5.12",
7473
"@types/node": "^20.14.8",
7574
"@types/react": "^18.2.66",

Diff for: src/__test__/cartSlice.test.tsx

+73-9
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// @ts-nochec
21
import { configureStore } from "@reduxjs/toolkit";
32

43
import cartReducer, {
@@ -49,6 +48,16 @@ describe("cartManageSlice", () => {
4948
expect(store.getState().cart.isLoading).toBeFalsy();
5049
});
5150

51+
it("should handle cartManage.rejected", async () => {
52+
const errorMessage = "Network Error";
53+
(axios.get as jest.Mock).mockRejectedValue(new Error(errorMessage));
54+
55+
await store.dispatch(cartManage());
56+
57+
expect(store.getState().cart.error).toBeTruthy();
58+
expect(store.getState().cart.isLoading).toBeFalsy();
59+
});
60+
5261
it("should handle addToCart.fulfilled", async () => {
5362
const mockItem = { id: "2", quantity: 1 };
5463
(axios.post as jest.Mock).mockResolvedValue({ data: mockItem });
@@ -58,31 +67,86 @@ describe("cartManageSlice", () => {
5867
expect(store.getState().cart.data).toContainEqual(mockItem);
5968
});
6069

70+
it("should handle addToCart.rejected", async () => {
71+
const errorMessage = "Failed to add item to cart";
72+
(axios.post as jest.Mock).mockRejectedValue(new Error(errorMessage));
73+
74+
await store.dispatch(addToCart({ productId: 2, quantity: 1 }));
75+
76+
expect(store.getState().cart.add.error).toEqual(errorMessage);
77+
});
78+
6179
it("should handle removeFromCart.fulfilled", async () => {
6280
(axios.put as jest.Mock).mockResolvedValue({ data: {} });
63-
// @ts-ignore
64-
await store.dispatch(removeFromCart("1"));
81+
await store.dispatch(removeFromCart());
6582

6683
expect(store.getState().cart.remove.isLoading).toBeFalsy();
6784
});
68-
it("should handle clear FromCart.fulfilled", async () => {
85+
86+
it("should handle removeFromCart.rejected", async () => {
87+
const errorMessage = "Failed to remove item from cart";
88+
(axios.put as jest.Mock).mockRejectedValue(new Error(errorMessage));
89+
90+
await store.dispatch(removeFromCart());
91+
92+
expect(store.getState().cart.remove.error).toBeTruthy();
93+
});
94+
95+
it("should handle cartDelete.fulfilled", async () => {
6996
(axios.delete as jest.Mock).mockResolvedValue({ data: {} });
70-
// @ts-ignore
71-
await store.dispatch(cartDelete("1"));
97+
await store.dispatch(cartDelete());
7298

7399
expect(store.getState().cart.delete.isLoading).toBeFalsy();
74100
});
75101

76-
it("should handle updateCarts.fulfilled", async () => {
77-
const mockItem = { productId: "1", quantity: 3 };
102+
it("should handle cartDelete.rejected", async () => {
103+
const errorMessage = "Failed to delete cart";
104+
(axios.delete as jest.Mock).mockRejectedValue(new Error(errorMessage));
105+
106+
await store.dispatch(cartDelete());
107+
108+
expect(store.getState().cart.delete.error).toBeTruthy();
109+
});
110+
111+
it("should handle updateCarts return undefined.", async () => {
112+
const mockItem = { id: "1", quantity: 3 };
78113
(axios.patch as jest.Mock).mockResolvedValue({ data: mockItem });
79114

80115
store.dispatch({
81116
type: "carts/cartManage/fulfilled",
82-
payload: [{ productId: "1", quantity: 2 }],
117+
payload: [{ id: "1", quantity: 2 }],
83118
});
84119
await store.dispatch(updateCarts({ productId: "1", quantity: 3 }));
85120

86121
expect(store.getState().cart.data[0]).toEqual(undefined);
87122
});
123+
124+
it("should handle updateCarts.rejected", async () => {
125+
const errorMessage = "Failed to update cart";
126+
(axios.patch as jest.Mock).mockRejectedValue(new Error(errorMessage));
127+
128+
await store.dispatch(updateCarts({ productId: "1", quantity: 3 }));
129+
130+
expect(store.getState().cart.update.error).toBeTruthy();
131+
});
132+
133+
it("should return undefined increaseQuantity", () => {
134+
store.dispatch({
135+
type: "carts/cartManage/fulfilled",
136+
payload: [{ id: "1", quantity: 2 }],
137+
});
138+
store.dispatch(increaseQuantity("1"));
139+
140+
expect(store.getState().cart.data.quantity).toEqual(undefined);
141+
});
142+
143+
it("should return undefined decreaseQuantity", () => {
144+
store.dispatch({
145+
type: "carts/cartManage/fulfilled",
146+
payload: [{ id: "1", quantity: 2 }],
147+
});
148+
store.dispatch(decreaseQuantity("1"));
149+
150+
expect(store.getState().cart.data.quantity).toEqual(undefined);
151+
});
88152
});

Diff for: src/__test__/deleteNotify.test.tsx

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import "@testing-library/jest-dom/jest-globals";
2+
import "@testing-library/jest-dom";
3+
import { render, screen, fireEvent } from "@testing-library/react";
4+
import { Provider } from "react-redux";
5+
import { BrowserRouter as Router } from "react-router-dom";
6+
7+
import store from "../redux/store";
8+
import DeleteNotify from "../components/common/notify/DeleteNotify";
9+
10+
describe("DeleteNotify component", () => {
11+
const mockOnConfirm = jest.fn();
12+
const mockOnCancel = jest.fn();
13+
14+
beforeEach(() => {
15+
render(
16+
<Provider store={store}>
17+
<Router>
18+
<DeleteNotify onConfirm={mockOnConfirm} onCancel={mockOnCancel} />
19+
</Router>
20+
</Provider>,
21+
);
22+
});
23+
24+
test('renders the "Clear Cart" button', () => {
25+
const clearCartButton = screen.getByText("Clear Cart");
26+
expect(clearCartButton).toBeInTheDocument();
27+
});
28+
29+
test("opens the modal when Clear Cart button is clicked", () => {
30+
const clearCartButton = screen.getByText("Clear Cart");
31+
fireEvent.click(clearCartButton);
32+
33+
const modalHeader = screen.getByText(
34+
"Are you sure you want to delete this product?",
35+
);
36+
expect(modalHeader).toBeInTheDocument();
37+
});
38+
39+
test("calls onConfirm and closes modal when is clicked", () => {
40+
const clearCartButton = screen.getByText("Clear Cart");
41+
fireEvent.click(clearCartButton);
42+
43+
const confirmButton = screen.getByText("Yes, I'm sure");
44+
fireEvent.click(confirmButton);
45+
46+
expect(mockOnConfirm).toHaveBeenCalledTimes(1);
47+
expect(
48+
screen.queryByText("Are you sure you want to delete this product?"),
49+
).toBeInTheDocument();
50+
});
51+
52+
test('calls onCancel and closes modal when "No, cancel" is clicked', () => {
53+
const clearCartButton = screen.getByText("Clear Cart");
54+
fireEvent.click(clearCartButton);
55+
56+
const cancelButton = screen.getByText("No, cancel");
57+
fireEvent.click(cancelButton);
58+
59+
expect(mockOnCancel).toHaveBeenCalledTimes(1);
60+
expect(
61+
screen.queryByText("Are you sure you want to delete this product?"),
62+
).toBeInTheDocument();
63+
});
64+
});

Diff for: src/__test__/orders.test.ts

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import { orders } from "../../type";
2+
import ordersReducer, {
3+
fetchOrders,
4+
updateOrderStatus,
5+
} from "../redux/reducers/ordersSlice";
6+
7+
describe("orders reducer", () => {
8+
const initialState = {
9+
isLoading: false,
10+
data: [] as unknown as orders,
11+
error: false,
12+
};
13+
14+
it("should handle initial state", () => {
15+
expect(ordersReducer(undefined, { type: "unknown" })).toEqual(initialState);
16+
});
17+
18+
it("should handle fetchOrders.pending", () => {
19+
const action = { type: fetchOrders.pending.type };
20+
const state = ordersReducer(initialState, action);
21+
expect(state).toEqual({
22+
...initialState,
23+
isLoading: true,
24+
});
25+
});
26+
27+
it("should handle fetchOrders.fulfilled", () => {
28+
const mockOrders = [
29+
{ id: 1, status: "pending" },
30+
{ id: 2, status: "completed" },
31+
];
32+
const action = { type: fetchOrders.fulfilled.type, payload: mockOrders };
33+
const state = ordersReducer(initialState, action);
34+
expect(state).toEqual({
35+
...initialState,
36+
isLoading: false,
37+
data: mockOrders,
38+
});
39+
});
40+
41+
it("should handle fetchOrders.rejected", () => {
42+
const action = { type: fetchOrders.rejected.type };
43+
const state = ordersReducer(initialState, action);
44+
expect(state).toEqual({
45+
...initialState,
46+
isLoading: false,
47+
error: true,
48+
});
49+
});
50+
51+
it("should handle updateOrderStatus.pending", () => {
52+
const action = { type: updateOrderStatus.pending.type };
53+
const state = ordersReducer(initialState, action);
54+
expect(state).toEqual({
55+
...initialState,
56+
isLoading: true,
57+
});
58+
});
59+
60+
it("should handle updateOrderStatus.rejected", () => {
61+
const action = { type: updateOrderStatus.rejected.type };
62+
const state = ordersReducer(initialState, action);
63+
expect(state).toEqual({
64+
...initialState,
65+
isLoading: false,
66+
error: true,
67+
});
68+
});
69+
70+
it("should handle updateOrderStatus.fulfilled", () => {
71+
const initialStateWithData: any = {
72+
...initialState,
73+
data: [
74+
{
75+
order: { id: 1 },
76+
products: [
77+
{ id: 101, status: "pending" },
78+
{ id: 102, status: "pending" },
79+
],
80+
},
81+
{
82+
order: { id: 2 },
83+
products: [{ id: 201, status: "pending" }],
84+
},
85+
],
86+
};
87+
88+
const action = {
89+
type: updateOrderStatus.fulfilled.type,
90+
payload: { orderId: 1, productId: 102, status: "completed" },
91+
};
92+
93+
const state = ordersReducer(initialStateWithData, action);
94+
95+
expect(state.data[0].products[1].status).toEqual("completed");
96+
expect(state.data[0].products[0].status).toEqual("pending");
97+
expect(state.data[1].products[0].status).toEqual("pending");
98+
});
99+
});

0 commit comments

Comments
 (0)