import '@testing-library/jest-dom' import { cleanup, render } from '@testing-library/react' import { axe, toHaveNoViolations } from 'jest-axe' import { createRef } from 'react' import { PktCard } from './Card' expect.extend(toHaveNoViolations) afterEach(cleanup) describe('PktCard', () => { describe('Rendering and basic functionality', () => { test('renders without errors', () => { const { container } = render(innhold) const article = container.querySelector('article.pkt-card') expect(article).toBeInTheDocument() }) test('renders content in children', () => { const { container } = render(

Test content here

) const content = container.querySelector('.pkt-card__content') expect(content).toBeInTheDocument() expect(content?.textContent).toContain('Test content here') }) test('renders basic structure correctly', () => { const { container } = render(Test content) const article = container.querySelector('article') const wrapper = article?.querySelector('.pkt-card__wrapper') const header = wrapper?.querySelector('.pkt-card__header') const content = wrapper?.querySelector('.pkt-card__content') expect(wrapper).toBeInTheDocument() expect(header).toBeInTheDocument() expect(content).toBeInTheDocument() }) test('forwards ref correctly', () => { const ref = createRef() const { unmount } = render(innhold) expect(ref.current).toBeInstanceOf(HTMLElement) unmount() expect(ref.current).toBeNull() }) }) describe('Properties and attributes', () => { test('applies default properties correctly', () => { const { container } = render(innhold) const article = container.querySelector('article') expect(article).toHaveClass('pkt-card--outlined') expect(article).toHaveClass('pkt-card--vertical') expect(article).toHaveClass('pkt-card--padding-default') expect(article).toHaveClass('pkt-card--border-on-hover') }) test('applies different skin properties correctly', () => { const skins = ['outlined', 'outlined-beige', 'gray', 'beige', 'green', 'blue'] as const for (const skin of skins) { const { container, unmount } = render(innhold) const article = container.querySelector('article') expect(article).toHaveClass(`pkt-card--${skin}`) unmount() } }) test('applies different layout properties correctly', () => { const layouts = ['vertical', 'horizontal'] as const for (const layout of layouts) { const { container, unmount } = render(innhold) const article = container.querySelector('article') expect(article).toHaveClass(`pkt-card--${layout}`) unmount() } }) test('applies different padding properties correctly', () => { const paddingOptions = ['none', 'default'] as const for (const padding of paddingOptions) { const { container, unmount } = render(innhold) const article = container.querySelector('article') expect(article).toHaveClass(`pkt-card--padding-${padding}`) unmount() } }) test('handles borderOnHover property correctly', () => { const { container } = render(innhold) const article = container.querySelector('article') expect(article).not.toHaveClass('pkt-card--border-on-hover') }) test('supports custom className', () => { const { container } = render(innhold) const wrapper = container.querySelector('.pkt-card-root') expect(wrapper).toHaveClass('custom-class') }) }) describe('Heading functionality', () => { test('renders heading when provided', () => { const { container } = render(innhold) const heading = container.querySelector('.pkt-card__heading') expect(heading).toBeInTheDocument() expect(heading?.textContent?.trim()).toBe('Test Card Title') }) test('renders subheading when provided', () => { const { container } = render(innhold) const subheading = container.querySelector('.pkt-card__subheading') expect(subheading).toBeInTheDocument() expect(subheading?.textContent).toBe('Test Subheading') }) test('applies correct heading level', () => { const { container } = render( innhold, ) const heading = container.querySelector('h2.pkt-card__heading') expect(heading).toBeInTheDocument() }) test('defaults to h3 heading level', () => { const { container } = render(innhold) const heading = container.querySelector('h3.pkt-card__heading') expect(heading).toBeInTheDocument() }) test('does not render header when no heading or subheading', () => { const { container } = render(innhold) const header = container.querySelector('.pkt-card__header') expect(header).not.toBeInTheDocument() }) }) describe('Link functionality', () => { test('renders as regular card when no clickCardLink', () => { const { container } = render(innhold) const link = container.querySelector('.pkt-card__link') expect(link).not.toBeInTheDocument() const article = container.querySelector('article') expect(article?.getAttribute('aria-label')).toBe('Test Title') }) test('renders as link card when clickCardLink provided', () => { const { container } = render( innhold, ) const linkHeading = container.querySelector('.pkt-card__link-heading') const link = container.querySelector('.pkt-card__link') expect(linkHeading).toBeInTheDocument() expect(link).toBeInTheDocument() expect(link?.getAttribute('href')).toBe('/test-url') expect(link?.textContent).toBe('Test Title') const article = container.querySelector('article') expect(article?.getAttribute('aria-label')).toBe('Test Title lenkekort') }) test('does not render plain heading when clickCardLink is set', () => { const { container } = render( innhold, ) const headings = container.querySelectorAll('.pkt-card__heading') // Should only have the link heading, not both expect(headings).toHaveLength(1) expect(headings[0]).toHaveClass('pkt-card__link-heading') }) test('handles openLinkInNewTab correctly', () => { const { container } = render( innhold, ) const link = container.querySelector('.pkt-card__link') expect(link?.getAttribute('target')).toBe('_blank') expect(link?.getAttribute('rel')).toBe('noopener noreferrer') }) test('applies correct aria-label for link cards with custom ariaLabel', () => { const { container } = render( innhold, ) const article = container.querySelector('article') expect(article?.getAttribute('aria-label')).toBe('Custom aria label') }) }) describe('Image functionality', () => { test('renders image when provided', () => { const { container } = render( innhold, ) const imageDiv = container.querySelector('.pkt-card__image') const img = imageDiv?.querySelector('img') expect(imageDiv).toBeInTheDocument() expect(img).toBeInTheDocument() expect(img?.getAttribute('src')).toBe('/test-image.jpg') expect(img?.getAttribute('alt')).toBe('Test image') }) test('does not render image when not provided', () => { const { container } = render(innhold) const imageDiv = container.querySelector('.pkt-card__image') expect(imageDiv).not.toBeInTheDocument() }) test('applies correct image shape classes', () => { const shapes = ['square', 'round'] as const for (const shape of shapes) { const { container, unmount } = render( innhold, ) const imageDiv = container.querySelector('.pkt-card__image') expect(imageDiv).toHaveClass(`pkt-card__image-${shape}`) unmount() } }) }) describe('Tags functionality', () => { test('renders tags when provided', () => { const tags = [ { text: 'Tag 1', skin: 'blue' as const }, { text: 'Tag 2', skin: 'green' as const }, ] const { container } = render(innhold) const tagsContainer = container.querySelector('.pkt-card__tags') expect(tagsContainer).toBeInTheDocument() expect(tagsContainer?.getAttribute('aria-label')).toBe('merkelapper') }) test('renders single tag with correct aria-label', () => { const tags = [{ text: 'Single Tag' }] const { container } = render(innhold) const tagsContainer = container.querySelector('.pkt-card__tags') expect(tagsContainer?.getAttribute('aria-label')).toBe('merkelapp') }) test('applies correct tag position classes', () => { const positions = ['top', 'bottom'] as const for (const position of positions) { const tags = [{ text: 'Test Tag' }] const { container, unmount } = render( innhold, ) const tagsContainer = container.querySelector('.pkt-card__tags') expect(tagsContainer).toHaveClass(`pkt-card__tags-${position}`) unmount() } }) test('does not render tags when array is empty', () => { const { container } = render(innhold) const tagsContainer = container.querySelector('.pkt-card__tags') expect(tagsContainer).not.toBeInTheDocument() }) }) describe('Metadata functionality', () => { test('renders metadata when provided', () => { const { container } = render( innhold, ) const metadata = container.querySelector('.pkt-card__metadata') const metaLead = metadata?.querySelector('.pkt-card__metadata-lead') const metaTrail = metadata?.querySelector('.pkt-card__metadata-trail') expect(metadata).toBeInTheDocument() expect(metaLead?.textContent).toBe('Author Name') expect(metaTrail?.textContent).toBe('2023-12-01') }) test('renders only metaLead when metaTrail not provided', () => { const { container } = render(innhold) const metaLead = container.querySelector('.pkt-card__metadata-lead') const metaTrail = container.querySelector('.pkt-card__metadata-trail') expect(metaLead).toBeInTheDocument() expect(metaTrail).not.toBeInTheDocument() }) test('renders only metaTrail when metaLead not provided', () => { const { container } = render(innhold) const metaLead = container.querySelector('.pkt-card__metadata-lead') const metaTrail = container.querySelector('.pkt-card__metadata-trail') expect(metaLead).not.toBeInTheDocument() expect(metaTrail).toBeInTheDocument() }) test('does not render metadata when neither provided', () => { const { container } = render(innhold) const metadata = container.querySelector('.pkt-card__metadata') expect(metadata).not.toBeInTheDocument() }) }) describe('Content placement and structure', () => { test('renders content elements in correct order', () => { const tags = [{ text: 'Test Tag' }] const { container } = render( innhold , ) const article = container.querySelector('article') const children = Array.from(article?.children || []) // Image first, then wrapper expect(children[0]).toHaveClass('pkt-card__image') expect(children[1]).toHaveClass('pkt-card__wrapper') const wrapperChildren = Array.from(children[1]?.children || []) // Order within wrapper: tags (top), header, content, metadata expect(wrapperChildren[0]).toHaveClass('pkt-card__tags-top') expect(wrapperChildren[1]).toHaveClass('pkt-card__header') expect(wrapperChildren[2]).toHaveClass('pkt-card__content') expect(wrapperChildren[3]).toHaveClass('pkt-card__metadata') }) test('places tags at bottom when tagPosition is bottom', () => { const tags = [{ text: 'Test Tag' }] const { container } = render( innhold, ) const wrapperChildren = Array.from( container.querySelector('.pkt-card__wrapper')?.children || [], ) // Order: header, content, tags (bottom) expect(wrapperChildren[0]).toHaveClass('pkt-card__header') expect(wrapperChildren[1]).toHaveClass('pkt-card__content') expect(wrapperChildren[2]).toHaveClass('pkt-card__tags-bottom') }) }) describe('Accessibility', () => { test('has no accessibility violations', async () => { const { container } = render(innhold) const results = await axe(container) expect(results).toHaveNoViolations() }) test('applies custom aria-label', () => { const { container } = render( innhold, ) const article = container.querySelector('article') expect(article?.getAttribute('aria-label')).toBe('Custom accessible label') }) test('falls back to heading for aria-label', () => { const { container } = render(innhold) const article = container.querySelector('article') expect(article?.getAttribute('aria-label')).toBe('Default Aria Label') }) test('falls back to "kort" when no heading or aria-label', () => { const { container } = render(innhold) const article = container.querySelector('article') expect(article?.getAttribute('aria-label')).toBe('kort') }) }) })