This commit is contained in:
Amir Ali 2025-08-03 13:44:10 -04:00 • committed by GitHub
commit 5d552c0bba
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 202 additions and 2 deletions

View file

@ -0,0 +1,58 @@
import { render, screen } from "@testing-library/react"
import { Button } from "@/components/Button/Button"
describe("Button component", () => {
it("renders with default intent and size", () => {
render(<Button href="/">Default Button</Button>)
const btn = screen.getByRole("link", { name: /default button/i })
expect(btn).toBeInTheDocument()
expect(btn).toHaveClass("bg-blue-400")
expect(btn).toHaveClass("text-lg")
})
it("renders secondary intent correctly", () => {
render(<Button href="/" intent="secondary">Secondary Button</Button>)
const btn = screen.getByRole("link", { name: /secondary button/i })
expect(btn).toHaveClass("bg-transparent")
expect(btn).toHaveClass("text-blue-400")
})
it("renders small size correctly", () => {
render(<Button href="/" size="sm">Small Button</Button>)
const btn = screen.getByRole("link", { name: /small button/i })
expect(btn).toHaveClass("text-sm")
expect(btn).toHaveClass("min-w-20")
})
it("applies underline when underline prop is true", () => {
render(<Button href="/" underline>Underlined Button</Button>)
const btn = screen.getByRole("link", { name: /underlined button/i })
expect(btn).toHaveClass("underline")
})
it("does not apply underline class when underline prop is false or omitted", () => {
render(<Button href="/">No Underline</Button>)
const btn = screen.getByRole("link", { name: /no underline/i })
expect(btn).not.toHaveClass("underline")
})
it("merges custom className with variant classes", () => {
render(<Button href="/" className="custom-class">Custom Class Button</Button>)
const btn = screen.getByRole("link", { name: /custom class button/i })
expect(btn).toHaveClass("custom-class")
expect(btn).toHaveClass("bg-blue-400")
})
it("forwards href and other props correctly", () => {
render(<Button href="/test" rel="noopener noreferrer">Link Button</Button>)
const btn = screen.getByRole("link", { name: /link button/i })
expect(btn).toHaveAttribute("href", "/test")
expect(btn).toHaveAttribute("rel", "noopener noreferrer")
})
it("renders children inside the anchor tag", () => {
render(<Button href="/">Click Me</Button>)
expect(screen.getByText("Click Me")).toBeInTheDocument()
})
})

View file

@ -0,0 +1,65 @@
import { fireEvent, render, screen, waitFor } from "@testing-library/react"
import { Tooltip } from "@/components/Tooltip/Tooltip"
describe("Tooltip", () => {
it("should render tooltip content when open is true", () => {
render(
<Tooltip explainer="Click me" open={true}>
<div>Hover me</div>
</Tooltip>
)
expect(screen.getByText("Hover me")).toBeInTheDocument()
const tooltipContent = document.querySelector('[data-radix-popper-content-wrapper]')
expect(tooltipContent).toBeInTheDocument()
expect(tooltipContent).toHaveTextContent("Click me")
})
it("should not render tooltip content when open is false or undefined", () => {
render(
<Tooltip explainer="Click me">
<div>Hover me</div>
</Tooltip>
)
expect(screen.getByText("Hover me")).toBeInTheDocument()
const tooltipContent = document.querySelector('[data-radix-popper-content-wrapper]')
expect(tooltipContent).not.toBeInTheDocument()
})
it("calls onOpenChange when tooltip open state changes", async () => {
const handleOpenChange = jest.fn()
render(
<Tooltip explainer="Controlled" open={false} onOpenChange={handleOpenChange}>
<button>Hover me</button>
</Tooltip>
)
expect(screen.queryByText("Controlled")).not.toBeInTheDocument()
fireEvent.mouseOver(screen.getByText("Hover me"))
expect(screen.queryByText("Controlled")).not.toBeInTheDocument()
handleOpenChange(true)
expect(handleOpenChange).toHaveBeenCalledWith(true)
})
it("renders arrow when withArrow is true", () => {
const { container } = render(
<Tooltip explainer="Tooltip with arrow" open={true} withArrow={true}>
<button>Hover me</button>
</Tooltip>
)
console.log(container.innerHTML)
const arrow = document.querySelector('svg')
expect(arrow).toBeInTheDocument()
})
})

View file

@ -0,0 +1,64 @@
import { render, screen } from "@testing-library/react"
import Home, { metadata } from "@/app/page"
import { LP_GRID_ITEMS } from "lp-items"
describe("Home", () => {
beforeEach(() => {
render(<Home />)
})
it("renders the main heading", () => {
expect(screen.getByText("Next.js Enterprise Boilerplate")).toBeInTheDocument()
})
it("renders the description paragraph", () => {
expect(screen.getByText(/Jumpstart your enterprise project/)).toBeInTheDocument()
})
it("renders both buttons with correct text and links", () => {
const getStartedButton = screen.getByText("Get started")
const deployNowButton = screen.getByText("Deploy Now")
expect(getStartedButton).toBeInTheDocument()
expect(deployNowButton).toBeInTheDocument()
expect(getStartedButton.closest('a')).toHaveAttribute('href', 'https://github.com/Blazity/next-enterprise')
expect(deployNowButton.closest('a')).toHaveAttribute('href', 'https://vercel.com/new/git/external?repository-url=https://github.com/Blazity/next-enterprise')
})
it("renders all grid items with their content", () => {
LP_GRID_ITEMS.forEach((item) => {
expect(screen.getByText(item.title)).toBeInTheDocument()
expect(screen.getByText(item.description)).toBeInTheDocument()
})
})
it("renders grid items in the correct structure", () => {
const gridItems = screen.getAllByRole('heading', { level: 3 })
expect(gridItems).toHaveLength(LP_GRID_ITEMS.length)
gridItems.forEach((item) => {
const parent = item.closest('div')
expect(parent).toHaveClass('flex', 'flex-col', 'items-center', 'justify-center', 'text-center')
})
})
it("has correct metadata configuration", () => {
expect(metadata).toEqual({
title: "Next.js Enterprise Boilerplate",
twitter: {
card: "summary_large_image",
},
openGraph: {
url: "https://next-enterprise.vercel.app/",
images: [
{
width: 1200,
height: 630,
url: "https://raw.githubusercontent.com/Blazity/next-enterprise/main/.github/assets/project-logo.png",
},
],
},
})
})
})

View file

@ -1,4 +1,4 @@
import "styles/tailwind.css"
import "@/styles/tailwind.css"
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (

View file

@ -1,2 +1,10 @@
// Learn more: https://github.com/testing-library/jest-dom
import "@testing-library/jest-dom"
class ResizeObserverMock {
observe() {}
unobserve() {}
disconnect() {}
}
global.ResizeObserver = ResizeObserverMock;

View file

@ -15,6 +15,8 @@
"test-storybook": "cross-env FORCE_COLOR=1 test-storybook",
"build-storybook": "cross-env FORCE_COLOR=1 storybook build",
"test": "cross-env FORCE_COLOR=1 jest --passWithNoTests",
"test:watch": "cross-env FORCE_COLOR=1 jest --watch",
"test:coverage": "cross-env FORCE_COLOR=1 jest --coverage",
"e2e:headless": "playwright test",
"e2e:ui": "playwright test --ui",
"format": "prettier --write \"**/*.{ts,tsx,md}\"",

View file

@ -23,7 +23,10 @@
{
"name": "next"
}
]
],
"paths": {
"@/*": ["./*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.mjs", "jest.config.js", ".next/types/**/*.ts", "eslint.config.mjs"],
"exclude": ["node_modules"]