Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
fd708b3
Initial plan
Copilot Mar 1, 2026
970af0a
docs: add high-impact contribution recommendations
Copilot Mar 1, 2026
87fe9f9
docs: add frontend animation contribution track
Copilot Mar 1, 2026
5620831
feat(frontend): add reusable spotlight motion cards for modern UI eff…
Copilot Mar 1, 2026
6603c1f
refactor(frontend): polish spotlight defaults and gradient classes
Copilot Mar 1, 2026
31ec83c
chore: revert incidental readme wording change
Copilot Mar 1, 2026
e11e2e0
docs: remove added recommendation section from readme
Copilot Mar 1, 2026
be41478
fix: default frontend user API base URL for dev and tests
Copilot Mar 1, 2026
e513eca
fix: resolve homepage screenshot visibility and console hydration war…
Copilot Mar 1, 2026
0a0cc9c
feat(frontend): improve homepage icons and footer styling
Copilot Mar 1, 2026
21eb078
feat(frontend): modernize navbar with scrollable saas-style navigation
Copilot Mar 1, 2026
48bc5c4
feat(frontend): add responsive navbar audit fixes with mobile burger …
Copilot Mar 1, 2026
6fa7666
Update frontend/__tests__/components/Navbar.test.tsx
imsks Mar 5, 2026
9f92717
Update frontend/lib/api/user.ts
imsks Mar 5, 2026
c7addba
fix(frontend): close mobile menu on desktop resize to prevent duplica…
Copilot Mar 5, 2026
1732f76
test(frontend): validate navbar closes menu at desktop breakpoint
Copilot Mar 5, 2026
d9e91b7
merge: sync with upstream development and resolve frontend conflicts
Copilot Mar 6, 2026
b01c89c
merge: connect branch history with development base
Copilot Mar 6, 2026
a72f32c
merge: connect branch history with latest upstream development
Copilot Mar 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions frontend/__tests__/app/homepage-sections.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { render, screen } from "@testing-library/react"
import Home from "@/app/page"

describe("Homepage sections visibility", () => {
it("keeps key below-the-fold sections visible on initial render", () => {
render(<Home />)

expect(
screen.getByRole("heading", { name: "What You'll Find" })
).toBeVisible()
expect(screen.getByRole("heading", { name: "Contribute Data" })).toBeVisible()
})

it("uses component icons instead of emoji placeholders in feature cards", () => {
render(<Home />)

expect(screen.queryByText("🏛️")).not.toBeInTheDocument()
expect(screen.queryByText("🏢")).not.toBeInTheDocument()
expect(screen.queryByText("📊")).not.toBeInTheDocument()
expect(screen.queryByText("💻")).not.toBeInTheDocument()
expect(screen.queryByText("🔧")).not.toBeInTheDocument()
})
})
16 changes: 16 additions & 0 deletions frontend/__tests__/components/Button.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { render, screen } from "@testing-library/react"
import Button from "@/components/ui/Button"

describe("Button", () => {
it("does not forward icon props to the DOM for link buttons", () => {
render(
<Button href='/dashboard' leftIcon={<span>L</span>} rightIcon={<span>R</span>}>
Explore
</Button>
)

const link = screen.getByRole("link", { name: /explore/i })
expect(link).not.toHaveAttribute("lefticon")
expect(link).not.toHaveAttribute("righticon")
})
})
17 changes: 17 additions & 0 deletions frontend/__tests__/components/Footer.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { render, screen } from "@testing-library/react"
import Footer from "@/components/layout/Footer"

describe("Footer", () => {
it("renders compact one-line content with github link", () => {
render(<Footer />)

expect(screen.getByText(/Building with ❤️ for 🇮🇳 Democracy/i)).toBeVisible()
expect(
screen.getByText(new RegExp(`© ${new Date().getFullYear()} Rajniti`, "i"))
).toBeVisible()
expect(screen.getByRole("link", { name: /github/i })).toHaveAttribute(
"href",
"https://github.com/imsks/rajniti"
)
})
})
68 changes: 68 additions & 0 deletions frontend/__tests__/components/Navbar.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { fireEvent, render, screen, within } from "@testing-library/react"
import Navbar from "@/components/layout/Navbar"

