From 4af95b051c83d869aefc6be1e9ebcd802d2eaee7 Mon Sep 17 00:00:00 2001 From: Tony Brierly Date: Mon, 22 Sep 2025 18:07:36 -0700 Subject: [PATCH 1/5] fix:#263 address ESlint issues for groupCard component --- .eslintignore | 1 - components/GroupCard/GroupCard.tsx | 26 ++++++++++++++++++++++---- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/.eslintignore b/.eslintignore index 5da1fefa..f6fe2201 100644 --- a/.eslintignore +++ b/.eslintignore @@ -35,7 +35,6 @@ components/Button/button.tsx components/Calendar/calendar.tsx components/GiftDetailsView/GiftDetailsView.tsx components/GiftSuggestionCard/GiftSuggestionCard.tsx -components/GroupCard/GroupCard.tsx components/ImageSelector/ImageSelector.tsx components/Input/input.tsx components/InviteCard/InviteCard.tsx diff --git a/components/GroupCard/GroupCard.tsx b/components/GroupCard/GroupCard.tsx index 9a6104f0..8ea47adb 100644 --- a/components/GroupCard/GroupCard.tsx +++ b/components/GroupCard/GroupCard.tsx @@ -1,13 +1,23 @@ +// Copyright (c) Gridiron Survivor. +// Licensed under the MIT License. + +import { JSX } from 'react'; import { GiftExchangeWithMemberCount } from '@/app/types/giftExchange'; import { formatDate } from '@/lib/utils'; import { ChevronRight, Users } from 'lucide-react'; import Link from 'next/link'; +import Image from 'next/image'; type GroupCardProps = { giftExchange: GiftExchangeWithMemberCount; }; -export const GroupCardSkeleton = () => { +/** + * GroupCardSkeleton component. + * Displays a loading skeleton placeholder for a GroupCard. + * @returns {JSX.Element} Loader skeleton element. + */ +export const GroupCardSkeleton = (): JSX.Element => { return (
@@ -26,14 +36,22 @@ export const GroupCardSkeleton = () => { ); }; -const GroupCard = ({ giftExchange }: GroupCardProps) => { +/** + * GroupCard component. Renders a styled card that displays + * various information about a gift exchange group. + * @param {GiftExchangeWithMemberCount} giftExchange - A unique gift exchange. + * @returns {JSX.Element} A group card element. + */ +const GroupCard = ({ giftExchange }: GroupCardProps): JSX.Element => { return (
- {`${giftExchange.name}

From 6669f64e69f285c4ac91fd3d5144075713d2276b Mon Sep 17 00:00:00 2001 From: Tony Brierly Date: Tue, 30 Sep 2025 15:36:12 -0700 Subject: [PATCH 2/5] test:#192 add unit tests for GroupCard component --- components/GroupCard/GroupCard.test.tsx | 61 +++++++++++++++++++++++++ components/GroupCard/GroupCard.tsx | 5 +- 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 components/GroupCard/GroupCard.test.tsx diff --git a/components/GroupCard/GroupCard.test.tsx b/components/GroupCard/GroupCard.test.tsx new file mode 100644 index 00000000..9149b945 --- /dev/null +++ b/components/GroupCard/GroupCard.test.tsx @@ -0,0 +1,61 @@ +// Copyright (c) Gridiron Survivor. +// Licensed under the MIT License. + +import { render, screen } from '@testing-library/react'; +import GroupCard, { GroupCardSkeleton } from './GroupCard'; +import { GiftExchangeWithMemberCount } from '@/app/types/giftExchange'; + +// Mock formatDate - Necessary to make date render correctly without regard to local time +jest.mock('@/lib/utils', () => ({ + formatDate: jest.fn(() => 'December 1, 2025'), +})); + +const mockGiftExchange: GiftExchangeWithMemberCount = { + gift_exchange_id: '123', + name: 'Group Name', + description: 'Group Description', + group_image: 'file.svg', + budget: '10-20', + drawing_date: '2025-12-01', + exchange_date: '2025-12-25', + owner_id: '456', + member_count: 3, +}; + +describe('GroupCard', () => { + it('renders group name, image, member count, and formatted date', () => { + render(); + + expect(screen.getByText(mockGiftExchange.name)).toBeInTheDocument(); + expect(screen.getByRole('presentation')).toHaveAttribute('src', mockGiftExchange.group_image); + expect(screen.getByText(`${mockGiftExchange.member_count} members`)).toBeInTheDocument(); + expect(screen.getByText('Draw: December 1, 2025')).toBeInTheDocument(); + }); + + it('renders singular "member" when member_count is 1', () => { + render( + , + ); + expect(screen.getByText('1 member')).toBeInTheDocument(); + }); + + it('renders plural "members" when member_count is not 1', () => { + render( + , + ); + expect(screen.getByText('2 members')).toBeInTheDocument(); + }); + + it('renders link with correct href', () => { + render(); + expect(screen.getByRole('link')).toHaveAttribute('href', `/gift-exchanges/${mockGiftExchange.gift_exchange_id}`); + }); +}); + +describe('GroupCardSkeleton', () => { + it('renders the skeleton with the testId', () => { + render(); + const skeleton = screen.getByTestId('group-card-skeleton'); + expect(skeleton).toBeInTheDocument(); + }); +}); diff --git a/components/GroupCard/GroupCard.tsx b/components/GroupCard/GroupCard.tsx index 8ea47adb..6875afcf 100644 --- a/components/GroupCard/GroupCard.tsx +++ b/components/GroupCard/GroupCard.tsx @@ -19,7 +19,10 @@ type GroupCardProps = { */ export const GroupCardSkeleton = (): JSX.Element => { return ( -
+
From 37ee639888436019a7b1090ddec77588f2cc631b Mon Sep 17 00:00:00 2001 From: Tony Brierly Date: Wed, 1 Oct 2025 19:11:33 -0700 Subject: [PATCH 3/5] Update to access element with getByAltText --- components/GroupCard/GroupCard.test.tsx | 2 +- components/LoadingSpinner/LoadingSpinner.test.tsx | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 components/LoadingSpinner/LoadingSpinner.test.tsx diff --git a/components/GroupCard/GroupCard.test.tsx b/components/GroupCard/GroupCard.test.tsx index 9149b945..15d0c92f 100644 --- a/components/GroupCard/GroupCard.test.tsx +++ b/components/GroupCard/GroupCard.test.tsx @@ -27,7 +27,7 @@ describe('GroupCard', () => { render(); expect(screen.getByText(mockGiftExchange.name)).toBeInTheDocument(); - expect(screen.getByRole('presentation')).toHaveAttribute('src', mockGiftExchange.group_image); + expect(screen.getByAltText('')).toHaveAttribute('src', mockGiftExchange.group_image); expect(screen.getByText(`${mockGiftExchange.member_count} members`)).toBeInTheDocument(); expect(screen.getByText('Draw: December 1, 2025')).toBeInTheDocument(); }); diff --git a/components/LoadingSpinner/LoadingSpinner.test.tsx b/components/LoadingSpinner/LoadingSpinner.test.tsx new file mode 100644 index 00000000..32e54a4b --- /dev/null +++ b/components/LoadingSpinner/LoadingSpinner.test.tsx @@ -0,0 +1,14 @@ +import { render, screen } from "@testing-library/react" +import { LoadingSpinner } from "./LoadingSpinner" + +describe('LoadingSpinner', () => { + it('renders without additional classes', () => { + render() + expect(screen.getByTestId('loading-spinner')).toBeInTheDocument() + }) + + it('renders with additional classes when className is passed', () => { + render() + expect(screen.getByTestId('loading-spinner')).toHaveClass('extra-classname') + }) +}) \ No newline at end of file From 4fa78935a64f8ff40cf767e1696c8553719655a3 Mon Sep 17 00:00:00 2001 From: Tony Brierly Date: Wed, 1 Oct 2025 19:36:00 -0700 Subject: [PATCH 4/5] Remove extra file --- components/LoadingSpinner/LoadingSpinner.test.tsx | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 components/LoadingSpinner/LoadingSpinner.test.tsx diff --git a/components/LoadingSpinner/LoadingSpinner.test.tsx b/components/LoadingSpinner/LoadingSpinner.test.tsx deleted file mode 100644 index 32e54a4b..00000000 --- a/components/LoadingSpinner/LoadingSpinner.test.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { render, screen } from "@testing-library/react" -import { LoadingSpinner } from "./LoadingSpinner" - -describe('LoadingSpinner', () => { - it('renders without additional classes', () => { - render() - expect(screen.getByTestId('loading-spinner')).toBeInTheDocument() - }) - - it('renders with additional classes when className is passed', () => { - render() - expect(screen.getByTestId('loading-spinner')).toHaveClass('extra-classname') - }) -}) \ No newline at end of file From 0095b547954008f120c8ac64960ee0517e252746 Mon Sep 17 00:00:00 2001 From: Tony Brierly Date: Thu, 9 Oct 2025 19:04:34 -0700 Subject: [PATCH 5/5] Revise to use preferred query method --- components/GroupCard/GroupCard.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/GroupCard/GroupCard.test.tsx b/components/GroupCard/GroupCard.test.tsx index 15d0c92f..9fe0d7c3 100644 --- a/components/GroupCard/GroupCard.test.tsx +++ b/components/GroupCard/GroupCard.test.tsx @@ -26,7 +26,7 @@ describe('GroupCard', () => { it('renders group name, image, member count, and formatted date', () => { render(); - expect(screen.getByText(mockGiftExchange.name)).toBeInTheDocument(); + expect(screen.getByRole('heading', {name: mockGiftExchange.name})).toBeInTheDocument(); expect(screen.getByAltText('')).toHaveAttribute('src', mockGiftExchange.group_image); expect(screen.getByText(`${mockGiftExchange.member_count} members`)).toBeInTheDocument(); expect(screen.getByText('Draw: December 1, 2025')).toBeInTheDocument();