Skip to content

Commit

Permalink
fix(test-cov): increase test coverage
Browse files Browse the repository at this point in the history
- add more tests to cover uncovered lines

[#Fixes #124]
  • Loading branch information
jkarenzi committed Jul 25, 2024
1 parent 5104bd9 commit 2a888fb
Show file tree
Hide file tree
Showing 6 changed files with 203 additions and 6 deletions.
22 changes: 22 additions & 0 deletions src/__test__/Cart/Cart.test.tsx
Original file line number Diff line number Diff line change
@@ -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 } });
Expand Down Expand Up @@ -79,3 +82,22 @@ describe('cartSlice', () => {
expect(state.error).toBeNull();
});
});

describe('Cart component', () => {
const store = configureStore({
reducer: {},
});

it('renders cart item', async () => {
render(
<Provider store={store}>
<CartItem id={1} price={100} name="Test Product" quantity={3} />
</Provider>
);

expect(screen.getByText('$300')).toBeInTheDocument();
expect(screen.getByText('Test Product')).toBeInTheDocument();
expect(screen.getByText('Size')).toBeInTheDocument();
expect(screen.getByText('3')).toBeInTheDocument();
});
});
169 changes: 164 additions & 5 deletions src/__test__/productDetails.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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,
Expand All @@ -42,7 +56,8 @@ const mockProduct = {
gallery: [],
tags: ['testTag'],
vendor: {
name: 'Tester',
firstName: 'Tester',
lastName: 'Testing',
email: '[email protected]',
picture: 'https://fake.png',
},
Expand All @@ -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,
},
}),
} = {}
) => {
Expand Down Expand Up @@ -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();
Expand All @@ -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(<ProductDetails />);

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(<ProductDetails />);

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('[email protected]')[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(<ProductDetails />);

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(<ProductDetails />);

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', () => {
Expand Down
13 changes: 13 additions & 0 deletions src/__test__/shop.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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(<Shop />);
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', () => {
Expand Down
2 changes: 1 addition & 1 deletion src/features/Auth/SignInSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ interface User {
};
}

interface SignInState {
export interface SignInState {
token: string | null;
user: User | null;
loading: boolean;
Expand Down
2 changes: 2 additions & 0 deletions src/pages/ProductDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,7 @@ function ProductDetails() {
<div className="flex items-center gap-2">
{Array.from({ length: 5 }, (_, i) => (
<FaStar
title="inputStar"
size="25"
color={
review.rating && i + 1 <= review.rating
Expand All @@ -681,6 +682,7 @@ function ProductDetails() {
Your review<span className="text-red-700"> *</span>
</h2>
<textarea
title="inputContent"
className="xs:w-full lg:w-4/5 h-40 rounded-md border-[1.5px] outline-none border-textareaBorder"
onChange={(e) =>
setReview({
Expand Down
1 change: 1 addition & 0 deletions src/pages/Shop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,7 @@ function Shop() {
</div>
<div className="xs:flex lg:hidden pl-2 py-2 mt-4 items-center justify-start gap-2 rounded-lg w-full bg-grayLight">
<CiFilter
title="filter"
size={20}
onClick={() => setToggleFilterMenu(true)}
className="cursor-pointer"
Expand Down

0 comments on commit 2a888fb

Please sign in to comment.