Add comprehensive E2E tests for homepage and refactor demo modal logic

- Implemented E2E tests for homepage sections: `HeroSection`, `Header`, `CTASection`, `AnimatedTerminal`, `FeatureSections`, and `Footer`, ensuring proper functionality, navigation, and accessibility.
- Introduced tests for mobile menu interactions, demo credentials modal, and terminal animations.
- Refactored demo modal logic to use a shared state managed in `page.tsx` for consistency across sections (`Header`, `HeroSection`, `CTASection`).
- Updated `Header`, `HeroSection`, and `CTASection` to receive `onOpenDemoModal` as props for triggering the modal.
This commit is contained in:
2025-11-08 18:22:58 +01:00
parent b630559e0b
commit 214d0b1765
6 changed files with 497 additions and 39 deletions

View File

@@ -4,6 +4,9 @@
* Showcases features, tech stack, and provides demos for developers
*/
'use client';
import { useState } from 'react';
import { Header } from '@/components/home/Header';
import { HeroSection } from '@/components/home/HeroSection';
import { ContextSection } from '@/components/home/ContextSection';
@@ -15,17 +18,20 @@ import { TechStackSection } from '@/components/home/TechStackSection';
import { PhilosophySection } from '@/components/home/PhilosophySection';
import { QuickStartCode } from '@/components/home/QuickStartCode';
import { CTASection } from '@/components/home/CTASection';
import { DemoCredentialsModal } from '@/components/home/DemoCredentialsModal';
export default function Home() {
const [demoModalOpen, setDemoModalOpen] = useState(false);
return (
<div className="min-h-screen">
{/* Header Navigation */}
<Header />
<Header onOpenDemoModal={() => setDemoModalOpen(true)} />
{/* Main Content */}
<main>
{/* Hero Section with CTAs */}
<HeroSection />
<HeroSection onOpenDemoModal={() => setDemoModalOpen(true)} />
{/* What is this template? */}
<ContextSection />
@@ -52,7 +58,7 @@ export default function Home() {
<QuickStartCode />
{/* Final CTA Section */}
<CTASection />
<CTASection onOpenDemoModal={() => setDemoModalOpen(true)} />
</main>
{/* Footer */}
@@ -91,6 +97,12 @@ export default function Home() {
</div>
</div>
</footer>
{/* Shared Demo Credentials Modal */}
<DemoCredentialsModal
open={demoModalOpen}
onClose={() => setDemoModalOpen(false)}
/>
</div>
);
}

View File

@@ -5,15 +5,16 @@
'use client';
import { useState } from 'react';
import Link from 'next/link';
import { motion } from 'framer-motion';
import { Github, Star, Play, ArrowRight } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { DemoCredentialsModal } from './DemoCredentialsModal';
export function CTASection() {
const [demoModalOpen, setDemoModalOpen] = useState(false);
interface CTASectionProps {
onOpenDemoModal: () => void;
}
export function CTASection({ onOpenDemoModal }: CTASectionProps) {
return (
<section className="relative overflow-hidden bg-gradient-to-br from-primary/10 via-background to-background">
@@ -66,7 +67,7 @@ export function CTASection() {
</a>
</Button>
<Button
onClick={() => setDemoModalOpen(true)}
onClick={onOpenDemoModal}
size="lg"
variant="outline"
className="gap-2 text-base group"
@@ -113,12 +114,6 @@ export function CTASection() {
</motion.div>
</motion.div>
</div>
{/* Demo Credentials Modal */}
<DemoCredentialsModal
open={demoModalOpen}
onClose={() => setDemoModalOpen(false)}
/>
</section>
);
}

View File

@@ -9,11 +9,13 @@ import { useState } from 'react';
import Link from 'next/link';
import { Menu, X, Github, Star } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { DemoCredentialsModal } from './DemoCredentialsModal';
import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/sheet';
export function Header() {
const [demoModalOpen, setDemoModalOpen] = useState(false);
interface HeaderProps {
onOpenDemoModal: () => void;
}
export function Header({ onOpenDemoModal }: HeaderProps) {
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
const navLinks = [
@@ -63,7 +65,7 @@ export function Header() {
{/* CTAs */}
<Button
onClick={() => setDemoModalOpen(true)}
onClick={onOpenDemoModal}
variant="default"
size="sm"
>
@@ -98,7 +100,7 @@ export function Header() {
onClick={() => setMobileMenuOpen(false)}
className="text-lg font-medium hover:text-primary transition-colors"
>
{link.href}
{link.label}
</Link>
))}
@@ -122,7 +124,7 @@ export function Header() {
<Button
onClick={() => {
setMobileMenuOpen(false);
setDemoModalOpen(true);
onOpenDemoModal();
}}
variant="default"
className="w-full"
@@ -144,12 +146,6 @@ export function Header() {
</Sheet>
</div>
</header>
{/* Demo Credentials Modal */}
<DemoCredentialsModal
open={demoModalOpen}
onClose={() => setDemoModalOpen(false)}
/>
</>
);
}

View File

@@ -5,15 +5,16 @@
'use client';
import { useState } from 'react';
import Link from 'next/link';
import { motion } from 'framer-motion';
import { ArrowRight, Github, Play } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { DemoCredentialsModal } from './DemoCredentialsModal';
export function HeroSection() {
const [demoModalOpen, setDemoModalOpen] = useState(false);
interface HeroSectionProps {
onOpenDemoModal: () => void;
}
export function HeroSection({ onOpenDemoModal }: HeroSectionProps) {
return (
<section className="relative overflow-hidden">
@@ -80,7 +81,7 @@ export function HeroSection() {
>
<Button
size="lg"
onClick={() => setDemoModalOpen(true)}
onClick={onOpenDemoModal}
className="gap-2 text-base group"
>
<Play className="h-5 w-5 group-hover:scale-110 transition-transform" aria-hidden="true" />
@@ -139,12 +140,6 @@ export function HeroSection() {
</motion.div>
</div>
</div>
{/* Demo Credentials Modal */}
<DemoCredentialsModal
open={demoModalOpen}
onClose={() => setDemoModalOpen(false)}
/>
</section>
);
}