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
35 changes: 35 additions & 0 deletions .bugster/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Bugster Configuration File
# This file contains your project configuration and test execution preferences.

# Project Information
project_name: bugster-nextjs-example
project_id: CNBx3CugMe1wRrG2ESHk
base_url: "http://localhost:3000"

# Project Authentication
credentials:
- id: admin
username: admin
password: admin

# Vercel Configuration
# You can create the Vercel Protection Bypass Secret for Automation in this link:
# https://vercel.com/d?to=/[team]/[project]/settings/deployment-protection&title=Deployment+Protection+settings
# x-vercel-protection-bypass: your-bypass-secret


# Test Execution Preferences
# Uncomment and modify the options below to customize test execution behavior.
# CLI options will override these settings when specified.
# preferences:
# tests:
# always_run:
# - .bugster/tests/test1.yaml
# - .bugster/tests/test2.yaml
# limit: 5 # Maximum number of tests to run
# headless: false # Run tests in headless mode
# silent: false # Run tests in silent mode
# verbose: false # Enable verbose output
# only_affected: false # Only run tests for affected files
# parallel: 5 # Maximum number of concurrent tests
# output: bugster_output.json # Save test results to JSON file
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# 🐛 Bugster - Automated Testing for Next.js

**Generate and run comprehensive tests for your Next.js applications with AI-powered automation.**

This is a demo shirt shop built with Next.js to showcase how Bugster can automatically generate and run tests for your web applications. Follow this step-by-step guide to try it from scratch!

## 🚀 Phase 1: Try Bugster Locally
Expand Down
73 changes: 66 additions & 7 deletions app/cart/order-summary.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,80 @@
import { OrderSummarySection } from '@/components/shopping-cart/order-summary-section';
import { ProceedToCheckout } from './proceed-to-checkout';
import { PromoCodeSection } from '@/components/shopping-cart/promo-code-section';
import { ShippingOptionsSection } from '@/components/shopping-cart/shipping-options-section';

export function OrderSummary({
showSummerBanner,
freeDelivery,
subtotal,
itemCount,
}: {
showSummerBanner: boolean;
freeDelivery: boolean;
subtotal: number;
itemCount: number;
}) {
// Using default value: proceedToCheckoutColor = 'blue'
const proceedToCheckoutColor = 'blue';
// Dynamic color based on cart value
const proceedToCheckoutColor = subtotal >= 100 ? 'green' : 'blue';

// Calculate estimated delivery date
const deliveryDate = new Date();
deliveryDate.setDate(deliveryDate.getDate() + (freeDelivery ? 3 : 5));
const formattedDeliveryDate = deliveryDate.toLocaleDateString('en-US', {
weekday: 'long',
month: 'long',
day: 'numeric',
});

return (
<OrderSummarySection
showSummerBanner={showSummerBanner}
freeDelivery={freeDelivery}
proceedToCheckout={<ProceedToCheckout color={proceedToCheckoutColor} />}
/>
<section className="mt-16 rounded-lg bg-gray-50 px-6 py-6 sm:p-6 lg:col-span-5 lg:mt-0 lg:p-8">
<div className="flex items-center justify-between">
<h2 className="text-lg font-medium text-gray-900">Order summary</h2>
{itemCount > 0 && (
<span className="inline-flex items-center rounded-full bg-blue-100 px-2.5 py-0.5 text-xs font-medium text-blue-800">
{itemCount} {itemCount === 1 ? 'item' : 'items'}
</span>
)}
</div>

{/* Estimated Delivery */}
{itemCount > 0 && (
<div className="mt-4 rounded-lg bg-green-50 p-3 border border-green-200">
<div className="flex items-center">
<svg className="h-5 w-5 text-green-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" />
</svg>
<div className="ml-3">
<p className="text-sm font-medium text-green-800">
Estimated delivery: {formattedDeliveryDate}
</p>
</div>
</div>
</div>
)}

{/* Promo Code Section */}
<div className="mt-6">
<PromoCodeSection subtotal={subtotal} />
</div>

{/* Shipping Options */}
<div className="mt-6">
<ShippingOptionsSection freeDelivery={freeDelivery} />
</div>

{/* Proceed to Checkout Button */}
<div className="mt-6">
<ProceedToCheckout color={proceedToCheckoutColor} />
</div>

{/* Order Summary Details */}
<OrderSummarySection
showSummerBanner={showSummerBanner}
freeDelivery={freeDelivery}
subtotal={subtotal}
itemCount={itemCount}
/>
</section>
);
}
110 changes: 100 additions & 10 deletions app/cart/page.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,111 @@
import { OrderSummary } from '@/app/cart/order-summary';
import { Main } from '@/components/main';
import { ShoppingCart } from '@/components/shopping-cart/shopping-cart';
import { getCart } from '@/lib/actions';
import { Suspense } from 'react';

