diff --git a/src/__test__/Cart/Cart.test.tsx b/src/__test__/Cart/Cart.test.tsx
index ee4867af..0c3d5611 100644
--- a/src/__test__/Cart/Cart.test.tsx
+++ b/src/__test__/Cart/Cart.test.tsx
@@ -1,12 +1,15 @@
import { configureStore } from '@reduxjs/toolkit';
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
+import { Provider } from 'react-redux';
+import { render, screen } from '@testing-library/react';
import cartReducer, {
fetchCartItems,
addCartItem,
updateCartItemQuantity,
removeCartItem,
} from '@/features/Cart/cartSlice';
+import CartItem from '@/components/Cart/CartItem';
describe('cartSlice', () => {
let store = configureStore({ reducer: { cartItems: cartReducer } });
@@ -79,3 +82,22 @@ describe('cartSlice', () => {
expect(state.error).toBeNull();
});
});
+
+describe('Cart component', () => {
+ const store = configureStore({
+ reducer: {},
+ });
+
+ it('renders cart item', async () => {
+ render(
+
+
+
+ );
+
+ expect(screen.getByText('$300')).toBeInTheDocument();
+ expect(screen.getByText('Test Product')).toBeInTheDocument();
+ expect(screen.getByText('Size')).toBeInTheDocument();
+ expect(screen.getByText('3')).toBeInTheDocument();
+ });
+});
diff --git a/src/__test__/productDetails.test.tsx b/src/__test__/productDetails.test.tsx
index f60ae28f..58d5e76f 100644
--- a/src/__test__/productDetails.test.tsx
+++ b/src/__test__/productDetails.test.tsx
@@ -3,13 +3,13 @@ import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import { Store, configureStore } from '@reduxjs/toolkit';
import { waitFor } from '@testing-library/dom';
-import { render, screen } from '@testing-library/react';
+import { fireEvent, render, screen } from '@testing-library/react';
import { Provider } from 'react-redux';
import { MemoryRouter, Route, Routes } from 'react-router';
import productsReducer, {
fetchProductDetails,
} from '@/features/Products/ProductSlice';
-import signInReducer from '@/features/Auth/SignInSlice';
+import signInReducer, { SignInState } from '@/features/Auth/SignInSlice';
import { AppDispatch, RootState } from '@/app/store';
import ProductDetails from '@/pages/ProductDetails';
import bestSellingReducer from '@/features/Popular/bestSellingProductSlice';
@@ -24,8 +24,22 @@ const mockProduct = {
totalQtySold: 25,
longDesc: 'This is a mock product used for testing purposes.',
shortDesc: 'This is a short description',
- category: 'Electronics',
- similarProducts: [],
+ category: {
+ id: 5,
+ name: 'Electronics',
+ },
+ similarProducts: [
+ {
+ id: 3,
+ name: 'Mock Similar Product',
+ image: '/images/mock.png',
+ averageRating: 0,
+ salesPrice: 100,
+ regularPrice: 200,
+ longDesc: 'This is a mock product used for testing purposes.',
+ shortDesc: 'This is a short description',
+ },
+ ],
reviews: [
{
id: 1,
@@ -42,7 +56,8 @@ const mockProduct = {
gallery: [],
tags: ['testTag'],
vendor: {
- name: 'Tester',
+ firstName: 'Tester',
+ lastName: 'Testing',
email: 'testervendor@gmail.com',
picture: 'https://fake.png',
},
@@ -57,6 +72,22 @@ const renderWithProviders = (
bestSellingProducts: bestSellingReducer,
signIn: signInReducer,
},
+ preloadedState: {
+ signIn: {
+ token: 'fake token',
+ user: null,
+ role: null,
+ loading: null,
+ error: null,
+ message: null,
+ needsVerification: false,
+ needs2FA: false,
+ vendor: {
+ id: null,
+ email: null,
+ },
+ } as unknown as SignInState,
+ },
}),
} = {}
) => {
@@ -101,6 +132,12 @@ describe('ProductDetails Page', () => {
expect(screen.getByText(/\$149.99/i)).toBeInTheDocument();
expect(screen.getByText('1')).toBeInTheDocument();
expect(screen.getByText('25')).toBeInTheDocument();
+ expect(screen.getByText('33% Off')).toBeInTheDocument();
+ expect(screen.getByText('Add to Cart')).toBeInTheDocument();
+ expect(screen.getByText('Add to wishlist')).toBeInTheDocument();
+ // expect(screen.getAllByTestId('ratingStar').length).toBe(4);
+ // expect(screen.getAllByTestId('halfStar').length).toBe(1);
+
expect(
screen.getByText(/This is a mock product used for testing purposes./i)
).toBeInTheDocument();
@@ -123,6 +160,128 @@ describe('ProductDetails Page', () => {
).toBeInTheDocument();
});
});
+
+ it('should display similar products', async () => {
+ mock
+ .onGet(`${import.meta.env.VITE_BASE_URL}/buyer/get_product/1`)
+ .reply(200, { product: mockProduct });
+
+ renderWithProviders();
+
+ await waitFor(() => {
+ expect(screen.getByText('Mock Similar Prod...')).toBeInTheDocument();
+ expect(screen.getByText('$100')).toBeInTheDocument();
+ expect(screen.getByText('50% Off')).toBeInTheDocument();
+ });
+ });
+
+ it('should display product details, reviews, about store', async () => {
+ mock
+ .onGet(`${import.meta.env.VITE_BASE_URL}/buyer/get_product/1`)
+ .reply(200, { product: mockProduct });
+
+ renderWithProviders();
+
+ await waitFor(() => {
+ expect(screen.getByText('Product Details')).toBeInTheDocument();
+ expect(
+ screen.getByText('This is a mock product used for testing purposes.')
+ ).toBeInTheDocument();
+ expect(
+ screen.getByText('This is a short description')
+ ).toBeInTheDocument();
+ });
+
+ fireEvent.click(screen.getByRole('button', { name: 'Reviews (1)' }));
+
+ await waitFor(() => {
+ expect(screen.getByText('new user')).toBeInTheDocument();
+ expect(screen.getByText('excellent product')).toBeInTheDocument();
+ });
+
+ fireEvent.click(screen.getByRole('button', { name: 'About Store' }));
+
+ await waitFor(() => {
+ expect(screen.getAllByText('Tester Testing')[0]).toBeInTheDocument();
+ expect(
+ screen.getAllByText('testervendor@gmail.com')[0]
+ ).toBeInTheDocument();
+ });
+ });
+
+ it('should display error message when no reviews are found', async () => {
+ mock
+ .onGet(`${import.meta.env.VITE_BASE_URL}/buyer/get_product/1`)
+ .reply(200, { product: { ...mockProduct, reviews: [] } });
+
+ renderWithProviders();
+
+ await waitFor(() => {
+ fireEvent.click(screen.getByRole('button', { name: 'Reviews (0)' }));
+ });
+
+ await waitFor(() => {
+ expect(screen.getByText('No reviews found')).toBeInTheDocument();
+ });
+ });
+
+ it('should submit a review successfully', async () => {
+ mock
+ .onGet(`${import.meta.env.VITE_BASE_URL}/buyer/get_product/1`)
+ .reply(200, { product: mockProduct });
+
+ mock
+ .onPost(`${import.meta.env.VITE_BASE_URL}/review`)
+ .reply(200, { message: 'Review submitted successfully' });
+
+ renderWithProviders();
+
+ mock
+ .onGet(`${import.meta.env.VITE_BASE_URL}/buyer/get_product/1`)
+ .reply(200, {
+ product: {
+ ...mockProduct,
+ reviews: [
+ {
+ id: 1,
+ user: {
+ id: 1,
+ firstName: 'new',
+ lastName: 'rating',
+ picture: 'http://fake.png',
+ },
+ rating: 1,
+ content: 'this is a bad product',
+ },
+ ],
+ },
+ });
+
+ await waitFor(() => {
+ const star = screen.getAllByTitle('inputStar')[0];
+ fireEvent.click(star);
+ const contentTextArea = screen.getByTitle('inputContent');
+ fireEvent.change(contentTextArea, {
+ target: {
+ value: 'this is a bad product',
+ },
+ });
+ });
+
+ await waitFor(() => {
+ const submitBtn = screen.getByText('Submit');
+ fireEvent.click(submitBtn);
+ });
+
+ await waitFor(() => {
+ fireEvent.click(screen.getByRole('button', { name: 'Reviews (1)' }));
+ });
+
+ await waitFor(() => {
+ expect(screen.getByText('this is a bad product')).toBeInTheDocument();
+ expect(screen.getByText('new rating')).toBeInTheDocument();
+ });
+ });
});
describe('Product Details async action', () => {
diff --git a/src/__test__/shop.test.tsx b/src/__test__/shop.test.tsx
index d6fe8d26..62f70e81 100644
--- a/src/__test__/shop.test.tsx
+++ b/src/__test__/shop.test.tsx
@@ -108,6 +108,19 @@ describe('Shop Component', () => {
expect(screen.queryByText(/Product 2/i)).not.toBeInTheDocument();
});
});
+
+ it('displays the filter section on mobile devices', async () => {
+ renderWithProviders();
+ const filterBtn = screen.getByTitle('filter');
+ fireEvent.click(filterBtn);
+
+ await waitFor(() => {
+ expect(screen.getAllByText('Filters')[1]).toBeInTheDocument();
+ expect(screen.getAllByText('Clear All')[1]).toBeInTheDocument();
+ expect(screen.getAllByText('Categories')[1]).toBeInTheDocument();
+ expect(screen.getAllByText('Rating')[1]).toBeInTheDocument();
+ });
+ });
});
describe('ProductSlice', () => {
diff --git a/src/components/salesMap/SalesMap.tsx b/src/components/salesMap/SalesMap.tsx
index fc3039f6..b7e8288b 100644
--- a/src/components/salesMap/SalesMap.tsx
+++ b/src/components/salesMap/SalesMap.tsx
@@ -53,7 +53,7 @@ function SalesMap() {
(label as any).html(
`
${(label as any).html()}
-
Sales: ${Data ? Data[code] : 0}
+
Sales: ${code in Data ? Data[code] : 0}
`
);
}}
diff --git a/src/features/Auth/SignInSlice.ts b/src/features/Auth/SignInSlice.ts
index 79120e39..d29c48eb 100644
--- a/src/features/Auth/SignInSlice.ts
+++ b/src/features/Auth/SignInSlice.ts
@@ -16,7 +16,7 @@ interface User {
};
}
-interface SignInState {
+export interface SignInState {
token: string | null;
user: User | null;
loading: boolean;
diff --git a/src/features/Orders/ordersSlice.ts b/src/features/Orders/ordersSlice.ts
index 2918ba7f..1c01b27c 100644
--- a/src/features/Orders/ordersSlice.ts
+++ b/src/features/Orders/ordersSlice.ts
@@ -1,7 +1,7 @@
import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit';
import axios from 'axios';
import Order from '@/interfaces/order';
-import { RootState } from '../../app/store';
+import { RootState, store } from '../../app/store';
interface OrdersState {
orders: Order[];
@@ -35,6 +35,31 @@ export const fetchOrders = createAsyncThunk('orders/fetchOrders', async () => {
},
};
});
+
+ const { signIn } = store.getState();
+
+ if (signIn.user?.userType.name === 'Admin') {
+ return orders;
+ }
+ if (signIn.user?.userType.name === 'Vendor') {
+ const filteredOrders: Order[] = [];
+ /* eslint-disable no-restricted-syntax */
+ for (const order of orders) {
+ const newDetails = [];
+ /* eslint-disable no-restricted-syntax */
+ for (const orderDetail of order.orderDetails) {
+ if (orderDetail.product.vendor.id === signIn.user.id) {
+ newDetails.push(orderDetail);
+ }
+ }
+
+ if (newDetails.length > 0) {
+ filteredOrders.push({ ...order, orderDetails: newDetails });
+ }
+ }
+
+ return filteredOrders;
+ }
return orders;
});
diff --git a/src/pages/Coupons.tsx b/src/pages/Coupons.tsx
index 2842afa1..f139312a 100644
--- a/src/pages/Coupons.tsx
+++ b/src/pages/Coupons.tsx
@@ -147,7 +147,7 @@ function Coupons() {
setSearchTerm(e.target.value)}
diff --git a/src/pages/ProductDetails.tsx b/src/pages/ProductDetails.tsx
index 37d2583e..1580c9be 100644
--- a/src/pages/ProductDetails.tsx
+++ b/src/pages/ProductDetails.tsx
@@ -689,6 +689,7 @@ function ProductDetails() {
{Array.from({ length: 5 }, (_, i) => (
*
setToggleFilterMenu(true)}
className="cursor-pointer"
diff --git a/src/routes/AppRoutes.tsx b/src/routes/AppRoutes.tsx
index 45f46682..bcaddad9 100644
--- a/src/routes/AppRoutes.tsx
+++ b/src/routes/AppRoutes.tsx
@@ -47,9 +47,22 @@ function AppRoutes() {
}
/>
} />
- } />
- } />
- } />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
} />
} />
diff --git a/vite.config.ts b/vite.config.ts
index 52d33ca7..a93cd035 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -32,6 +32,14 @@ export default defineConfig({
'src/pages/Coupons.tsx',
'src/pages/EditCoupon.tsx',
'src/pages/customer.tsx',
+ 'src/components/Cart/Cart.tsx',
+ 'src/components/bannerAds/bannerSection.tsx',
+ 'src/components/Checkout/Checkout.tsx',
+ 'src/components/dashBoard/EditProduct.tsx',
+ 'src/components/home/FeaturedSection.tsx',
+ 'src/components/home/BestSellerSection.tsx',
+ 'src/layout/HomeLayout.tsx',
+ 'src/layout/DashbordLayout.tsx',
],
},
},