file re-org
Some checks failed
Deploy to Web Server flyer-crawler.projectium.com / deploy (push) Failing after 53s
Some checks failed
Deploy to Web Server flyer-crawler.projectium.com / deploy (push) Failing after 53s
This commit is contained in:
129
src/pages/admin/components/AdminBrandManager.test.tsx
Normal file
129
src/pages/admin/components/AdminBrandManager.test.tsx
Normal file
@@ -0,0 +1,129 @@
|
||||
// src/components/AdminBrandManager.test.tsx
|
||||
import React from 'react';
|
||||
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
||||
import { describe, it, expect, vi, beforeEach, type Mock } from 'vitest';
|
||||
import toast from 'react-hot-toast';
|
||||
import { AdminBrandManager } from './AdminBrandManager';
|
||||
import * as apiClient from '../../../services/apiClient';
|
||||
import type { Brand } from '../../../types';
|
||||
|
||||
// Mock the apiClient module
|
||||
vi.mock('../services/apiClient');
|
||||
|
||||
// Mock react-hot-toast
|
||||
vi.mock('react-hot-toast', () => ({
|
||||
default: {
|
||||
loading: vi.fn(),
|
||||
success: vi.fn(),
|
||||
error: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
const mockBrands: Brand[] = [
|
||||
{ brand_id: 1, name: 'No Frills', store_name: 'No Frills', logo_url: null },
|
||||
{ brand_id: 2, name: 'Compliments', store_name: 'Sobeys', logo_url: 'http://example.com/compliments.png' },
|
||||
];
|
||||
|
||||
describe('AdminBrandManager', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should render a loading state initially', () => {
|
||||
(apiClient.fetchAllBrands as Mock).mockReturnValue(new Promise(() => {})); // Never resolves
|
||||
render(<AdminBrandManager />);
|
||||
expect(screen.getByText('Loading brands...')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render an error message if fetching brands fails', async () => {
|
||||
(apiClient.fetchAllBrands as Mock).mockRejectedValue(new Error('Network Error'));
|
||||
render(<AdminBrandManager />);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Failed to load brands: Network Error')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should render the list of brands when data is fetched successfully', async () => {
|
||||
(apiClient.fetchAllBrands as Mock).mockResolvedValue(mockBrands);
|
||||
render(<AdminBrandManager />);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('heading', { name: /brand management/i })).toBeInTheDocument();
|
||||
expect(screen.getByText('No Frills')).toBeInTheDocument();
|
||||
expect(screen.getByText('(Sobeys)')).toBeInTheDocument();
|
||||
expect(screen.getByAltText('Compliments logo')).toBeInTheDocument();
|
||||
expect(screen.getByText('No Logo')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle successful logo upload', async () => {
|
||||
(apiClient.fetchAllBrands as Mock).mockResolvedValue(mockBrands);
|
||||
(apiClient.uploadBrandLogo as Mock).mockResolvedValue({ logoUrl: 'http://example.com/new-logo.png' });
|
||||
(toast.loading as Mock).mockReturnValue('toast-1');
|
||||
|
||||
render(<AdminBrandManager />);
|
||||
await waitFor(() => expect(screen.getByText('No Frills')).toBeInTheDocument());
|
||||
|
||||
const file = new File(['logo'], 'logo.png', { type: 'image/png' });
|
||||
const input = screen.getAllByRole('textbox', { hidden: true })[0]; // Find the first file input
|
||||
|
||||
fireEvent.change(input, { target: { files: [file] } });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(apiClient.uploadBrandLogo).toHaveBeenCalledWith(1, file);
|
||||
expect(toast.loading).toHaveBeenCalledWith('Uploading logo...');
|
||||
expect(toast.success).toHaveBeenCalledWith('Logo updated successfully!', { id: 'toast-1' });
|
||||
// Check if the UI updates with the new logo
|
||||
expect(screen.getByAltText('No Frills logo')).toHaveAttribute('src', 'http://example.com/new-logo.png');
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle failed logo upload', async () => {
|
||||
(apiClient.fetchAllBrands as Mock).mockResolvedValue(mockBrands);
|
||||
(apiClient.uploadBrandLogo as Mock).mockRejectedValue(new Error('Upload failed'));
|
||||
(toast.loading as Mock).mockReturnValue('toast-2');
|
||||
|
||||
render(<AdminBrandManager />);
|
||||
await waitFor(() => expect(screen.getByText('No Frills')).toBeInTheDocument());
|
||||
|
||||
const file = new File(['logo'], 'logo.png', { type: 'image/png' });
|
||||
const input = screen.getAllByRole('textbox', { hidden: true })[0];
|
||||
|
||||
fireEvent.change(input, { target: { files: [file] } });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(toast.error).toHaveBeenCalledWith('Upload failed: Upload failed', { id: 'toast-2' });
|
||||
});
|
||||
});
|
||||
|
||||
it('should show an error toast for invalid file type', async () => {
|
||||
(apiClient.fetchAllBrands as Mock).mockResolvedValue(mockBrands);
|
||||
render(<AdminBrandManager />);
|
||||
await waitFor(() => expect(screen.getByText('No Frills')).toBeInTheDocument());
|
||||
|
||||
const file = new File(['text'], 'document.txt', { type: 'text/plain' });
|
||||
const input = screen.getAllByRole('textbox', { hidden: true })[0];
|
||||
|
||||
fireEvent.change(input, { target: { files: [file] } });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(toast.error).toHaveBeenCalledWith('Invalid file type. Please upload a PNG, JPG, WEBP, or SVG.');
|
||||
expect(apiClient.uploadBrandLogo).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('should show an error toast for oversized file', async () => {
|
||||
(apiClient.fetchAllBrands as Mock).mockResolvedValue(mockBrands);
|
||||
render(<AdminBrandManager />);
|
||||
await waitFor(() => expect(screen.getByText('No Frills')).toBeInTheDocument());
|
||||
|
||||
const file = new File(['a'.repeat(3 * 1024 * 1024)], 'large.png', { type: 'image/png' });
|
||||
const input = screen.getAllByRole('textbox', { hidden: true })[0];
|
||||
|
||||
fireEvent.change(input, { target: { files: [file] } });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(toast.error).toHaveBeenCalledWith('File is too large. Maximum size is 2MB.');
|
||||
expect(apiClient.uploadBrandLogo).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user