260 lines
9.8 KiB
Python
260 lines
9.8 KiB
Python
"""
|
|
Tests for static file serving (CSS, JS).
|
|
|
|
This module tests that CSS and JavaScript files are properly served
|
|
through FastAPI's static files mounting.
|
|
"""
|
|
import pytest
|
|
from httpx import ASGITransport, AsyncClient
|
|
|
|
from src.server.fastapi_app import app
|
|
|
|
|
|
@pytest.fixture
|
|
async def client():
|
|
"""Create an async test client for the FastAPI app."""
|
|
transport = ASGITransport(app=app)
|
|
async with AsyncClient(transport=transport, base_url="http://test") as ac:
|
|
yield ac
|
|
|
|
|
|
class TestCSSFileServing:
|
|
"""Test CSS file serving functionality."""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_styles_css_accessible(self, client):
|
|
"""Test that styles.css is accessible."""
|
|
response = await client.get("/static/css/styles.css")
|
|
|
|
assert response.status_code == 200
|
|
assert "text/css" in response.headers.get("content-type", "")
|
|
assert len(response.text) > 0
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_ux_features_css_accessible(self, client):
|
|
"""Test that ux_features.css is accessible."""
|
|
response = await client.get("/static/css/ux_features.css")
|
|
|
|
assert response.status_code == 200
|
|
assert "text/css" in response.headers.get("content-type", "")
|
|
assert len(response.text) > 0
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_css_contains_expected_variables(self, client):
|
|
"""Test that CSS variables are defined in base/variables.css."""
|
|
# Variables are now in a separate module file
|
|
response = await client.get("/static/css/base/variables.css")
|
|
|
|
assert response.status_code == 200
|
|
content = response.text
|
|
|
|
# Check for Fluent UI design system variables
|
|
assert "--color-bg-primary:" in content
|
|
assert "--color-accent:" in content
|
|
assert "--font-family:" in content
|
|
assert "--spacing-" in content
|
|
assert "--border-radius-" in content
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_css_contains_dark_theme_support(self, client):
|
|
"""Test that dark theme support is in base/variables.css."""
|
|
# Dark theme variables are now in a separate module file
|
|
response = await client.get("/static/css/base/variables.css")
|
|
|
|
assert response.status_code == 200
|
|
content = response.text
|
|
|
|
# Check for dark theme variables
|
|
assert '[data-theme="dark"]' in content
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_css_contains_responsive_design(self, client):
|
|
"""Test that CSS files contain responsive design media queries."""
|
|
# Responsive styles are now in utilities/responsive.css
|
|
response = await client.get("/static/css/utilities/responsive.css")
|
|
assert response.status_code == 200
|
|
assert "@media" in response.text
|
|
|
|
# Test ux_features.css
|
|
response = await client.get("/static/css/ux_features.css")
|
|
assert response.status_code == 200
|
|
assert "@media" in response.text
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_ux_features_css_contains_accessibility(self, client):
|
|
"""Test that ux_features.css contains accessibility features."""
|
|
response = await client.get("/static/css/ux_features.css")
|
|
|
|
assert response.status_code == 200
|
|
content = response.text
|
|
|
|
# Check for accessibility features
|
|
assert ".sr-only" in content # Screen reader only
|
|
assert "prefers-contrast" in content # High contrast mode
|
|
assert ".keyboard-focus" in content # Keyboard navigation
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_nonexistent_css_returns_404(self, client):
|
|
"""Test that requesting a nonexistent CSS file returns 404."""
|
|
response = await client.get("/static/css/nonexistent.css")
|
|
# Static files might return HTML or 404, just ensure CSS exists
|
|
assert response.status_code in [200, 404]
|
|
|
|
|
|
class TestJavaScriptFileServing:
|
|
"""Test JavaScript file serving functionality."""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_app_js_accessible(self, client):
|
|
"""Test that app.js is accessible."""
|
|
response = await client.get("/static/js/app.js")
|
|
|
|
# File might not exist yet, but if it does, it should be served correctly
|
|
if response.status_code == 200:
|
|
assert "javascript" in response.headers.get("content-type", "").lower()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_websocket_client_js_accessible(self, client):
|
|
"""Test that websocket_client.js is accessible."""
|
|
response = await client.get("/static/js/websocket_client.js")
|
|
|
|
# File might not exist yet, but if it does, it should be served correctly
|
|
if response.status_code == 200:
|
|
assert "javascript" in response.headers.get("content-type", "").lower()
|
|
|
|
|
|
class TestHTMLTemplatesCSS:
|
|
"""Test that HTML templates correctly reference CSS files."""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_index_page_references_css(self, client):
|
|
"""Test that index.html correctly references CSS files."""
|
|
response = await client.get("/")
|
|
|
|
assert response.status_code == 200
|
|
content = response.text
|
|
|
|
# Check for CSS references
|
|
assert '/static/css/styles.css' in content
|
|
assert '/static/css/ux_features.css' in content
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_login_page_references_css(self, client):
|
|
"""Test that login.html correctly references CSS files."""
|
|
response = await client.get("/login")
|
|
|
|
assert response.status_code == 200
|
|
content = response.text
|
|
|
|
# Check for CSS reference
|
|
assert '/static/css/styles.css' in content
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_setup_page_references_css(self, client):
|
|
"""Test that setup.html correctly references CSS files."""
|
|
response = await client.get("/setup")
|
|
|
|
assert response.status_code == 200
|
|
content = response.text
|
|
|
|
# Check for CSS reference
|
|
assert '/static/css/styles.css' in content
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_queue_page_references_css(self, client):
|
|
"""Test that queue.html correctly references CSS files."""
|
|
response = await client.get("/queue")
|
|
|
|
assert response.status_code == 200
|
|
content = response.text
|
|
|
|
# Check for CSS reference
|
|
assert '/static/css/styles.css' in content
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_css_paths_are_absolute(self, client):
|
|
"""Test that CSS paths in templates are absolute paths."""
|
|
pages = ["/", "/login", "/setup", "/queue"]
|
|
|
|
for page in pages:
|
|
response = await client.get(page)
|
|
assert response.status_code == 200
|
|
content = response.text
|
|
|
|
# Ensure CSS links start with /static (absolute paths)
|
|
if 'href="/static/css/' in content:
|
|
# Good - using absolute paths
|
|
assert 'href="static/css/' not in content
|
|
elif 'href="static/css/' in content:
|
|
msg = f"Page {page} uses relative CSS paths"
|
|
pytest.fail(msg)
|
|
|
|
|
|
class TestCSSContentIntegrity:
|
|
"""Test CSS content integrity and structure."""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_styles_css_structure(self, client):
|
|
"""Test that styles.css is a modular entry point with @import statements."""
|
|
response = await client.get("/static/css/styles.css")
|
|
assert response.status_code == 200
|
|
|
|
content = response.text
|
|
|
|
# styles.css is now an entry point with @import statements
|
|
assert "@import" in content
|
|
|
|
# Check for imports of base, components, pages, and utilities
|
|
assert 'base/' in content or "base" in content.lower()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_css_variables_file_structure(self, client):
|
|
"""Test that base/variables.css has proper structure."""
|
|
response = await client.get("/static/css/base/variables.css")
|
|
assert response.status_code == 200
|
|
|
|
content = response.text
|
|
|
|
# Should have CSS variable definitions
|
|
assert ":root" in content
|
|
|
|
# Should not have syntax errors (basic check)
|
|
# Count braces - should be balanced
|
|
open_braces = content.count("{")
|
|
close_braces = content.count("}")
|
|
assert open_braces == close_braces, "CSS has unbalanced braces"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_ux_features_css_structure(self, client):
|
|
"""Test that ux_features.css has proper structure."""
|
|
response = await client.get("/static/css/ux_features.css")
|
|
assert response.status_code == 200
|
|
|
|
content = response.text
|
|
|
|
# Should not have syntax errors (basic check)
|
|
open_braces = content.count("{")
|
|
close_braces = content.count("}")
|
|
assert open_braces == close_braces, "CSS has unbalanced braces"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_css_file_sizes_reasonable(self, client):
|
|
"""Test that CSS files are not empty and have reasonable sizes."""
|
|
# Test styles.css (now just @imports, so smaller)
|
|
response = await client.get("/static/css/styles.css")
|
|
assert response.status_code == 200
|
|
assert len(response.text) > 100, "styles.css seems too small"
|
|
assert len(response.text) < 500000, "styles.css seems unusually large"
|
|
|
|
# Test variables.css (has actual content)
|
|
response = await client.get("/static/css/base/variables.css")
|
|
assert response.status_code == 200
|
|
assert len(response.text) > 500, "variables.css seems too small"
|
|
|
|
# Test ux_features.css
|
|
response = await client.get("/static/css/ux_features.css")
|
|
assert response.status_code == 200
|
|
assert len(response.text) > 100, "ux_features.css seems too small"
|
|
msg = "ux_features.css seems unusually large"
|
|
assert len(response.text) < 100000, msg
|