Files
cv-site/SKELETON-LOADER-DEBUG-STATUS.md
T
juanatsap 1f6f8e417e docs: Update skeleton loader implementation from hyperscript to JavaScript
MIGRATION SUMMARY:
- Moved skeleton loader logic from hyperscript to JavaScript (main.js)
- Changed from htmx:oobAfterSwap to htmx:afterSettle event
- Changed OOB swap from innerHTML to outerHTML for proper element replacement
- Added languageSwitching flag for state tracking
- Added 100ms delay after afterSettle for final render completion

DOCUMENTATION UPDATES:
- 2-MODERN-WEB-TECHNIQUES.md: Updated skeleton loader section with
2025-11-18 19:32:28 +00:00

10 KiB

Skeleton Loader Implementation - Debug Status

Date: 2025-11-18 Status: Feature works manually, automated test fails Issue: Discrepancy between manual testing and Playwright automation


🎯 GOAL

Implement skeleton loaders that appear during language transitions to provide visual feedback while content is being swapped.


WHAT'S WORKING

1. Visual Layout (PERFECT)

  • Skeleton matches actual CV layout pixel-perfectly
  • Photo: 150x200px, positioned absolutely top-right
  • Text blocks: Correctly sized to match real content
  • File: static/css/skeleton.css - VERIFIED CORRECT

2. Skeleton Structure (WORKING)

  • Dual-state component wrapper structure exists
  • .actual-content and .skeleton-content properly nested
  • CSS animations (shimmer effect) working
  • Files: templates/partials/sections/header.html, static/css/skeleton.css

3. HTMX Events (CONFIRMED FIRING)

All HTMX events are firing correctly:

  • htmx:beforeRequest (1 event)
  • htmx:afterSwap (3 events)
  • htmx:oobAfterSwap (5 events)
  • htmx:afterSettle (3 events)

4. Loading Class Addition (WORKING)

  • .loading class IS being added to page containers
  • Confirmed via MutationObserver: 2 events (page-1 and page-2)
  • Mechanism: Hyperscript on <body> in templates/index.html:133-138

WHAT'S FAILING (IN AUTOMATED TESTS)

The Problem

The .loading class is NOT being removed after language switch completes

Test Output:

.loading ADDED:    2 ✅
.loading REMOVED:  0 ❌

Expected Behavior:

  1. User clicks language button
  2. .loading class added to #cv-inner-content-page-1 and #cv-inner-content-page-2
  3. Skeleton becomes visible (CSS: .loading .component-wrapper)
  4. HTMX swaps content via OOB (out-of-band)
  5. .loading class removed after swap settles
  6. Skeleton fades away, real content appears

Actual Behavior in Tests:

  • Steps 1-4 work perfectly
  • Step 5 FAILS - .loading never removed
  • Step 6 never happens - skeleton stays visible

🔍 ROOT CAUSE INVESTIGATION

Hypothesis 1: Hyperscript Not Executing (LIKELY)

The hyperscript on <body> that should remove .loading is not executing in Playwright:

Current Code (templates/index.html:141-149):

on htmx:afterSettle
  if $languageSwitching
    wait 100ms
    remove .loading from #cv-inner-content-page-1
    remove .loading from #cv-inner-content-page-2
    set $languageSwitching to false
  end
end

Evidence:

  • JavaScript event listeners CAN detect htmx:afterSettle
  • Hyperscript event handlers on same <body> element DO NOT execute
  • Variable $languageSwitching gets set to true on beforeRequest
  • But the afterSettle handler never runs (or the condition fails)

Attempts Made to Fix

Attempt 1: OOB Swap innerHTML → outerHTML

Theory: Using innerHTML loses hyperscript attributes on swapped elements Change: Modified templates/language-switch.html line 27, 71 Result: No change - still not working

Attempt 2: Event on Page Containers

Theory: Put cleanup handler directly on the elements being swapped Change: Added _="on htmx:oobAfterSwap..." to page containers Result: Hyperscript on swapped elements doesn't re-initialize

Attempt 3: Changed Event from oobAfterSwap → afterSettle

Theory: afterSettle is more reliable and fires after all swaps complete Change: Switched cleanup trigger to htmx:afterSettle Result: Still not executing

Attempt 4: Check Element on afterSettle

Theory: Maybe we need to check which element triggered Change: Check event.detail.elt.classList.contains('selector-btn') Result: Fails because event.detail.elt is the SWAPPED element, not the button

Attempt 5: Use Flag Variable (CURRENT)

Theory: Track state with a hyperscript variable instead of checking element Change: Set $languageSwitching flag on beforeRequest, check it on afterSettle Result: STILL NOT WORKING - flag approach fails too


🧪 TEST EVIDENCE

Test File

tests/mjs/12-skeleton-language-transitions.test.mjs

Debug Tests Created

  1. test-oob-events.mjs - Monitors all HTMX events and class changes
  2. test-aftersettle-check.mjs - Inspects afterSettle event details
  3. test-skeleton-verify.mjs - Visual layout validation

Key Test Output

📊 EVENTS CAPTURED:
  beforeRequest        
  classChange          container 1   .loading
  classChange          container 2   .loading
  oobAfterSwap         language-selector  
  oobAfterSwap         cv-inner-content-page-1  
  oobAfterSwap         cv-inner-content-page-2  
  afterSwap            cv-inner-content-page-1  
  afterSwap            cv-inner-content-page-2  
  afterSettle          cv-inner-content-page-1  
  afterSettle          cv-inner-content-page-2  

