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
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@

# testing
/coverage
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/

# next.js
/.next/
Expand Down Expand Up @@ -50,3 +54,7 @@ next-env.d.ts

# claude code
.claude

# Playwright
node_modules/
/playwright/.auth/
99 changes: 77 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
# TRE - Next.js TypeScript Starter
# TRE - Childcan Website

A modern, production-ready Next.js starter template with TypeScript, Tailwind CSS v4, and best practices built-in.
A modern Next.js website built with TypeScript, Tailwind CSS v4, and Sanity CMS integration.

## 🚀 Features

- ⚡ **Next.js 15.5** - The latest version of Next.js with App Router
- ⚡ **Next.js 16** - Latest version with App Router
- 🔷 **TypeScript** - Type safety and better developer experience
- 🎨 **Tailwind CSS v4** - The latest version with modern CSS capabilities
- 📦 **Optimized Build** - Production-ready build configuration
- 🧪 **Type Checking** - Strict TypeScript configuration
- 🎯 **Developer Experience** - ESLint, Prettier-ready, and hot reload
- 🎨 **Tailwind CSS v4** - Modern CSS capabilities with @theme directives
- 📦 **Sanity CMS** - Headless CMS for content management
- 🧪 **E2E Testing** - Playwright test suite for quality assurance
- 🎯 **Developer Experience** - ESLint, Prettier, and hot reload
- 📱 **Responsive** - Mobile-first design approach
- 🌙 **Dark Mode** - Built-in dark mode support
- 📝 **Template System** - Issue and PR templates included
- 🗺️ **Google Maps** - Interactive location features

## 📋 Prerequisites

