From e9a8488a486fe80f3a82cc344ed6a9ca7aa1679f Mon Sep 17 00:00:00 2001 From: Suresh <115452537+sureshsuriya@users.noreply.github.com> Date: Wed, 22 Jul 2026 00:11:21 +0530 Subject: [PATCH] feat(footer): add social media icons to bottom bar --- app/components/Footer.accessibility.test.tsx | 15 ++++++-- app/components/Footer.empty-fallback.test.tsx | 10 ++--- .../Footer.mouse-interactivity.test.tsx | 15 ++++---- .../Footer.responsive-breakpoints.test.tsx | 2 +- app/components/Footer.test.tsx | 37 +++++++++++++++---- app/components/Footer.tsx | 19 ++++++++++ 6 files changed, 73 insertions(+), 25 deletions(-) diff --git a/app/components/Footer.accessibility.test.tsx b/app/components/Footer.accessibility.test.tsx index e8856bed7..ead906e4c 100644 --- a/app/components/Footer.accessibility.test.tsx +++ b/app/components/Footer.accessibility.test.tsx @@ -44,15 +44,22 @@ describe('Footer — Accessibility & Screen Reader Compliance', () => { it('renders social links with descriptive aria-labels for screen readers', () => { render(); - expect(screen.getByRole('link', { name: 'CommitPulse on GitHub' })).toBeInTheDocument(); + // Social links now appear twice: once in the Connect column (with text) and once in the bottom bar icon strip. + // getAllByRole prevents the 'Found multiple elements' error. + const githubLinks = screen.getAllByRole('link', { name: 'CommitPulse on GitHub' }); + expect(githubLinks.length).toBeGreaterThanOrEqual(1); + expect(githubLinks[0]).toHaveAttribute('href', 'https://github.com/JhaSourav07/commitpulse'); expect(screen.getByRole('link', { name: 'Creator Sourav Jha on GitHub' })).toBeInTheDocument(); - expect(screen.getByRole('link', { name: 'Join CommitPulse on Discord' })).toBeInTheDocument(); + const discordLinks = screen.getAllByRole('link', { name: 'Join CommitPulse on Discord' }); + expect(discordLinks.length).toBeGreaterThanOrEqual(1); - expect(screen.getByRole('link', { name: 'Creator on X' })).toBeInTheDocument(); + const xLinks = screen.getAllByRole('link', { name: 'Creator on X' }); + expect(xLinks.length).toBeGreaterThanOrEqual(1); - expect(screen.getByRole('link', { name: 'Creator on LinkedIn' })).toBeInTheDocument(); + const linkedinLinks = screen.getAllByRole('link', { name: 'Creator on LinkedIn' }); + expect(linkedinLinks.length).toBeGreaterThanOrEqual(1); }); it('applies visible focus ring classes to all interactive links', () => { diff --git a/app/components/Footer.empty-fallback.test.tsx b/app/components/Footer.empty-fallback.test.tsx index ddccd2aaa..58c129064 100644 --- a/app/components/Footer.empty-fallback.test.tsx +++ b/app/components/Footer.empty-fallback.test.tsx @@ -95,11 +95,11 @@ describe('Footer empty-fallback and edge-cases', () => { expect(homeLink).not.toHaveAttribute('aria-label'); // undefined ariaLabel expect(homeLink).not.toHaveAttribute('target'); // not external - // External Link Component - const githubLink = screen.getByRole('link', { name: 'CommitPulse on GitHub' }); - expect(githubLink).toBeInTheDocument(); - expect(githubLink).toHaveAttribute('target', '_blank'); - expect(githubLink).toHaveAttribute('rel', 'noopener noreferrer'); + // External Link Component — now appears twice (Connect column + bottom bar icon strip) + const githubLinks = screen.getAllByRole('link', { name: 'CommitPulse on GitHub' }); + expect(githubLinks.length).toBeGreaterThanOrEqual(1); + expect(githubLinks[0]).toHaveAttribute('target', '_blank'); + expect(githubLinks[0]).toHaveAttribute('rel', 'noopener noreferrer'); }); it('renders correct current year when system date environment changes', () => { diff --git a/app/components/Footer.mouse-interactivity.test.tsx b/app/components/Footer.mouse-interactivity.test.tsx index 15efbc0f5..387c25288 100644 --- a/app/components/Footer.mouse-interactivity.test.tsx +++ b/app/components/Footer.mouse-interactivity.test.tsx @@ -35,19 +35,18 @@ describe('Footer - real component coverage (CI-safe)', () => { it('renders social links using aria-labels (no ambiguity)', () => { render(); - expect(screen.getByRole('link', { name: 'CommitPulse on GitHub' })).toHaveAttribute( - 'href', - expect.stringContaining('github.com') - ); + // Social links now appear twice: once in the Connect column and once in the bottom bar icon strip. + const githubLinks = screen.getAllByRole('link', { name: 'CommitPulse on GitHub' }); + expect(githubLinks.length).toBeGreaterThanOrEqual(1); + expect(githubLinks[0]).toHaveAttribute('href', expect.stringContaining('github.com')); expect(screen.getByRole('link', { name: 'Creator Sourav Jha on GitHub' })).toHaveAttribute( 'href', expect.stringContaining('github.com') ); - expect(screen.getByRole('link', { name: 'Join CommitPulse on Discord' })).toHaveAttribute( - 'href', - expect.stringContaining('discord') - ); + const discordLinks = screen.getAllByRole('link', { name: 'Join CommitPulse on Discord' }); + expect(discordLinks.length).toBeGreaterThanOrEqual(1); + expect(discordLinks[0]).toHaveAttribute('href', expect.stringContaining('discord')); }); }); diff --git a/app/components/Footer.responsive-breakpoints.test.tsx b/app/components/Footer.responsive-breakpoints.test.tsx index f0e2b2ed9..38c53c95b 100644 --- a/app/components/Footer.responsive-breakpoints.test.tsx +++ b/app/components/Footer.responsive-breakpoints.test.tsx @@ -104,7 +104,7 @@ describe('Footer Responsive Breakpoints', () => { const { container } = render(); const flexColContainers = container.querySelectorAll('.flex.flex-col'); - expect(flexColContainers.length).toBe(8); + expect(flexColContainers.length).toBeGreaterThanOrEqual(8); const navList = container.querySelector('nav.flex.flex-col.gap-2'); expect(navList).toBeInTheDocument(); diff --git a/app/components/Footer.test.tsx b/app/components/Footer.test.tsx index e529e8079..05b8bdec5 100644 --- a/app/components/Footer.test.tsx +++ b/app/components/Footer.test.tsx @@ -58,11 +58,13 @@ describe('Footer Component', () => { it('renders Discord community link', () => { render(); - const discordLink = screen.getByRole('link', { - name: /Discord/i, + // Discord now appears twice: once in the Connect column (text + icon) and once in the bottom bar icon strip. + const discordLinks = screen.getAllByRole('link', { + name: /Join CommitPulse on Discord/i, }); - expect(discordLink).toHaveAttribute('href', 'https://discord.gg/f84SDraEBH'); + expect(discordLinks.length).toBeGreaterThanOrEqual(1); + expect(discordLinks[0]).toHaveAttribute('href', 'https://discord.gg/f84SDraEBH'); }); it('exposes the footer as a semantic contentinfo landmark for screen readers', () => { @@ -114,10 +116,14 @@ describe('Footer Component', () => { const connectHeading = screen.getByRole('heading', { name: /Connect/i }); expect(connectHeading).toBeInTheDocument(); - // Check for social links - expect(screen.getByRole('link', { name: /Creator on X/i })).toBeInTheDocument(); - expect(screen.getByRole('link', { name: /LinkedIn/i })).toBeInTheDocument(); - expect(screen.getByRole('link', { name: /Discord/i })).toBeInTheDocument(); + // Social links now appear twice (Connect column + bottom bar icon strip); use getAllByRole. + expect(screen.getAllByRole('link', { name: /Creator on X/i }).length).toBeGreaterThanOrEqual(1); + expect( + screen.getAllByRole('link', { name: /Creator on LinkedIn/i }).length + ).toBeGreaterThanOrEqual(1); + expect( + screen.getAllByRole('link', { name: /Join CommitPulse on Discord/i }).length + ).toBeGreaterThanOrEqual(1); }); it('has proper responsive layout classes', () => { @@ -159,4 +165,21 @@ describe('Footer Component', () => { expect(link.className).toContain('focus:ring'); }); }); + + it('renders social icon strip in the bottom bar with correct links and no duplicate creator icon', () => { + render(); + + // Project GitHub, Discord, X, LinkedIn each appear twice: + // once in the Connect column (with text label) and once in the bottom bar icon strip. + expect(screen.getAllByRole('link', { name: 'CommitPulse on GitHub' })).toHaveLength(2); + expect(screen.getAllByRole('link', { name: 'Join CommitPulse on Discord' })).toHaveLength(2); + expect(screen.getAllByRole('link', { name: 'Creator on X' })).toHaveLength(2); + expect(screen.getAllByRole('link', { name: 'Creator on LinkedIn' })).toHaveLength(2); + + // The creator's personal GitHub link must appear only once (Connect column only, not in bottom bar). + expect(screen.getAllByRole('link', { name: 'Creator Sourav Jha on GitHub' })).toHaveLength(1); + + // The bottom bar nav landmark must be present with an accessible label. + expect(screen.getByRole('navigation', { name: 'Social media links' })).toBeInTheDocument(); + }); }); diff --git a/app/components/Footer.tsx b/app/components/Footer.tsx index d312dd36b..580455663 100644 --- a/app/components/Footer.tsx +++ b/app/components/Footer.tsx @@ -273,6 +273,25 @@ export function Footer() { {/* Bottom Section */}
{t('footer.copyright', { year: currentYear.toString() })}
+ + {/* Social Icon Strip */} + +{t('footer.made_with')}