BREAKING CHANGE: API parameter renamed from 'extended' to 'long' ## Breaking Change: Terminology Standardization Renamed 'extended' to 'long' across entire codebase for consistency: **Backend (Go):** - internal/handlers/cv.go (7 locations) - Migration logic to auto-convert 'extended' → 'long' cookies - API validation now rejects 'extended', requires 'long' - Toggle state logic updated - internal/handlers/pdf_test.go (17 occurrences) - Test function renamed: TestExportPDF_ExtendedWithSkills → TestExportPDF_LongWithSkills - All test cases, parameters, and expected filenames updated - internal/pdf/generator.go (2 comment updates) **Frontend:** - PDF-EXPORT-FEATURE.md (3 occurrences) - doc/3-API.md (parameter documentation) - doc/7-CUSTOMIZATION.md (examples updated) - templates/partials/modals/pdf-modal.html (button text, URLs) - static/js/main.js (migration logic) - static/hyperscript/toggles._hs (toggle logic) - tests/mjs/24-pdf-download-params.test.mjs (test expectations) - tests/mjs/test-preference-migration.test.mjs (NEW) - tests/mjs/verify-migration.test.mjs (NEW) **PDFs Renamed:** - cv-extended-with_skills-jamr-2025-en.pdf → cv-long-with_skills-jamr-2025-en.pdf - cv-extended-with_skills-jamr-2025-es.pdf → cv-long-with_skills-jamr-2025-es.pdf **Migration:** Automatic cookie migration from 'extended' → 'long' for seamless UX ## New Feature: Compact Sidebar Fonts Reduces page count for short CV with skills from 6 → 5 pages: **Implementation:** - Location: internal/pdf/generator.go (lines 154-215) - Cookie detection: `cookies["cv-length"] == "short"` - Font reduction: 2-6% (0.94-0.98em) - very subtle - Only activates for: `length=short` + `version=with_skills` - Long version: Always uses full-size fonts **Impact:** - Page count: 6 pages → 5 pages (16.7% reduction) - Readability: Maintained - fonts remain professional - Design philosophy: Subtle, natural content flow **Testing:** - New test: TestPDFGenerator_CompactSidebarFonts - Comprehensive coverage of cookie detection and PDF generation - Manual verification: 5-page PDF with compact but readable fonts **Documentation:** - doc/LONG-PDF-GENERATION.md (NEW, 13 KB) - Complete feature documentation - Implementation details with code examples - Font size breakdown table - Testing and troubleshooting guides - Compact sidebar fonts section (comprehensive) **Files Changed:** - 11 modified (backend + frontend + docs) - 5 new files (2 PDFs, 1 doc, 2 tests) - 2 files renamed (PDFs) **Tests:** All Go tests passing, API validation verified, PDF generation tested
CV Project - Test Suite
⚠️ CRITICAL: SINGLE SOURCE OF TRUTH
These tests ARE the specification. These tests ARE the requirements.
If a test passes but the feature doesn't work → THE TEST IS WRONG If a feature works but the test fails → THE FEATURE IS WRONG If something breaks and the test didn't catch it → THE TEST IS INCOMPLETE
Non-Negotiable Rules
- NO CODE CHANGES without corresponding test validation
- ALL bug fixes MUST include a test that would have caught the bug
- EVERY feature MUST have test coverage before deployment
- IF A TEST PASSES, THE FEATURE MUST WORK PERFECTLY
Quick Start
# Run ALL tests (the complete specification)
bun tests/run-all.mjs
# Run individual test
bun tests/mjs/0-zoom.test.mjs
bun tests/mjs/1-toggles.test.mjs
bun tests/mjs/2-keyboard-shortcuts.test.mjs
bun tests/mjs/3-hyperscript.test.mjs
bun tests/mjs/4-htmx.test.mjs
bun tests/mjs/5-language.test.mjs
bun tests/mjs/6-modals.test.mjs
bun tests/mjs/7-mobile-responsive.test.mjs
Test Suite Structure
tests/
├── mjs/ # 🎯 ACTIVE TESTS - SOURCE OF TRUTH
│ ├── 0-zoom.test.mjs
│ ├── 1-toggles.test.mjs
│ ├── 2-keyboard-shortcuts.test.mjs
│ ├── 3-hyperscript.test.mjs
│ ├── 4-htmx.test.mjs
│ ├── 5-language.test.mjs
│ ├── 6-modals.test.mjs
│ ├── 7-mobile-responsive.test.mjs
│ └── README.md
├── archive/ # Historical tests (reference only)
├── screenshots/ # Visual verification
├── run-all.mjs # Master test runner
└── TEST-SUMMARY.md # Complete documentation
NO OTHER FILES. NO EXCEPTIONS.
The 8 Tests (Complete Specification)
0-zoom.test.mjs
What it validates:
- Zoom control elements exist and are accessible
- Zoom toggle shows/hides control
- Zoom slider changes page zoom
- Real-time zoom updates (no page refresh)
If this fails: Zoom functionality is broken
1-toggles.test.mjs
What it validates:
- Length toggle (short/long CV)
- Icon toggle (show/hide icons) - with screenshot verification
- Theme toggle (default/clean)
- Action bar and menu synchronization
- localStorage persistence
- Real-time rendering (no refresh needed)
If this fails: Toggle functionality is broken Historical bug caught: Icon toggle class mismatch (.show-logos vs .show-icons)
2-keyboard-shortcuts.test.mjs
What it validates:
- L key toggles CV length
- I key toggles icons
- V key toggles theme
- ? key opens shortcuts modal
- Shortcuts ignored in input/textarea fields
If this fails: Keyboard navigation is broken
3-hyperscript.test.mjs
What it validates:
- No parse errors on page load
- All functions defined (toggleCVLength, toggleIcons, toggleTheme, handleKeyboardShortcut)
- Keyboard event handlers work
- Def statement count ≤3 (hyperscript parser limit)
- Proper operator precedence (parentheses around
or/and)
If this fails: Hyperscript integration is broken Historical bug caught: Exceeded 3 def statement limit
4-htmx.test.mjs
What it validates:
- HTMX library loaded
- HTMX elements present (hx-get, hx-post, hx-swap, hx-target)
- Request/response cycle works
- Loading indicators configured
If this fails: HTMX integration is broken
5-language.test.mjs
What it validates:
- Language toggle controls exist
- Default language is English
- Spanish loads via URL parameter (?lang=es)
- Language toggle button works
- localStorage/cookie persistence
If this fails: Internationalization is broken
6-modals.test.mjs
What it validates:
- Modal elements exist (info, shortcuts, PDF)
- ? key opens shortcuts modal
- Info and PDF modals open correctly
- ESC key closes modals
- Accessibility attributes (role, aria-label, aria-modal)
If this fails: Modal functionality is broken
7-mobile-responsive.test.mjs
What it validates:
- Mobile viewport (375px) - no horizontal scroll
- Tablet viewport (768px) - proper layout
- Touch interactions (hamburger menu)
- Responsive breakpoints (320px - 1920px)
- Viewport meta tag
- Touch-friendly button sizes (≥44px)
- Text readability (≥14px font)
If this fails: Mobile experience is broken
Test Output Format
Every test provides:
- ✅ Clear pass/fail indicators
- 📊 Summary of results
- ❌ Detailed error messages with file:line references
- 🎉 Success confirmation
- 💡 Browser stays open for manual verification
When Tests Fail
Investigation Protocol
- Read the test output - It tells you EXACTLY what failed
- Look at the browser - Tests leave browser open for inspection
- Check screenshots (if test uses them)
- Read the test code - It's the specification
- Fix the code OR fix the test - One of them is wrong
Fixing Tests vs Fixing Code
Fix the CODE if:
- The test correctly describes desired behavior
- The implementation doesn't match the test
- The test caught a real bug
Fix the TEST if:
- The test doesn't match actual requirements
- The test has false positives/negatives
- The test is outdated
After fixing EITHER, verify:
bun tests/run-all.mjs # ALL tests must pass
Adding New Tests
Numbering Convention
Tests are numbered 0-9 for execution order:
- Use next available number (8, 9, ...)
- Numbers indicate priority/dependency
- Master runner auto-discovers numbered tests
Test Template
#!/usr/bin/env bun
/**
* {FEATURE} TEST
* ==============
* What this validates and why it matters
*/
import { chromium } from 'playwright';
const URL = "http://localhost:1999";
async function test{Feature}() {
console.log('🔍 {FEATURE} TEST\n');
console.log('='.repeat(70));
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage({ viewport: { width: 1920, height: 1080 } });
const errors = [];
const testResults = [];
// Track errors
page.on('console', msg => {
if (msg.type() === 'error') {
errors.push(msg.text());
console.log(`❌ ERROR: ${msg.text()}`);
}
});
// ... test implementation ...
// ALWAYS provide summary
console.log("\n" + "=".repeat(70));
console.log("📊 TEST SUMMARY\n");
// ... summary ...
console.log("\nBrowser will stay open for manual inspection.");
console.log("Press Ctrl+C when done.\n");
await new Promise(() => {}); // Keep browser open
}
await test{Feature}();
Required Test Components
Every test MUST include:
- Clear purpose statement - What does this test validate?
- Error tracking - Capture console errors
- Test results array - Track pass/fail for each assertion
- Summary output - Show what passed/failed
- Browser stays open - For manual verification
- File:line references - When tests fail
Test Requirements
- Server: Running on http://localhost:1999
- Browser: Playwright Chromium (headed mode)
- Runtime: Bun (
#!/usr/bin/env bun) - Exit: Ctrl+C after manual verification
Archive Directory
tests/archive/ contains 60+ historical tests organized by category:
- toggles/ - Toggle implementation evolution
- zoom/ - Zoom functionality iterations
- hyperscript/ - Hyperscript debugging
- htmx/ - HTMX behavior validation
- keyboard/ - Keyboard shortcut iterations
- language/ - Language switching attempts
- visual/ - Visual regression tests
- performance/ - Performance benchmarks
- integration/ - Full integration tests
- misc/ - One-off debugging tests
Purpose: Historical reference and edge case documentation Status: Superseded by systematic test suite Usage: Reference only - DO NOT RUN
Accountability
Every time something breaks in production:
-
Which test should have caught this?
- If test exists → Fix the test
- If test missing → Write the test
-
Why didn't the test catch it?
- Incomplete coverage → Expand test
- False positive → Fix assertions
- Wrong assumptions → Update spec
-
How do we prevent this?
- Add regression test
- Document in TEST-SUMMARY.md
- Update this README
Success Criteria
✅ All 8 tests pass ✅ Browser manual verification confirms ✅ No console errors ✅ Features work as specified
If any test fails, deployment is BLOCKED.
Last Updated: 2025-11-17 Test Count: 8 active, 60+ archived Status: Production specification Responsibility: These tests define what "working" means