refactor: Integrate PreferencesMiddleware and update handlers

Complete middleware integration with comprehensive testing:

1. Middleware Integration
   - Added PreferencesMiddleware to middleware chain in routes
   - Order: Recovery → Logger → SecurityHeaders → Preferences → Mux
   - Reads all preference cookies once per request
   - Stores in context for handlers to access

2. Handler Updates
   - cv_pages.go: Home handler uses middleware.GetPreferences()
   - cv_htmx.go: All toggle handlers use middleware preferences
   - Eliminated manual cookie reading in handlers
   - Migration logic handled entirely by middleware

3. Comprehensive Middleware Tests
   - Created preferences_test.go with 10+ test functions
   - Tests: default values, migrations, cookie setting, context access
   - Verified: extended→long, true→show, false→hide migrations
   - All tests passing

Benefits:
- Performance: Cookies read once per request (not multiple times)
- Consistency: All handlers get same preference values
- Maintainability: Migration logic centralized in middleware
- Testability: Easy to mock preferences via context

Testing:
- All unit tests pass (handlers + middleware)
- Build succeeds
- No breaking changes
This commit is contained in:
juanatsap
2025-11-20 17:56:47 +00:00
parent 399ddded6c
commit ae89d84e07
6 changed files with 515 additions and 56 deletions
+134
View File
@@ -0,0 +1,134 @@
#!/usr/bin/env bun
/**
* Quick debug to see what's happening with tooltips
*/
import { chromium } from 'playwright';
const URL = "http://localhost:1999";
async function debugTooltip() {
console.log('🔍 TOOLTIP DEBUG\n');
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage({ viewport: { width: 1920, height: 1080 } });
await page.goto(URL);
await page.waitForTimeout(2000);
console.log("\n1️⃣ Checking button and tooltip setup...");
const buttonInfo = await page.evaluate(() => {
const btn = document.querySelector('#action-bar-pdf-btn');
if (!btn) return { found: false };
const computedBefore = window.getComputedStyle(btn, '::before');
return {
found: true,
classes: Array.from(btn.classList),
dataTooltip: btn.getAttribute('data-tooltip'),
beforeStyles: {
content: computedBefore.content,
position: computedBefore.position,
opacity: computedBefore.opacity,
visibility: computedBefore.visibility,
display: computedBefore.display,
fontSize: computedBefore.fontSize,
fontWeight: computedBefore.fontWeight,
background: computedBefore.background,
color: computedBefore.color,
left: computedBefore.left,
top: computedBefore.top,
transform: computedBefore.transform,
zIndex: computedBefore.zIndex
}
};
});
console.log('\n📊 Button Information:');
console.log(' Classes:', buttonInfo.classes.join(', '));
console.log(' data-tooltip:', buttonInfo.dataTooltip);
console.log('\n🎨 ::before Pseudo-element Styles:');
console.log(' content:', buttonInfo.beforeStyles.content);
console.log(' position:', buttonInfo.beforeStyles.position);
console.log(' opacity:', buttonInfo.beforeStyles.opacity);
console.log(' visibility:', buttonInfo.beforeStyles.visibility);
console.log(' display:', buttonInfo.beforeStyles.display);
console.log(' fontSize:', buttonInfo.beforeStyles.fontSize);
console.log(' fontWeight:', buttonInfo.beforeStyles.fontWeight);
console.log(' background:', buttonInfo.beforeStyles.background);
console.log(' color:', buttonInfo.beforeStyles.color);
console.log(' left:', buttonInfo.beforeStyles.left);
console.log(' top:', buttonInfo.beforeStyles.top);
console.log(' transform:', buttonInfo.beforeStyles.transform);
console.log(' z-index:', buttonInfo.beforeStyles.zIndex);
console.log('\n2️⃣ Checking if tooltip CSS file is loaded...');
const cssCheck = await page.evaluate(() => {
// Check all link tags
const links = Array.from(document.querySelectorAll('link[rel="stylesheet"]'));
const cssLinks = links.map(l => l.href);
// Try to find tooltip rules
let tooltipRulesFound = [];
for (const sheet of document.styleSheets) {
try {
const rules = Array.from(sheet.cssRules || []);
for (const rule of rules) {
if (rule.cssText && (rule.cssText.includes('.has-tooltip') || rule.cssText.includes('has-tooltip'))) {
tooltipRulesFound.push(rule.cssText.substring(0, 100));
}
}
} catch (e) {
// Skip cross-origin sheets
}
}
return {
cssLinks,
tooltipRulesFound
};
});
console.log('\n📄 CSS Files Loaded:');
cssCheck.cssLinks.forEach(link => console.log(' -', link));
console.log('\n📋 Tooltip CSS Rules Found:', cssCheck.tooltipRulesFound.length);
if (cssCheck.tooltipRulesFound.length > 0) {
console.log(' Sample rules:');
cssCheck.tooltipRulesFound.slice(0, 3).forEach(rule => console.log(' -', rule));
}
console.log('\n3️⃣ Testing hover...');
console.log('Hovering over PDF button in 2 seconds...');
await page.waitForTimeout(2000);
await page.hover('#action-bar-pdf-btn');
await page.waitForTimeout(1000);
const afterHover = await page.evaluate(() => {
const btn = document.querySelector('#action-bar-pdf-btn');
const computedBefore = window.getComputedStyle(btn, '::before');
return {
opacity: computedBefore.opacity,
visibility: computedBefore.visibility,
transform: computedBefore.transform
};
});
console.log('\n🖱️ After Hover:');
console.log(' opacity:', afterHover.opacity, '(should be 1)');
console.log(' visibility:', afterHover.visibility, '(should be visible)');
console.log(' transform:', afterHover.transform);
console.log('\n💡 Browser is open. Try hovering over the buttons yourself!');
console.log('Press Ctrl+C when done.\n');
await new Promise(() => {}); // Keep browser open
}
await debugTooltip();