forked from retoor/devplacepy
chore: reorganize test files into domain-specific subdirectories under tests/
Split the monolithic test directory into three tiers (unit, api, e2e) with a path-mirroring directory structure. Added corresponding Makefile targets (test-unit, test-api, test-e2e) and updated all documentation references (CLAUDE.md, README.md, testing-cicd.html, testing-framework.html, testing-make.html) to reflect the new layout and naming conventions.
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
# retoor <retoor@molodetz.nl>
|
||||
|
||||
from uuid import uuid4
|
||||
from datetime import datetime, timezone
|
||||
from tests.conftest import BASE_URL
|
||||
from devplacepy.database import get_table
|
||||
from devplacepy.utils import make_combined_slug
|
||||
def seed_admin_news(count=3):
|
||||
news_table = get_table("news")
|
||||
news_table.delete()
|
||||
for i in range(count):
|
||||
eid = f"admin_test_news_{i}"
|
||||
if news_table.find_one(external_id=eid):
|
||||
continue
|
||||
uid = str(uuid4())
|
||||
title = f"Admin News Article {i}"
|
||||
slug = make_combined_slug(title, uid)
|
||||
news_table.insert(
|
||||
{
|
||||
"uid": uid,
|
||||
"slug": slug,
|
||||
"title": title,
|
||||
"external_id": eid,
|
||||
"grade": 5 + i,
|
||||
"status": "draft" if i == 0 else "published",
|
||||
"show_on_landing": 1 if i == 1 else 0,
|
||||
"source_name": "AdminTest",
|
||||
"synced_at": datetime.now(timezone.utc).isoformat(),
|
||||
"description": f"Test article {i} for admin tests.",
|
||||
}
|
||||
)
|
||||
def seed_extra_users(count=30):
|
||||
users = get_table("users")
|
||||
existing_count = len(list(users.all()))
|
||||
if existing_count > 5:
|
||||
return
|
||||
for i in range(count):
|
||||
uid = str(uuid4())
|
||||
users.insert(
|
||||
{
|
||||
"uid": uid,
|
||||
"username": f"pagu_{i:04d}",
|
||||
"email": f"pagu{i:04d}@test.devplace",
|
||||
"password_hash": "x",
|
||||
"role": "Member",
|
||||
"is_active": True,
|
||||
"created_at": datetime.now(timezone.utc).isoformat(),
|
||||
}
|
||||
)
|
||||
def _seed_target_user():
|
||||
uid = str(uuid4())
|
||||
get_table("users").insert(
|
||||
{
|
||||
"uid": uid,
|
||||
"username": f"target_{uid[:8]}",
|
||||
"email": f"target_{uid[:8]}@test.devplace",
|
||||
"password_hash": "x",
|
||||
"role": "Member",
|
||||
"is_active": True,
|
||||
"created_at": datetime.now(timezone.utc).isoformat(),
|
||||
}
|
||||
)
|
||||
return uid
|
||||
import time
|
||||
import requests
|
||||
DEFAULT_MAINTENANCE_MESSAGE = (
|
||||
"DevPlace is undergoing scheduled maintenance. Please check back shortly."
|
||||
)
|
||||
OPERATIONAL_FIELDS = (
|
||||
"rate_limit_per_minute",
|
||||
"rate_limit_window_seconds",
|
||||
"session_max_age_days",
|
||||
"session_remember_days",
|
||||
"registration_open",
|
||||
"maintenance_mode",
|
||||
"maintenance_message",
|
||||
)
|
||||
def _save_settings(page, **fields):
|
||||
page.goto(f"{BASE_URL}/admin/settings", wait_until="domcontentloaded")
|
||||
for name, value in fields.items():
|
||||
locator = page.locator(f"#{name}")
|
||||
tag = locator.evaluate("el => el.tagName.toLowerCase()")
|
||||
if tag == "select":
|
||||
page.select_option(f"#{name}", value)
|
||||
else:
|
||||
locator.fill(value)
|
||||
page.click("button:has-text('Save Settings')")
|
||||
page.wait_for_url("**/admin/settings", wait_until="domcontentloaded")
|
||||
|
||||
|
||||
def test_admin_settings_save(alice):
|
||||
page, _ = alice
|
||||
page.goto(f"{BASE_URL}/admin/settings", wait_until="domcontentloaded")
|
||||
assert page.is_visible("#site_name")
|
||||
original = page.locator("#site_tagline").input_value()
|
||||
newval = f"tagline-{uuid4().hex[:8]}"
|
||||
try:
|
||||
page.fill("#site_tagline", newval)
|
||||
page.click("button:has-text('Save Settings')")
|
||||
page.wait_for_url("**/admin/settings", wait_until="domcontentloaded")
|
||||
assert page.locator("#site_tagline").input_value() == newval
|
||||
finally:
|
||||
page.fill("#site_tagline", original)
|
||||
page.click("button:has-text('Save Settings')")
|
||||
page.wait_for_url("**/admin/settings", wait_until="domcontentloaded")
|
||||
|
||||
|
||||
def test_operational_fields_render(alice):
|
||||
page, _ = alice
|
||||
page.goto(f"{BASE_URL}/admin/settings", wait_until="domcontentloaded")
|
||||
assert page.is_visible("text=Operational")
|
||||
for field in OPERATIONAL_FIELDS:
|
||||
assert page.is_visible(f"#{field}"), field
|
||||
|
||||
|
||||
def test_maintenance_mode_admin_retains_access(alice):
|
||||
page, _ = alice
|
||||
try:
|
||||
_save_settings(page, maintenance_mode="1")
|
||||
page.goto(f"{BASE_URL}/admin/settings", wait_until="domcontentloaded")
|
||||
assert page.is_visible("#maintenance_mode")
|
||||
login = requests.get(f"{BASE_URL}/auth/login")
|
||||
assert login.status_code == 200
|
||||
finally:
|
||||
_save_settings(page, maintenance_mode="0")
|
||||
Reference in New Issue
Block a user