feat: add scenarios list page with metrics and quick actions
- Introduced a new template for listing scenarios associated with a project. - Added metrics for total, active, draft, and archived scenarios. - Implemented quick actions for creating new scenarios and reviewing project overview. - Enhanced navigation with breadcrumbs for better user experience. refactor: update Opex and Profitability templates for consistency - Changed titles and button labels for clarity in Opex and Profitability templates. - Updated form IDs and action URLs for better alignment with new naming conventions. - Improved navigation links to include scenario and project overviews. test: add integration tests for Opex calculations - Created new tests for Opex calculation HTML and JSON flows. - Validated successful calculations and ensured correct data persistence. - Implemented tests for currency mismatch and unsupported frequency scenarios. test: enhance project and scenario route tests - Added tests to verify scenario list rendering and calculator shortcuts. - Ensured scenario detail pages link back to the portfolio correctly. - Validated project detail pages show associated scenarios accurately.
This commit is contained in:
@@ -48,7 +48,7 @@ def test_capex_calculation_html_flow(
|
||||
f"/calculations/capex?project_id={project_id}&scenario_id={scenario_id}"
|
||||
)
|
||||
assert form_page.status_code == 200
|
||||
assert "Initial Capex Planner" in form_page.text
|
||||
assert "Capex Planner" in form_page.text
|
||||
|
||||
response = client.post(
|
||||
f"/calculations/capex?project_id={project_id}&scenario_id={scenario_id}",
|
||||
@@ -71,7 +71,7 @@ def test_capex_calculation_html_flow(
|
||||
},
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert "Initial capex calculation completed successfully." in response.text
|
||||
assert "Capex calculation completed successfully." in response.text
|
||||
assert "Capex Summary" in response.text
|
||||
assert "$1,200,000.00" in response.text or "1,200,000" in response.text
|
||||
assert "USD" in response.text
|
||||
|
||||
@@ -15,7 +15,7 @@ def _create_project(client: TestClient, name: str) -> int:
|
||||
"name": name,
|
||||
"location": "Nevada",
|
||||
"operation_type": "open_pit",
|
||||
"description": "Project for processing opex testing",
|
||||
"description": "Project for opex testing",
|
||||
},
|
||||
)
|
||||
assert response.status_code == 201
|
||||
@@ -37,7 +37,7 @@ def _create_scenario(client: TestClient, project_id: int, name: str) -> int:
|
||||
return response.json()["id"]
|
||||
|
||||
|
||||
def test_processing_opex_calculation_html_flow(
|
||||
def test_opex_calculation_html_flow(
|
||||
client: TestClient,
|
||||
unit_of_work_factory: Callable[[], UnitOfWork],
|
||||
) -> None:
|
||||
@@ -45,13 +45,13 @@ def test_processing_opex_calculation_html_flow(
|
||||
scenario_id = _create_scenario(client, project_id, "Opex HTML Scenario")
|
||||
|
||||
form_page = client.get(
|
||||
f"/calculations/processing-opex?project_id={project_id}&scenario_id={scenario_id}"
|
||||
f"/calculations/opex?project_id={project_id}&scenario_id={scenario_id}"
|
||||
)
|
||||
assert form_page.status_code == 200
|
||||
assert "Processing Opex Planner" in form_page.text
|
||||
assert "Opex Planner" in form_page.text
|
||||
|
||||
response = client.post(
|
||||
f"/calculations/processing-opex?project_id={project_id}&scenario_id={scenario_id}",
|
||||
f"/calculations/opex?project_id={project_id}&scenario_id={scenario_id}",
|
||||
data={
|
||||
"components[0][name]": "Power",
|
||||
"components[0][category]": "energy",
|
||||
@@ -75,21 +75,21 @@ def test_processing_opex_calculation_html_flow(
|
||||
"parameters[evaluation_horizon_years]": "3",
|
||||
"parameters[apply_escalation]": "1",
|
||||
"options[persist]": "1",
|
||||
"options[snapshot_notes]": "Processing opex HTML flow",
|
||||
"options[snapshot_notes]": "Opex HTML flow",
|
||||
},
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert "Processing opex calculation completed successfully." in response.text
|
||||
assert "Opex calculation completed successfully." in response.text
|
||||
assert "Opex Summary" in response.text
|
||||
assert "$22,000.00" in response.text or "22,000" in response.text
|
||||
|
||||
with unit_of_work_factory() as uow:
|
||||
assert uow.project_processing_opex is not None
|
||||
assert uow.scenario_processing_opex is not None
|
||||
assert uow.project_opex is not None
|
||||
assert uow.scenario_opex is not None
|
||||
|
||||
project_snapshots = uow.project_processing_opex.list_for_project(
|
||||
project_snapshots = uow.project_opex.list_for_project(
|
||||
project_id)
|
||||
scenario_snapshots = uow.scenario_processing_opex.list_for_scenario(
|
||||
scenario_snapshots = uow.scenario_opex.list_for_scenario(
|
||||
scenario_id)
|
||||
|
||||
assert len(project_snapshots) == 1
|
||||
@@ -119,7 +119,7 @@ def test_processing_opex_calculation_html_flow(
|
||||
assert scenario_snapshot.currency_code == "USD"
|
||||
|
||||
|
||||
def test_processing_opex_calculation_json_flow(
|
||||
def test_opex_calculation_json_flow(
|
||||
client: TestClient,
|
||||
unit_of_work_factory: Callable[[], UnitOfWork],
|
||||
) -> None:
|
||||
@@ -170,7 +170,7 @@ def test_processing_opex_calculation_json_flow(
|
||||
}
|
||||
|
||||
response = client.post(
|
||||
f"/calculations/processing-opex?project_id={project_id}&scenario_id={scenario_id}",
|
||||
f"/calculations/opex?project_id={project_id}&scenario_id={scenario_id}",
|
||||
json=payload,
|
||||
)
|
||||
assert response.status_code == 200
|
||||
@@ -206,12 +206,12 @@ def test_processing_opex_calculation_json_flow(
|
||||
assert data["metrics"]["annual_average"] == pytest.approx(expected_average)
|
||||
|
||||
with unit_of_work_factory() as uow:
|
||||
assert uow.project_processing_opex is not None
|
||||
assert uow.scenario_processing_opex is not None
|
||||
assert uow.project_opex is not None
|
||||
assert uow.scenario_opex is not None
|
||||
|
||||
project_snapshot = uow.project_processing_opex.latest_for_project(
|
||||
project_snapshot = uow.project_opex.latest_for_project(
|
||||
project_id)
|
||||
scenario_snapshot = uow.scenario_processing_opex.latest_for_scenario(
|
||||
scenario_snapshot = uow.scenario_opex.latest_for_scenario(
|
||||
scenario_id)
|
||||
|
||||
assert project_snapshot is not None
|
||||
@@ -232,7 +232,7 @@ def test_processing_opex_calculation_json_flow(
|
||||
|
||||
|
||||
@pytest.mark.parametrize("content_type", ["form", "json"])
|
||||
def test_processing_opex_calculation_currency_mismatch(
|
||||
def test_opex_calculation_currency_mismatch(
|
||||
client: TestClient,
|
||||
unit_of_work_factory: Callable[[], UnitOfWork],
|
||||
content_type: str,
|
||||
@@ -260,7 +260,7 @@ def test_processing_opex_calculation_currency_mismatch(
|
||||
"options": {"persist": True},
|
||||
}
|
||||
response = client.post(
|
||||
f"/calculations/processing-opex?project_id={project_id}&scenario_id={scenario_id}",
|
||||
f"/calculations/opex?project_id={project_id}&scenario_id={scenario_id}",
|
||||
json=payload,
|
||||
)
|
||||
assert response.status_code == 422
|
||||
@@ -270,7 +270,7 @@ def test_processing_opex_calculation_currency_mismatch(
|
||||
"components[0].currency" in entry for entry in body.get("errors", []))
|
||||
else:
|
||||
response = client.post(
|
||||
f"/calculations/processing-opex?project_id={project_id}&scenario_id={scenario_id}",
|
||||
f"/calculations/opex?project_id={project_id}&scenario_id={scenario_id}",
|
||||
data={
|
||||
"components[0][name]": "Power",
|
||||
"components[0][category]": "energy",
|
||||
@@ -298,12 +298,12 @@ def test_processing_opex_calculation_currency_mismatch(
|
||||
"components[0].currency" in entry for entry in combined_errors)
|
||||
|
||||
with unit_of_work_factory() as uow:
|
||||
assert uow.project_processing_opex is not None
|
||||
assert uow.scenario_processing_opex is not None
|
||||
assert uow.project_opex is not None
|
||||
assert uow.scenario_opex is not None
|
||||
|
||||
project_snapshots = uow.project_processing_opex.list_for_project(
|
||||
project_snapshots = uow.project_opex.list_for_project(
|
||||
project_id)
|
||||
scenario_snapshots = uow.scenario_processing_opex.list_for_scenario(
|
||||
scenario_snapshots = uow.scenario_opex.list_for_scenario(
|
||||
scenario_id)
|
||||
|
||||
assert project_snapshots == []
|
||||
Reference in New Issue
Block a user