Skip to content

Commit

Permalink
Merge branch 'develop' into feat-integrate-payments
Browse files Browse the repository at this point in the history
  • Loading branch information
EddyShimwa committed Jul 26, 2024
2 parents c3a4e84 + 362caba commit f373af5
Show file tree
Hide file tree
Showing 18 changed files with 999 additions and 238 deletions.
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 22 additions & 1 deletion 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 All @@ -22,7 +25,7 @@ describe('cartSlice', () => {
});

it('should fetch cart items successfully', async () => {
const mockCartItems = [{ id: 1, name: 'Product 1', quantity: 2 }];
const mockCartItems = [{ id: 1, name: 'Product 1', quantity: 2, image: 'product_image.png' }];

Check failure on line 28 in src/__test__/Cart/Cart.test.tsx

View workflow job for this annotation

GitHub Actions / build (20.x)

Replace `{·id:·1,·name:·'Product·1',·quantity:·2,·image:·'product_image.png'·}` with `⏎······{·id:·1,·name:·'Product·1',·quantity:·2,·image:·'product_image.png'·},⏎····`
httpMock
.onGet(`${process.env.VITE_BASE_URL}/cart`)
.reply(200, { cartItems: mockCartItems });
Expand Down Expand Up @@ -79,3 +82,21 @@ 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" image='product_IMAGE.png' quantity={3} />

Check failure on line 94 in src/__test__/Cart/Cart.test.tsx

View workflow job for this annotation

GitHub Actions / build (20.x)

Replace `·id={1}·price={100}·name="Test·Product"·image='product_IMAGE.png'·quantity={3}` with `⏎··········id={1}⏎··········price={100}⏎··········name="Test·Product"⏎··········image="product_IMAGE.png"⏎··········quantity={3}⏎·······`
</Provider>
);

expect(screen.getByText('$300')).toBeInTheDocument();
expect(screen.getByText('Test Product')).toBeInTheDocument();
expect(screen.getByText('3')).toBeInTheDocument();
});
});
148 changes: 148 additions & 0 deletions src/__test__/dashBoard/Categories.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import React from 'react';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { Provider } from 'react-redux';
import { configureStore } from '@reduxjs/toolkit';
import { MemoryRouter } from 'react-router-dom';
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import Category from '@/components/dashBoard/Category';
import categoriesReducer from '@/features/Products/categorySlice';

const renderWithProviders = (ui: React.ReactElement) => {
const store = configureStore({ reducer: { categories: categoriesReducer } });
return render(
<Provider store={store}>
<MemoryRouter>{ui}</MemoryRouter>
</Provider>
);
};

