172 lines
5.7 KiB
Python
172 lines
5.7 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
"""
|
||
|
|
Comprehensive Frontend Validation for QBPOS Help Website
|
||
|
|
Checks: Responsive CSS, accessibility, cache versions, file integrity
|
||
|
|
"""
|
||
|
|
|
||
|
|
import os
|
||
|
|
import re
|
||
|
|
from pathlib import Path
|
||
|
|
from collections import defaultdict
|
||
|
|
|
||
|
|
def check_responsive_breakpoints(css_file):
|
||
|
|
"""Validate responsive breakpoints are properly configured"""
|
||
|
|
issues = []
|
||
|
|
with open(css_file, 'r', encoding='utf-8') as f:
|
||
|
|
content = f.read()
|
||
|
|
|
||
|
|
# Required breakpoints
|
||
|
|
required_breakpoints = [
|
||
|
|
(r'@media.*max-width:\s*767px', 'Mobile (≤767px)'),
|
||
|
|
(r'@media.*min-width:\s*768px.*max-width:\s*1024px', 'Tablet (768-1024px)'),
|
||
|
|
(r'@media.*min-width:\s*1025px', 'Desktop (≥1025px)')
|
||
|
|
]
|
||
|
|
|
||
|
|
for pattern, name in required_breakpoints:
|
||
|
|
if not re.search(pattern, content, re.IGNORECASE):
|
||
|
|
issues.append(f"Missing breakpoint: {name}")
|
||
|
|
|
||
|
|
return issues
|
||
|
|
|
||
|
|
def check_accessibility_features(css_file):
|
||
|
|
"""Check for accessibility features"""
|
||
|
|
issues = []
|
||
|
|
with open(css_file, 'r', encoding='utf-8') as f:
|
||
|
|
content = f.read()
|
||
|
|
|
||
|
|
# Required accessibility features
|
||
|
|
if ':focus' not in content:
|
||
|
|
issues.append("Missing focus states for keyboard navigation")
|
||
|
|
|
||
|
|
if 'skip-link' not in content:
|
||
|
|
issues.append("Missing skip-to-content link for screen readers")
|
||
|
|
|
||
|
|
return issues
|
||
|
|
|
||
|
|
def check_cache_versions(base_dir):
|
||
|
|
"""Check that all HTML files reference consistent cache version"""
|
||
|
|
versions = defaultdict(int)
|
||
|
|
|
||
|
|
for html_file in Path(base_dir).rglob('*.htm*'):
|
||
|
|
try:
|
||
|
|
with open(html_file, 'r', encoding='utf-8', errors='ignore') as f:
|
||
|
|
content = f.read()
|
||
|
|
|
||
|
|
# Find all version parameters
|
||
|
|
matches = re.findall(r'\?v=(\d+)', content)
|
||
|
|
for version in matches:
|
||
|
|
versions[version] += 1
|
||
|
|
except Exception:
|
||
|
|
continue
|
||
|
|
|
||
|
|
return versions
|
||
|
|
|
||
|
|
def check_text_wrapping(css_file):
|
||
|
|
"""Ensure text wrapping is enabled for mobile"""
|
||
|
|
issues = []
|
||
|
|
with open(css_file, 'r', encoding='utf-8') as f:
|
||
|
|
content = f.read()
|
||
|
|
|
||
|
|
# Check for word-wrap in mobile section
|
||
|
|
mobile_section = re.search(r'@media.*max-width:\s*767px.*?(?=@media|$)', content, re.DOTALL)
|
||
|
|
if mobile_section:
|
||
|
|
mobile_css = mobile_section.group(0)
|
||
|
|
if 'word-wrap' not in mobile_css and 'overflow-wrap' not in mobile_css:
|
||
|
|
issues.append("Missing word-wrap for mobile devices")
|
||
|
|
|
||
|
|
return issues
|
||
|
|
|
||
|
|
def validate_frontend():
|
||
|
|
"""Run all validation checks"""
|
||
|
|
base_dir = Path('/home/pts/Documents/QBPOS_Help_Web/QB_Help_Web/POS_Help')
|
||
|
|
css_file = base_dir / 'responsive.css'
|
||
|
|
|
||
|
|
print("=" * 60)
|
||
|
|
print("FRONTEND VALIDATION REPORT")
|
||
|
|
print("=" * 60)
|
||
|
|
|
||
|
|
all_passed = True
|
||
|
|
|
||
|
|
# 1. Responsive Breakpoints
|
||
|
|
print("\n1. Responsive Layout Validation:")
|
||
|
|
issues = check_responsive_breakpoints(css_file)
|
||
|
|
if issues:
|
||
|
|
all_passed = False
|
||
|
|
for issue in issues:
|
||
|
|
print(f" ❌ {issue}")
|
||
|
|
else:
|
||
|
|
print(" ✅ All responsive breakpoints configured correctly")
|
||
|
|
|
||
|
|
# 2. Accessibility
|
||
|
|
print("\n2. Accessibility Features:")
|
||
|
|
issues = check_accessibility_features(css_file)
|
||
|
|
if issues:
|
||
|
|
all_passed = False
|
||
|
|
for issue in issues:
|
||
|
|
print(f" ❌ {issue}")
|
||
|
|
else:
|
||
|
|
print(" ✅ Accessibility features implemented")
|
||
|
|
|
||
|
|
# 3. Text Wrapping
|
||
|
|
print("\n3. Text Wrapping:")
|
||
|
|
issues = check_text_wrapping(css_file)
|
||
|
|
if issues:
|
||
|
|
all_passed = False
|
||
|
|
for issue in issues:
|
||
|
|
print(f" ❌ {issue}")
|
||
|
|
else:
|
||
|
|
print(" ✅ Text wrapping enabled for mobile")
|
||
|
|
|
||
|
|
# 4. Cache Versions
|
||
|
|
print("\n4. Cache Version Consistency:")
|
||
|
|
versions = check_cache_versions(base_dir)
|
||
|
|
if versions:
|
||
|
|
latest_version = max(versions.keys())
|
||
|
|
print(f" 📦 Latest cache version: v={latest_version}")
|
||
|
|
print(f" 📊 Files using latest version: {versions[latest_version]}")
|
||
|
|
|
||
|
|
# Show other versions if any
|
||
|
|
other_versions = {v: c for v, c in versions.items() if v != latest_version}
|
||
|
|
if other_versions:
|
||
|
|
all_passed = False
|
||
|
|
print(" ⚠️ Files using older versions:")
|
||
|
|
for v, count in sorted(other_versions.items()):
|
||
|
|
print(f" v={v}: {count} files")
|
||
|
|
else:
|
||
|
|
print(" ✅ All files using consistent cache version")
|
||
|
|
|
||
|
|
# 5. File Structure
|
||
|
|
print("\n5. File Structure:")
|
||
|
|
htm_files = list(base_dir.rglob('*.htm'))
|
||
|
|
css_files = list(base_dir.rglob('*.css'))
|
||
|
|
js_files = list(base_dir.rglob('*.js'))
|
||
|
|
|
||
|
|
print(f" 📄 HTML files: {len(htm_files)}")
|
||
|
|
print(f" 🎨 CSS files: {len(css_files)}")
|
||
|
|
print(f" ⚡ JavaScript files: {len(js_files)}")
|
||
|
|
print(" ✅ File structure intact")
|
||
|
|
|
||
|
|
# 6. Mobile Font Sizes
|
||
|
|
print("\n6. Mobile Font Configuration:")
|
||
|
|
with open(css_file, 'r', encoding='utf-8') as f:
|
||
|
|
content = f.read()
|
||
|
|
|
||
|
|
mobile_font = re.search(r'@media.*max-width:\s*767px.*?font-size:\s*(\d+)px', content, re.DOTALL)
|
||
|
|
desktop_dtree = re.search(r'@media.*min-width:\s*1025px.*?\.dtree.*?font-size:\s*(\d+)px', content, re.DOTALL)
|
||
|
|
|
||
|
|
if mobile_font:
|
||
|
|
print(f" 📱 Mobile content font: {mobile_font.group(1)}px")
|
||
|
|
if desktop_dtree:
|
||
|
|
print(f" 🖥️ Desktop navigation font: {desktop_dtree.group(1)}px")
|
||
|
|
print(" ✅ Font sizes properly separated by device")
|
||
|
|
|
||
|
|
print("\n" + "=" * 60)
|
||
|
|
if all_passed:
|
||
|
|
print("✅ ALL FRONTEND CHECKS PASSED!")
|
||
|
|
else:
|
||
|
|
print("⚠️ SOME ISSUES FOUND - See details above")
|
||
|
|
print("=" * 60)
|
||
|
|
|
||
|
|
if __name__ == '__main__':
|
||
|
|
validate_frontend()
|