| 
 | 1 | +import { faUser, faChartBar } from '@fortawesome/free-solid-svg-icons'  | 
 | 2 | +import { render, screen } from '@testing-library/react'  | 
 | 3 | +import React from 'react'  | 
 | 4 | +import '@testing-library/jest-dom'  | 
 | 5 | +import DashboardCard from 'components/DashboardCard'  | 
 | 6 | + | 
 | 7 | +jest.mock('components/AnchorTitle', () => ({  | 
 | 8 | +  __esModule: true,  | 
 | 9 | +  default: ({  | 
 | 10 | +    title,  | 
 | 11 | +    className,  | 
 | 12 | +    ...props  | 
 | 13 | +  }: {  | 
 | 14 | +    title: string  | 
 | 15 | +    className?: string  | 
 | 16 | +    [key: string]: unknown  | 
 | 17 | +  }) => (  | 
 | 18 | +    <span className={className} data-testid="anchor-title" {...props}>  | 
 | 19 | +      {title}  | 
 | 20 | +    </span>  | 
 | 21 | +  ),  | 
 | 22 | +}))  | 
 | 23 | + | 
 | 24 | +jest.mock('components/SecondaryCard', () => ({  | 
 | 25 | +  __esModule: true,  | 
 | 26 | +  default: ({  | 
 | 27 | +    title,  | 
 | 28 | +    children,  | 
 | 29 | +    className,  | 
 | 30 | +    ...props  | 
 | 31 | +  }: {  | 
 | 32 | +    _icon: unknown  | 
 | 33 | +    title: React.ReactNode  | 
 | 34 | +    children: React.ReactNode  | 
 | 35 | +    className?: string  | 
 | 36 | +    [key: string]: unknown  | 
 | 37 | +  }) => (  | 
 | 38 | +    <div data-testid="secondary-card" className={className} {...props}>  | 
 | 39 | +      <h3>{title}</h3>  | 
 | 40 | +      <div data-testid="secondary-content">{children}</div>  | 
 | 41 | +    </div>  | 
 | 42 | +  ),  | 
 | 43 | +}))  | 
 | 44 | + | 
 | 45 | +describe('DashboardCard', () => {  | 
 | 46 | +  const baseProps = {  | 
 | 47 | +    title: 'Test Card',  | 
 | 48 | +    icon: faUser,  | 
 | 49 | +    className: undefined,  | 
 | 50 | +    stats: undefined,  | 
 | 51 | +  }  | 
 | 52 | + | 
 | 53 | +  beforeEach(() => {  | 
 | 54 | +    jest.clearAllMocks()  | 
 | 55 | +  })  | 
 | 56 | + | 
 | 57 | +  describe('Essential Rendering', () => {  | 
 | 58 | +    it('renders successfully with minimal required props', () => {  | 
 | 59 | +      render(<DashboardCard title="Test Card" icon={faUser} />)  | 
 | 60 | +      expect(screen.getByTestId('secondary-card')).toBeInTheDocument()  | 
 | 61 | +      expect(screen.getByTestId('anchor-title')).toHaveTextContent('Test Card')  | 
 | 62 | +      expect(screen.getByTestId('secondary-content')).toBeInTheDocument()  | 
 | 63 | +    })  | 
 | 64 | + | 
 | 65 | +    it('renders all text content correctly', () => {  | 
 | 66 | +      render(<DashboardCard {...baseProps} stats="42" />)  | 
 | 67 | +      expect(screen.getByTestId('anchor-title')).toHaveTextContent('Test Card')  | 
 | 68 | +      expect(screen.getByText('42')).toBeInTheDocument()  | 
 | 69 | +    })  | 
 | 70 | +  })  | 
 | 71 | + | 
 | 72 | +  describe('Conditional Rendering', () => {  | 
 | 73 | +    it('renders stats when provided', () => {  | 
 | 74 | +      render(<DashboardCard {...baseProps} stats="123" />)  | 
 | 75 | +      expect(screen.getByText('123')).toBeInTheDocument()  | 
 | 76 | +    })  | 
 | 77 | + | 
 | 78 | +    it('does not render stats paragraph if stats is not provided', () => {  | 
 | 79 | +      render(<DashboardCard {...baseProps} />)  | 
 | 80 | +      expect(screen.queryByText('123')).not.toBeInTheDocument()  | 
 | 81 | +    })  | 
 | 82 | + | 
 | 83 | +    it('does not render <p> if stats is an empty string', () => {  | 
 | 84 | +      render(<DashboardCard {...baseProps} stats="" />)  | 
 | 85 | +      const p = screen.getByTestId('secondary-content').querySelector('p')  | 
 | 86 | +      expect(p).not.toBeInTheDocument()  | 
 | 87 | +    })  | 
 | 88 | +  })  | 
 | 89 | + | 
 | 90 | +  describe('Prop-based Behavior', () => {  | 
 | 91 | +    it('applies custom className', () => {  | 
 | 92 | +      render(<DashboardCard {...baseProps} className="custom-class" />)  | 
 | 93 | +      expect(screen.getByTestId('secondary-card')).toHaveClass('custom-class')  | 
 | 94 | +    })  | 
 | 95 | + | 
 | 96 | +    it('applies multiple custom classes', () => {  | 
 | 97 | +      render(<DashboardCard {...baseProps} className="foo bar baz" />)  | 
 | 98 | +      expect(screen.getByTestId('secondary-card')).toHaveClass('foo')  | 
 | 99 | +      expect(screen.getByTestId('secondary-card')).toHaveClass('bar')  | 
 | 100 | +      expect(screen.getByTestId('secondary-card')).toHaveClass('baz')  | 
 | 101 | +    })  | 
 | 102 | + | 
 | 103 | +    it('renders different icons based on prop', () => {  | 
 | 104 | +      const { rerender } = render(<DashboardCard {...baseProps} icon={faUser} />)  | 
 | 105 | +      expect(screen.getByTestId('secondary-content').querySelector('svg')).toBeInTheDocument()  | 
 | 106 | +      rerender(<DashboardCard {...baseProps} icon={faChartBar} />)  | 
 | 107 | +      expect(screen.getByTestId('secondary-content').querySelector('svg')).toBeInTheDocument()  | 
 | 108 | +    })  | 
 | 109 | +  })  | 
 | 110 | + | 
 | 111 | +  describe('DOM Structure', () => {  | 
 | 112 | +    it('renders FontAwesomeIcon with correct icon', () => {  | 
 | 113 | +      render(<DashboardCard {...baseProps} />)  | 
 | 114 | +      expect(screen.getByTestId('secondary-content').querySelector('svg')).toBeInTheDocument()  | 
 | 115 | +    })  | 
 | 116 | + | 
 | 117 | +    it('renders stats inside a <p> tag', () => {  | 
 | 118 | +      render(<DashboardCard {...baseProps} stats="StatsText" />)  | 
 | 119 | +      const p = screen.getByText('StatsText')  | 
 | 120 | +      expect(p.tagName).toBe('P')  | 
 | 121 | +    })  | 
 | 122 | + | 
 | 123 | +    it('always renders the span for icon/stats', () => {  | 
 | 124 | +      render(<DashboardCard {...baseProps} />)  | 
 | 125 | +      const span = screen.getByTestId('secondary-content').querySelector('span')  | 
 | 126 | +      expect(span).toBeInTheDocument()  | 
 | 127 | +      expect(span).toHaveClass('flex', 'items-center', 'gap-2', 'text-2xl', 'font-light')  | 
 | 128 | +    })  | 
 | 129 | + | 
 | 130 | +    it('renders correct DOM structure and classes', () => {  | 
 | 131 | +      render(<DashboardCard {...baseProps} stats="42" className="test-class" />)  | 
 | 132 | +      const card = screen.getByTestId('secondary-card')  | 
 | 133 | +      expect(card).toHaveClass('overflow-hidden')  | 
 | 134 | +      expect(card).toHaveClass('transition-colors')  | 
 | 135 | +      expect(card).toHaveClass('duration-300')  | 
 | 136 | +      expect(card).toHaveClass('hover:bg-blue-100')  | 
 | 137 | +      expect(card).toHaveClass('dark:hover:bg-blue-950')  | 
 | 138 | +      expect(card).toHaveClass('test-class')  | 
 | 139 | +    })  | 
 | 140 | +  })  | 
 | 141 | + | 
 | 142 | +  describe('Edge Cases', () => {  | 
 | 143 | +    it('renders stats as string and handles edge cases', () => {  | 
 | 144 | +      render(<DashboardCard {...baseProps} stats={'0'} />)  | 
 | 145 | +      expect(screen.getByText('0')).toBeInTheDocument()  | 
 | 146 | +      render(<DashboardCard {...baseProps} stats={'-999'} />)  | 
 | 147 | +      expect(screen.getByText('-999')).toBeInTheDocument()  | 
 | 148 | +      render(<DashboardCard {...baseProps} stats={'9999999999'} />)  | 
 | 149 | +      expect(screen.getByText('9999999999')).toBeInTheDocument()  | 
 | 150 | +    })  | 
 | 151 | + | 
 | 152 | +    it('renders with an empty string title', () => {  | 
 | 153 | +      render(<DashboardCard {...baseProps} title="" />)  | 
 | 154 | +      expect(screen.getByTestId('anchor-title')).toHaveTextContent('')  | 
 | 155 | +    })  | 
 | 156 | + | 
 | 157 | +    it('renders with a very long title', () => {  | 
 | 158 | +      const longTitle = 'A'.repeat(1000)  | 
 | 159 | +      render(<DashboardCard {...baseProps} title={longTitle} />)  | 
 | 160 | +      expect(screen.getByTestId('anchor-title')).toHaveTextContent(longTitle)  | 
 | 161 | +    })  | 
 | 162 | + | 
 | 163 | +    it('does not render <p> if stats is undefined or null', () => {  | 
 | 164 | +      const { unmount } = render(<DashboardCard {...baseProps} stats={undefined} />)  | 
 | 165 | +      expect(screen.getByTestId('secondary-content').querySelector('p')).not.toBeInTheDocument()  | 
 | 166 | +      unmount()  | 
 | 167 | +      render(<DashboardCard {...baseProps} stats={null as unknown as string} />)  | 
 | 168 | +      expect(screen.getByTestId('secondary-content').querySelector('p')).not.toBeInTheDocument()  | 
 | 169 | +    })  | 
 | 170 | +  })  | 
 | 171 | + | 
 | 172 | +  describe('Accessibility', () => {  | 
 | 173 | +    it('is accessible with semantic structure', () => {  | 
 | 174 | +      render(<DashboardCard {...baseProps} stats="A11y" />)  | 
 | 175 | +      expect(screen.getByTestId('secondary-card')).toBeInTheDocument()  | 
 | 176 | +      expect(screen.getByTestId('anchor-title')).toBeInTheDocument()  | 
 | 177 | +    })  | 
 | 178 | +  })  | 
 | 179 | + | 
 | 180 | +  describe('Component Integration', () => {  | 
 | 181 | +    it('renders AnchorTitle and SecondaryCard with correct props', () => {  | 
 | 182 | +      render(<DashboardCard {...baseProps} stats="integration" className="integration-class" />)  | 
 | 183 | +      expect(screen.getByTestId('anchor-title')).toHaveTextContent('Test Card')  | 
 | 184 | +      expect(screen.getByTestId('secondary-card')).toHaveClass('integration-class')  | 
 | 185 | +      expect(screen.getByTestId('secondary-content')).toBeInTheDocument()  | 
 | 186 | +    })  | 
 | 187 | + | 
 | 188 | +    it('ignores unknown/extra props', () => {  | 
 | 189 | +      // @ts-expect-error purposely passing extra prop  | 
 | 190 | +      render(<DashboardCard {...baseProps} extraProp="shouldBeIgnored" />)  | 
 | 191 | +      expect(screen.getByTestId('secondary-card')).toBeInTheDocument()  | 
 | 192 | +    })  | 
 | 193 | +  })  | 
 | 194 | + | 
 | 195 | +  describe('Performance and Optimization', () => {  | 
 | 196 | +    it('renders efficiently with multiple re-renders', () => {  | 
 | 197 | +      const { rerender } = render(<DashboardCard {...baseProps} stats="0" />)  | 
 | 198 | +      for (let i = 0; i < 10; i++) {  | 
 | 199 | +        rerender(<DashboardCard {...baseProps} stats={i.toString()} />)  | 
 | 200 | +        expect(screen.getByText(i.toString())).toBeInTheDocument()  | 
 | 201 | +      }  | 
 | 202 | +    })  | 
 | 203 | + | 
 | 204 | +    it('handles rapid prop changes gracefully', () => {  | 
 | 205 | +      const { rerender } = render(<DashboardCard {...baseProps} stats="start" />)  | 
 | 206 | +      const icons = [faUser, faChartBar]  | 
 | 207 | +      const titles = ['A', 'B', 'C']  | 
 | 208 | +      for (let i = 0; i < 3; i++) {  | 
 | 209 | +        rerender(  | 
 | 210 | +          <DashboardCard  | 
 | 211 | +            title={titles[i]}  | 
 | 212 | +            icon={icons[i % 2]}  | 
 | 213 | +            stats={i.toString()}  | 
 | 214 | +            className={`class${i}`}  | 
 | 215 | +          />  | 
 | 216 | +        )  | 
 | 217 | +        expect(screen.getByTestId('anchor-title')).toHaveTextContent(titles[i])  | 
 | 218 | +        expect(screen.getByText(i.toString())).toBeInTheDocument()  | 
 | 219 | +        expect(screen.getByTestId('secondary-card')).toHaveClass(`class${i}`)  | 
 | 220 | +      }  | 
 | 221 | +    })  | 
 | 222 | +  })  | 
 | 223 | +})  | 
0 commit comments