Files
site-builder/craft/src/utils/sitesmith-profile.test.ts
T
shadowdaoandClaude Sonnet 5.5 220f560972 feat(site-builder): Sitesmith business profile wizard and one-click section regenerate
5-step profile wizard (name/type, services, area, tone, palette preview) saved to
extras.sitesmithProfile and sent with every Sitesmith request. Regenerate this
section rewrites the selected block for the business as a single undo step.

Refs #58

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 11:55:33 -07:00

53 lines
2.3 KiB
TypeScript

import { describe, test, expect } from 'vitest';
import {
EMPTY_PROFILE, normalizeProfile, validateProfile, isProfileComplete, profileToPrompt, profileSummary,
} from './sitesmith-profile';
const good: any = { business_name: 'Acme', business_type: 'Plumber', services: ['Drains', 'Leaks'], area: 'Austin', tone: 'bold' };
describe('sitesmith-profile', () => {
test('EMPTY_PROFILE is incomplete and names every required field', () => {
const v = validateProfile(EMPTY_PROFILE);
expect(v.ok).toBe(false);
expect(Object.keys(v.errors).sort()).toEqual(['business_name', 'business_type', 'services']);
});
test('complete profile validates; area and notes are optional', () => {
expect(isProfileComplete({ ...good, area: '' })).toBe(true);
expect(validateProfile(good).ok).toBe(true);
});
test('whitespace-only answers do not count', () => {
expect(isProfileComplete({ ...good, business_name: ' ' })).toBe(false);
expect(isProfileComplete({ ...good, services: [' ', ''] })).toBe(false);
});
test('normalize drops unknown keys, dedupes/trims services, falls back on a bad tone', () => {
const n = normalizeProfile({ ...good, services: [' Drains ', 'Drains', 7, ''], tone: 'loud', evil: '<x>' })!;
expect(n.services).toEqual(['Drains']);
expect(n.tone).toBe('friendly');
expect(n).not.toHaveProperty('evil');
expect(n).not.toHaveProperty('notes');
expect(normalizeProfile('nope')).toBeNull();
expect(normalizeProfile([])).toBeNull();
});
test('normalized profile stays under the 2000-char backend cap even for huge input', () => {
const big = 'x'.repeat(5000);
const n = normalizeProfile({ business_name: big, business_type: big, services: Array(50).fill(big).map((s, i) => s + i), area: big, tone: 'calm', notes: big })!;
expect(JSON.stringify(n).length).toBeLessThan(2000);
});
test('profileToPrompt carries name, type, services, area and tone', () => {
const line = profileToPrompt(normalizeProfile(good)!);
expect(line).toContain('Acme is a Plumber');
expect(line).toContain('Drains, Leaks');
expect(line).toContain('Austin');
expect(line).toContain('Tone: bold');
});
test('profileSummary skips an empty area', () => {
expect(profileSummary(normalizeProfile({ ...good, area: '' })!)).toBe('Acme · Plumber');
});
});