fix: Mobile hamburger menu and iPad sidebar visibility
Mobile fixes: - Add click toggle handler for hamburger menu (was hover-only) - Menu now opens/closes on tap and closes when clicking outside - Keep hover support for desktop iPad fixes: - Sidebar content now visible on touch devices (901-1280px) - Added (hover: hover) media query to prevent hide-on-hover on tablets Security improvements: - Replace exec.CommandContext with go-git library for git operations - Add path traversal and command injection prevention - Fix race condition in template hot reload - Add environment-based cookie Secure flag Code quality: - Add constants.go for magic numbers - Remove unused code (ParsePreferenceToggleRequest, DomainError) - Add FOUC prevention with inline critical CSS - Add Makefile dev/run/clean targets - Fix README git clone URL - Add doc/DECISIONS.md for architectural decisions Tests: - Add hamburger menu click toggle tests - Add iPad sidebar visibility tests - Update security tests for go-git implementation - Add cookie Secure flag tests
This commit is contained in:
@@ -25,7 +25,7 @@ async function testMobileResponsive() {
|
||||
console.log('📱 MOBILE RESPONSIVE TEST\n');
|
||||
console.log('='.repeat(70));
|
||||
|
||||
const browser = await chromium.launch({ headless: false });
|
||||
const browser = await chromium.launch({ headless: true });
|
||||
const errors = [];
|
||||
const testResults = [];
|
||||
|
||||
@@ -88,43 +88,77 @@ async function testMobileResponsive() {
|
||||
testResults.push({ test: 'Mobile Viewport (375px)', passed: mobileViewportPassed });
|
||||
|
||||
// ========================================================================
|
||||
// TEST 2: Touch interactions (hamburger menu)
|
||||
// TEST 2: Hamburger Menu Click Toggle (Mobile)
|
||||
// ========================================================================
|
||||
console.log("\n2️⃣ Testing Touch Interactions...");
|
||||
console.log("\n2️⃣ Testing Hamburger Menu Click Toggle...");
|
||||
|
||||
const hamburger = await mobilePage.$('.hamburger-btn');
|
||||
if (hamburger) {
|
||||
// Tap hamburger to open menu
|
||||
await hamburger.tap();
|
||||
await mobilePage.waitForTimeout(500);
|
||||
// Click hamburger to open menu (simulates mobile tap)
|
||||
await hamburger.click();
|
||||
await mobilePage.waitForTimeout(300);
|
||||
|
||||
const menuTest = await mobilePage.evaluate(() => {
|
||||
const menuOpenTest = await mobilePage.evaluate(() => {
|
||||
const menu = document.querySelector('.navigation-menu');
|
||||
if (!menu) return { found: false };
|
||||
|
||||
const isOpen = menu.classList.contains('menu-open') ||
|
||||
window.getComputedStyle(menu).display !== 'none';
|
||||
const hasMenuOpen = menu.classList.contains('menu-open');
|
||||
const computedStyle = window.getComputedStyle(menu);
|
||||
const isVisible = computedStyle.opacity === '1' && computedStyle.maxHeight !== '0px';
|
||||
|
||||
return {
|
||||
found: true,
|
||||
isOpen,
|
||||
isVisible: menu.offsetHeight > 0
|
||||
hasMenuOpen,
|
||||
isVisible,
|
||||
maxHeight: computedStyle.maxHeight
|
||||
};
|
||||
});
|
||||
|
||||
console.log(` Menu found: ${menuTest.found ? '✅' : '❌'}`);
|
||||
console.log(` Menu opens on tap: ${menuTest.isOpen ? '✅' : '❌'}`);
|
||||
console.log(` ${menuTest.found && menuTest.isOpen ? '✅ PASS' : '❌ FAIL'} - Touch interactions`);
|
||||
testResults.push({ test: 'Touch Interactions', passed: menuTest.found && menuTest.isOpen });
|
||||
console.log(` Menu found: ${menuOpenTest.found ? '✅' : '❌'}`);
|
||||
console.log(` Has menu-open class: ${menuOpenTest.hasMenuOpen ? '✅' : '❌'}`);
|
||||
console.log(` Menu visible: ${menuOpenTest.isVisible ? '✅' : '❌'}`);
|
||||
|
||||
const openPassed = menuOpenTest.found && menuOpenTest.hasMenuOpen;
|
||||
console.log(` ${openPassed ? '✅ PASS' : '❌ FAIL'} - Menu opens on click`);
|
||||
testResults.push({ test: 'Menu Opens on Click', passed: openPassed });
|
||||
|
||||
// TEST 2B: Click again to close
|
||||
await hamburger.click();
|
||||
await mobilePage.waitForTimeout(300);
|
||||
|
||||
const menuCloseTest = await mobilePage.evaluate(() => {
|
||||
const menu = document.querySelector('.navigation-menu');
|
||||
return {
|
||||
hasMenuOpen: menu?.classList.contains('menu-open') ?? false
|
||||
};
|
||||
});
|
||||
|
||||
const closePassed = !menuCloseTest.hasMenuOpen;
|
||||
console.log(` Menu closes on second click: ${closePassed ? '✅' : '❌'}`);
|
||||
testResults.push({ test: 'Menu Closes on Click', passed: closePassed });
|
||||
|
||||
// TEST 2C: Click outside to close
|
||||
await hamburger.click(); // Open again
|
||||
await mobilePage.waitForTimeout(300);
|
||||
await mobilePage.click('body', { position: { x: 300, y: 400 } }); // Click outside
|
||||
await mobilePage.waitForTimeout(300);
|
||||
|
||||
const outsideCloseTest = await mobilePage.evaluate(() => {
|
||||
const menu = document.querySelector('.navigation-menu');
|
||||
return {
|
||||
hasMenuOpen: menu?.classList.contains('menu-open') ?? false
|
||||
};
|
||||
});
|
||||
|
||||
const outsidePassed = !outsideCloseTest.hasMenuOpen;
|
||||
console.log(` Menu closes on outside click: ${outsidePassed ? '✅' : '❌'}`);
|
||||
testResults.push({ test: 'Menu Closes on Outside Click', passed: outsidePassed });
|
||||
|
||||
// Close menu
|
||||
if (menuTest.isOpen) {
|
||||
await hamburger.tap();
|
||||
await mobilePage.waitForTimeout(300);
|
||||
}
|
||||
} else {
|
||||
console.log(` ⚠️ SKIP - Hamburger menu not found`);
|
||||
testResults.push({ test: 'Touch Interactions', passed: true });
|
||||
testResults.push({ test: 'Menu Opens on Click', passed: false });
|
||||
testResults.push({ test: 'Menu Closes on Click', passed: false });
|
||||
testResults.push({ test: 'Menu Closes on Outside Click', passed: false });
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
@@ -274,10 +308,8 @@ async function testMobileResponsive() {
|
||||
console.log("⚠️ SOME TESTS FAILED - See details above");
|
||||
}
|
||||
|
||||
console.log("\nBrowser will stay open for manual inspection.");
|
||||
console.log("Press Ctrl+C when done.\n");
|
||||
|
||||
await new Promise(() => {}); // Keep browser open
|
||||
await browser.close();
|
||||
process.exit(failedTests === 0 ? 0 : 1);
|
||||
}
|
||||
|
||||
await testMobileResponsive();
|
||||
|
||||
Reference in New Issue
Block a user