Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}
1 change: 1 addition & 0 deletions __mocks__/fileMock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = 'test-file-stub';
1 change: 1 addition & 0 deletions __mocks__/styleMock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = {};
77 changes: 77 additions & 0 deletions __tests__/components/AddressBar.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import React from "react";
import { render, screen } from "@testing-library/react";
import { Provider } from "react-redux";
import { MemoryRouter } from "react-router-dom";
import configureStore from "redux-mock-store";
import AddressBar from "../../src/components/AddressBar";

const mockStore = configureStore([]);

const renderWithProviders = (ui, { initialState }) => {
const store = mockStore(initialState);
return render(
<Provider store={store}>
<MemoryRouter>{ui}</MemoryRouter>
</Provider>
);
};

describe("AddressBar", () => {
test("displays the selected address if it exists", () => {
const initialState = {
address: {
selectedAddressId: 2,
addresses: [
{ id: 1, street: "1st Street", neighborhood: "Old Town", district: "East District", is_primary: false },
{ id: 2, street: "2nd Avenue", neighborhood: "Downtown", district: "Central District", is_primary: true },
],
},
};

renderWithProviders(<AddressBar />, { initialState });

expect(screen.getByText(/2nd Avenue, Downtown, Central District/i)).toBeInTheDocument();
});

test("shows fallback message when no addresses exist", () => {
const initialState = {
address: {
selectedAddressId: null,
addresses: [],
},
};

renderWithProviders(<AddressBar />, { initialState });

expect(screen.getByText(/Add your delivery address/i)).toBeInTheDocument();
});

test("displays primary address if no selected address is set", () => {
const initialState = {
address: {
selectedAddressId: null,
addresses: [
{ id: 3, street: "Main Street", neighborhood: "Greenwood", district: "Northside", is_primary: true },
],
},
};

renderWithProviders(<AddressBar />, { initialState });

expect(screen.getByText(/Main Street, Greenwood, Northside/i)).toBeInTheDocument();
});

test("link navigates to /Address", () => {
const initialState = {
address: {
selectedAddressId: null,
addresses: [],
},
};

renderWithProviders(<AddressBar />, { initialState });

const link = screen.getByRole("link");
expect(link).toHaveAttribute("href", "/Address");
});
});
46 changes: 46 additions & 0 deletions __tests__/components/CategoryFilter.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import CategoryFilter from '../../src/components/CategoryFilter';

describe('CategoryFilter', () => {
const mockOnSelect = jest.fn();

beforeEach(() => {
mockOnSelect.mockClear();
});

test('renders all category buttons', () => {
render(
<CategoryFilter selectedCategory="All Categories" onSelectCategory={mockOnSelect} />
);

const buttons = screen.getAllByRole('button');
expect(buttons.length).toBeGreaterThanOrEqual(10);

expect(screen.getByText('All Categories')).toBeInTheDocument();
expect(screen.getByText('Baked Goods')).toBeInTheDocument();
expect(screen.getByText('Organic Products')).toBeInTheDocument();
});

test('highlights the selected category', () => {
render(
<CategoryFilter selectedCategory="Fruits & Vegetables" onSelectCategory={mockOnSelect} />
);

const selectedButton = screen.getByText('Fruits & Vegetables');
expect(selectedButton).toHaveStyle('background-color: #50703C');
expect(selectedButton).toHaveStyle('color: #fff');
});

test('calls onSelectCategory when a category is clicked', () => {
render(
<CategoryFilter selectedCategory="All Categories" onSelectCategory={mockOnSelect} />
);

const button = screen.getByText('Meat & Seafood');
fireEvent.click(button);

expect(mockOnSelect).toHaveBeenCalledTimes(1);
expect(mockOnSelect).toHaveBeenCalledWith('Meat & Seafood');
});
});
76 changes: 76 additions & 0 deletions __tests__/components/FavoriteRestaurantList.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import configureStore from 'redux-mock-store';
import { Provider } from 'react-redux';
import { MemoryRouter } from 'react-router-dom';
import FavoriteRestaurantList from '../../src/components/FavoriteRestaurantList';

jest.mock("react-slick", () => {
return ({ children }) => <div data-testid="mock-slider">{children}</div>;
});

const mockStore = configureStore([]);

const renderWithProviders = (ui, { initialState }) => {
const store = mockStore(initialState);
return render(
<Provider store={store}>
<MemoryRouter>{ui}</MemoryRouter>
</Provider>
);
};

