import React from 'react'; import { render, screen, fireEvent } from '@testing-library/react'; import '@testing-library/jest-dom'; import { TripCard } from '../TripCard'; import { TripCardApiData } from '../types'; import { tealiumTrackingHandler } from '../../../helpers/tracking/TrackingHandler'; jest.mock('../../../helpers/tracking/TrackingHandler', () => ({ tealiumTrackingHandler: jest.fn() })); const mockCard: TripCardApiData = { cruise_id: '2074350', image: 'https://example.com/image.jpg', headline: 'Mediterranean from Barcelona', date: 'Oct 2025 - Oct 2025', duration: 'Seven Days', destination: 'Barcelona → Marseille', ship: 'MSC Seaside', price: '£2000', logo: 'https://example.com/logo.png', logo_url: 'https://example.com', logo_name: 'MSC Cruises', cta_url: 'https://example.com/cruise', cta_text: 'View Itinerary' }; describe('TripCard', () => { beforeEach(() => { jest.clearAllMocks(); }); it('renders card with all required data', () => { render(); expect( screen.getByText('Mediterranean from Barcelona') ).toBeInTheDocument(); expect(screen.getByText('Oct 2025 - Oct 2025')).toBeInTheDocument(); expect(screen.getByText('Seven Days')).toBeInTheDocument(); expect(screen.getByText('Barcelona → Marseille')).toBeInTheDocument(); expect(screen.getByText('MSC Seaside')).toBeInTheDocument(); expect(screen.getByText('£2000')).toBeInTheDocument(); expect(screen.getByText('From')).toBeInTheDocument(); expect(screen.getByText('View Itinerary')).toBeInTheDocument(); }); it('renders image with correct src and alt', () => { render(); const image = screen.getByAltText('Mediterranean from Barcelona'); expect(image).toHaveAttribute('src', 'https://example.com/image.jpg'); }); it('renders offer label when provided', () => { const cardWithOffer = { ...mockCard, offer_label: 'Special Offer' }; render(); expect(screen.getByText('Special Offer')).toBeInTheDocument(); }); it('renders gift banner when provided', () => { const cardWithGift = { ...mockCard, gift_banner: 'Free gift with purchase' }; render(); expect(screen.getByText('Free gift with purchase')).toBeInTheDocument(); }); it('renders original price when provided', () => { const cardWithOriginalPrice = { ...mockCard, original_price: '£2500' }; render(); expect(screen.getByText('£2500pp')).toBeInTheDocument(); }); it('does not render "From" when price is "Enquire now"', () => { const cardWithEnquire = { ...mockCard, price: 'Enquire now' }; render(); expect(screen.queryByText('From')).not.toBeInTheDocument(); expect(screen.getByText('Enquire now')).toBeInTheDocument(); }); it('renders all CTA links with correct href and target', () => { render(); const links = screen.getAllByRole('link'); const imageLink = links[0]; const headlineLink = links[1]; const ctaButton = screen.getByText('View Itinerary').closest('a'); expect(imageLink).toHaveAttribute('href', 'https://example.com/cruise'); expect(imageLink).toHaveAttribute('target', '_blank'); expect(headlineLink).toHaveAttribute('href', 'https://example.com/cruise'); expect(ctaButton).toHaveAttribute('href', 'https://example.com/cruise'); }); it('renders logo with link when provided', () => { render(); const logoLink = screen.getByRole('link', { name: /partner logo/i }); expect(logoLink).toHaveAttribute('href', 'https://example.com'); const logoImg = screen.getByAltText('Partner logo'); expect(logoImg).toHaveAttribute('src', 'https://example.com/logo.png'); }); it('shows card image after it loads', () => { render(); const cardImage = screen.getByAltText('Mediterranean from Barcelona'); expect(cardImage).toHaveStyle({ display: 'none' }); fireEvent.load(cardImage); expect(cardImage).toHaveStyle({ display: 'block' }); }); describe('Tracking', () => { it('calls tealiumTrackingHandler when headline is clicked', () => { render(); const headlineLink = screen.getAllByRole('link')[1]; fireEvent.click(headlineLink); expect(tealiumTrackingHandler).toHaveBeenCalledWith( 'trip card: Mediterranean from Barcelona', 'navigation', 'click', 'Mediterranean from Barcelona', undefined, { app_content_location: expect.any(String) } ); }); it('calls tealiumTrackingHandler when image is clicked', () => { render(); const imageLink = screen.getAllByRole('link')[0]; fireEvent.click(imageLink); expect(tealiumTrackingHandler).toHaveBeenCalledWith( 'trip card: img click', 'navigation', 'click', 'Mediterranean from Barcelona', undefined, { app_content_location: expect.any(String) } ); }); it('calls tealiumTrackingHandler when CTA button is clicked', () => { render(); const ctaButton = screen.getByText('View Itinerary'); fireEvent.click(ctaButton); expect(tealiumTrackingHandler).toHaveBeenCalledWith( 'trip card: View Itinerary', 'navigation', 'click', 'Mediterranean from Barcelona', undefined, { app_content_location: expect.any(String) } ); }); it('calls tealiumTrackingHandler with default CTA text when not provided', () => { const cardWithoutCTAText = { ...mockCard, cta_text: undefined }; render(); const ctaButton = screen.getByText('View Itinerary'); fireEvent.click(ctaButton); expect(tealiumTrackingHandler).toHaveBeenCalledWith( 'trip card: View Itinerary', 'navigation', 'click', 'Mediterranean from Barcelona', undefined, { app_content_location: expect.any(String) } ); }); it('calls tealiumTrackingHandler when logo is clicked with empty logo_name', () => { const cardWithoutLogoName = { ...mockCard, logo_name: '' }; render(); const logoLink = screen.getByRole('link', { name: /partner logo/i }); fireEvent.click(logoLink); expect(tealiumTrackingHandler).toHaveBeenCalledWith( 'trip card: ', 'navigation', 'click', 'Mediterranean from Barcelona', undefined, { app_content_location: expect.any(String) } ); }); it('calls tealiumTrackingHandler with logo_name when provided', () => { const cardWithLogoName = { ...mockCard, logo_name: 'MSC Cruises' }; render(); const logoLink = screen.getByRole('link', { name: /partner logo/i }); fireEvent.click(logoLink); expect(tealiumTrackingHandler).toHaveBeenCalledWith( 'trip card: MSC Cruises', 'navigation', 'click', 'Mediterranean from Barcelona', undefined, { app_content_location: expect.any(String) } ); }); }); });