mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-21 14:21:46 +00:00
test(front): add test suite frontend (WIP)
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
import { render, screen, fireEvent, act } from '../../../tests/helpers/render';
|
||||
|
||||
// Mock photoService — all functions are no-ops / return null
|
||||
vi.mock('../../services/photoService', () => ({
|
||||
getCached: vi.fn(() => null),
|
||||
isLoading: vi.fn(() => false),
|
||||
fetchPhoto: vi.fn(),
|
||||
onThumbReady: vi.fn(() => () => {}),
|
||||
}));
|
||||
|
||||
// Mock IntersectionObserver as a class constructor
|
||||
const mockDisconnect = vi.fn();
|
||||
const mockObserve = vi.fn();
|
||||
|
||||
class MockIntersectionObserver {
|
||||
callback: (entries: Partial<IntersectionObserverEntry>[]) => void;
|
||||
constructor(callback: (entries: Partial<IntersectionObserverEntry>[]) => void) {
|
||||
this.callback = callback;
|
||||
}
|
||||
observe = mockObserve;
|
||||
disconnect = mockDisconnect;
|
||||
unobserve = vi.fn();
|
||||
}
|
||||
|
||||
beforeAll(() => {
|
||||
(globalThis as any).IntersectionObserver = MockIntersectionObserver;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mockDisconnect.mockClear();
|
||||
mockObserve.mockClear();
|
||||
});
|
||||
|
||||
import PlaceAvatar from './PlaceAvatar';
|
||||
|
||||
const basePlaceNoImage = {
|
||||
id: 1,
|
||||
name: 'Eiffel Tower',
|
||||
image_url: null,
|
||||
google_place_id: null,
|
||||
osm_id: null,
|
||||
lat: 48.8584,
|
||||
lng: 2.2945,
|
||||
};
|
||||
|
||||
const basePlaceWithImage = {
|
||||
...basePlaceNoImage,
|
||||
image_url: 'https://example.com/eiffel.jpg',
|
||||
};
|
||||
|
||||
describe('PlaceAvatar', () => {
|
||||
it('FE-COMP-AVATAR-001: renders an image when image_url is provided', () => {
|
||||
render(<PlaceAvatar place={basePlaceWithImage} />);
|
||||
const img = screen.getByRole('img');
|
||||
expect(img).toBeTruthy();
|
||||
expect((img as HTMLImageElement).src).toContain('eiffel.jpg');
|
||||
});
|
||||
|
||||
it('FE-COMP-AVATAR-002: image has correct alt text equal to place.name', () => {
|
||||
render(<PlaceAvatar place={basePlaceWithImage} />);
|
||||
const img = screen.getByAltText('Eiffel Tower');
|
||||
expect(img).toBeTruthy();
|
||||
});
|
||||
|
||||
it('FE-COMP-AVATAR-003: renders an icon (no img) when no image_url', () => {
|
||||
render(<PlaceAvatar place={basePlaceNoImage} />);
|
||||
expect(screen.queryByRole('img')).toBeNull();
|
||||
// The wrapper div should still be present
|
||||
const { container } = render(<PlaceAvatar place={basePlaceNoImage} />);
|
||||
expect(container.querySelector('div')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('FE-COMP-AVATAR-004: uses category color as background color', () => {
|
||||
const { container } = render(
|
||||
<PlaceAvatar place={basePlaceWithImage} category={{ color: '#ff5733', icon: 'MapPin' }} />
|
||||
);
|
||||
const wrapper = container.firstElementChild as HTMLElement;
|
||||
expect(wrapper.style.backgroundColor).toBe('rgb(255, 87, 51)');
|
||||
});
|
||||
|
||||
it('FE-COMP-AVATAR-005: uses default indigo color when no category provided', () => {
|
||||
const { container } = render(<PlaceAvatar place={basePlaceWithImage} />);
|
||||
const wrapper = container.firstElementChild as HTMLElement;
|
||||
expect(wrapper.style.backgroundColor).toBe('rgb(99, 102, 241)');
|
||||
});
|
||||
|
||||
it('FE-COMP-AVATAR-006: falls back to icon when image fails to load', () => {
|
||||
render(<PlaceAvatar place={basePlaceWithImage} />);
|
||||
const img = screen.getByRole('img');
|
||||
// Simulate image load error
|
||||
act(() => {
|
||||
fireEvent.error(img);
|
||||
});
|
||||
// After error, img is removed and icon takes over
|
||||
expect(screen.queryByRole('img')).toBeNull();
|
||||
});
|
||||
|
||||
it('FE-COMP-AVATAR-007: respects the size prop for container dimensions', () => {
|
||||
const { container } = render(<PlaceAvatar place={basePlaceWithImage} size={64} />);
|
||||
const wrapper = container.firstElementChild as HTMLElement;
|
||||
expect(wrapper.style.width).toBe('64px');
|
||||
expect(wrapper.style.height).toBe('64px');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user