describe('Category Component', () => {
let mock: MockAdapter;

beforeEach(() => {
mock = new MockAdapter(axios);
});

afterEach(() => {
mock.restore();
});

it('should render the component with initial state', () => {
renderWithProviders(<Category />);
expect(screen.getByText(/Categories/i)).toBeInTheDocument();
});

it('renders Categories component with category icons', async () => {
mock.onGet('/api/categories').reply(200, [
{
id: 1,
name: 'Category 1',
description: 'Description 1',
icon: 'https://example.com/icon1.png',
},
{
id: 2,
name: 'Category 2',
description: 'Description 2',
icon: 'https://example.com/icon2.png',
},
]);

renderWithProviders(<Category />);

const icons = await screen.findAllByRole('img');
icons.forEach((icon) => {
expect(icon).toHaveAttribute('alt');
});
});

it('paginates categories', async () => {
mock.onGet('/api/categories').reply(
200,
Array.from({ length: 20 }, (_, i) => ({
id: i + 1,
name: `Category ${i + 1}`,
description: `Description ${i + 1}`,
icon: `https://example.com/icon${i + 1}.png`,
}))
);

renderWithProviders(<Category />);

const nextPageButton = await screen.findByRole('button', { name: /next/i });
fireEvent.click(nextPageButton);
expect(nextPageButton).toBeInTheDocument();
});

it('should render the component with initial state', async () => {
renderWithProviders(<Category />);
await waitFor(() =>
expect(screen.getByText(/Categories/i)).toBeInTheDocument()
);
});

it('paginates categories', async () => {
mock.onGet('/api/categories').reply(
200,
Array.from({ length: 20 }, (_, i) => ({
id: i + 1,
name: `Category ${i + 1}`,
description: `Description ${i + 1}`,
icon: `https://example.com/icon${i + 1}.png`,
}))
);

renderWithProviders(<Category />);

const nextPageButton = await screen.findByRole('button', { name: /next/i });
fireEvent.click(nextPageButton);
expect(nextPageButton).toBeInTheDocument();
});

it('should display validation errors if form is submitted with invalid data', async () => {
renderWithProviders(<Category />);

// Open the form
fireEvent.click(screen.getByText(/Add Category/i));

// Trigger form submission
fireEvent.click(screen.getByText(/Save/i));

// Wait for validation errors to appear
await waitFor(() => {
expect(screen.getByText(/Name/i)).toBeInTheDocument();
expect(screen.getByText(/Icon/i)).toBeInTheDocument();
expect(screen.getByText(/Description/i)).toBeInTheDocument();
});
});

it('should submit form and handle API response', async () => {
mock.onPost(`${import.meta.env.VITE_BASE_URL}/category/`).reply(201);

renderWithProviders(<Category />);

// Open the form
fireEvent.click(screen.getByText(/Add Category/i));

// Fill out the form
fireEvent.change(screen.getByPlaceholderText(/Name of the category/i), {
target: { value: 'New Category' },
});
fireEvent.change(
screen.getByPlaceholderText(/Description of the category/i),
{
target: { value: 'Category description' },
}
);
fireEvent.change(screen.getByPlaceholderText(/URL of the category icon/i), {
target: { value: 'https://example.com/icon.png' },
});

fireEvent.click(screen.getByText(/Save/i));

await waitFor(() => {
expect(mock.history.post.length).toBe(1);
});
});
});
46 changes: 16 additions & 30 deletions src/__test__/dashBoard/Seller.test.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import axios from 'axios';
import { Provider } from 'react-redux';
import { MemoryRouter } from 'react-router-dom';
import { describe, it, expect } from 'vitest';
import { describe, it, expect, beforeEach } from 'vitest';
import MockAdapter from 'axios-mock-adapter';
import { render, screen, fireEvent } from '@testing-library/react';
import { render, screen, waitFor } from '@testing-library/react';
import { configureStore } from '@reduxjs/toolkit';
import Seller from '@/pages/Seller';
import productReducer from '@/app/Dashboard/AllProductSlices';
Expand Down Expand Up @@ -82,42 +82,25 @@ describe('Seller Component', () => {
expect(screen.getByText('Sellers')).toBeInTheDocument();
});

it('should display elements of the table', () => {
renderWithProviders(<Seller />);

expect(screen.getByText(/Image/)).toBeInTheDocument();
expect(screen.getByText(/First Name/)).toBeInTheDocument();
expect(screen.getByText(/Last Name/)).toBeInTheDocument();
expect(screen.getByText(/Email/)).toBeInTheDocument();
expect(screen.getByText(/Items Count/)).toBeInTheDocument();
expect(screen.getByText(/Date/)).toBeInTheDocument();
expect(screen.getByText(/Status/)).toBeInTheDocument();
expect(screen.getByText(/Action/)).toBeInTheDocument();
});

it('should filter sellers by search term', async () => {
// Mock API response
it('should display elements of the table', async () => {
mock
.onGet(`${import.meta.env.VITE_BASE_URL}/user/getAllUsers`)
.reply(200, { users: mockBuyers });

// Render component
renderWithProviders(<Seller />);

// Dispatch fetchBuyers to populate the state
await store.dispatch(fetchBuyers() as any);

// Perform search action
const searchInput = screen.getByPlaceholderText('Search Seller');
fireEvent.change(searchInput, { target: { value: 'Vendor1' } });

// Check filtered results
expect(screen.getByText('Vendor1')).toBeInTheDocument();
expect(screen.queryByText('Customer1')).not.toBeInTheDocument();
await waitFor(() => {
expect(screen.getByText('Name')).toBeInTheDocument();
expect(screen.getByText('Email')).toBeInTheDocument();
expect(screen.getByText('Items')).toBeInTheDocument();
expect(screen.getByText('Date')).toBeInTheDocument();
expect(screen.getByText('Status')).toBeInTheDocument();
expect(screen.getByText('Action')).toBeInTheDocument();
});
});

it('should handle loading state', async () => {
// Mock API response
mock
.onGet(`${import.meta.env.VITE_BASE_URL}/user/getAllUsers`)
.reply(200, { users: mockBuyers });
Expand All @@ -137,7 +120,10 @@ describe('Seller Component', () => {

renderWithProviders(<Seller />);
await store.dispatch(fetchBuyers() as any);
expect(screen.queryByText('Vendor1')).toBeNull();
expect(screen.queryByText('Customer1')).toBeNull();

await waitFor(() => {
expect(screen.queryByText('Vendor1')).toBeNull();
expect(screen.queryByText('Customer1')).toBeNull();
});
});
});
Loading

0 comments on commit f373af5

Please sign in to comment.