Skip to content

Commit 0496951

Browse files
anurag2787kasya
andauthored
Fix #1807: Added test for DashboardCard component (#2058)
* Added test for DashboardCard component * Added more test --------- Co-authored-by: Kate Golovanova <[email protected]>
1 parent 09937b2 commit 0496951

File tree

1 file changed

+238
-0
lines changed

1 file changed

+238
-0
lines changed
Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
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+
const p = screen.getByTestId('secondary-content').querySelector('p')
81+
expect(p).not.toBeInTheDocument()
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+
const heading = screen.getByRole('heading', { level: 3 })
179+
expect(heading).toBeInTheDocument()
180+
181+
const statsP = screen.getByText('A11y')
182+
expect(statsP.tagName).toBe('P')
183+
})
184+
it('maintains accessible markup with no stats', () => {
185+
render(<DashboardCard {...baseProps} />)
186+
187+
const heading = screen.getByRole('heading', { level: 3 })
188+
expect(heading).toBeInTheDocument()
189+
190+
const paragraphs = screen.queryAllByRole('paragraph')
191+
expect(paragraphs).toHaveLength(0)
192+
})
193+
})
194+
195+
describe('Component Integration', () => {
196+
it('renders AnchorTitle and SecondaryCard with correct props', () => {
197+
render(<DashboardCard {...baseProps} stats="integration" className="integration-class" />)
198+
expect(screen.getByTestId('anchor-title')).toHaveTextContent('Test Card')
199+
expect(screen.getByTestId('secondary-card')).toHaveClass('integration-class')
200+
expect(screen.getByTestId('secondary-content')).toBeInTheDocument()
201+
})
202+
203+
it('ignores unknown/extra props', () => {
204+
// @ts-expect-error purposely passing extra prop
205+
render(<DashboardCard {...baseProps} extraProp="shouldBeIgnored" />)
206+
expect(screen.getByTestId('secondary-card')).toBeInTheDocument()
207+
})
208+
})
209+
210+
describe('Performance and Optimization', () => {
211+
it('renders efficiently with multiple re-renders', () => {
212+
const { rerender } = render(<DashboardCard {...baseProps} stats="0" />)
213+
for (let i = 0; i < 10; i++) {
214+
rerender(<DashboardCard {...baseProps} stats={i.toString()} />)
215+
expect(screen.getByText(i.toString())).toBeInTheDocument()
216+
}
217+
})
218+
219+
it('handles rapid prop changes gracefully', () => {
220+
const { rerender } = render(<DashboardCard {...baseProps} stats="start" />)
221+
const icons = [faUser, faChartBar]
222+
const titles = ['A', 'B', 'C']
223+
for (let i = 0; i < 3; i++) {
224+
rerender(
225+
<DashboardCard
226+
title={titles[i]}
227+
icon={icons[i % 2]}
228+
stats={i.toString()}
229+
className={`class${i}`}
230+
/>
231+
)
232+
expect(screen.getByTestId('anchor-title')).toHaveTextContent(titles[i])
233+
expect(screen.getByText(i.toString())).toBeInTheDocument()
234+
expect(screen.getByTestId('secondary-card')).toHaveClass(`class${i}`)
235+
}
236+
})
237+
})
238+
})

0 commit comments

Comments
 (0)