Files
cv-site/tests/mjs/34-mobile-button-opacity-test.mjs
T
juanatsap 2eafb78954 fix: Mobile view improvements - accordion styling and modal centering
Fixed two critical mobile view issues:

1. Extended CV Sidebar Accordion:
   - Updated sidebar.html to use native <details> element (was div with onclick)
   - Styled accordion header to match CV title badges dark theme (#303030)
   - Applied consistent styling: dark gray background, light text, uppercase, no spacing
   - Result: Sidebars now collapse/expand properly with native HTML functionality

2. PDF Download Modal Centering:
   - Added JavaScript-based centering for mobile viewports (≤768px)
   - Uses inline styles with !important flag to override browser defaults
   - Updated download button to call openPdfModal() function
   - Result: Modal is perfectly centered on mobile (0px offset)

Technical notes:
   - Modal centering required setProperty() with 'important' flag
   - Accordion matches cv-title-badges-header style exactly
   - All tests passing: accordion toggle, modal centering

Files modified:
   - templates/partials/cv/sidebar.html
   - static/css/05-responsive/_breakpoints.css
   - static/js/main.js
   - templates/partials/widgets/download-button.html

Tests added:
   - tests/mjs/43-mobile-accordion-and-modal-test.mjs
   - tests/mjs/46-visual-accordion-style-test.mjs
2025-11-22 16:23:05 +00:00

139 lines
4.4 KiB
JavaScript
Executable File

#!/usr/bin/env node
/**
* Test: Mobile Button Opacity - 50% default, 100% on hover
*
* Verifies that on mobile view (max-width: 900px):
* - All fixed buttons have 50% opacity (0.5) by default
* - Buttons become 100% opaque (1.0) on hover
* - Buttons: download, print-friendly, shortcuts, theme-switcher, info
*/
import { chromium } from 'playwright';
const TEST_URL = 'http://localhost:1999';
const VIEWPORT_WIDTH = 375; // Mobile width
const VIEWPORT_HEIGHT = 812; // iPhone X height
async function testMobileButtonOpacity() {
console.log('🧪 Testing Mobile Button Opacity (50% default, 100% hover)');
console.log('='.repeat(70));
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({
viewport: { width: VIEWPORT_WIDTH, height: VIEWPORT_HEIGHT },
deviceScaleFactor: 2,
});
const page = await context.newPage();
// Disable cache to ensure fresh CSS
await page.route('**/*', (route) => {
route.continue({
headers: {
...route.request().headers(),
'Cache-Control': 'no-cache, no-store, must-revalidate',
},
});
});
try {
// Navigate to the page
await page.goto(TEST_URL, { waitUntil: 'networkidle' });
console.log(`✅ Navigated to ${TEST_URL}`);
// Wait for page to be fully loaded
await page.waitForTimeout(1000);
// Test buttons
const buttons = [
{ selector: '.download-btn', name: 'Download' },
{ selector: '.print-friendly-btn', name: 'Print Friendly' },
{ selector: '.shortcuts-btn', name: 'Shortcuts' },
{ selector: '.color-theme-switcher', name: 'Theme Switcher' },
{ selector: '.info-button', name: 'Info' },
];
console.log('\n📱 Testing Mobile Button Opacities:');
console.log('-'.repeat(70));
let allTestsPassed = true;
for (const button of buttons) {
try {
// Check if button exists
const buttonElement = await page.$(button.selector);
if (!buttonElement) {
console.log(`${button.name}: Button not found`);
allTestsPassed = false;
continue;
}
// Get default opacity
const defaultOpacity = await page.evaluate((sel) => {
const btn = document.querySelector(sel);
return btn ? window.getComputedStyle(btn).opacity : null;
}, button.selector);
// Test default opacity (should be 0.5)
const defaultOpacityNum = parseFloat(defaultOpacity);
const isDefaultCorrect = Math.abs(defaultOpacityNum - 0.5) < 0.01;
if (isDefaultCorrect) {
console.log(`${button.name}: Default opacity = ${defaultOpacity} (expected ~0.5)`);
} else {
console.log(`${button.name}: Default opacity = ${defaultOpacity} (expected ~0.5)`);
allTestsPassed = false;
}
// Hover over button and check opacity
await buttonElement.hover();
await page.waitForTimeout(500); // Wait for transition
const hoverOpacity = await page.evaluate((sel) => {
const btn = document.querySelector(sel);
return btn ? window.getComputedStyle(btn).opacity : null;
}, button.selector);
// Test hover opacity (should be 1.0)
const hoverOpacityNum = parseFloat(hoverOpacity);
const isHoverCorrect = Math.abs(hoverOpacityNum - 1.0) < 0.01;
if (isHoverCorrect) {
console.log(` ✅ Hover opacity = ${hoverOpacity} (expected ~1.0)`);
} else {
console.log(` ❌ Hover opacity = ${hoverOpacity} (expected ~1.0)`);
allTestsPassed = false;
}
// Move mouse away to reset
await page.mouse.move(0, 0);
await page.waitForTimeout(500);
} catch (error) {
console.log(`${button.name}: Error - ${error.message}`);
allTestsPassed = false;
}
}
console.log('-'.repeat(70));
if (allTestsPassed) {
console.log('\n✅ ALL TESTS PASSED - Mobile button opacity working correctly!');
console.log(' • Default opacity: 0.5 (50% transparent)');
console.log(' • Hover opacity: 1.0 (fully opaque)');
} else {
console.log('\n❌ SOME TESTS FAILED - Check output above for details');
}
await browser.close();
process.exit(allTestsPassed ? 0 : 1);
} catch (error) {
console.error('\n❌ Test error:', error);
await browser.close();
process.exit(1);
}
}
// Run the test
testMobileButtonOpacity();