Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
58 changes: 58 additions & 0 deletions __tests__/components/button.spec.tsx
Original file line number Diff line number Diff line change
@@ -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()
})
})
65 changes: 65 additions & 0 deletions __tests__/components/tooltip.spec.tsx
Original file line number Diff line number Diff line change
@@ -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()
})

})
64 changes: 64 additions & 0 deletions __tests__/pages/home.spec.tsx
Original file line number Diff line number Diff line change
@@ -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",
},
],
},
})
})
})
2 changes: 1 addition & 1 deletion app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import "styles/tailwind.css"
import "@/styles/tailwind.css"

export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
Expand Down
8 changes: 8 additions & 0 deletions jest.setup.js
Original file line number Diff line number Diff line change
@@ -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;
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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}\"",
Expand Down
5 changes: 4 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand Down