feat(PORT-004A): add workspace bootstrap and scoped settings
This commit is contained in:
100
tests/test_workspace.py
Normal file
100
tests/test_workspace.py
Normal file
@@ -0,0 +1,100 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from uuid import uuid4
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from app.main import app
|
||||
from app.models.workspace import WorkspaceRepository
|
||||
|
||||
UUID4_RE = re.compile(
|
||||
r"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$",
|
||||
re.IGNORECASE,
|
||||
)
|
||||
|
||||
|
||||
def _install_workspace_repo(tmp_path, monkeypatch) -> WorkspaceRepository:
|
||||
from app.models import workspace as workspace_module
|
||||
|
||||
repo = WorkspaceRepository(base_path=tmp_path / "workspaces")
|
||||
monkeypatch.setattr(workspace_module, "_workspace_repo", repo)
|
||||
return repo
|
||||
|
||||
|
||||
def test_workspace_repository_persists_workspace_specific_portfolio_config(tmp_path) -> None:
|
||||
repo = WorkspaceRepository(base_path=tmp_path / "workspaces")
|
||||
workspace_id = str(uuid4())
|
||||
|
||||
created = repo.create_workspace(workspace_id)
|
||||
created.loan_amount = 123_456.0
|
||||
repo.save_portfolio_config(workspace_id, created)
|
||||
|
||||
reloaded = repo.load_portfolio_config(workspace_id)
|
||||
|
||||
assert repo.workspace_exists(workspace_id)
|
||||
assert reloaded.loan_amount == 123_456.0
|
||||
assert reloaded.gold_value == created.gold_value
|
||||
|
||||
|
||||
def test_root_without_workspace_cookie_shows_welcome_page(tmp_path, monkeypatch) -> None:
|
||||
_install_workspace_repo(tmp_path, monkeypatch)
|
||||
|
||||
with TestClient(app) as client:
|
||||
response = client.get("/")
|
||||
|
||||
assert response.status_code == 200
|
||||
assert "Create a private workspace URL" in response.text
|
||||
assert "Get started" in response.text
|
||||
|
||||
|
||||
def test_bootstrap_endpoint_creates_workspace_cookie_and_redirects(tmp_path, monkeypatch) -> None:
|
||||
repo = _install_workspace_repo(tmp_path, monkeypatch)
|
||||
|
||||
with TestClient(app) as client:
|
||||
response = client.get("/workspaces/bootstrap", follow_redirects=False)
|
||||
|
||||
assert response.status_code in {302, 303, 307}
|
||||
location = response.headers["location"]
|
||||
workspace_id = location.strip("/")
|
||||
assert UUID4_RE.match(workspace_id)
|
||||
assert repo.workspace_exists(workspace_id)
|
||||
assert response.cookies.get("workspace_id") == workspace_id
|
||||
|
||||
|
||||
def test_root_with_valid_workspace_cookie_redirects_to_workspace(tmp_path, monkeypatch) -> None:
|
||||
repo = _install_workspace_repo(tmp_path, monkeypatch)
|
||||
workspace_id = str(uuid4())
|
||||
repo.create_workspace(workspace_id)
|
||||
|
||||
with TestClient(app) as client:
|
||||
response = client.get("/", cookies={"workspace_id": workspace_id}, follow_redirects=False)
|
||||
|
||||
assert response.status_code in {302, 303, 307}
|
||||
assert response.headers["location"] == f"/{workspace_id}"
|
||||
|
||||
|
||||
def test_unknown_workspace_route_shows_friendly_recovery_path(tmp_path, monkeypatch) -> None:
|
||||
_install_workspace_repo(tmp_path, monkeypatch)
|
||||
|
||||
with TestClient(app) as client:
|
||||
response = client.get("/00000000-0000-4000-8000-000000000000")
|
||||
|
||||
assert response.status_code == 200
|
||||
assert "Workspace not found" in response.text
|
||||
assert "Get started" in response.text
|
||||
|
||||
|
||||
def test_workspace_settings_round_trip_uses_workspace_storage(tmp_path, monkeypatch) -> None:
|
||||
repo = _install_workspace_repo(tmp_path, monkeypatch)
|
||||
workspace_id = str(uuid4())
|
||||
config = repo.create_workspace(workspace_id)
|
||||
config.monthly_budget = 9_999.0
|
||||
repo.save_portfolio_config(workspace_id, config)
|
||||
|
||||
with TestClient(app) as client:
|
||||
response = client.get(f"/{workspace_id}/settings")
|
||||
|
||||
assert response.status_code == 200
|
||||
assert "Settings" in response.text
|
||||
assert "9,999" in response.text or "9999" in response.text
|
||||
Reference in New Issue
Block a user