-
-
Couldn't load subscription status.
- Fork 248
Fix #1912: Added test for SecondaryCard component #2069
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
f1b7c8d
64b30cb
e57cf30
405c5f7
91dc02d
381d84f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,129 @@ | ||||||||||||||||||||||||||||||||||||||
| import { faUser } from '@fortawesome/free-solid-svg-icons'; | ||||||||||||||||||||||||||||||||||||||
| import { render, screen } from '@testing-library/react'; | ||||||||||||||||||||||||||||||||||||||
| import SecondaryCard from 'components/SecondaryCard'; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| describe('SecondaryCard Component', () => { | ||||||||||||||||||||||||||||||||||||||
| const defaultProps = { | ||||||||||||||||||||||||||||||||||||||
| title: 'Test Title', | ||||||||||||||||||||||||||||||||||||||
| icon: faUser, | ||||||||||||||||||||||||||||||||||||||
| children: <p>Test children</p>, | ||||||||||||||||||||||||||||||||||||||
| className: 'custom-class', | ||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| describe('Renders successfully with minimal required props', () => { | ||||||||||||||||||||||||||||||||||||||
| it('renders successfully with only a title', () => { | ||||||||||||||||||||||||||||||||||||||
| render(<SecondaryCard title={defaultProps.title} />); | ||||||||||||||||||||||||||||||||||||||
| expect(screen.getByText(defaultProps.title)).toBeInTheDocument(); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| it('renders successfully with only children', () => { | ||||||||||||||||||||||||||||||||||||||
| render(<SecondaryCard>{defaultProps.children}</SecondaryCard>); | ||||||||||||||||||||||||||||||||||||||
| expect(screen.getByText('Test children')).toBeInTheDocument(); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| it('renders successfully with no props at all', () => { | ||||||||||||||||||||||||||||||||||||||
| const { container } = render(<SecondaryCard />); | ||||||||||||||||||||||||||||||||||||||
| expect(container.querySelector('.mb-8')).toBeInTheDocument(); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| describe('Conditional rendering logic', () => { | ||||||||||||||||||||||||||||||||||||||
| it('does not render the h2 title element when title prop is not provided', () => { | ||||||||||||||||||||||||||||||||||||||
| render(<SecondaryCard />); | ||||||||||||||||||||||||||||||||||||||
| const titleElement = screen.queryByRole('heading'); | ||||||||||||||||||||||||||||||||||||||
| expect(titleElement).not.toBeInTheDocument(); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| it('renders the h2 title element when title prop is provided', () => { | ||||||||||||||||||||||||||||||||||||||
| render(<SecondaryCard title={defaultProps.title} />); | ||||||||||||||||||||||||||||||||||||||
| const titleElement = screen.getByRole('heading', { name: 'Test Title' }); | ||||||||||||||||||||||||||||||||||||||
| expect(titleElement).toBeInTheDocument(); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| it('does not render the icon when icon prop is not provided', () => { | ||||||||||||||||||||||||||||||||||||||
| const { container } = render(<SecondaryCard title={defaultProps.title} />); | ||||||||||||||||||||||||||||||||||||||
| const iconElement = container.querySelector('svg'); | ||||||||||||||||||||||||||||||||||||||
| expect(iconElement).not.toBeInTheDocument(); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| describe('Prop-based behavior - different props affect output', () => { | ||||||||||||||||||||||||||||||||||||||
| it('renders a title and an icon when both are provided', () => { | ||||||||||||||||||||||||||||||||||||||
| render(<SecondaryCard title={defaultProps.title} icon={defaultProps.icon} />); | ||||||||||||||||||||||||||||||||||||||
| expect(screen.getByText(defaultProps.title)).toBeInTheDocument(); | ||||||||||||||||||||||||||||||||||||||
| expect(screen.getByRole('img', { hidden: true })).toBeInTheDocument(); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| it('renders children content correctly', () => { | ||||||||||||||||||||||||||||||||||||||
| render(<SecondaryCard>{defaultProps.children}</SecondaryCard>); | ||||||||||||||||||||||||||||||||||||||
| expect(screen.getByText('Test children')).toBeInTheDocument(); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| describe('Text and content rendering', () => { | ||||||||||||||||||||||||||||||||||||||
| it('displays the correct text for the title', () => { | ||||||||||||||||||||||||||||||||||||||
| const customTitle = 'My Custom Title'; | ||||||||||||||||||||||||||||||||||||||
| render(<SecondaryCard title={customTitle} />); | ||||||||||||||||||||||||||||||||||||||
| expect(screen.getByText(customTitle)).toBeInTheDocument(); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| it('renders complex children nodes', () => { | ||||||||||||||||||||||||||||||||||||||
| const complexChildren = ( | ||||||||||||||||||||||||||||||||||||||
| <div> | ||||||||||||||||||||||||||||||||||||||
| <span>Nested Content</span> | ||||||||||||||||||||||||||||||||||||||
| <button>Click Me</button> | ||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||
| render(<SecondaryCard>{complexChildren}</SecondaryCard>); | ||||||||||||||||||||||||||||||||||||||
| expect(screen.getByText('Nested Content')).toBeInTheDocument(); | ||||||||||||||||||||||||||||||||||||||
| expect(screen.getByRole('button', { name: 'Click Me' })).toBeInTheDocument(); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| describe('Handles edge cases and invalid inputs', () => { | ||||||||||||||||||||||||||||||||||||||
| it('handles an empty string for the title prop by not rendering the title element', () => { | ||||||||||||||||||||||||||||||||||||||
| render(<SecondaryCard title="" />); | ||||||||||||||||||||||||||||||||||||||
| const titleElement = screen.queryByRole('heading'); | ||||||||||||||||||||||||||||||||||||||
| expect(titleElement).not.toBeInTheDocument(); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| it('handles null children gracefully by rendering nothing for the children', () => { | ||||||||||||||||||||||||||||||||||||||
| const { container } = render( | ||||||||||||||||||||||||||||||||||||||
| <SecondaryCard title="Title">{null}</SecondaryCard> | ||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||
| const cardElement = container.firstChild; | ||||||||||||||||||||||||||||||||||||||
| const titleElement = screen.getByRole('heading', { name: 'Title' }); | ||||||||||||||||||||||||||||||||||||||
| expect(titleElement).toBeInTheDocument(); | ||||||||||||||||||||||||||||||||||||||
| expect(cardElement.childNodes.length).toBe(1); | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
| it('handles null children gracefully by rendering nothing for the children', () => { | |
| const { container } = render( | |
| <SecondaryCard title="Title">{null}</SecondaryCard> | |
| ); | |
| const cardElement = container.firstChild; | |
| const titleElement = screen.getByRole('heading', { name: 'Title' }); | |
| expect(titleElement).toBeInTheDocument(); | |
| expect(cardElement.childNodes.length).toBe(1); | |
| }); | |
| it('handles null children gracefully by rendering nothing for the children', () => { | |
| const { container } = render( | |
| <SecondaryCard title="Title">{null}</SecondaryCard> | |
| ); | |
| const heading = screen.getByRole('heading', { level: 2, name: 'Title' }); | |
| expect(heading).toBeInTheDocument(); | |
| // Ensure no extra visible text/content beyond the title | |
| expect(container.textContent?.trim()).toBe('Title'); | |
| }); |
🤖 Prompt for AI Agents
frontend/__tests__/unit/components/SecondaryCard.test.tsx around lines 90 to 98:
the test currently asserts a brittle DOM structure by checking
cardElement.childNodes.length; remove that childNodes length assertion and
instead assert via content/role queries that only the title is rendered and no
children content exists (for example, use screen.queryByText or
within(cardElement).queryByRole/queryByText to assert there is no extra content
or region rendered for children when children is null). Ensure the test verifies
presence of the heading and uses queryBy* to assert absence of any child content
rather than relying on node count.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Target the actual h2 element when asserting classes
getByText may resolve a child node (e.g., span) inside the h2, causing false negatives. Query the heading element directly.
Apply this diff:
- render(<SecondaryCard title={defaultProps.title} />);
- const titleElement = screen.getByText(defaultProps.title);
- expect(titleElement).toHaveClass('mb-4', 'flex', 'flex-row', 'items-center', 'gap-2', 'text-2xl', 'font-semibold');
+ render(<SecondaryCard title={defaultProps.title} />);
+ const heading = screen.getByRole('heading', { level: 2, name: defaultProps.title });
+ expect(heading).toHaveClass(
+ 'mb-4',
+ 'flex',
+ 'flex-row',
+ 'items-center',
+ 'gap-2',
+ 'text-2xl',
+ 'font-semibold'
+ );📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| it('has the correct classNames for the h2 title element', () => { | |
| render(<SecondaryCard title={defaultProps.title} />); | |
| const titleElement = screen.getByText(defaultProps.title); | |
| expect(titleElement).toHaveClass('mb-4', 'flex', 'flex-row', 'items-center', 'gap-2', 'text-2xl', 'font-semibold'); | |
| }); | |
| it('has the correct classNames for the h2 title element', () => { | |
| render(<SecondaryCard title={defaultProps.title} />); | |
| const heading = screen.getByRole('heading', { level: 2, name: defaultProps.title }); | |
| expect(heading).toHaveClass( | |
| 'mb-4', | |
| 'flex', | |
| 'flex-row', | |
| 'items-center', | |
| 'gap-2', | |
| 'text-2xl', | |
| 'font-semibold' | |
| ); | |
| }); |
🤖 Prompt for AI Agents
In frontend/__tests__/unit/components/SecondaryCard.test.tsx around lines 117 to
121, the test uses getByText which can match a child node (like a span) instead
of the h2; replace that lookup with a heading-specific query (e.g.,
getByRole('heading', { level: 2, name: defaultProps.title }) or
getByRole('heading', { name: defaultProps.title, level: 2 }) ) so the assertion
targets the actual h2 element, then run the same toHaveClass assertion against
that heading element.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Avoid coupling to implementation details; assert icon absence via role, not 'svg' tag
Selecting the SVG tag tightly couples the test to FontAwesome’s DOM. Using role keeps it implementation-agnostic.
Apply this diff:
📝 Committable suggestion
🤖 Prompt for AI Agents