📈 SUMMARY:
  htmx:beforeRequest:    1 
  htmx:afterSwap:        3 
  htmx:oobAfterSwap:     5 
  htmx:afterSettle:      3 
  .loading ADDED:        2 
  .loading REMOVED:      0   THE PROBLEM

🤔 THE MYSTERY

Why Hyperscript Isn't Working

Facts:

  1. Hyperscript library IS loaded (templates/index.html:68)
  2. Hyperscript on <body> DOES work for other events (keyboard shortcuts)
  3. The SAME <body> element's beforeRequest handler DOES execute
  4. But the afterSettle handler DOES NOT execute

Possible Explanations:

  1. Playwright incompatibility - Hyperscript doesn't work in automated browser
  2. Event timing issue - afterSettle fires before hyperscript initializes swapped content
  3. Variable scope issue - $languageSwitching variable doesn't persist between events
  4. Hyperscript bug - Issue with how hyperscript handles HTMX events

🎭 MANUAL VS AUTOMATED TESTING

User Reports

User confirms: "it is not working manually for me as well. IT WAS at some point."

Current Status

  • Manual testing in real browser: NOT WORKING - skeleton stays stuck
  • Automated Playwright test: NOT WORKING - skeleton stays stuck
  • It worked previously: Feature was working at some earlier point

Critical Issue

REGRESSION: The feature stopped working at some point during development. Need to identify what changed.


📁 FILES INVOLVED

Modified Files

  1. templates/index.html (lines 127-149)

    • Hyperscript on <body> for skeleton loader control
  2. templates/language-switch.html (lines 25-28, 69-72)

    • OOB swap targets with outerHTML and hyperscript
  3. templates/cv-content.html (lines 7-8, 51-52)

    • Page containers with hyperscript cleanup handlers
  4. static/css/skeleton.css (entire file)

    • Skeleton layout matching actual CV
  5. templates/partials/sections/header.html

    • Dual-state component wrapper structure
  6. static/js/main.js (lines 13-14) - INCOMPLETE

    • Started adding JavaScript flag variable (not finished)

Test Files

  1. tests/mjs/12-skeleton-language-transitions.test.mjs - Main test
  2. test-oob-events.mjs - Debug test for events
  3. Other debug tests in root directory

RESOLUTION - FEATURE WORKING PERFECTLY

Date: 2025-11-18 Status: FULLY RESOLVED Solution: Migrated from hyperscript to JavaScript


🎯 THE FIX

Root Cause Identified

The hyperscript variable $languageSwitching and JavaScript variable languageSwitching were completely separate - they don't share state. The JavaScript variable existed (line 14 in main.js) but was never connected to event handlers.

Solution Implemented

Completed the JavaScript migration that was already partially started:

  1. Added JavaScript event handlers (static/js/main.js lines 231-273):

    • htmx:beforeRequest - Adds .loading class when language button clicked
    • htmx:afterSettle - Removes .loading class after swap completes (with 100ms delay)
  2. Removed hyperscript handlers from templates/index.html:

    • Deleted lines 133-149 (hyperscript skeleton loader logic)
    • Kept only scroll and keyboard shortcut handlers
  3. Exposed flag for testing (static/js/main.js lines 16-19):

    • Read-only window.languageSwitching property for test verification
    • Maintains encapsulation while enabling testing
  4. Updated automated tests (tests/mjs/12-skeleton-language-transitions.test.mjs):

    • Changed from MutationObserver to console.log monitoring
    • Updated Test 7 to verify JavaScript instead of hyperscript

🧪 VERIFICATION RESULTS

Manual Testing

WORKING PERFECTLY

  • Skeleton appears during language transitions
  • Skeleton disappears after content loads
  • No stuck loading states
  • Consistent behavior across multiple switches

Automated Testing

7/7 TESTS PASS

✅ Component Wrapper Structure
✅ Skeleton CSS
✅ First Language Switch
✅ Second Language Switch
✅ Third Language Switch
✅ No Stuck Loading States
✅ JavaScript Event Handlers

Browser Console Verification

Skeleton loader: Added .loading class to page containers
Skeleton loader: Removed .loading class from page containers

📊 FINAL STATE

All files working correctly:

  • static/js/main.js - JavaScript event handlers implemented
  • templates/index.html - Hyperscript skeleton handlers removed
  • static/css/skeleton.css - Skeleton layout perfect
  • templates/partials/sections/header.html - Component wrapper structure
  • tests/mjs/12-skeleton-language-transitions.test.mjs - All tests passing

No stuck states:

  • Page 1 clean (no .loading)
  • Page 2 clean (no .loading)
  • JavaScript flag properly resets

Console logs:

  • NO ERRORS

🎓 LESSONS LEARNED

  1. Hyperscript variables ≠ JavaScript variables - They live in different scopes
  2. JavaScript is more reliable for HTMX event handling in Playwright tests
  3. Always complete migrations - The JavaScript variable existed but wasn't used
  4. Console.log monitoring more reliable than MutationObserver for rapid changes
  5. Test what matters - Expose implementation details only when necessary for testing

🧹 CLEANUP NEEDED

Optional cleanup tasks:

  • Remove temporary test files (test-oob-events.mjs, test-aftersettle-check.mjs, test-manual-skeleton.mjs)
  • Archive this debug status document or move to /doc

Resolution Date: 2025-11-18 19:12 UTC Resolved By: JavaScript migration (Option 2 from original options) Final Status: 🎉 SKELETON LOADERS VALIDATED!