Expand Down Expand Up @@ -56,31 +55,48 @@ Open [http://localhost:3000](http://localhost:3000) in your browser to see the r

## 📜 Available Scripts

### Development

- `npm run dev` - Start the development server with Turbopack
- `npm run build` - Build the application for production
- `npm run start` - Start the production server
- `npm run lint` - Run ESLint to check code quality (if configured)
- `npm run lint` - Run ESLint to check code quality
- `npm run format` - Format code with Prettier

### Testing

- `npm test` - Run all Playwright tests (headless)
- `npm run test:ui` - Run tests with interactive UI mode
- `npm run test:smoke` - Run quick smoke tests to verify all pages load
- `npm run test:headed` - Run tests in headed mode (visible browser)
- `npm run test:debug` - Run tests in debug mode with Playwright Inspector

## 📁 Project Structure

```
tre/
├── app/ # Next.js App Router directory
│ ├── (main-route)/ # Main website routes
│ │ ├── page.tsx # Home page
│ │ ├── about-us/ # About page
│ │ ├── contact/ # Contact page
│ │ ├── events/ # Events pages
│ │ └── ... # Other routes
│ ├── sanity/ # Sanity Studio integration
│ ├── layout.tsx # Root layout component
│ ├── page.tsx # Home page
│ ├── globals.css # Global styles with Tailwind
│ └── favicon.ico # Favicon
├── public/ # Static files
├── .github/ # GitHub templates
│ ├── ISSUE_TEMPLATE/ # Issue templates
│ └── pull_request_template.md
├── .env.example # Environment variables template
├── .gitignore # Git ignore rules
│ └── globals.css # Global styles with Tailwind
├── components/ # Reusable React components
│ └── header/ # Header and navigation
├── e2e/ # Playwright E2E tests
│ ├── smoke.spec.ts # Page load tests
│ ├── navigation.spec.ts # Navigation tests
│ └── forms.spec.ts # Form interaction tests
├── public/ # Static files
├── .env.example # Environment variables template
├── playwright.config.ts # Playwright test configuration
├── next.config.ts # Next.js configuration
├── package.json # Project dependencies
├── postcss.config.mjs # PostCSS configuration for Tailwind
├── tsconfig.json # TypeScript configuration
└── README.md # This file
└── tsconfig.json # TypeScript configuration
```

## 🎨 Tailwind CSS v4
Expand Down Expand Up @@ -149,6 +165,45 @@ To start the production server:
npm run start
```

## 🧪 Testing

This project uses [Playwright](https://playwright.dev/) for end-to-end testing.

### Running Tests

```bash
# Quick smoke tests (recommended before deployment)
npm run test:smoke

# All tests with interactive UI
npm run test:ui

# Run all tests headless
npm test

# Debug a specific test
npm run test:debug
```

### Test Structure

The test suite is located in the `e2e/` directory:

- **smoke.spec.ts** - Verifies all pages load without errors
- **navigation.spec.ts** - Tests header navigation and responsive design
- **forms.spec.ts** - Form interaction tests (customize for your forms)

### What Gets Tested

- ✅ All pages load successfully
- ✅ No console errors on key pages
- ✅ Navigation links work correctly
- ✅ Mobile menu functionality
- ✅ Responsive design across devices
- ✅ Cross-browser compatibility (Chrome, Firefox, Safari)

For more details, see [e2e/README.md](e2e/README.md).

## 🚀 Deployment

### Vercel (Recommended)
Expand Down
94 changes: 94 additions & 0 deletions e2e/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Playwright Test Suite

## Quick Start

```bash
# Run all tests (headless)
npm test

# Run tests with UI mode (recommended for development)
npm run test:ui

# Run only smoke tests (fast, checks all pages load)
npm run test:smoke

# Run tests in headed mode (see browser)
npm run test:headed

# Debug mode (opens Playwright Inspector)
npm run test:debug
```

## Test Structure

### `smoke.spec.ts`

Fast tests that verify all pages load without errors. Run these first after deployment.

### `navigation.spec.ts`

Tests for header navigation, mobile menu, and responsive design.

### `forms.spec.ts`

Form interaction tests (mostly skipped - customize based on your forms).

## What to Update

1. **Forms tests** - Currently skipped. Update selectors to match your actual form fields
2. **Navigation tests** - Verify the link selectors match your header structure
3. **Add dynamic route tests** - Test `/our-families-stories/[slug]` and `/events/[slug]` with real slugs
4. **Base URL** - Update `playwright.config.ts` to uncomment `baseURL` if you want to use relative paths in tests
5. **Web Server** - Uncomment `webServer` config if you want Playwright to auto-start your dev server

## Testing Workflow

**Before deploying:**

```bash
npm run test:smoke # Quick verification (2-3 minutes)
```

**Full test run:**

```bash
npm test # Runs across all browsers
```

**Visual debugging:**

```bash
npm run test:ui # Interactive UI, great for writing new tests
```

## Next Steps

- [ ] Customize form tests in `forms.spec.ts`
- [ ] Add tests for dynamic routes with real content
- [ ] Add visual regression tests if needed
- [ ] Set up CI/CD to run tests automatically
- [ ] Uncomment mobile browser testing in `playwright.config.ts` if needed

## CI Integration

The config is CI-ready. On CI:

- Tests run with 2 retries (0 retries locally)
- Uses single worker for stability
- Configured for continuous integration environments

## Browsers Tested

- ✅ Desktop: Chromium, Firefox, Safari (WebKit)

Mobile browser testing is available but currently disabled. To enable:

1. Uncomment the mobile projects in `playwright.config.ts`

To test only one browser:

```bash
npx playwright test --project=chromium
npx playwright test --project=firefox
npx playwright test --project=webkit
```
53 changes: 53 additions & 0 deletions e2e/forms.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { test, expect } from "@playwright/test";

/**
* Forms and interactions tests
* Verify forms are present and can be interacted with
*/

test.describe("Contact Form", () => {
test.skip("contact form is visible", async ({ page }) => {
// Skip by default - enable once you verify the form structure
await page.goto("/contact");

// Update these selectors based on your actual form structure
const form = page.locator("form");
await expect(form).toBeVisible();
});

test.skip("contact form fields are present", async ({ page }) => {
// Skip by default - customize based on your form fields
await page.goto("/contact");

// Example - update with your actual field names/IDs
await expect(page.locator('input[name="name"]')).toBeVisible();
await expect(page.locator('input[name="email"]')).toBeVisible();
await expect(page.locator('textarea[name="message"]')).toBeVisible();
});

test.skip("can fill out and submit contact form", async ({ page }) => {
// Skip by default - customize based on your form
await page.goto("/contact");

// Fill form
await page.fill('input[name="name"]', "Test User");
await page.fill('input[name="email"]', "test@example.com");
await page.fill('textarea[name="message"]', "This is a test message");

// Submit
await page.click('button[type="submit"]');

// Verify success (customize based on your success message/redirect)
await expect(page.locator("text=/thank you|success/i")).toBeVisible();
});
});

test.describe("Search Functionality", () => {
test.skip("search bar is present on homepage", async ({ page }) => {
// Skip by default - enable if you have search
await page.goto("/");

const searchBar = page.locator('input[type="search"]');
await expect(searchBar).toBeVisible();
});
});
74 changes: 74 additions & 0 deletions e2e/navigation.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { test, expect } from "@playwright/test";

/**
* Navigation tests - verify core user flows work
*/

test.describe("Navigation", () => {
test("header navigation is visible and functional", async ({ page }) => {
await page.goto("/");

// Check header is visible
const header = page.locator("header");
await expect(header).toBeVisible();
});

test("can navigate between pages via header links", async ({ page }) => {
await page.goto("/");

// Click on About Us link (adjust selector as needed)
await page.click('a[href*="about"]');
await expect(page).toHaveURL(/about/);

// Navigate to another page
await page.click('a[href*="contact"]');
await expect(page).toHaveURL(/contact/);
});

test("mobile menu works on small screens", async ({ page }) => {
// Set mobile viewport
await page.setViewportSize({ width: 375, height: 667 });
await page.goto("/");

// Mobile menu should be present
const header = page.locator("header");
await expect(header).toBeVisible();
});

test("all header links are clickable", async ({ page }) => {
await page.goto("/");

// Get all navigation links
const navLinks = page.locator('header a[href^="/"]');
const count = await navLinks.count();

// Verify we have navigation links
expect(count).toBeGreaterThan(0);

// Verify each link has an href
for (let i = 0; i < count; i++) {
const href = await navLinks.nth(i).getAttribute("href");
expect(href).toBeTruthy();
}
});
});

test.describe("Responsive Design", () => {
test("homepage is responsive on mobile", async ({ page }) => {
await page.setViewportSize({ width: 375, height: 667 });
await page.goto("/");
await page.waitForLoadState("networkidle");

// Take screenshot for visual reference
await page.screenshot({ path: "test-results/mobile-homepage.png" });
});

test("homepage is responsive on desktop", async ({ page }) => {
await page.setViewportSize({ width: 1920, height: 1080 });
await page.goto("/");
await page.waitForLoadState("networkidle");

// Take screenshot for visual reference
await page.screenshot({ path: "test-results/desktop-homepage.png" });
});
});
Loading