fix: Differentiate zoom and info button colors, fix button visibility in responsive mode
Issues fixed: 1. Zoom button now uses purple color (rgba(155, 89, 182, 0.7)) instead of blue 2. Info button keeps blue color (rgba(52, 152, 219, 0.7)) 3. Both buttons now show distinct colors in default state, not just on hover 4. Device detection now considers viewport width, not just user agent 5. Buttons no longer hide in responsive mode at desktop viewport sizes Changes: - Updated zoom-toggle-btn to use purple background color - Updated info-button to use blue background color (explicit, not var) - Modified device-detection.js to check viewport width (≤900px) in addition to UA - Added resize listener to update device class dynamically - Created test (67-button-colors-and-visibility-test.mjs) to verify fixes Testing: - Desktop (1278px): All buttons visible with distinct colors - Mobile (375px): Zoom/shortcuts hidden, core buttons visible - Device detection now viewport-aware (prevents hiding at desktop sizes)
This commit is contained in:
+279
@@ -0,0 +1,279 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { chromium } from 'playwright';
|
||||
|
||||
/**
|
||||
* TEST: Button Colors and Visibility Across Viewports
|
||||
*
|
||||
* Verifies:
|
||||
* 1. Zoom button is purple (#9b59b6), not blue
|
||||
* 2. Info button is blue (#3498db) - different from zoom
|
||||
* 3. All buttons visible at desktop viewport (1278px) even in mobile mode
|
||||
* 4. Zoom/keyboard buttons properly hidden at mobile viewport (<900px)
|
||||
*/
|
||||
|
||||
const VIEWPORTS = {
|
||||
desktop: {
|
||||
width: 1278,
|
||||
height: 800,
|
||||
name: 'Desktop (1278px)',
|
||||
// Simulate mobile user agent to test that buttons still show at desktop size
|
||||
userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1',
|
||||
hasTouch: true
|
||||
},
|
||||
mobile: {
|
||||
width: 375,
|
||||
height: 667,
|
||||
name: 'Mobile Portrait (375px)',
|
||||
userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1',
|
||||
hasTouch: true
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert RGB color to hex format for comparison
|
||||
*/
|
||||
function rgbToHex(rgb) {
|
||||
const match = rgb.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
|
||||
if (!match) return rgb;
|
||||
|
||||
const r = parseInt(match[1]);
|
||||
const g = parseInt(match[2]);
|
||||
const b = parseInt(match[3]);
|
||||
|
||||
return '#' + [r, g, b].map(x => {
|
||||
const hex = x.toString(16);
|
||||
return hex.length === 1 ? '0' + hex : hex;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
async function testViewport(browser, viewport) {
|
||||
const context = await browser.newContext({
|
||||
viewport: { width: viewport.width, height: viewport.height },
|
||||
userAgent: viewport.userAgent,
|
||||
hasTouch: viewport.hasTouch
|
||||
});
|
||||
const page = await context.newPage();
|
||||
|
||||
await page.goto('http://localhost:1999/?lang=en');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Wait a bit for device detection to run
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
const results = await page.evaluate(() => {
|
||||
// Get all button elements
|
||||
const downloadBtn = document.querySelector('.download-btn');
|
||||
const printBtn = document.querySelector('.print-friendly-btn');
|
||||
const themeBtn = document.querySelector('.color-theme-switcher');
|
||||
const zoomToggle = document.querySelector('.zoom-toggle-btn');
|
||||
const shortcutsBtn = document.querySelector('.shortcuts-btn');
|
||||
const infoBtn = document.querySelector('.info-button');
|
||||
const backToTop = document.querySelector('.back-to-top');
|
||||
|
||||
// Get device class
|
||||
const hasDesktopClass = document.documentElement.classList.contains('is-desktop');
|
||||
const hasMobileClass = document.documentElement.classList.contains('is-mobile-device');
|
||||
|
||||
// Helper to check if element is visible
|
||||
function isVisible(el) {
|
||||
if (!el) return false;
|
||||
const style = window.getComputedStyle(el);
|
||||
return style.display !== 'none' &&
|
||||
style.visibility !== 'hidden' &&
|
||||
style.opacity !== '0';
|
||||
}
|
||||
|
||||
// Get button colors (background-color)
|
||||
function getBackgroundColor(el) {
|
||||
if (!el) return 'N/A';
|
||||
return window.getComputedStyle(el).backgroundColor;
|
||||
}
|
||||
|
||||
return {
|
||||
viewport: {
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight
|
||||
},
|
||||
deviceClass: {
|
||||
isDesktop: hasDesktopClass,
|
||||
isMobile: hasMobileClass
|
||||
},
|
||||
buttons: {
|
||||
download: {
|
||||
exists: !!downloadBtn,
|
||||
visible: isVisible(downloadBtn),
|
||||
color: getBackgroundColor(downloadBtn)
|
||||
},
|
||||
print: {
|
||||
exists: !!printBtn,
|
||||
visible: isVisible(printBtn),
|
||||
color: getBackgroundColor(printBtn)
|
||||
},
|
||||
theme: {
|
||||
exists: !!themeBtn,
|
||||
visible: isVisible(themeBtn),
|
||||
color: getBackgroundColor(themeBtn)
|
||||
},
|
||||
zoomToggle: {
|
||||
exists: !!zoomToggle,
|
||||
visible: isVisible(zoomToggle),
|
||||
color: getBackgroundColor(zoomToggle),
|
||||
hoverColor: zoomToggle ? window.getComputedStyle(zoomToggle, ':hover').backgroundColor : 'N/A'
|
||||
},
|
||||
shortcuts: {
|
||||
exists: !!shortcutsBtn,
|
||||
visible: isVisible(shortcutsBtn),
|
||||
color: getBackgroundColor(shortcutsBtn)
|
||||
},
|
||||
info: {
|
||||
exists: !!infoBtn,
|
||||
visible: isVisible(infoBtn),
|
||||
color: getBackgroundColor(infoBtn)
|
||||
},
|
||||
backToTop: {
|
||||
exists: !!backToTop,
|
||||
visible: isVisible(backToTop),
|
||||
color: getBackgroundColor(backToTop)
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
await page.screenshot({
|
||||
path: `tests/screenshots/button-test-${viewport.width}px.png`,
|
||||
fullPage: false
|
||||
});
|
||||
|
||||
await context.close();
|
||||
return results;
|
||||
}
|
||||
|
||||
(async () => {
|
||||
const browser = await chromium.launch({ headless: true });
|
||||
|
||||
console.log('🎨 Button Colors and Visibility Test\n');
|
||||
console.log('Testing: Color differentiation and responsive visibility\n');
|
||||
|
||||
const allResults = {};
|
||||
const failures = [];
|
||||
|
||||
for (const [key, viewport] of Object.entries(VIEWPORTS)) {
|
||||
console.log(`📱 Testing: ${viewport.name}`);
|
||||
console.log('='.repeat(60));
|
||||
|
||||
const results = await testViewport(browser, viewport);
|
||||
allResults[key] = results;
|
||||
|
||||
console.log(`\nViewport: ${results.viewport.width}×${results.viewport.height}`);
|
||||
console.log(`Device class: ${results.deviceClass.isDesktop ? 'Desktop' : 'Mobile'}\n`);
|
||||
|
||||
// Print button status
|
||||
console.log('Button Visibility:');
|
||||
console.log(` 📥 Download: ${results.buttons.download.visible ? '✅ Visible' : '❌ Hidden'}`);
|
||||
console.log(` 🖨️ Print: ${results.buttons.print.visible ? '✅ Visible' : '❌ Hidden'}`);
|
||||
console.log(` 🎨 Theme: ${results.buttons.theme.visible ? '✅ Visible' : '❌ Hidden'}`);
|
||||
console.log(` 🔍 Zoom: ${results.buttons.zoomToggle.visible ? '✅ Visible' : '❌ Hidden'}`);
|
||||
console.log(` ⌨️ Shortcuts: ${results.buttons.shortcuts.visible ? '✅ Visible' : '❌ Hidden'}`);
|
||||
console.log(` ℹ️ Info: ${results.buttons.info.visible ? '✅ Visible' : '❌ Hidden'}`);
|
||||
console.log(` ⬆️ Back: ${results.buttons.backToTop.visible ? '✅ Visible' : '❌ Hidden'}`);
|
||||
|
||||
// Color verification for zoom and info buttons
|
||||
if (results.buttons.zoomToggle.exists) {
|
||||
const zoomColor = rgbToHex(results.buttons.zoomToggle.color);
|
||||
console.log(`\n 🔍 Zoom color: ${zoomColor} ${results.buttons.zoomToggle.color}`);
|
||||
}
|
||||
if (results.buttons.info.exists) {
|
||||
const infoColor = rgbToHex(results.buttons.info.color);
|
||||
console.log(` ℹ️ Info color: ${infoColor} ${results.buttons.info.color}`);
|
||||
}
|
||||
|
||||
// Validation rules
|
||||
const issues = [];
|
||||
|
||||
if (viewport.width > 900) {
|
||||
// DESKTOP VIEWPORT (even with mobile UA)
|
||||
console.log('\n📋 Validating desktop viewport (>900px)...');
|
||||
|
||||
// All buttons should be visible (except back-to-top which appears after scrolling)
|
||||
if (!results.buttons.download.visible) issues.push('Download button not visible at desktop size');
|
||||
if (!results.buttons.print.visible) issues.push('Print button not visible at desktop size');
|
||||
if (!results.buttons.theme.visible) issues.push('Theme button not visible at desktop size');
|
||||
if (!results.buttons.zoomToggle.visible) issues.push('Zoom toggle button not visible at desktop size');
|
||||
if (!results.buttons.shortcuts.visible) issues.push('Shortcuts button not visible at desktop size');
|
||||
if (!results.buttons.info.visible) issues.push('Info button not visible at desktop size');
|
||||
// Note: Back-to-top button is hidden until user scrolls - this is expected behavior
|
||||
|
||||
// Device class should be desktop at this viewport
|
||||
if (!results.deviceClass.isDesktop) {
|
||||
issues.push('Device class should be "is-desktop" at viewport >900px');
|
||||
}
|
||||
|
||||
// Verify zoom button is NOT blue (should be purple #9b59b6 or similar)
|
||||
if (results.buttons.zoomToggle.exists) {
|
||||
const zoomColor = rgbToHex(results.buttons.zoomToggle.color);
|
||||
const infoColor = results.buttons.info.exists ? rgbToHex(results.buttons.info.color) : null;
|
||||
|
||||
// The colors should be different
|
||||
if (zoomColor === infoColor) {
|
||||
issues.push(`Zoom and Info buttons have the SAME color (${zoomColor}) - they should be different!`);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// MOBILE VIEWPORT
|
||||
console.log('\n📋 Validating mobile viewport (≤900px)...');
|
||||
|
||||
// Core buttons should be visible
|
||||
if (!results.buttons.download.visible) issues.push('Download button not visible on mobile');
|
||||
if (!results.buttons.print.visible) issues.push('Print button not visible on mobile');
|
||||
if (!results.buttons.theme.visible) issues.push('Theme button not visible on mobile');
|
||||
if (!results.buttons.info.visible) issues.push('Info button not visible on mobile');
|
||||
if (!results.buttons.backToTop.visible) issues.push('Back to top button not visible on mobile');
|
||||
|
||||
// Zoom and shortcuts should be hidden on mobile
|
||||
if (results.buttons.zoomToggle.visible) issues.push('Zoom toggle should be hidden at mobile viewport');
|
||||
if (results.buttons.shortcuts.visible) issues.push('Shortcuts button should be hidden at mobile viewport');
|
||||
|
||||
// Device class should be mobile
|
||||
if (!results.deviceClass.isMobile) {
|
||||
issues.push('Device class should be "is-mobile-device" at viewport ≤900px with mobile UA');
|
||||
}
|
||||
}
|
||||
|
||||
if (issues.length > 0) {
|
||||
console.log('\n❌ ISSUES FOUND:');
|
||||
issues.forEach(issue => {
|
||||
console.log(` - ${issue}`);
|
||||
failures.push(`${viewport.name}: ${issue}`);
|
||||
});
|
||||
} else {
|
||||
console.log('\n✅ All checks passed');
|
||||
}
|
||||
|
||||
console.log('\n');
|
||||
}
|
||||
|
||||
// Final summary
|
||||
console.log('='.repeat(60));
|
||||
console.log('FINAL SUMMARY\n');
|
||||
|
||||
if (failures.length === 0) {
|
||||
console.log('✅ ALL TESTS PASSED\n');
|
||||
console.log('Button colors are distinct:');
|
||||
console.log(' 🔍 Zoom button: Purple (#9b59b6)');
|
||||
console.log(' ℹ️ Info button: Blue (#3498db)');
|
||||
console.log('\nButton visibility works correctly:');
|
||||
console.log(' ✅ All buttons visible at desktop viewport (>900px)');
|
||||
console.log(' ✅ Zoom/shortcuts hidden at mobile viewport (≤900px)');
|
||||
console.log(' ✅ Device detection considers viewport width\n');
|
||||
} else {
|
||||
console.log(`❌ ${failures.length} ISSUE(S) FOUND:\n`);
|
||||
failures.forEach((failure, i) => {
|
||||
console.log(`${i + 1}. ${failure}`);
|
||||
});
|
||||
console.log('');
|
||||
}
|
||||
|
||||
await browser.close();
|
||||
process.exit(failures.length === 0 ? 0 : 1);
|
||||
})();
|
||||
Reference in New Issue
Block a user