import { cleanup, fireEvent, render, screen, within } from '@testing-library/react' import { afterEach, describe, expect, it } from 'vitest' import { PARTNER_TICKER_ITEM_WIDTH_PX, PARTNER_TICKER_MIN_DURATION_SECONDS, PARTNER_TICKER_SPEED_PX_PER_SECOND, PartnerTicker, partnerTickerDurationSeconds, } from '@/spa/components/ui/partner-ticker' const logos = ['RSM', 'WWK', 'münchen.tv'].map((name) => ({ id: name, label: {name}, })) describe('homepage partner ticker', () => { afterEach(() => cleanup()) it('derives a calm duration from the exact single-copy track length', () => { expect(partnerTickerDurationSeconds(0)).toBe(0) expect(partnerTickerDurationSeconds(1)).toBe(PARTNER_TICKER_MIN_DURATION_SECONDS) expect(partnerTickerDurationSeconds(12)).toBe( (12 * PARTNER_TICKER_ITEM_WIDTH_PX) / PARTNER_TICKER_SPEED_PX_PER_SECOND, ) expect(partnerTickerDurationSeconds(12)).toBe(65) }) it('duplicates one identical track and translates by exactly one copy', () => { render() const copies = screen.getAllByTestId('partner-ticker-copy') expect(copies).toHaveLength(2) expect(copies[1].getAttribute('aria-hidden')).toBe('true') expect(within(copies[0]).getAllByText(/RSM|WWK|münchen.tv/)).toHaveLength(logos.length) expect(within(copies[1]).getAllByText(/RSM|WWK|münchen.tv/)).toHaveLength(logos.length) const ticker = screen.getByTestId('partner-ticker') const styles = ticker.querySelector('style')?.textContent || '' expect(styles).toContain('to { transform: translateX(-50%); }') }) it('pauses for pointer hover and keyboard focus within the ticker', () => { render() const ticker = screen.getByTestId('partner-ticker') const track = screen.getByTestId('partner-ticker-track') expect(track.style.animationPlayState).toBe('running') fireEvent.mouseEnter(ticker) expect(track.style.animationPlayState).toBe('paused') fireEvent.mouseLeave(ticker) expect(track.style.animationPlayState).toBe('running') fireEvent.focus(ticker) expect(track.style.animationPlayState).toBe('paused') fireEvent.blur(ticker) expect(track.style.animationPlayState).toBe('running') }) it('provides a non-animated, horizontally accessible reduced-motion presentation', () => { render() const ticker = screen.getByTestId('partner-ticker') const styles = ticker.querySelector('style')?.textContent || '' expect(ticker.getAttribute('tabindex')).toBe('0') expect(styles).toContain('@media (prefers-reduced-motion: reduce)') expect(styles).toContain('overflow-x: auto !important') expect(styles).toContain('animation: none !important') expect(styles).toContain('.partner-ticker-copy[aria-hidden="true"]') expect(styles).toContain('display: none !important') }) })