2025-04-10 14:47:33 +10:00

110 lines
4.0 KiB
Python

# tests/conftest.py
import pytest
import os
from app import create_app, db, discover_and_register_modules # Keep import
from config import TestingConfig
from app.models import User
from tests.test_control_panel import create_test_user, login # Or move helpers to a shared file
# Determine the instance path for removing the test DB later
instance_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'instance')
TEST_DB_PATH = os.path.join(instance_path, 'test.db')
# --- Use 'function' scope for better isolation ---
@pytest.fixture(scope='function')
def app():
"""
Function-scoped test Flask application. Configured for testing.
Handles creation and teardown of the test database FOR EACH TEST.
Initializes modules AFTER database creation.
"""
# Create app with TestingConfig, skip module init initially
app = create_app(TestingConfig, init_modules=False)
# Establish an application context before accessing db
with app.app_context():
print(f"\n--- Setting up test database for function at {app.config['SQLALCHEMY_DATABASE_URI']} ---")
# Ensure instance folder exists
try:
os.makedirs(app.instance_path)
except OSError:
pass # Already exists
# Remove old test database file if it exists (paranoid check)
if os.path.exists(TEST_DB_PATH):
# print(f"--- Removing old test database file: {TEST_DB_PATH} ---") # Can be noisy
os.remove(TEST_DB_PATH)
# Create tables based on models
db.create_all()
print("--- Test database tables created ---") # Keep this print for confirmation
# --- FIX: Run discovery AFTER DB setup ---
print("--- Initializing modules after DB setup ---") # Keep this print
discover_and_register_modules(app) # <-- UNCOMMENTED / ADDED THIS LINE
# --- End Module Discovery ---
# Yield the app instance for use in the single test function
yield app
# --- Teardown (runs after each test function) ---
# print("\n--- Tearing down test database for function ---") # Can be noisy
db.session.remove()
db.drop_all()
# Optional: Remove the test database file after test run
# if os.path.exists(TEST_DB_PATH):
# os.remove(TEST_DB_PATH)
# --- Use 'function' scope ---
@pytest.fixture(scope='function')
def client(app):
"""
Provides a Flask test client for the function-scoped app.
"""
return app.test_client()
# --- Use 'function' scope ---
@pytest.fixture(scope='function')
def runner(app):
"""
Provides a Flask test CLI runner for the function-scoped app.
"""
return app.test_cli_runner()
# --- ADDED Fixture for Logged-In Admin Client ---
@pytest.fixture(scope='function')
def admin_client(client, app):
"""
Provides a test client already logged in as a pre-created admin user.
Uses the function-scoped 'client' and 'app' fixtures.
"""
admin_username = "fixture_admin"
admin_email = "fixture_admin@example.com" # Unique email
admin_password = "password"
# Create admin user within the app context provided by the 'app' fixture
with app.app_context():
create_test_user(
username=admin_username,
email=admin_email,
password=admin_password,
role="admin"
)
# Log the admin user in using the 'client' fixture
login_res = login(client, admin_username, admin_password)
# Basic check to ensure login likely succeeded (redirect expected)
if login_res.status_code != 302:
pytest.fail("Admin login failed during fixture setup.")
# Yield the already-logged-in client for the test
yield client
# Teardown (logout) is optional as function scope cleans up,
# but can be added for explicit cleanup if needed.
# client.get(url_for('auth.logout'))
# --- Potential Future Fixtures ---
# (Keep commented out potential session fixture)