db6b727902
20 component tests covering Button (variants, disabled state, event handlers) and ProductCard (rendering, price formatting, sale badge, image fallback). README documents the full suite: 151 tests across 10 files, how to run, mock patterns, and what's missing by priority (checkout flow, admin routes, more components).
77 lines
2.5 KiB
TypeScript
77 lines
2.5 KiB
TypeScript
import { describe, it, expect } from 'vitest'
|
|
import { render, screen } from '@testing-library/react'
|
|
import { ProductCard } from '@/components/storefront/ProductCard'
|
|
|
|
vi.mock('next/link', () => ({
|
|
default: ({ href, children, className }: any) => (
|
|
<a href={href} className={className}>{children}</a>
|
|
),
|
|
}))
|
|
|
|
const baseProduct = {
|
|
id: 'prod-1',
|
|
title: 'Maglietta Blu',
|
|
slug: 'maglietta-blu',
|
|
basePrice: 2999,
|
|
currency: 'EUR',
|
|
images: [{ url: '/uploads/prod-1/photo.jpg', altText: 'Maglietta blu' }],
|
|
}
|
|
|
|
describe('ProductCard', () => {
|
|
it('renders the product title', () => {
|
|
render(<ProductCard product={baseProduct} />)
|
|
expect(screen.getByText('Maglietta Blu')).toBeTruthy()
|
|
})
|
|
|
|
it('formats price correctly (cents → euros with 2 decimals)', () => {
|
|
render(<ProductCard product={baseProduct} />)
|
|
expect(screen.getByText(/29\.99/)).toBeTruthy()
|
|
})
|
|
|
|
it('shows the currency', () => {
|
|
render(<ProductCard product={baseProduct} />)
|
|
expect(screen.getByText(/EUR/)).toBeTruthy()
|
|
})
|
|
|
|
it('links to the correct product URL', () => {
|
|
const { container } = render(<ProductCard product={baseProduct} />)
|
|
const link = container.querySelector('a')
|
|
expect(link?.getAttribute('href')).toBe('/products/maglietta-blu')
|
|
})
|
|
|
|
it('renders the product image when images are present', () => {
|
|
render(<ProductCard product={baseProduct} />)
|
|
const img = screen.getByRole('img')
|
|
expect(img.getAttribute('src')).toBe('/uploads/prod-1/photo.jpg')
|
|
})
|
|
|
|
it('uses altText when provided', () => {
|
|
render(<ProductCard product={baseProduct} />)
|
|
expect(screen.getByRole('img').getAttribute('alt')).toBe('Maglietta blu')
|
|
})
|
|
|
|
it('falls back to product title as alt text when altText is null', () => {
|
|
const product = {
|
|
...baseProduct,
|
|
images: [{ url: '/img.jpg', altText: null }],
|
|
}
|
|
render(<ProductCard product={product} />)
|
|
expect(screen.getByRole('img').getAttribute('alt')).toBe('Maglietta Blu')
|
|
})
|
|
|
|
it('shows "No image" placeholder when images array is empty', () => {
|
|
render(<ProductCard product={{ ...baseProduct, images: [] }} />)
|
|
expect(screen.getByText('No image')).toBeTruthy()
|
|
})
|
|
|
|
it('does not render img tag when no images', () => {
|
|
render(<ProductCard product={{ ...baseProduct, images: [] }} />)
|
|
expect(screen.queryByRole('img')).toBeNull()
|
|
})
|
|
|
|
it('formats price = 0 correctly', () => {
|
|
render(<ProductCard product={{ ...baseProduct, basePrice: 0 }} />)
|
|
expect(screen.getByText(/0\.00/)).toBeTruthy()
|
|
})
|
|
})
|