export default function CartPage() {
// Using default values: showSummerBanner = false, freeDelivery = false
const showSummerBanner = false;
const freeDelivery = false;
async function CartPageContent() {
const { items } = await getCart();

// Calculate total to determine free delivery eligibility
const subtotal = items.reduce((total, item) => {
// Handle different product types with their respective prices
const productPrices: Record<string, number> = {
'shirt': 20.00,
'sticker-circle': 12.99,
'sticker-star': 15.99,
'sticker-emoji': 10.99,
'sticker-nature': 14.99,
'sticker-geometric': 13.99,
'sticker-holographic': 18.99,
};

const price = productPrices[item.id] || 20.00; // Default to shirt price
return total + (price * item.quantity);
}, 0);

// Dynamic logic for banners and free delivery
const showSummerBanner = new Date().getMonth() >= 5 && new Date().getMonth() <= 7; // June-August
const freeDelivery = subtotal >= 50; // Free delivery for orders over $50
const itemCount = items.reduce((count, item) => count + item.quantity, 0);

return (
<Main>
<div className="bg-white">
<div className="mx-auto max-w-2xl px-4 pb-24 pt-16 sm:px-6 lg:max-w-7xl lg:px-8">
{/* Cart Header */}
<div className="mb-8">
<h1 className="text-3xl font-bold tracking-tight text-gray-900 sm:text-4xl">
Shopping Cart
</h1>
{itemCount > 0 && (
<p className="mt-2 text-sm text-gray-600">
{itemCount} {itemCount === 1 ? 'item' : 'items'} in your cart
</p>
)}
</div>

{/* Free Delivery Banner */}
{!freeDelivery && subtotal > 0 && (
<div className="mb-8 rounded-lg bg-blue-50 p-4 border border-blue-200">
<div className="flex items-center">
<div className="flex-shrink-0">
<svg className="h-5 w-5 text-blue-400" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
</svg>
</div>
<div className="ml-3">
<p className="text-sm font-medium text-blue-800">
Add ${(50 - subtotal).toFixed(2)} more to qualify for free delivery!
</p>
</div>
</div>
</div>
)}

{/* Main Cart Grid */}
<div className="lg:grid lg:grid-cols-12 lg:items-start lg:gap-x-12 xl:gap-x-16">
<ShoppingCart />
<OrderSummary
showSummerBanner={showSummerBanner}
freeDelivery={freeDelivery}
subtotal={subtotal}
itemCount={itemCount}
/>
</div>
</div>
</div>
</Main>
);
}

function CartPageFallback() {
return (
<Main>
<div className="lg:grid lg:grid-cols-12 lg:items-start lg:gap-x-12 xl:gap-x-16">
<ShoppingCart />
<OrderSummary
showSummerBanner={showSummerBanner}
freeDelivery={freeDelivery}
/>
<div className="bg-white">
<div className="mx-auto max-w-2xl px-4 pb-24 pt-16 sm:px-6 lg:max-w-7xl lg:px-8">
<div className="animate-pulse">
<div className="h-8 w-48 bg-gray-200 rounded mb-4"></div>
<div className="h-4 w-32 bg-gray-200 rounded mb-8"></div>
<div className="lg:grid lg:grid-cols-12 lg:items-start lg:gap-x-12 xl:gap-x-16">
<div className="lg:col-span-7">
<div className="h-64 bg-gray-200 rounded"></div>
</div>
<div className="lg:col-span-5">
<div className="h-96 bg-gray-200 rounded"></div>
</div>
</div>
</div>
</div>
</div>
</Main>
);
}

export default function CartPage() {
return (
<Suspense fallback={<CartPageFallback />}>
<CartPageContent />
</Suspense>
);
}
78 changes: 78 additions & 0 deletions app/stickers/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { Main } from '@/components/main';
import { StickerProductCard } from '@/components/stickers/sticker-product-card';

const stickerProducts = [
{
id: 'sticker-circle',
name: 'Circle Sticker Pack',
price: 12.99,
image: '/images/stickers/circle-sticker.png',
description: 'A pack of colorful circular stickers perfect for decoration',
colors: ['Red', 'Blue', 'Green', 'Yellow']
},
{
id: 'sticker-star',
name: 'Star Sticker Collection',
price: 15.99,
image: '/images/stickers/star-sticker.png',
description: 'Shiny star stickers that glow in the dark',
colors: ['Gold', 'Silver', 'Blue', 'Purple']
},
{
id: 'sticker-emoji',
name: 'Emoji Sticker Set',
price: 10.99,
image: '/images/stickers/emoji-sticker.png',
description: 'Express yourself with these fun emoji stickers',
colors: ['Multi-color']
},
{
id: 'sticker-nature',
name: 'Nature Sticker Pack',
price: 14.99,
image: '/images/stickers/nature-sticker.png',
description: 'Beautiful nature-themed stickers with plants and animals',
colors: ['Green', 'Brown', 'Multi-color']
},
{
id: 'sticker-geometric',
name: 'Geometric Sticker Set',
price: 13.99,
image: '/images/stickers/geometric-sticker.png',
description: 'Modern geometric patterns for a contemporary look',
colors: ['Black', 'White', 'Gold', 'Silver']
},
{
id: 'sticker-holographic',
name: 'Holographic Sticker Pack',
price: 18.99,
image: '/images/stickers/holographic-sticker.png',
description: 'Shimmering holographic stickers that change colors',
colors: ['Rainbow', 'Silver', 'Gold']
}
];

export default function StickersPage() {
return (
<Main>
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div className="py-16">
<div className="text-center">
<h1 className="text-4xl font-bold tracking-tight text-gray-900 sm:text-5xl">
Stickers Collection
</h1>
<p className="mt-4 text-xl text-gray-600">
Discover our amazing collection of high-quality stickers
</p>
</div>

<div className="mt-12 grid grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-3">
{stickerProducts.map((product) => (
<StickerProductCard key={product.id} product={product} />
))}
</div>
</div>
</div>
</Main>
);
}
8 changes: 7 additions & 1 deletion components/navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,13 @@ export function Navigation() {
key={page}
className="flex items-center text-sm font-medium text-gray-700 hover:text-gray-800"
>
{page === 'Home' ? <Link href="/">Home</Link> : page}
{page === 'Home' ? (
<Link href="/">Home</Link>
) : page === 'Stickers' ? (
<Link href="/stickers">Stickers</Link>
) : (
page
)}
</span>
);
})}
Expand Down
Loading