simulator / tests /test_streamlit_app.py
mathiassandnes's picture
Claude Opus 4.5
Add Streamlit integration tests
648a32a
Raw History Blame Contribute Delete
3.63 kB
"""Integration tests for Streamlit app.
These tests actually run the Streamlit app to catch API errors
that unit tests miss (like wrong parameter names).
"""
import pytest
import subprocess
import sys
import time
import os
import signal
class TestStreamlitAppRuns:
"""Test that the Streamlit app actually runs without errors."""
def test_app_python_syntax_valid(self):
"""App has valid Python syntax."""
app_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
app_path = os.path.join(app_dir, "app.py")
# Compile the file to check for syntax errors
with open(app_path, "r") as f:
source = f.read()
try:
compile(source, app_path, "exec")
except SyntaxError as e:
pytest.fail(f"Syntax error in app.py: {e}")
class TestStreamlitAPIUsage:
"""Check for common Streamlit API mistakes by parsing the code."""
def test_no_invalid_dataframe_width(self):
"""st.dataframe should use use_container_width, not width="stretch"."""
app_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
app_path = os.path.join(app_dir, "app.py")
with open(app_path, "r") as f:
content = f.read()
# Find all st.dataframe calls with wrong width parameter
import re
# Look for st.dataframe with width="stretch" (wrong)
# But NOT use_container_width (correct)
pattern = r'st\.dataframe\([^)]*[^_]width\s*=\s*["\']stretch["\']'
matches = re.findall(pattern, content)
if matches:
pytest.fail(
f"Found st.dataframe with 'width=\"stretch\"' parameter. "
f"Use 'use_container_width=True' instead.\n"
f"Matches: {matches}"
)
def test_no_undefined_variables_in_fstrings(self):
"""Check for common f-string variable errors."""
app_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
app_path = os.path.join(app_dir, "app.py")
with open(app_path, "r") as f:
lines = f.readlines()
# Check each f-string for obvious issues
import re
for i, line in enumerate(lines, 1):
# Find f-strings
if 'f"' in line or "f'" in line:
# Check for empty braces (common mistake)
if "{}" in line:
pytest.fail(f"Line {i}: Empty braces in f-string: {line.strip()}")
class TestAppWithStreamlitTesting:
"""Use Streamlit's built-in testing framework if available."""
@pytest.fixture
def app(self):
"""Create AppTest instance."""
try:
from streamlit.testing.v1 import AppTest
except ImportError:
pytest.skip("streamlit.testing not available (requires streamlit>=1.28)")
app_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
app_path = os.path.join(app_dir, "app.py")
# Run the app
at = AppTest.from_file(app_path)
at.run(timeout=30)
return at
def test_app_runs_without_exception(self, app):
"""App renders without raising exceptions."""
assert not app.exception, f"App raised exception: {app.exception}"
def test_app_has_header(self, app):
"""App has a header element."""
# The app should have rendered some content
assert len(app.markdown) > 0 or len(app.header) > 0, "App has no content"
def test_app_has_sidebar(self, app):
"""App has sidebar elements."""
assert len(app.sidebar) > 0, "App has no sidebar"