9dcc73ecfe
Deploy to Dev / Deploy & Smoke Test (push) Successful in 21s
- Fix applyConfig self-recursion (const _origApply captured the hoisted wrapper itself): site.json config — theme, portfolio, socials, bio — was never applied; site silently fell back to hardcoded brown defaults - Strengthen theme test to assert the configured primary color exactly - Portfolio covers: styled placeholder on missing image (like locations), restore img when Immich carousel kicks in; overlay always visible on touch - Optional hero photo via site.heroImage with soft scrim (activates only when the image loads); site.json points at /images/hero.jpg - Option cards: equal height, centered content - /#book deep link also works via hashchange Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
62 lines
2.3 KiB
JavaScript
62 lines
2.3 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('configured theme is applied (primary color matches site.json)', async ({ page, request }) => {
|
|
const config = await (await request.get('/config/site.json')).json();
|
|
const expected = (config.theme?.primaryColor || '').toLowerCase();
|
|
expect(expected).toMatch(/^#[a-f0-9]{6}$/);
|
|
|
|
await page.goto('/');
|
|
// Config is fetched on window load; wait until the var flips from the CSS default
|
|
await page.waitForFunction(
|
|
exp => getComputedStyle(document.documentElement).getPropertyValue('--color-primary').trim().toLowerCase() === exp,
|
|
expected,
|
|
{ timeout: 8_000 }
|
|
);
|
|
});
|
|
});
|