import {describe, expect, it, vi, beforeEach, afterEach} from 'vitest' import { render, screen, userEvent, mockShop, mockMinisSDK, resetAllMocks, } from '../../test-utils' import { MerchantCard, MerchantCardContainer, MerchantCardHeader, MerchantCardInfo, MerchantCardName, MerchantCardRating, } from './merchant-card' // Mock hooks vi.mock('../../hooks/navigation/useShopNavigation', () => ({ useShopNavigation: () => ({ navigateToShop: mockMinisSDK.navigateToShop, navigateToProduct: mockMinisSDK.navigateToProduct, }), })) // Mock utils with simple implementations vi.mock('../../utils', () => ({ extractBrandTheme: vi.fn(() => ({ type: 'default', backgroundColor: 'white', })), getFeaturedImages: vi.fn(() => []), formatReviewCount: vi.fn((count: number) => { if (count >= 1000) return `${(count / 1000).toFixed(1)}k` return count.toString() }), normalizeRating: vi.fn((rating: number) => rating.toFixed(1)), })) vi.mock('../../utils/colors', () => ({ isDarkColor: vi.fn(() => false), })) describe('MerchantCard', () => { beforeEach(() => { resetAllMocks() }) afterEach(() => { vi.clearAllMocks() }) describe('Rendering', () => { it('renders with basic shop information', () => { const shop = mockShop() render() expect(screen.getByText(shop.name)).toBeInTheDocument() // createShop returns 4.3 rating with 50 reviews expect(screen.getByText('4.3 (50)')).toBeInTheDocument() // Rating and review count }) it('renders shop logo when available', () => { const shop = mockShop({ visualTheme: { logoImage: { url: 'https://example.com/logo.png', altText: 'Shop Logo', sensitive: false, }, featuredImages: [], id: '123', }, }) render() const logo = screen.getByAltText(`${shop.name} logo`) expect(logo).toBeInTheDocument() expect(logo).toHaveAttribute('src', 'https://example.com/logo.png') }) it('renders shop initial when logo is not available', () => { const shop = mockShop({ name: 'Test Shop', visualTheme: null, }) render() expect(screen.getByText('T')).toBeInTheDocument() }) it('renders without reviews when not available', () => { const shop = mockShop({ reviewAnalytics: { averageRating: null, reviewCount: 0, }, }) render() expect( screen.queryByTestId('merchant-card-rating') ).not.toBeInTheDocument() }) }) describe('Interactions', () => { it('handles shop click navigation', async () => { const user = userEvent.setup() const shop = mockShop() render() const card = screen.getByText(shop.name).closest('div') ?.parentElement?.parentElement await user.click(card!) expect(mockMinisSDK.navigateToShop).toHaveBeenCalledWith({ shopId: shop.id, }) }) it('does not navigate when touchable is false', async () => { const user = userEvent.setup() const shop = mockShop() render() const card = screen.getByText(shop.name).closest('div') ?.parentElement?.parentElement await user.click(card!) expect(mockMinisSDK.navigateToShop).not.toHaveBeenCalled() }) }) describe('Custom Composition', () => { it('renders with custom children layout', () => { const shop = mockShop() render(
Custom Name
) expect(screen.getByTestId('custom-layout')).toBeInTheDocument() expect(screen.getByText('Custom Name')).toBeInTheDocument() // createShop returns 4.3 rating with 50 reviews expect(screen.getByText('4.3 (50)')).toBeInTheDocument() }) it('allows individual component usage', () => { const shop = mockShop() render( ) expect(screen.getByText(shop.name)).toBeInTheDocument() // createShop returns 4.3 rating with 50 reviews expect(screen.getByText('4.3 (50)')).toBeInTheDocument() }) }) describe('Edge Cases', () => { it('handles shop without visual theme', () => { const shop = mockShop({ visualTheme: null, }) render() expect(screen.getByText(shop.name)).toBeInTheDocument() }) it('handles shop with empty name', () => { const shop = mockShop({ name: '', }) render() // Should still render with empty name const heading = screen.getByRole('heading', {level: 3}) expect(heading).toBeInTheDocument() }) it('handles very long shop names', () => { const shop = mockShop({ name: 'This is a very long shop name that should be truncated in the UI', }) render() const nameElement = screen.getByText(shop.name) expect(nameElement).toHaveClass('truncate') }) it('handles high review counts', () => { const shop = mockShop({ reviewAnalytics: { averageRating: 4.8, reviewCount: 12500, }, }) render() expect(screen.getByText('4.8 (12.5k)')).toBeInTheDocument() }) }) describe('Accessibility', () => { it('maintains proper heading hierarchy', () => { const shop = mockShop() render() const heading = screen.getByRole('heading', {level: 3}) expect(heading).toHaveTextContent(shop.name) }) it('provides fallback alt text for logo', () => { const shop = mockShop({ visualTheme: { logoImage: { url: 'https://example.com/logo.png', altText: null, sensitive: false, }, featuredImages: [], id: '123', }, }) render() const logo = screen.getByAltText(`${shop.name} logo`) expect(logo).toBeInTheDocument() }) }) })