4aa534d1f7
Deploy to Dev / Deploy & Smoke Test (push) Successful in 23s
- tests/api.spec.js: 17 tests covering public booking API and admin CRUD (health, POST bookings, auth rejection, stats, filters, PATCH, CSV export) - tests/booking.spec.js: 12 tests covering the 7-step booking wizard (open/close, date validation, step progression, contract scroll+signature, payment checkbox, full end-to-end booking flow) - tests/dashboard.spec.js: 15 tests covering the admin dashboard (login, wrong passphrase, Enter key, sign out, overview stats, calendar month nav, bookings table, search filter, row expand, CSV download) - tests/portfolio.spec.js: 7 tests covering the portfolio site (nav, book button, portfolio section, config, health, theme color) - playwright.config.js: Chromium headless, BASE_URL + ADMIN_SECRET via env - Fix dangling client-email input outside step-panel (was visible, making the booking modal taller and hiding the Next button in headless mode) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
64 lines
2.4 KiB
JavaScript
64 lines
2.4 KiB
JavaScript
// @ts-check
|
|
const { test, expect } = require('@playwright/test');
|
|
|
|
test.describe('Portfolio site', () => {
|
|
test('loads and shows site name in nav', async ({ page }) => {
|
|
await page.goto('/');
|
|
// #header-logo is the visible nav brand link
|
|
const logo = page.locator('#header-logo, .logo').filter({ visible: true }).first();
|
|
await expect(logo).toBeVisible();
|
|
await expect(logo).toContainText(/.+/); // non-empty
|
|
});
|
|
|
|
test('navigation renders with Book a Session button', async ({ page }) => {
|
|
await page.goto('/');
|
|
const bookBtn = page.locator('button:has-text("Book a Session"), a:has-text("Book a Session")').first();
|
|
await expect(bookBtn).toBeVisible();
|
|
});
|
|
|
|
test('portfolio section is visible', async ({ page }) => {
|
|
await page.goto('/');
|
|
// Wait for page to load config and render
|
|
await page.waitForLoadState('networkidle');
|
|
const portfolio = page.locator('#portfolio, section#portfolio, [id*="portfolio"]').first();
|
|
await expect(portfolio).toBeAttached();
|
|
});
|
|
|
|
test('config/site.json is served', async ({ page }) => {
|
|
const res = await page.request.get('/config/site.json');
|
|
expect(res.status()).toBe(200);
|
|
const json = await res.json();
|
|
expect(json).toHaveProperty('site');
|
|
expect(json).toHaveProperty('booking');
|
|
expect(json).toHaveProperty('theme');
|
|
});
|
|
|
|
test('health endpoint returns ok', async ({ page }) => {
|
|
const res = await page.request.get('/health');
|
|
expect(res.status()).toBe(200);
|
|
});
|
|
|
|
test('API health returns {ok:true}', async ({ page }) => {
|
|
const res = await page.request.get('/api/health');
|
|
expect(res.status()).toBe(200);
|
|
const json = await res.json();
|
|
expect(json.ok).toBe(true);
|
|
});
|
|
|
|
test('pink theme is applied (primary color is rose/pink)', async ({ page }) => {
|
|
await page.goto('/');
|
|
const primary = await page.evaluate(() =>
|
|
getComputedStyle(document.documentElement).getPropertyValue('--color-primary').trim()
|
|
);
|
|
// Should be a pink/rose hex — starts with #B or #b (our dusty rose #B06A7A)
|
|
expect(primary.toLowerCase()).toMatch(/^#[a-f0-9]{6}$/i);
|
|
// Hue should be in the red-pink range: R > G and R > B
|
|
const hex = primary.replace('#', '');
|
|
const r = parseInt(hex.slice(0, 2), 16);
|
|
const g = parseInt(hex.slice(2, 4), 16);
|
|
const b = parseInt(hex.slice(4, 6), 16);
|
|
expect(r).toBeGreaterThan(g);
|
|
expect(r).toBeGreaterThan(b);
|
|
});
|
|
});
|