describe('FavoriteRestaurantList', () => {
const restaurantSample = {
id: 1,
restaurantName: 'Testaurant',
image_url: 'https://example.com/image.jpg',
rating: 4.5,
listings: 3,
workingDays: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'],
workingHoursStart: '08:00',
workingHoursEnd: '22:00'
};

test('renders favorite restaurants when available', () => {
const initialState = {
restaurant: {
favoriteRestaurantsIDs: [1],
restaurantsProximity: [restaurantSample],
},
};

renderWithProviders(<FavoriteRestaurantList />, { initialState });

expect(screen.getByText('Favorites')).toBeInTheDocument();
expect(screen.getByText('Testaurant')).toBeInTheDocument();
expect(screen.getByTestId('mock-slider')).toBeInTheDocument();
});

test('returns null when no favorite restaurants', () => {
const initialState = {
restaurant: {
favoriteRestaurantsIDs: [],
restaurantsProximity: [],
},
};

const { container } = renderWithProviders(<FavoriteRestaurantList />, { initialState });
expect(container.firstChild).toBeNull();
});

test('renders action buttons', () => {
const initialState = {
restaurant: {
favoriteRestaurantsIDs: [1],
restaurantsProximity: [restaurantSample],
},
};

renderWithProviders(<FavoriteRestaurantList />, { initialState });

expect(screen.getByText('State')).toBeInTheDocument();
expect(screen.getByText('API')).toBeInTheDocument();
expect(screen.getByRole('link', { name: '' })).toHaveAttribute('href', '/favorites');
});
});
22 changes: 22 additions & 0 deletions __tests__/components/FlashDealsFloatingBadge.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import FlashDealsFloatingBadge from '../../src/components/FlashDealsFloatingBadge';

describe('FlashDealsFloatingBadge', () => {
test('renders with correct text and icon', () => {
render(<FlashDealsFloatingBadge onClick={() => {}} />);

expect(screen.getByText('Flash Deals')).toBeInTheDocument();
expect(document.querySelector('.bi-lightning-fill')).toBeInTheDocument();
});

test('calls onClick when clicked', () => {
const handleClick = jest.fn();
render(<FlashDealsFloatingBadge onClick={handleClick} />);

const badge = screen.getByText('Flash Deals').parentElement;
fireEvent.click(badge);

expect(handleClick).toHaveBeenCalledTimes(1);
});
});
94 changes: 94 additions & 0 deletions __tests__/components/FlashDealsModal.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import FlashDealsModal from '../../src/components/FlashDealsModal';
import { Provider } from 'react-redux';
import configureStore from 'redux-mock-store';
import { MemoryRouter } from 'react-router-dom';
import thunk from 'redux-thunk';

jest.mock('@src/redux/thunks/restaurantThunks.js', () => ({
getFlashDealsThunk: () => ({ type: 'MOCK_GET_FLASH_DEALS' }),
}));

const mockStore = configureStore({
middlewares: [thunk],
});


const renderWithProviders = (ui, { initialState }) => {
const store = mockStore(initialState);
return {
...render(
<Provider store={store}>
<MemoryRouter>{ui}</MemoryRouter>
</Provider>
),
store,
};
};

describe('FlashDealsModal', () => {
const mockRestaurants = [
{
id: 1,
restaurantName: 'Pizza Place',
flash_deals_available: true,
image_url: '',
rating: 4.5,
distance_km: 2.3,
},
];

const initialStateWithData = {
restaurant: {
flashDealsRestaurants: mockRestaurants,
flashDealsLoading: false,
},
};

const initialStateLoading = {
restaurant: {
flashDealsRestaurants: [],
flashDealsLoading: true,
},
};

test('renders modal content with available discounts and restaurants', () => {
renderWithProviders(<FlashDealsModal show={true} onHide={jest.fn()} />, {
initialState: initialStateWithData,
});

expect(screen.getByText('Available Discounts:')).toBeInTheDocument();
expect(screen.getByText('Pizza Place')).toBeInTheDocument();
expect(screen.getByText('Flash Deal Available')).toBeInTheDocument();
});

test('renders loading spinner when loading is true', () => {
renderWithProviders(<FlashDealsModal show={true} onHide={jest.fn()} />, {
initialState: initialStateLoading,
});

expect(screen.getAllByText('Loading Flash Deals...')).toHaveLength(2);
expect(screen.getByRole('status')).toBeInTheDocument(); // spinner
});

test('calls onHide when Close button is clicked', () => {
const mockOnHide = jest.fn();

renderWithProviders(<FlashDealsModal show={true} onHide={mockOnHide} />, {
initialState: initialStateWithData,
});

fireEvent.click(screen.getByText('Close'));
expect(mockOnHide).toHaveBeenCalledTimes(1);
});

test('dispatches getFlashDealsThunk when modal is shown', () => {
const { store } = renderWithProviders(<FlashDealsModal show={true} onHide={() => {}} />, {
initialState: initialStateWithData,
});

const actions = store.getActions();
expect(actions).toEqual(expect.arrayContaining([{ type: 'MOCK_GET_FLASH_DEALS' }]));
});
});
20 changes: 20 additions & 0 deletions __tests__/components/Footer.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import Footer from '../../src/components/Footer';
import { BrowserRouter } from 'react-router-dom';

const renderWithRouter = (ui) => render(<BrowserRouter>{ui}</BrowserRouter>);

describe('Footer component', () => {
test('renders FreshDeal logo', () => {
renderWithRouter(<Footer />);
const logo = screen.getByAltText(/FreshDeal Logo/i);
expect(logo).toBeInTheDocument();
});

test('renders social media links', () => {
renderWithRouter(<Footer />);
const socialLinks = screen.getAllByRole('link');
expect(socialLinks.length).toBeGreaterThanOrEqual(4);
});
});
Loading
Loading