describe("Navbar", () => {
it("renders scrollable primary navigation links for the default variant", () => {
render(<Navbar variant='default' />)

const nav = screen.getByRole("navigation", { name: /primary navigation/i })
expect(nav.firstElementChild).toHaveClass("overflow-x-auto")

expect(within(nav).getByRole("link", { name: /explore politicians/i })).toHaveAttribute(
"href",
"/dashboard"
)
expect(within(nav).getByRole("link", { name: /about/i })).toHaveAttribute(
"href",
"#about"
)
expect(within(nav).getByRole("link", { name: /contribute/i })).toHaveAttribute(
"href",
"#contribute"
)
expect(within(nav).getByRole("link", { name: /join community/i })).toHaveAttribute(
"href",
"https://chat.whatsapp.com/IceA98FSHHuDmXOwv8WH7v"
)
})

it("renders dashboard navigation links including bug report", () => {
render(<Navbar variant='dashboard' />)

const nav = screen.getByRole("navigation", { name: /primary navigation/i })
expect(within(nav).getByRole("link", { name: /home/i })).toBeVisible()
expect(within(nav).getByRole("link", { name: /politicians/i })).toBeVisible()
expect(within(nav).getByRole("link", { name: /found a bug/i })).toHaveAttribute(
"href",
"https://github.com/imsks/rajniti/issues/new"
)
})

it("toggles mobile burger menu and renders mobile links", () => {
render(<Navbar variant='default' />)

const toggle = screen.getByRole("button", { name: /open menu/i })
fireEvent.click(toggle)

const mobileNav = screen.getByRole("navigation", { name: /mobile navigation/i })
expect(within(mobileNav).getByRole("link", { name: /explore politicians/i })).toHaveAttribute(
"href",
"/dashboard"
)

fireEvent.click(screen.getByRole("button", { name: /close menu/i }))
expect(screen.queryByRole("navigation", { name: /mobile navigation/i })).not.toBeInTheDocument()
})

it("closes mobile menu when resizing to desktop viewport", () => {
render(<Navbar variant='default' />)

fireEvent.click(screen.getByRole("button", { name: /open menu/i }))
expect(screen.getByRole("navigation", { name: /mobile navigation/i })).toBeInTheDocument()

Object.defineProperty(window, "innerWidth", { configurable: true, writable: true, value: 640 })
fireEvent(window, new Event("resize"))

expect(screen.queryByRole("navigation", { name: /mobile navigation/i })).not.toBeInTheDocument()
})
})
20 changes: 20 additions & 0 deletions frontend/__tests__/components/PreambleSection.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { render } from "@testing-library/react"
import PreambleSection from "@/components/PreambleSection"

describe("PreambleSection", () => {
it("renders Ashoka Chakra spokes with fixed precision coordinates", () => {
const { container } = render(<PreambleSection />)
const spokes = container.querySelectorAll("line")

expect(spokes).toHaveLength(24)
spokes.forEach((spoke) => {
;(["x1", "y1", "x2", "y2"] as const).forEach((attr) => {
const value = spoke.getAttribute(attr)
expect(value).not.toBeNull()
expect(Number.isFinite(Number(value))).toBe(true)
const fractional = value?.split(".")[1] ?? ""
expect(fractional.length).toBeLessThanOrEqual(4)
})
})
})
})
38 changes: 38 additions & 0 deletions frontend/__tests__/components/SpotlightCard.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { fireEvent, render, screen } from "@testing-library/react"
import SpotlightCard from "@/components/ui/SpotlightCard"

describe("SpotlightCard", () => {
it("renders children content", () => {
render(
<SpotlightCard>
<p>Card content</p>
</SpotlightCard>
)

expect(screen.getByText("Card content")).toBeInTheDocument()
})

it("updates spotlight position CSS variables on mouse move", () => {
const { container } = render(
<SpotlightCard>
<p>Interactive content</p>
</SpotlightCard>
)

const card = container.firstElementChild as HTMLDivElement
Object.defineProperty(card, "getBoundingClientRect", {
value: () =>
({
left: 100,
top: 50,
width: 200,
height: 100,
}) as DOMRect,
})

fireEvent.mouseMove(card, { clientX: 200, clientY: 100 })

expect(card.style.getPropertyValue("--spotlight-x")).toBe("50%")
expect(card.style.getPropertyValue("--spotlight-y")).toBe("50%")
})
})
Loading