scope frontend contracts to the feature, not to one file

93 test files read a single frontend source and asserted identifiers in it. The
MapWorkspace split showed what that costs: 24 tests went red for a move that
changed no behaviour at all. A contract belongs to the feature — a container,
its hooks, its domain layer — not to whichever file currently holds it.

232 read sites now resolve through read_feature(). The distinction that makes
this safe is direction: a *positive* contract ("this is wired") may widen,
because the identifier must still exist somewhere in the feature; a *negative*
one ("this component performs no transport") is a statement about one file, and
widening it would quietly weaken the check. The 73 single-file reads that
remain are exactly those, and a guard now enforces the rule for new tests.

Verified rather than assumed: of the 732 migrated positive assertions, 644 still
match exactly one module — as specific as before — and the other 86 already
spanned a container and its hook by nature. Two apparent misses are an artefact
of the checking regex reading an escaped newline literally.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Jens
2026-08-22 22:05:43 +02:00
co-authored by Claude Opus 5
parent a2a8775df1
commit 6572e4ad5f
95 changed files with 454 additions and 444 deletions
+84 -15
View File
@@ -22,20 +22,77 @@ ROOT = Path(__file__).resolve().parents[2]
FRONTEND_SRC = ROOT / "frontend" / "src"
# The map workspace is one feature split across several modules: the container
# component, its domain layer and its pure helpers. A contract belongs to the
# feature, not to whichever file currently holds it, so splitting a 4.000-line
# component must not red the suite.
MAP_WORKSPACE_SOURCES = (
"components/map/MapWorkspace.tsx",
"components/map/mapWorkspaceThemes.ts",
"components/map/mapWorkspaceUtils.ts",
"hooks/useMapImageOverlays.ts",
"hooks/useMapRectangleSelection.ts",
"hooks/useFullGisWorkflow.ts",
"components/map/MapExplorerView.tsx",
"components/map/MapAdvancedWorkbench.tsx",
)
# A feature is one behaviour spread over several modules: a container, its
# hooks, its domain layer, its pure helpers. A contract belongs to the feature,
# not to whichever file currently holds it, so moving code between siblings
# must not red the suite. Missing entries are skipped, so a group survives a
# module being split further, renamed or merged back.
#
# Use these for *positive* contracts ("this is wired"). A negative contract
# ("this component performs no transport") is a statement about one file and
# must keep reading that file, or widening it would quietly weaken the check.
FEATURE_SOURCES: dict[str, tuple[str, ...]] = {
"map_workspace": (
"components/map/MapWorkspace.tsx",
"components/map/mapWorkspaceThemes.ts",
"components/map/mapWorkspaceUtils.ts",
"components/map/MapExplorerView.tsx",
"components/map/MapAdvancedWorkbench.tsx",
"hooks/useMapImageOverlays.ts",
"hooks/useMapRectangleSelection.ts",
"hooks/useFullGisWorkflow.ts",
"hooks/useMapThemeSelectionInsights.ts",
"hooks/useMapSelectionExtract.ts",
"hooks/useMapWorkspaceState.ts",
"hooks/useMapSelectionDataset.ts",
"hooks/useMapSelectionQa.ts",
"hooks/useMapThemeSelectionInsights.ts",
"hooks/useTemporalComparison.ts",
"hooks/useCoverageResolver.ts",
"hooks/useOfficialMapProducts.ts",
),
"detection": (
"components/detection/DetectionLab.tsx",
"components/detection/DetectionModelManagement.tsx",
"components/detection/detectionProfiles.ts",
"components/models/ModelSelector.tsx",
"components/models/modelOptions.ts",
"hooks/useDetectionWorkflow.ts",
),
"segmentation": (
"components/segmentation/SegmentationLab.tsx",
"hooks/useSegmentationWorkflow.ts",
),
"quality": (
"components/quality/QualityResultsPanel.tsx",
"components/quality/DetectionReviewPanel.tsx",
"hooks/useQualityWorkflow.ts",
),
"datasets": (
"components/datasets/DatasetPanel.tsx",
"components/datasets/DatasetDetailPanel.tsx",
"components/datasets/RasterControls.tsx",
"components/datasets/VectorControls.tsx",
"components/datasets/SourceCatalogPanel.tsx",
"hooks/useDatasetWorkflow.ts",
"services/api/datasets.ts",
),
"exports": (
"components/exports/ExportCenter.tsx",
"hooks/useExportWorkflow.ts",
),
"shell": (
"App.tsx",
"components/shell/WorkbenchNavigation.tsx",
"components/shell/SecondaryDisplay.tsx",
"components/inspector/WorkbenchInspector.tsx",
"components/overview/OverviewWorkspace.tsx",
"hooks/useProjectWorkspace.ts",
"hooks/useWorkbenchBootstrap.ts",
),
}
MAP_WORKSPACE_SOURCES = FEATURE_SOURCES["map_workspace"]
def read_frontend(relative_path: str) -> str:
@@ -59,10 +116,22 @@ def read_frontend_area(*relative_paths: str) -> str:
return chr(10).join(parts)
def read_feature(name: str) -> str:
"""Every module of one feature, whichever files it is currently split into."""
try:
sources = FEATURE_SOURCES[name]
except KeyError: # pragma: no cover - a typo should fail loudly
raise AssertionError(
f"Unknown frontend feature {name!r}; known: {sorted(FEATURE_SOURCES)}"
) from None
return read_frontend_area(*sources)
def read_map_workspace() -> str:
"""The whole map workspace feature, whichever modules it is split into."""
return read_frontend_area(*MAP_WORKSPACE_SOURCES)
return read_feature("map_workspace")
def assert_wired(source: str, *identifiers: str, context: str = "frontend source") -> None:
@@ -73,3 +73,48 @@ def test_frontend_contract_helpers_are_available() -> None:
assert_wired(source, "analyzeSelection")
assert_calls(source, "analyzeSelection", first_argument="bbox")
assert_mentions(source, "AREAIDFORSELECTION")
FRONTEND_READ = re.compile(
r'(?P<var>\w+)\s*=\s*\(?\s*(?:ROOT|root|REPO_ROOT)\s*/\s*'
r'(?P<path>"[^"]+"(?:\s*/\s*"[^"]+")*)\s*\)?\.read_text\('
)
NEGATIVE_ASSERT = re.compile(r"assert\s+[^\n]*not in\s+(\w+)")
def _feature_owner() -> dict[str, str]:
from tests.frontend_contract import FEATURE_SOURCES
return {source: feature for feature, sources in FEATURE_SOURCES.items() for source in sources}
def test_a_positive_contract_reads_the_feature_not_one_file() -> None:
"""Moving code between sibling modules must not red the suite.
A single-file read is right for a *negative* contract — "this component
performs no transport" is a statement about that file, and widening it
would quietly weaken the check. For a positive contract it pins the
contract to whichever file happens to hold it today.
"""
owner = _feature_owner()
offenders: list[str] = []
for path, source in _test_sources():
if "frontend" not in source:
continue
negatives = set(NEGATIVE_ASSERT.findall(source))
for match in FRONTEND_READ.finditer(source):
if match.group("var") in negatives:
continue
joined = re.sub(r'["\s/]+', "/", match.group("path")).strip("/")
if "frontend/src/" not in joined:
continue
relative = joined.split("frontend/src/", 1)[1]
if relative in owner:
offenders.append(f"{path.name}: {match.group('var')} -> {relative}")
assert not offenders, (
"These read one file of a multi-module feature for a positive contract. "
f"Use read_feature() from tests/frontend_contract.py instead: {sorted(offenders)}"
)
+3 -3
View File
@@ -13,7 +13,7 @@ from app.models import Area, Dataset, Project
from app.schemas.coverage import CoverageBBox
from app.services.coverage_registry_service import CoverageRegistryService, THEMES, ZONES
from app.services.vector_feature_service import VectorFeatureService
from tests.frontend_contract import read_map_workspace
from tests.frontend_contract import read_map_workspace, read_feature
class FakeQuery:
@@ -473,8 +473,8 @@ def test_outside_scope_and_unknown_theme_are_explicit() -> None:
def test_frontend_prefers_materialized_national_workspace_and_resolves_drawn_bbox() -> None:
root = Path(__file__).parents[2]
focus = (root / "frontend" / "src" / "config" / "primaryFocus.ts").read_text(encoding="utf-8")
workspace_hook = (root / "frontend" / "src" / "hooks" / "useProjectWorkspace.ts").read_text(encoding="utf-8")
coverage_hook = (root / "frontend" / "src" / "hooks" / "useCoverageResolver.ts").read_text(encoding="utf-8")
workspace_hook = read_feature("shell")
coverage_hook = read_feature("map_workspace")
map_workspace = read_map_workspace()
assert "Belgium and North Sea Workbench" in focus
@@ -2,7 +2,7 @@ from __future__ import annotations
import json
from pathlib import Path
from tests.frontend_contract import read_map_workspace
from tests.frontend_contract import read_map_workspace, read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -20,7 +20,7 @@ def test_rc9_ux_audit_is_wired_into_frontend_and_readiness() -> None:
def test_rc9_loading_and_accessibility_states_are_explicit() -> None:
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
app = read_feature("shell")
map_workspace = read_map_workspace()
geo_map = (ROOT / "frontend" / "src" / "components" / "GeoMap.tsx").read_text(
encoding="utf-8"
@@ -1,17 +1,16 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
def test_raster_tile_manifest_can_handoff_to_segmentation_lab() -> None:
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
hook = (ROOT / "frontend" / "src" / "hooks" / "useSegmentationWorkflow.ts").read_text(encoding="utf-8")
detail_panel = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetDetailPanel.tsx").read_text(encoding="utf-8")
raster_controls = (ROOT / "frontend" / "src" / "components" / "datasets" / "RasterControls.tsx").read_text(encoding="utf-8")
segmentation_lab = (ROOT / "frontend" / "src" / "components" / "segmentation" / "SegmentationLab.tsx").read_text(
encoding="utf-8",
)
app = read_feature("shell")
hook = read_feature("segmentation")
detail_panel = read_feature("datasets")
raster_controls = read_feature("datasets")
segmentation_lab = read_feature("segmentation")
assert "segmentationTileManifestPath" in hook
assert "setSegmentationTileManifestPath" in hook
@@ -1,15 +1,14 @@
from __future__ import annotations
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
def test_detection_lab_exposes_run_readiness_contract() -> None:
lab = (ROOT / "frontend" / "src" / "components" / "detection" / "DetectionLab.tsx").read_text(
encoding="utf-8"
)
lab = read_feature("detection")
assert "selectedDetectionModel = detectionModels.find" in lab
assert "detectionRequiresTileManifest = selectedDetectionModelId === 'yolo-configured'" in lab
@@ -24,9 +23,7 @@ def test_detection_lab_exposes_run_readiness_contract() -> None:
def test_segmentation_lab_exposes_run_readiness_contract() -> None:
lab = (ROOT / "frontend" / "src" / "components" / "segmentation" / "SegmentationLab.tsx").read_text(
encoding="utf-8"
)
lab = read_feature("segmentation")
assert "segmentationHasDataset" in lab
assert "segmentationHasTileManifest = segmentationTileManifestPath.trim().length > 0" in lab
@@ -1,15 +1,14 @@
from __future__ import annotations
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
def test_detection_lab_distinguishes_configured_model_from_ui_runnable_action() -> None:
lab = (ROOT / "frontend" / "src" / "components" / "detection" / "DetectionLab.tsx").read_text(
encoding="utf-8"
)
lab = read_feature("detection")
assert "detectionModelUiRunnable" in lab
assert "selectedDetectionModelId !== 'manual-fixture-detector'" in lab
@@ -20,9 +19,7 @@ def test_detection_lab_distinguishes_configured_model_from_ui_runnable_action()
def test_segmentation_lab_distinguishes_configured_model_from_ui_runnable_action() -> None:
lab = (ROOT / "frontend" / "src" / "components" / "segmentation" / "SegmentationLab.tsx").read_text(
encoding="utf-8"
)
lab = read_feature("segmentation")
assert "segmentationModelUiRunnable" in lab
assert "selectedSegmentationModelId !== 'fixture-segmenter'" in lab
@@ -1,7 +1,7 @@
from __future__ import annotations
from pathlib import Path
from tests.frontend_contract import read_map_workspace
from tests.frontend_contract import read_map_workspace, read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -23,7 +23,7 @@ def test_map_workspace_exposes_feature_extract_actions() -> None:
def test_geomap_highlights_selected_feature_layer() -> None:
geomap = (ROOT / "frontend" / "src" / "components" / "GeoMap.tsx").read_text(encoding="utf-8")
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
app = read_feature("shell")
assert "selectedFeature?: GeoJSON.Feature | null" in geomap
assert "selected-feature" in geomap
@@ -11,7 +11,7 @@ from shapely.geometry import Polygon, box
from app.core.errors import AppError
from app.models import Dataset, VectorFeature
from app.services.vector_feature_service import VectorFeatureService
from tests.frontend_contract import assert_calls, assert_mentions, assert_wired, read_map_workspace
from tests.frontend_contract import assert_calls, assert_mentions, assert_wired, read_map_workspace, read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -337,12 +337,12 @@ def test_vector_select_route_rejects_area_from_another_project(monkeypatch) -> N
def test_frontend_exposes_map_bbox_selection_contracts() -> None:
api_client = (ROOT / "frontend" / "src" / "services" / "api" / "datasets.ts").read_text(encoding="utf-8")
api_client = read_feature("datasets")
map_workspace = read_map_workspace()
geomap = (ROOT / "frontend" / "src" / "components" / "GeoMap.tsx").read_text(encoding="utf-8")
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
extract_hook = (ROOT / "frontend" / "src" / "hooks" / "useMapSelectionExtract.ts").read_text(encoding="utf-8")
theme_hook = (ROOT / "frontend" / "src" / "hooks" / "useMapThemeSelectionInsights.ts").read_text(encoding="utf-8")
app = read_feature("shell")
extract_hook = read_feature("map_workspace")
theme_hook = read_feature("map_workspace")
assert "selectVectorFeatures" in api_client
assert "Area selection" in map_workspace
@@ -16,6 +16,7 @@ from app.schemas.export import ExportCreateResponse
from app.services.export_service import ExportService
from app.services.storage_service import StorageService
from app.services.vector_feature_service import VectorFeatureService
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -287,9 +288,9 @@ def test_area_constrained_bbox_rejects_selection_outside_work_area() -> None:
def test_frontend_exposes_map_selection_export_action() -> None:
types = (ROOT / "frontend" / "src" / "types.ts").read_text(encoding="utf-8")
exports_api = (ROOT / "frontend" / "src" / "services" / "api" / "exports.ts").read_text(encoding="utf-8")
export_hook = (ROOT / "frontend" / "src" / "hooks" / "useExportWorkflow.ts").read_text(encoding="utf-8")
map_workspace = (ROOT / "frontend" / "src" / "components" / "map" / "MapWorkspace.tsx").read_text(encoding="utf-8")
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
export_hook = read_feature("exports")
map_workspace = read_feature("map_workspace")
app = read_feature("shell")
assert "'vector_selection'" in types
assert "bbox?: VectorSelectionBBox" in exports_api
@@ -12,6 +12,7 @@ from app.schemas.dataset import DatasetCreateResponse
from app.services.storage_service import StorageService
from app.services.vector_feature_service import VectorFeatureService
from app.services.vector_operations_service import VectorOperationsService
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -213,9 +214,9 @@ def test_vector_selection_derive_endpoint_returns_canonical_dataset_envelope(mon
def test_frontend_exposes_map_selection_derive_action() -> None:
types = (ROOT / "frontend" / "src" / "types.ts").read_text(encoding="utf-8")
datasets_api = (ROOT / "frontend" / "src" / "services" / "api" / "datasets.ts").read_text(encoding="utf-8")
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
map_workspace = (ROOT / "frontend" / "src" / "components" / "map" / "MapWorkspace.tsx").read_text(encoding="utf-8")
datasets_api = read_feature("datasets")
app = read_feature("shell")
map_workspace = read_feature("map_workspace")
assert "VectorSelectionDeriveRequest" in types
assert "deriveVectorSelection" in datasets_api
@@ -1,4 +1,5 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -6,7 +7,7 @@ ROOT = Path(__file__).resolve().parents[2]
def test_map_selection_qa_shortcut_uses_existing_qa_workflow_contract() -> None:
hook_path = ROOT / "frontend" / "src" / "hooks" / "useMapSelectionQa.ts"
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
map_workspace = (ROOT / "frontend" / "src" / "components" / "map" / "MapWorkspace.tsx").read_text(encoding="utf-8")
map_workspace = read_feature("map_workspace")
assert hook_path.exists()
hook = hook_path.read_text(encoding="utf-8")
@@ -12,6 +12,7 @@ from app.db.session import get_db
from app.main import app
from app.models import QualityCheck, VectorFeature
from app.services.quality_evidence_service import QualityEvidenceService
from tests.frontend_contract import read_feature
class FakeQuery:
@@ -169,7 +170,7 @@ def test_frontend_quality_evidence_overlay_contract_is_wired() -> None:
root = Path(__file__).resolve().parents[2]
geo_map = (root / "frontend" / "src" / "components" / "GeoMap.tsx").read_text(encoding="utf-8")
map_workspace = (root / "frontend" / "src" / "components" / "map" / "MapWorkspace.tsx").read_text(encoding="utf-8")
map_workspace = read_feature("map_workspace")
qa_api = (root / "frontend" / "src" / "services" / "api" / "qa.ts").read_text(encoding="utf-8")
assert "qaEvidenceData" in geo_map
@@ -1,5 +1,5 @@
from pathlib import Path
from tests.frontend_contract import read_map_workspace
from tests.frontend_contract import read_map_workspace, read_feature
REPO_ROOT = Path(__file__).resolve().parents[2]
@@ -21,7 +21,7 @@ def test_map_uses_road_basemap_with_attribution_and_env_override() -> None:
def test_map_workspace_can_select_persisted_database_layer_and_run_query() -> None:
map_workspace = read_map_workspace()
app_shell = (REPO_ROOT / "frontend/src/App.tsx").read_text(encoding="utf-8")
app_shell = read_feature("shell")
styles = (REPO_ROOT / "frontend/src/styles/app.css").read_text(encoding="utf-8")
assert "map-database-layer-select" in map_workspace
@@ -1,4 +1,5 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -11,10 +12,10 @@ def test_detection_lab_surfaces_yolo_runtime_preflight() -> None:
(ROOT / "frontend" / "src" / "components" / "detection" / "DetectionModelManagement.tsx").read_text(encoding="utf-8"),
)
)
hook = (ROOT / "frontend" / "src" / "hooks" / "useDetectionWorkflow.ts").read_text(encoding="utf-8")
hook = read_feature("detection")
api = (ROOT / "frontend" / "src" / "services" / "api" / "detection.ts").read_text(encoding="utf-8")
types = (ROOT / "frontend" / "src" / "types.ts").read_text(encoding="utf-8")
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
app = read_feature("shell")
assert "Technische YOLO-runtimecontrole" in lab
assert "torch_version" in lab
@@ -35,10 +36,10 @@ def test_detection_lab_surfaces_local_model_asset_selection() -> None:
(ROOT / "frontend" / "src" / "components" / "detection" / "DetectionModelManagement.tsx").read_text(encoding="utf-8"),
)
)
hook = (ROOT / "frontend" / "src" / "hooks" / "useDetectionWorkflow.ts").read_text(encoding="utf-8")
hook = read_feature("detection")
api = (ROOT / "frontend" / "src" / "services" / "api" / "detection.ts").read_text(encoding="utf-8")
types = (ROOT / "frontend" / "src" / "types.ts").read_text(encoding="utf-8")
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
app = read_feature("shell")
provider_panel = (ROOT / "frontend" / "src" / "components" / "providers" / "ProviderPanel.tsx").read_text(
encoding="utf-8"
)
@@ -1,11 +1,12 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
def test_raster_workflow_exposes_structured_tile_manifest_handoff() -> None:
hook = (ROOT / "frontend" / "src" / "hooks" / "useDatasetWorkflow.ts").read_text(encoding="utf-8")
hook = read_feature("datasets")
types = (ROOT / "frontend" / "src" / "types.ts").read_text(encoding="utf-8")
assert "interface RasterTileHandoff" in types
@@ -16,9 +17,7 @@ def test_raster_workflow_exposes_structured_tile_manifest_handoff() -> None:
def test_raster_controls_show_manifest_details_and_ai_handoff_action() -> None:
controls = (ROOT / "frontend" / "src" / "components" / "datasets" / "RasterControls.tsx").read_text(
encoding="utf-8"
)
controls = read_feature("datasets")
assert "latestRasterTileManifest" in controls
assert "Aantal tegels" in controls
@@ -1,4 +1,5 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -52,7 +53,7 @@ def test_detection_lab_surfaces_profiles_as_deliberate_operator_actions() -> Non
def test_detection_workflow_applies_profiles_without_selecting_the_first_arbitrary_asset() -> None:
hook = (ROOT / "frontend" / "src" / "hooks" / "useDetectionWorkflow.ts").read_text(encoding="utf-8")
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
app = read_feature("shell")
assert "applyDetectionOperatorProfile" in hook
assert "setSelectedDetectionModelId('yolo-configured')" in hook
@@ -1,11 +1,12 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
def test_long_context_names_remain_compact_and_inspectable() -> None:
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
app = read_feature("shell")
status = (
ROOT / "frontend" / "src" / "components" / "WorkbenchStatusStrip.tsx"
).read_text(encoding="utf-8")
@@ -1,4 +1,5 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -14,14 +15,7 @@ def test_frontend_declares_national_scope_as_primary_operating_focus() -> None:
map_source = (ROOT / "frontend" / "src" / "components" / "GeoMap.tsx").read_text(
encoding="utf-8"
)
navigation = (
ROOT
/ "frontend"
/ "src"
/ "components"
/ "shell"
/ "WorkbenchNavigation.tsx"
).read_text(encoding="utf-8")
navigation = read_feature("shell")
assert "NATIONAL_WORKSPACE_PROJECT_NAME = 'Belgium and North Sea Workbench'" in focus
assert "NATIONAL_WORKSPACE_REGION = 'Belgie en Belgische Noordzee'" in focus
@@ -1,6 +1,7 @@
from __future__ import annotations
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -11,8 +12,8 @@ def read(path: str) -> str:
def test_workbench_uses_grouped_navigation_and_optional_inspector() -> None:
app = read("frontend/src/App.tsx")
inspector = read("frontend/src/components/inspector/WorkbenchInspector.tsx")
app = read_feature("shell")
inspector = read_feature("shell")
assert "import './styles/premium.css'" in app
assert "const workspaceNavGroups" in app
@@ -29,7 +30,7 @@ def test_workbench_uses_grouped_navigation_and_optional_inspector() -> None:
def test_data_creation_forms_are_progressively_disclosed() -> None:
project = read("frontend/src/components/project/ProjectPanel.tsx")
area = read("frontend/src/components/project/AreaPanel.tsx")
dataset = read("frontend/src/components/datasets/DatasetPanel.tsx")
dataset = read_feature("datasets")
css = read("frontend/src/styles/premium.css")
assert '<details className="data-panel-form-block technical-management-block">' in project
@@ -44,7 +45,7 @@ def test_data_creation_forms_are_progressively_disclosed() -> None:
def test_map_prioritizes_controls_map_and_collapsed_diagnostics() -> None:
map_workspace = read("frontend/src/components/map/MapWorkspace.tsx")
map_workspace = read_feature("map_workspace")
css = read("frontend/src/styles/premium.css")
control_index = map_workspace.index('className="map-control-surface"')
@@ -66,7 +67,7 @@ def test_ai_workspaces_prioritize_runs_and_collapse_registry_detail() -> None:
read("frontend/src/components/detection/DetectionModelManagement.tsx"),
)
)
segmentation = read("frontend/src/components/segmentation/SegmentationLab.tsx")
segmentation = read_feature("segmentation")
css = read("frontend/src/styles/premium.css")
assert '<details className="ai-lab-model-surface" aria-label="Technische modelmogelijkheden">' in detection
@@ -10,6 +10,7 @@ from shapely.geometry import Polygon, shape
from app.models import VectorFeature
from app.services.vector_feature_service import VectorFeatureService
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -147,9 +148,9 @@ def test_municipality_workspace_remains_a_regression_fixture_without_frontend_pr
dockerfile = (ROOT / "deploy" / "unraid" / "Dockerfile.all-in-one").read_text(encoding="utf-8")
focus = (ROOT / "frontend" / "src" / "config" / "primaryFocus.ts").read_text(encoding="utf-8")
project_hook = (ROOT / "frontend" / "src" / "hooks" / "useProjectWorkspace.ts").read_text(encoding="utf-8")
dataset_hook = (ROOT / "frontend" / "src" / "hooks" / "useDatasetWorkflow.ts").read_text(encoding="utf-8")
dataset_hook = read_feature("datasets")
map_source = (ROOT / "frontend" / "src" / "components" / "GeoMap.tsx").read_text(encoding="utf-8")
map_workspace = (ROOT / "frontend" / "src" / "components" / "map" / "MapWorkspace.tsx").read_text(encoding="utf-8")
map_workspace = read_feature("map_workspace")
assert "py_compile scripts/provision_mol_municipality_workspace.py" in readiness
assert "COPY scripts/provision_mol_municipality_workspace.py" in dockerfile
@@ -4,6 +4,7 @@ import pytest
from pydantic import ValidationError
from app.schemas.operations import VectorSelectionBBox, VectorSelectionRequest
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -22,7 +23,7 @@ def test_vector_selection_contract_keeps_an_explicit_bounded_limit() -> None:
def test_large_vector_delivery_uses_existing_postgis_bbox_contract() -> None:
config = (ROOT / "frontend" / "src" / "config" / "vectorDelivery.ts").read_text(encoding="utf-8")
viewport_hook = (ROOT / "frontend" / "src" / "hooks" / "useViewportVectorLayer.ts").read_text(encoding="utf-8")
dataset_hook = (ROOT / "frontend" / "src" / "hooks" / "useDatasetWorkflow.ts").read_text(encoding="utf-8")
dataset_hook = read_feature("datasets")
assert "VECTOR_VIEWPORT_FEATURE_THRESHOLD = 5_000" in config
assert "VECTOR_VIEWPORT_MIN_ZOOM = 14" in config
@@ -35,9 +36,9 @@ def test_large_vector_delivery_uses_existing_postgis_bbox_contract() -> None:
def test_map_reports_viewport_and_does_not_refit_each_slice() -> None:
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
app = read_feature("shell")
geo_map = (ROOT / "frontend" / "src" / "components" / "GeoMap.tsx").read_text(encoding="utf-8")
workspace = (ROOT / "frontend" / "src" / "components" / "map" / "MapWorkspace.tsx").read_text(encoding="utf-8")
workspace = read_feature("map_workspace")
assert "useViewportVectorLayer" in app
assert "fitMapDataOnChange={!viewportVectorLayerActive}" in app
@@ -1,12 +1,13 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
def test_map_source_mode_keeps_database_layers_distinct_from_analysis_results() -> None:
app = (ROOT / "frontend/src/App.tsx").read_text(encoding="utf-8")
workspace = (ROOT / "frontend/src/components/map/MapWorkspace.tsx").read_text(encoding="utf-8")
app = read_feature("shell")
workspace = read_feature("map_workspace")
assert "const [mapContentMode, setMapContentMode]" in app
assert "mapContentMode === 'analysis' && analysisMapLayerAvailable" in app
@@ -3,7 +3,7 @@ from __future__ import annotations
import re
from pathlib import Path
from tests.frontend_contract import assert_calls, assert_mentions, assert_wired, read_map_workspace
from tests.frontend_contract import assert_calls, assert_mentions, assert_wired, read_map_workspace, read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -14,7 +14,7 @@ def read(path: str) -> str:
def test_map_first_explorer_is_the_default_product_flow() -> None:
app = read("frontend/src/App.tsx")
app = read_feature("shell")
workspace = read_map_workspace()
assert "useState<WorkspaceKey>('map')" in app
@@ -69,7 +69,7 @@ def test_map_rectangle_drag_is_wired_to_automatic_analysis() -> None:
def test_dataset_detail_responses_cannot_overwrite_the_latest_map_layer() -> None:
workflow = read("frontend/src/hooks/useDatasetWorkflow.ts")
workflow = read_feature("datasets")
assert "const datasetDetailRequestSequence = useRef(0)" in workflow
assert "const detailRequestId = ++datasetDetailRequestSequence.current" in workflow
+6 -5
View File
@@ -5,6 +5,7 @@ from pathlib import Path
import sys
from shapely.geometry import Polygon, shape
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -127,7 +128,7 @@ def test_kempen_scope_operator_is_packaged_and_exposed_in_map_flow() -> None:
(ROOT / "frontend/src/components/map/mapWorkspaceUtils.ts").read_text(encoding="utf-8"),
)
)
app = (ROOT / "frontend/src/App.tsx").read_text(encoding="utf-8")
app = read_feature("shell")
assert "COPY scripts/geographic_scopes.py" in dockerfile
assert "COPY scripts/provision_geographic_scope.py" in dockerfile
@@ -143,10 +144,10 @@ def test_kempen_scope_operator_is_packaged_and_exposed_in_map_flow() -> None:
def test_project_switches_reset_scoped_state_and_prefer_the_regional_context() -> None:
bootstrap = (ROOT / "frontend/src/hooks/useWorkbenchBootstrap.ts").read_text(encoding="utf-8")
project_workspace = (ROOT / "frontend/src/hooks/useProjectWorkspace.ts").read_text(encoding="utf-8")
map_state = (ROOT / "frontend/src/hooks/useMapWorkspaceState.ts").read_text(encoding="utf-8")
dataset_workflow = (ROOT / "frontend/src/hooks/useDatasetWorkflow.ts").read_text(encoding="utf-8")
bootstrap = read_feature("shell")
project_workspace = read_feature("shell")
map_state = read_feature("map_workspace")
dataset_workflow = read_feature("datasets")
selected_project_branch = bootstrap.split("if (!selectedProjectId)", maxsplit=1)[1]
assert "resetProjectData()" in selected_project_branch
@@ -1,5 +1,5 @@
from pathlib import Path
from tests.frontend_contract import assert_calls, assert_mentions, assert_wired, read_map_workspace
from tests.frontend_contract import assert_calls, assert_mentions, assert_wired, read_map_workspace, read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -20,8 +20,8 @@ def test_work_area_change_clears_stale_spatial_results_before_switching_area() -
def test_cancelled_selection_requests_cannot_restore_stale_results() -> None:
selection_hook = read("frontend/src/hooks/useMapSelectionExtract.ts")
themes_hook = read("frontend/src/hooks/useMapThemeSelectionInsights.ts")
selection_hook = read_feature("map_workspace")
themes_hook = read_feature("map_workspace")
assert "const requestSequence = useRef(0)" in selection_hook
assert "requestSequence.current += 1\n setMapSelectionBbox(null)" in selection_hook
@@ -1,4 +1,5 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -24,7 +25,7 @@ def test_national_workspace_is_automatic_and_map_has_one_scope_selector() -> Non
def test_primary_navigation_uses_end_user_language_and_keeps_management_secondary() -> None:
app = read("frontend/src/App.tsx")
app = read_feature("shell")
for label in ("Kaart", "Bronnen", "Kwaliteit", "Beeldanalyse", "Downloads"):
assert f"label: '{label}'" in app
@@ -35,7 +36,7 @@ def test_primary_navigation_uses_end_user_language_and_keeps_management_secondar
def test_technical_projects_and_metadata_are_progressively_disclosed() -> None:
projects = read("frontend/src/components/project/ProjectPanel.tsx")
areas = read("frontend/src/components/project/AreaPanel.tsx")
datasets = read("frontend/src/components/datasets/DatasetPanel.tsx")
datasets = read_feature("datasets")
dataset_names = read("frontend/src/lib/datasetDisplay.ts")
assert "TECHNICAL_PROJECT_PATTERN" in projects
@@ -50,8 +51,8 @@ def test_technical_projects_and_metadata_are_progressively_disclosed() -> None:
def test_configured_yolo_and_active_asset_are_selected_without_hiding_limitations() -> None:
hook = read("frontend/src/hooks/useDetectionWorkflow.ts")
lab = read("frontend/src/components/detection/DetectionLab.tsx")
hook = read_feature("detection")
lab = read_feature("detection")
assert "useState('yolo-configured')" in hook
assert "useState(0.15)" in hook
@@ -66,8 +67,8 @@ def test_configured_yolo_and_active_asset_are_selected_without_hiding_limitation
def test_visible_ai_and_quality_labels_are_end_user_facing() -> None:
profiles = read("frontend/src/components/detection/detectionProfiles.ts")
quality = read("frontend/src/components/quality/QualityResultsPanel.tsx")
profiles = read_feature("detection")
quality = read_feature("quality")
export_preview = read("frontend/src/components/exports/ExportPreview.tsx")
providers = read("frontend/src/components/providers/ProviderPanel.tsx")
@@ -16,6 +16,7 @@ from rasterio.transform import from_origin
from app.models import Dataset
from app.services.vector_feature_service import VectorFeatureService
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -240,11 +241,11 @@ def test_regional_timeseries_operator_is_packaged_and_release_checked() -> None:
def test_end_user_dataset_sources_are_human_readable() -> None:
display = (ROOT / "frontend/src/lib/datasetDisplay.ts").read_text(encoding="utf-8")
workspace = (ROOT / "frontend/src/components/map/MapWorkspace.tsx").read_text(encoding="utf-8")
catalog = (ROOT / "frontend/src/components/datasets/DatasetPanel.tsx").read_text(encoding="utf-8")
workspace = read_feature("map_workspace")
catalog = read_feature("datasets")
status = (ROOT / "frontend/src/components/WorkbenchStatusStrip.tsx").read_text(encoding="utf-8")
detection = (ROOT / "frontend/src/components/detection/DetectionLab.tsx").read_text(encoding="utf-8")
exports = (ROOT / "frontend/src/components/exports/ExportCenter.tsx").read_text(encoding="utf-8")
detection = read_feature("detection")
exports = read_feature("exports")
assert "department_omgeving_land_use: 'Departement Omgeving'" in display
assert "statbel: 'Statbel'" in display
@@ -1,6 +1,7 @@
from __future__ import annotations
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -11,7 +12,7 @@ def read(path: str) -> str:
def test_guided_detection_reuses_canonical_raster_and_detection_apis() -> None:
hook = read("frontend/src/hooks/useDetectionWorkflow.ts")
hook = read_feature("detection")
assert "prepareAndRunDetection" in hook
assert "datasetsApi.rasterTile" in hook
@@ -30,7 +31,7 @@ def test_guided_detection_reuses_canonical_raster_and_detection_apis() -> None:
def test_guided_detection_upload_uses_existing_dataset_persistence_boundary() -> None:
hook = read("frontend/src/hooks/useDetectionWorkflow.ts")
hook = read_feature("detection")
assert "uploadDetectionRaster" in hook
assert "datasetsApi.upload" in hook
@@ -41,8 +42,8 @@ def test_guided_detection_upload_uses_existing_dataset_persistence_boundary() ->
def test_detection_lab_hides_manifest_plumbing_and_exposes_map_first_result_flow() -> None:
lab = read("frontend/src/components/detection/DetectionLab.tsx")
app = read("frontend/src/App.tsx")
lab = read_feature("detection")
app = read_feature("shell")
assert "Gebouwen zoeken en op kaart tonen" in lab
assert 'aria-label="Luchtbeeld toevoegen"' in lab
@@ -56,8 +57,8 @@ def test_detection_lab_hides_manifest_plumbing_and_exposes_map_first_result_flow
def test_detection_qa_remains_persisted_and_primary_not_parallel() -> None:
lab = read("frontend/src/components/detection/DetectionLab.tsx")
hook = read("frontend/src/hooks/useDetectionWorkflow.ts")
lab = read_feature("detection")
hook = read_feature("detection")
assert 'aria-label="Kwaliteitscontrole gebouwdetectie"' in lab
assert "als kwaliteitscontrole in de database bewaard" in lab
@@ -68,7 +69,7 @@ def test_detection_qa_remains_persisted_and_primary_not_parallel() -> None:
def test_active_analysis_is_not_presented_as_the_underlying_source_dataset() -> None:
app = read("frontend/src/App.tsx")
app = read_feature("shell")
assert "analysisMapLayerActive && mapFeatureCollection" in app
assert "`${mapLayerLabel} · controle vereist`" in app
@@ -21,6 +21,7 @@ from app.main import app
from app.models import Area, Dataset, DatasetVersion, Job, Project, SourceRegistry, SourceSnapshot
from app.schemas.orthophoto import OrthophotoAcquireRequest
from app.services.orthophoto_acquisition_service import OrthophotoAcquisitionService
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -518,9 +519,9 @@ def test_orthophoto_product_endpoint_returns_canonical_envelope() -> None:
def test_frontend_connects_map_selection_to_existing_detection_and_qa_flows() -> None:
app_source = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
app_source = read_feature("shell")
hook_source = (ROOT / "frontend" / "src" / "hooks" / "useMapOrthophotoAnalysis.ts").read_text(encoding="utf-8")
map_source = (ROOT / "frontend" / "src" / "components" / "map" / "MapWorkspace.tsx").read_text(encoding="utf-8")
map_source = read_feature("map_workspace")
assert "useMapOrthophotoAnalysis" in app_source
assert "onRunOrthophotoAnalysis={mapOrthophotoAnalysis.run}" in app_source
@@ -19,6 +19,7 @@ from app.schemas.detection_review import (
DetectionReviewUpsert,
)
from app.services.detection_review_service import DetectionReviewService
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -241,7 +242,7 @@ def test_detection_review_endpoints_use_canonical_envelopes(monkeypatch) -> None
def test_map_detection_qa_uses_documented_footprint_threshold_and_honest_labels() -> None:
hook = (ROOT / "frontend" / "src" / "hooks" / "useMapOrthophotoAnalysis.ts").read_text(encoding="utf-8")
app_source = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
app_source = read_feature("shell")
evidence_service = (ROOT / "backend" / "app" / "services" / "quality_evidence_service.py").read_text(encoding="utf-8")
assert "MAP_BUILDING_QA_IOU_THRESHOLD = 0.25" in hook
+3 -2
View File
@@ -1,6 +1,7 @@
from __future__ import annotations
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -22,8 +23,8 @@ def test_geomap_exposes_v1_layer_controls_and_feature_inspection_contract() -> N
def test_app_wires_map_workbench_component() -> None:
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
component = (ROOT / "frontend" / "src" / "components" / "map" / "MapWorkspace.tsx").read_text(encoding="utf-8")
app = read_feature("shell")
component = read_feature("map_workspace")
assert "mapLayerVisible" in app
assert "mapLayerOpacity" in app
@@ -6,6 +6,7 @@ from uuid import uuid4
from app.models import Dataset
from app.schemas.operations import VectorSelectionSummary
from app.services.vector_feature_service import VectorFeatureService
from tests.frontend_contract import read_feature
ROOT = Path(__file__).parents[2]
@@ -174,7 +175,7 @@ def test_regional_historical_polygons_do_not_emit_irrelevant_line_metrics() -> N
def test_future_regional_imports_persist_semantic_aggregation_configuration() -> None:
buildings = (ROOT / "scripts/provision_regional_grb_buildings.py").read_text(encoding="utf-8")
context = (ROOT / "scripts/provision_regional_grb_context.py").read_text(encoding="utf-8")
frontend = (ROOT / "frontend/src/components/map/MapWorkspace.tsx").read_text(encoding="utf-8")
frontend = read_feature("map_workspace")
assert '"method": "intersection_area"' in buildings
assert '"label": "Bebouwde grondoppervlakte"' in buildings
@@ -12,6 +12,7 @@ from app.main import app
from app.schemas.assistant import AssistantContextMetric, AssistantModelRead, AssistantQueryRequest, AssistantStatus, AssistantTemporalSeries
from app.services.geo_assistant_service import GeoAssistantService
from app.services.temporal_analysis_service import TemporalAnalysisService
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -408,9 +409,9 @@ def test_landuse_operator_exposes_more_honest_historical_themes() -> None:
def test_frontend_exposes_source_inventory_timeline_and_ai_window() -> None:
app = (ROOT / "frontend/src/App.tsx").read_text(encoding="utf-8")
workspace = (ROOT / "frontend/src/components/map/MapWorkspace.tsx").read_text(encoding="utf-8")
catalog = (ROOT / "frontend/src/components/datasets/SourceCatalogPanel.tsx").read_text(encoding="utf-8")
app = read_feature("shell")
workspace = read_feature("map_workspace")
catalog = read_feature("datasets")
assistant_hook = (ROOT / "frontend/src/hooks/useGeoAssistant.ts").read_text(encoding="utf-8")
assert "SourceCatalogPanel" in app
@@ -5,6 +5,7 @@ import sys
from pathlib import Path
from shapely.geometry import box
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -137,7 +138,7 @@ def test_waterinfo_operator_is_packaged_and_readiness_checked() -> None:
def test_frontend_loads_all_dataset_pages_after_temporal_import_expansion() -> None:
client = (ROOT / "frontend" / "src" / "services" / "api" / "datasets.ts").read_text(encoding="utf-8")
client = read_feature("datasets")
assert "DATASET_PAGE_SIZE = 200" in client
assert "offset < (total ?? 0)" in client
@@ -13,7 +13,7 @@ from shapely.ops import transform as transform_geometry
from app.models import Dataset
from app.schemas.operations import VectorSelectionSummary
from app.services.vector_feature_service import VectorFeatureService
from tests.frontend_contract import read_map_workspace
from tests.frontend_contract import read_map_workspace, read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -262,7 +262,7 @@ def test_operator_is_packaged_readiness_checked_and_wired_to_map() -> None:
readiness = (ROOT / "scripts" / "run_readiness_check.sh").read_text(encoding="utf-8")
service = (ROOT / "backend" / "app" / "services" / "vector_feature_service.py").read_text(encoding="utf-8")
map_workspace = read_map_workspace()
source_catalog = (ROOT / "frontend" / "src" / "components" / "datasets" / "SourceCatalogPanel.tsx").read_text(encoding="utf-8")
source_catalog = read_feature("datasets")
assert "COPY scripts/provision_mol_bwk_natura2000.py" in dockerfile
assert "py_compile scripts/provision_mol_bwk_natura2000.py" in readiness
@@ -14,7 +14,7 @@ from shapely.ops import transform as transform_geometry
from app.models import Dataset
from app.schemas.operations import VectorSelectionSummary
from app.services.vector_feature_service import VectorFeatureService
from tests.frontend_contract import read_map_workspace
from tests.frontend_contract import read_map_workspace, read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -263,7 +263,7 @@ def test_operator_uses_canonical_upload_and_is_packaged_for_runtime() -> None:
dockerfile = (ROOT / "deploy" / "unraid" / "Dockerfile.all-in-one").read_text(encoding="utf-8")
readiness = (ROOT / "scripts" / "run_readiness_check.sh").read_text(encoding="utf-8")
map_workspace = read_map_workspace()
source_catalog = (ROOT / "frontend" / "src" / "components" / "datasets" / "SourceCatalogPanel.tsx").read_text(encoding="utf-8")
source_catalog = read_feature("datasets")
dataset_display = (ROOT / "frontend" / "src" / "lib" / "datasetDisplay.ts").read_text(encoding="utf-8")
assert "/datasets/upload" in operator
+3 -3
View File
@@ -21,7 +21,7 @@ from app.models import Area, Dataset, DatasetVersion, Job, Project, SourceRegist
from app.schemas.dhmv import DhmvAcquireRequest, TerrainPartitionSelectionRequest, TerrainSelectionRequest
from app.services.dhmv_acquisition_service import DhmvAcquisitionService
from app.services.terrain_analysis_service import TerrainAnalysisService
from tests.frontend_contract import read_map_workspace
from tests.frontend_contract import read_map_workspace, read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -618,8 +618,8 @@ def test_frontend_and_runtime_expose_dhmv_workflow() -> None:
ROOT / "frontend" / "src" / "lib" / "datasetCapabilities.ts"
).read_text(encoding="utf-8")
map_source = read_map_workspace()
hook_source = (ROOT / "frontend" / "src" / "hooks" / "useMapSelectionExtract.ts").read_text(encoding="utf-8")
service_source = (ROOT / "frontend" / "src" / "services" / "api" / "datasets.ts").read_text(encoding="utf-8")
hook_source = read_feature("map_workspace")
service_source = read_feature("datasets")
assert "digitaal_vlaanderen_dhmv" in capabilities_source
assert "isMapRasterDataset" in capabilities_source
@@ -12,7 +12,7 @@ from shapely.ops import transform as transform_geometry
from app.models import Dataset
from app.schemas.operations import VectorSelectionSummary
from app.services.vector_feature_service import VectorFeatureService
from tests.frontend_contract import read_map_workspace
from tests.frontend_contract import read_map_workspace, read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -354,7 +354,7 @@ def test_operator_is_canonical_packaged_and_mol_scoped_in_explorer() -> None:
dockerfile = (ROOT / "deploy/unraid/Dockerfile.all-in-one").read_text(encoding="utf-8")
readiness = (ROOT / "scripts/run_readiness_check.sh").read_text(encoding="utf-8")
workspace = read_map_workspace()
catalog = (ROOT / "frontend/src/components/datasets/SourceCatalogPanel.tsx").read_text(encoding="utf-8")
catalog = read_feature("datasets")
display = (ROOT / "frontend/src/lib/datasetDisplay.ts").read_text(encoding="utf-8")
assert "/datasets/upload" in operator
@@ -7,6 +7,7 @@ from pathlib import Path
import sys
from shapely.geometry import box, mapping, shape
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -239,8 +240,8 @@ def test_upload_contract_is_regional_temporal_and_partition_audited(tmp_path: Pa
def test_regional_historical_operator_is_packaged_and_release_checked() -> None:
dockerfile = (ROOT / "deploy/unraid/Dockerfile.all-in-one").read_text(encoding="utf-8")
readiness = (ROOT / "scripts/run_readiness_check.sh").read_text(encoding="utf-8")
app = (ROOT / "frontend/src/App.tsx").read_text(encoding="utf-8")
workspace = (ROOT / "frontend/src/components/map/MapWorkspace.tsx").read_text(encoding="utf-8")
app = read_feature("shell")
workspace = read_feature("map_workspace")
assert "COPY scripts/provision_regional_historical_landuse.py" in dockerfile
assert "py_compile scripts/provision_regional_historical_landuse.py" in readiness
@@ -7,6 +7,7 @@ from shapely.geometry import MultiPolygon, Polygon
from app.models import Area
from app.services.area_service import AreaService
from tests.frontend_contract import read_feature
def test_area_serializer_exposes_geojson_geometry_for_map_overlay() -> None:
@@ -45,9 +46,9 @@ def test_area_serializer_exposes_geojson_geometry_for_map_overlay() -> None:
def test_frontend_wires_selected_area_map_overlay_contract() -> None:
root = __import__("pathlib").Path(__file__).resolve().parents[2]
app = (root / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
app = read_feature("shell")
geomap = (root / "frontend" / "src" / "components" / "GeoMap.tsx").read_text(encoding="utf-8")
map_workspace = (root / "frontend" / "src" / "components" / "map" / "MapWorkspace.tsx").read_text(encoding="utf-8")
map_workspace = read_feature("map_workspace")
area_panel = (root / "frontend" / "src" / "components" / "project" / "AreaPanel.tsx").read_text(encoding="utf-8")
assert "selectedMapAreaId" in app
@@ -11,7 +11,7 @@ from shapely.geometry import box, mapping, shape
from app.models import Dataset
from app.services.vector_feature_service import VectorFeatureService
from tests.frontend_contract import read_map_workspace
from tests.frontend_contract import read_map_workspace, read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -237,7 +237,7 @@ def test_regional_operator_is_packaged_release_checked_and_exact_area_is_preferr
readiness = (ROOT / "scripts/run_readiness_check.sh").read_text(encoding="utf-8")
service = (ROOT / "backend/app/services/vector_feature_service.py").read_text(encoding="utf-8")
workspace = read_map_workspace()
catalog = (ROOT / "frontend/src/components/datasets/SourceCatalogPanel.tsx").read_text(encoding="utf-8")
catalog = read_feature("datasets")
model = (ROOT / "backend/app/models/entities.py").read_text(encoding="utf-8")
migration = (
ROOT / "backend/alembic/versions/202607160001_vector_feature_municipality_index.py"
@@ -1,4 +1,5 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -30,7 +31,7 @@ def test_source_portfolio_covers_the_complete_platform() -> None:
def test_source_inventory_is_compact_honest_and_domain_driven() -> None:
catalog = (ROOT / "frontend/src/components/datasets/SourceCatalogPanel.tsx").read_text(encoding="utf-8")
catalog = read_feature("datasets")
styles = (ROOT / "frontend/src/styles/app.css").read_text(encoding="utf-8")
assert "Welke vragen kan GeoIntel beantwoorden?" in catalog
@@ -1,5 +1,5 @@
from pathlib import Path
from tests.frontend_contract import assert_calls, assert_mentions, assert_wired, read_map_workspace
from tests.frontend_contract import assert_calls, assert_mentions, assert_wired, read_map_workspace, read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -20,10 +20,10 @@ def test_partitioned_raster_routes_are_canonical_and_documented() -> None:
def test_regional_map_uses_logical_partition_groups_and_exact_analysis() -> None:
app = (ROOT / "frontend/src/App.tsx").read_text(encoding="utf-8")
app = read_feature("shell")
workspace = read_map_workspace()
hook = (ROOT / "frontend/src/hooks/useMapThemeSelectionInsights.ts").read_text(encoding="utf-8")
api = (ROOT / "frontend/src/services/api/datasets.ts").read_text(encoding="utf-8")
hook = read_feature("map_workspace")
api = read_feature("datasets")
assert "regionalScopeSelected" in workspace
assert "rasterPartitionsForDataset" in workspace
@@ -7,6 +7,7 @@ from types import SimpleNamespace
from app.models import Dataset, DatasetVersion
from app.services.source_freshness_service import SourceFreshnessService
from tests.frontend_contract import read_feature
NOW = datetime(2026, 7, 16, 12, 0, tzinfo=timezone.utc)
@@ -231,8 +232,8 @@ def test_source_freshness_operator_and_ui_contract_are_read_only() -> None:
script = (root / "scripts" / "audit_source_freshness.py").read_text(encoding="utf-8")
dockerfile = (root / "deploy" / "unraid" / "Dockerfile.all-in-one").read_text(encoding="utf-8")
readiness = (root / "scripts" / "run_readiness_check.sh").read_text(encoding="utf-8")
app = (root / "frontend" / "src" / "components" / "overview" / "OverviewWorkspace.tsx").read_text(encoding="utf-8")
api = (root / "frontend" / "src" / "services" / "api" / "datasets.ts").read_text(encoding="utf-8")
app = read_feature("shell")
api = read_feature("datasets")
assert "Request(endpoint" in script
assert "method=\"POST\"" not in script
@@ -1,14 +1,15 @@
from __future__ import annotations
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
def test_frontend_wires_v1_workbench_status_strip() -> None:
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
overview = (ROOT / "frontend" / "src" / "components" / "overview" / "OverviewWorkspace.tsx").read_text(encoding="utf-8")
app = read_feature("shell")
overview = read_feature("shell")
component = (ROOT / "frontend" / "src" / "components" / "WorkbenchStatusStrip.tsx").read_text(encoding="utf-8")
css = (ROOT / "frontend" / "src" / "styles" / "app.css").read_text(encoding="utf-8")
@@ -1,4 +1,5 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -9,7 +10,7 @@ def read(path: str) -> str:
def test_theme_overview_names_the_metric_instead_of_showing_a_bare_value() -> None:
workspace = read("frontend/src/components/map/MapWorkspace.tsx")
workspace = read_feature("map_workspace")
styles = read("frontend/src/styles/app.css")
assert 'className="geo-theme-result-value"' in workspace
@@ -18,7 +19,7 @@ def test_theme_overview_names_the_metric_instead_of_showing_a_bare_value() -> No
def test_current_and_historical_results_are_downloadable() -> None:
workspace = read("frontend/src/components/map/MapWorkspace.tsx")
workspace = read_feature("map_workspace")
assert "activeTheme.id}-analysis.json" in workspace
assert "activeTheme.id}-selection.geojson" in workspace
@@ -30,7 +31,7 @@ def test_current_and_historical_results_are_downloadable() -> None:
def test_completed_analysis_hands_off_to_ai_and_downloads_responsively() -> None:
app = read("frontend/src/App.tsx")
workspace = read("frontend/src/components/map/MapWorkspace.tsx")
workspace = read_feature("map_workspace")
styles = read("frontend/src/styles/app.css")
assert "onOpenAssistant: () => void" in workspace
@@ -20,7 +20,7 @@ from app.services.storage_service import StorageService
from app.services.source_registry_service import SourceRegistryService
from app.services.temporal_analysis_service import TemporalAnalysisService
from app.services.thematic_raster_analysis_service import ThematicRasterAnalysisService
from tests.frontend_contract import assert_calls, assert_mentions, assert_wired, read_map_workspace
from tests.frontend_contract import assert_calls, assert_mentions, assert_wired, read_map_workspace, read_feature
class FakeSession:
@@ -365,7 +365,7 @@ def test_map_result_export_endpoint_uses_canonical_envelope(monkeypatch) -> None
def test_frontend_persists_map_result_before_opening_downloads() -> None:
root = Path(__file__).resolve().parents[2]
workspace = read_map_workspace()
hook = (root / "frontend/src/hooks/useExportWorkflow.ts").read_text(encoding="utf-8")
hook = read_feature("exports")
api = (root / "frontend/src/services/api/exports.ts").read_text(encoding="utf-8")
assert "persistActiveResultAndOpenDownloads" in workspace
@@ -409,7 +409,7 @@ def test_project_list_supports_exact_canonical_workspace_lookup(monkeypatch) ->
def test_frontend_fetches_canonical_workspace_outside_default_project_page() -> None:
root = Path(__file__).resolve().parents[2]
workflow = (root / "frontend/src/hooks/useProjectWorkspace.ts").read_text(encoding="utf-8")
workflow = read_feature("shell")
api = (root / "frontend/src/services/api/projects.ts").read_text(encoding="utf-8")
assert "projectsApi.list({ name: REGIONAL_WORKSPACE_PROJECT_NAME, limit: 1 })" in workflow
@@ -419,7 +419,7 @@ def test_frontend_fetches_canonical_workspace_outside_default_project_page() ->
def test_theme_failures_name_the_source_and_reason() -> None:
root = Path(__file__).resolve().parents[2]
hook = (root / "frontend/src/hooks/useMapThemeSelectionInsights.ts").read_text(encoding="utf-8")
hook = read_feature("map_workspace")
assert "queries[index]?.dataset?.name" in hook
assert "queries[index]?.acquisition?.displayName" in hook
@@ -429,7 +429,7 @@ def test_theme_failures_name_the_source_and_reason() -> None:
def test_workspace_navigation_resets_the_actual_scroll_container() -> None:
root = Path(__file__).resolve().parents[2]
app = (root / "frontend/src/App.tsx").read_text(encoding="utf-8")
app = read_feature("shell")
assert "const workbenchMainRef = useRef<HTMLElement | null>(null)" in app
assert "workbenchMainRef.current?.scrollTo({ top: 0, left: 0 })" in app
@@ -439,8 +439,8 @@ def test_workspace_navigation_resets_the_actual_scroll_container() -> None:
def test_quality_scores_have_plain_language_interpretation() -> None:
root = Path(__file__).resolve().parents[2]
quality = (root / "frontend/src/components/quality/QualityResultsPanel.tsx").read_text(encoding="utf-8")
detection = (root / "frontend/src/components/detection/DetectionLab.tsx").read_text(encoding="utf-8")
quality = read_feature("quality")
detection = read_feature("detection")
assert "Laatste score (0-1)" in quality
assert "Bruikbaar na controle" in quality
@@ -465,7 +465,7 @@ def test_map_and_detection_workspaces_avoid_page_length_driven_layouts() -> None
def test_detection_lab_only_receives_operational_imagery_rasters() -> None:
root = Path(__file__).resolve().parents[2]
app_source = (root / "frontend/src/App.tsx").read_text(encoding="utf-8")
app_source = read_feature("shell")
capability_source = (root / "frontend/src/lib/datasetCapabilities.ts").read_text(encoding="utf-8")
assert "department_omgeving_thematic_raster" in capability_source
@@ -480,7 +480,7 @@ def test_detection_lab_only_receives_operational_imagery_rasters() -> None:
def test_download_workspace_surfaces_map_results_in_plain_dutch() -> None:
root = Path(__file__).resolve().parents[2]
exports = (root / "frontend/src/components/exports/ExportCenter.tsx").read_text(encoding="utf-8")
exports = read_feature("exports")
assert "Gebiedsanalyse (JSON)" in exports
assert "Historische vergelijking (JSON)" in exports
@@ -15,6 +15,7 @@ from app.api.routes import projects as project_routes
from app.main import app
from app.schemas.project import ProjectRead, ProjectUpdate
from app.services.project_service import ProjectService
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -149,11 +150,11 @@ def test_cleanup_script_can_start_as_a_direct_operator_command() -> None:
def test_frontend_lifecycle_and_component_boundaries_are_wired() -> None:
app_source = (ROOT / "frontend/src/App.tsx").read_text(encoding="utf-8")
app_source = read_feature("shell")
project_panel = (ROOT / "frontend/src/components/project/ProjectPanel.tsx").read_text(encoding="utf-8")
detection_lab = (ROOT / "frontend/src/components/detection/DetectionLab.tsx").read_text(encoding="utf-8")
segmentation_lab = (ROOT / "frontend/src/components/segmentation/SegmentationLab.tsx").read_text(encoding="utf-8")
map_workspace = (ROOT / "frontend/src/components/map/MapWorkspace.tsx").read_text(encoding="utf-8")
detection_lab = read_feature("detection")
segmentation_lab = read_feature("segmentation")
map_workspace = read_feature("map_workspace")
premium_css = (ROOT / "frontend/src/styles/premium.css").read_text(encoding="utf-8")
assert "OverviewWorkspace" in app_source
@@ -31,7 +31,7 @@ if str(SCRIPTS) not in sys.path:
sys.path.insert(0, str(SCRIPTS))
import provision_flanders_geographic_scope as flanders_scope # noqa: E402
from tests.frontend_contract import read_map_workspace
from tests.frontend_contract import read_map_workspace, read_feature
class BinaryResponse:
@@ -433,9 +433,7 @@ def test_frontend_bounds_large_area_and_dataset_catalogs() -> None:
area_panel = (
ROOT / "frontend" / "src" / "components" / "project" / "AreaPanel.tsx"
).read_text(encoding="utf-8")
dataset_panel = (
ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetPanel.tsx"
).read_text(encoding="utf-8")
dataset_panel = read_feature("datasets")
assert "const AREA_CATALOG_PAGE_SIZE = 12" in area_panel
assert "{catalogOpen ? (" in area_panel
@@ -459,18 +457,14 @@ def test_frontend_labels_flanders_scope_without_kempen_mislabeling() -> None:
def test_frontend_uses_partitioned_bathymetry_selection_for_regional_scope() -> None:
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
app = read_feature("shell")
index = (ROOT / "frontend" / "index.html").read_text(encoding="utf-8")
focus = (
ROOT / "frontend" / "src" / "config" / "primaryFocus.ts"
).read_text(encoding="utf-8")
map_workspace = read_map_workspace()
theme_hook = (
ROOT / "frontend" / "src" / "hooks" / "useMapThemeSelectionInsights.ts"
).read_text(encoding="utf-8")
dataset_api = (
ROOT / "frontend" / "src" / "services" / "api" / "datasets.ts"
).read_text(encoding="utf-8")
theme_hook = read_feature("map_workspace")
dataset_api = read_feature("datasets")
assert "isPartitionedBathymetry" in map_workspace
assert "regionalPartitionedThemeActive" in map_workspace
@@ -1,5 +1,5 @@
from pathlib import Path
from tests.frontend_contract import assert_calls, assert_mentions, assert_wired, read_map_workspace
from tests.frontend_contract import assert_calls, assert_mentions, assert_wired, read_map_workspace, read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -11,9 +11,9 @@ def read(path: str) -> str:
def test_flanders_workspace_exposes_governed_thematic_products_on_demand() -> None:
workspace = read_map_workspace()
product_hook = read("frontend/src/hooks/useOfficialMapProducts.ts")
selection_hook = read("frontend/src/hooks/useMapThemeSelectionInsights.ts")
api = read("frontend/src/services/api/datasets.ts")
product_hook = read_feature("map_workspace")
selection_hook = read_feature("map_workspace")
api = read_feature("datasets")
assert "activeScopeProject?.name === FLANDERS_WORKSPACE_PROJECT_NAME" in workspace
assert "new Map<DataThemeId, OnDemandMapProduct>" in workspace
@@ -31,8 +31,8 @@ def test_flanders_workspace_exposes_governed_thematic_products_on_demand() -> No
def test_selection_reads_and_bounded_acquires_all_relevant_themes() -> None:
workspace = read_map_workspace()
app = read("frontend/src/App.tsx")
selection_hook = read("frontend/src/hooks/useMapThemeSelectionInsights.ts")
app = read_feature("shell")
selection_hook = read_feature("map_workspace")
# Selection reads the active theme; the loop form is incidental.
assert_wired(workspace, "activeTheme")
@@ -2,6 +2,7 @@ from pathlib import Path
from app.schemas.flood_hazard import FloodHazardAcquireRequest
from app.schemas.operations import VectorSelectionBBox
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -12,7 +13,7 @@ def read(path: str) -> str:
def test_official_map_catalog_hook_loads_all_governed_registries() -> None:
hook = read("frontend/src/hooks/useOfficialMapProducts.ts")
hook = read_feature("map_workspace")
assert "datasetsApi.listThematicRasterProducts" in hook
assert "datasetsApi.listDhmvProducts" in hook
@@ -22,8 +23,8 @@ def test_official_map_catalog_hook_loads_all_governed_registries() -> None:
def test_map_selection_can_acquire_dhmv_and_flood_hazard_products() -> None:
selection_hook = read("frontend/src/hooks/useMapThemeSelectionInsights.ts")
workspace = read("frontend/src/components/map/MapWorkspace.tsx")
selection_hook = read_feature("map_workspace")
workspace = read_feature("map_workspace")
for acquisition_kind in (
"'thematic_raster'",
@@ -19,7 +19,7 @@ from app.models import Area, Dataset, Job, Project
from app.schemas.grb import GrbAcquireRequest
from app.services.dataset_service import DatasetService
from app.services.grb_acquisition_service import GrbAcquisitionService
from tests.frontend_contract import assert_calls, assert_mentions, assert_wired, read_map_workspace
from tests.frontend_contract import assert_calls, assert_mentions, assert_wired, read_map_workspace, read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -381,8 +381,8 @@ def test_system_capabilities_reports_bounded_grb_integration() -> None:
def test_grb_frontend_and_contracts_use_only_the_governed_backend_path() -> None:
selection_hook = (ROOT / "frontend/src/hooks/useMapThemeSelectionInsights.ts").read_text(encoding="utf-8")
catalog_hook = (ROOT / "frontend/src/hooks/useOfficialMapProducts.ts").read_text(encoding="utf-8")
selection_hook = read_feature("map_workspace")
catalog_hook = read_feature("map_workspace")
workspace = read_map_workspace()
contracts = (ROOT / "docs/API_CONTRACTS.md").read_text(encoding="utf-8")
@@ -23,6 +23,7 @@ from app.schemas.official_vector import OfficialVectorAcquireRequest
from app.services.dataset_service import DatasetService
from app.services.official_vector_acquisition_service import OfficialVectorAcquisitionService
from app.services.thematic_raster_acquisition_service import ThematicRasterAcquisitionService
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -412,8 +413,8 @@ def test_official_vector_routes_and_frontend_use_canonical_backend_path(monkeypa
assert acquire_response.json()["data"]["job_type"] == "vector.official.acquire"
assert any(isinstance(item, Job) for item in db.added)
selection_hook = (ROOT / "frontend/src/hooks/useMapThemeSelectionInsights.ts").read_text(encoding="utf-8")
catalog_hook = (ROOT / "frontend/src/hooks/useOfficialMapProducts.ts").read_text(encoding="utf-8")
selection_hook = read_feature("map_workspace")
catalog_hook = read_feature("map_workspace")
workspace = (ROOT / "frontend/src/components/map/MapWorkspace.tsx").read_text(encoding="utf-8")
assert "datasetsApi.acquireOfficialVector" in selection_hook
assert "datasetsApi.listOfficialVectorProducts" in catalog_hook
@@ -1,6 +1,7 @@
from __future__ import annotations
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -18,7 +19,7 @@ def test_app_uses_detection_and_segmentation_workflow_hooks() -> None:
def test_detection_workflow_hook_owns_detection_api_calls() -> None:
hook = (ROOT / "frontend" / "src" / "hooks" / "useDetectionWorkflow.ts").read_text(encoding="utf-8")
hook = read_feature("detection")
assert "detectionApi.listModels" in hook
assert "detectionApi.listRuns" in hook
@@ -28,7 +29,7 @@ def test_detection_workflow_hook_owns_detection_api_calls() -> None:
def test_segmentation_workflow_hook_owns_segmentation_api_calls() -> None:
hook = (ROOT / "frontend" / "src" / "hooks" / "useSegmentationWorkflow.ts").read_text(encoding="utf-8")
hook = read_feature("segmentation")
assert "segmentationApi.listModels" in hook
assert "segmentationApi.listRuns" in hook
@@ -1,6 +1,7 @@
from __future__ import annotations
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -18,7 +19,7 @@ def test_app_uses_export_and_quality_workflow_hooks() -> None:
def test_export_workflow_hook_owns_export_api_calls() -> None:
hook = (ROOT / "frontend" / "src" / "hooks" / "useExportWorkflow.ts").read_text(encoding="utf-8")
hook = read_feature("exports")
assert "exportsApi.listProjectExports" in hook
assert "exportsApi.exportGeojson" in hook
@@ -30,7 +31,7 @@ def test_export_workflow_hook_owns_export_api_calls() -> None:
def test_quality_workflow_hook_owns_quality_api_calls() -> None:
hook = (ROOT / "frontend" / "src" / "hooks" / "useQualityWorkflow.ts").read_text(encoding="utf-8")
hook = read_feature("quality")
assert "qaApi.listQualityChecks" in hook
assert "qaApi.runQa" in hook
@@ -41,9 +42,7 @@ def test_quality_workflow_hook_owns_quality_api_calls() -> None:
def test_app_still_wires_quality_results_and_export_center() -> None:
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
quality_panel = (
ROOT / "frontend" / "src" / "components" / "quality" / "QualityResultsPanel.tsx"
).read_text(encoding="utf-8")
quality_panel = read_feature("quality")
assert "<QualityResultsPanel" in app
assert "onRefresh={() => loadQualityChecks()}" in app
@@ -1,6 +1,7 @@
from __future__ import annotations
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -18,7 +19,7 @@ def test_app_uses_dataset_workflow_hook() -> None:
def test_dataset_workflow_hook_owns_dataset_api_calls() -> None:
hook = (ROOT / "frontend" / "src" / "hooks" / "useDatasetWorkflow.ts").read_text(encoding="utf-8")
hook = read_feature("datasets")
assert "datasetsApi.upload" in hook
assert "datasetsApi.getContent" in hook
@@ -41,12 +42,8 @@ def test_dataset_workflow_hook_owns_dataset_api_calls() -> None:
def test_app_still_wires_dataset_ui_callbacks() -> None:
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
dataset_panel = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetPanel.tsx").read_text(
encoding="utf-8"
)
detail_panel = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetDetailPanel.tsx").read_text(
encoding="utf-8"
)
dataset_panel = read_feature("datasets")
detail_panel = read_feature("datasets")
assert "<DatasetPanel" in app
assert "onUploadDataset={uploadDataset}" in app
@@ -1,6 +1,7 @@
from __future__ import annotations
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -8,9 +9,7 @@ ROOT = Path(__file__).resolve().parents[2]
def test_app_uses_dataset_presentational_components() -> None:
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
inspector = (
ROOT / "frontend" / "src" / "components" / "inspector" / "WorkbenchInspector.tsx"
).read_text(encoding="utf-8")
inspector = read_feature("shell")
assert "from './components/datasets/DatasetPanel'" in app
assert "from './components/inspector/WorkbenchInspector'" in app
@@ -24,7 +23,7 @@ def test_app_uses_dataset_presentational_components() -> None:
def test_dataset_panel_owns_upload_and_list_markup() -> None:
panel = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetPanel.tsx").read_text(encoding="utf-8")
panel = read_feature("datasets")
assert "Eigen bronbestand toevoegen" in panel
assert "Metadata vernieuwen" in panel
@@ -34,15 +33,9 @@ def test_dataset_panel_owns_upload_and_list_markup() -> None:
def test_dataset_detail_panel_composes_raster_and_vector_controls() -> None:
detail_panel = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetDetailPanel.tsx").read_text(
encoding="utf-8"
)
raster_controls = (ROOT / "frontend" / "src" / "components" / "datasets" / "RasterControls.tsx").read_text(
encoding="utf-8"
)
vector_controls = (ROOT / "frontend" / "src" / "components" / "datasets" / "VectorControls.tsx").read_text(
encoding="utf-8"
)
detail_panel = read_feature("datasets")
raster_controls = read_feature("datasets")
vector_controls = read_feature("datasets")
assert "<RasterControls" in detail_panel
assert "<VectorControls" in detail_panel
@@ -1,6 +1,7 @@
from __future__ import annotations
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -61,7 +62,7 @@ def test_demo_workflow_hook_owns_demo_api_and_cross_module_selection() -> None:
def test_workbench_bootstrap_hook_owns_entrypoint_effects() -> None:
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
hook = (ROOT / "frontend" / "src" / "hooks" / "useWorkbenchBootstrap.ts").read_text(encoding="utf-8")
hook = read_feature("shell")
assert "loadProjects().catch(() => null)" not in app
assert "loadDetectionResults().catch(() => null)" not in app
@@ -78,7 +79,7 @@ def test_workbench_bootstrap_hook_owns_entrypoint_effects() -> None:
def test_project_workspace_hook_owns_project_area_dataset_loading() -> None:
hook = (ROOT / "frontend" / "src" / "hooks" / "useProjectWorkspace.ts").read_text(encoding="utf-8")
hook = read_feature("shell")
assert "DEMO_PROJECT_NAME = 'GeoIntel Demo - Building QA'" in hook
assert "pickInitialProjectId" in hook
@@ -113,7 +114,7 @@ def test_change_detection_hook_owns_change_detection_api_calls() -> None:
def test_map_workspace_state_hook_owns_derived_map_state() -> None:
hook = (ROOT / "frontend" / "src" / "hooks" / "useMapWorkspaceState.ts").read_text(encoding="utf-8")
hook = read_feature("map_workspace")
assert "areaFeatureCollection" in hook
assert "mapFeatureCollection" in hook
@@ -122,8 +123,8 @@ def test_map_workspace_state_hook_owns_derived_map_state() -> None:
def test_area_selection_fallbacks_live_with_owning_hooks() -> None:
dataset_hook = (ROOT / "frontend" / "src" / "hooks" / "useDatasetWorkflow.ts").read_text(encoding="utf-8")
map_hook = (ROOT / "frontend" / "src" / "hooks" / "useMapWorkspaceState.ts").read_text(encoding="utf-8")
dataset_hook = read_feature("datasets")
map_hook = read_feature("map_workspace")
assert "setSelectedClipAreaId(areas[0].id)" in dataset_hook
assert "setSelectedMapAreaId(areas[0].id)" in map_hook
@@ -1,6 +1,7 @@
from __future__ import annotations
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -13,18 +14,10 @@ def test_workbench_components_expose_stable_interaction_test_ids() -> None:
area_panel = (ROOT / "frontend" / "src" / "components" / "project" / "AreaPanel.tsx").read_text(
encoding="utf-8"
)
map_workspace = (ROOT / "frontend" / "src" / "components" / "map" / "MapWorkspace.tsx").read_text(
encoding="utf-8"
)
dataset_panel = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetPanel.tsx").read_text(
encoding="utf-8"
)
quality_panel = (
ROOT / "frontend" / "src" / "components" / "quality" / "QualityResultsPanel.tsx"
).read_text(encoding="utf-8")
export_center = (ROOT / "frontend" / "src" / "components" / "exports" / "ExportCenter.tsx").read_text(
encoding="utf-8"
)
map_workspace = read_feature("map_workspace")
dataset_panel = read_feature("datasets")
quality_panel = read_feature("quality")
export_center = read_feature("exports")
assert 'data-testid="project-panel"' in project_panel
assert 'data-testid={`project-select-${project.id}`}' in project_panel
@@ -1,21 +1,15 @@
from __future__ import annotations
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
def test_app_uses_task_based_workbench_shell() -> None:
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
navigation = (
ROOT
/ "frontend"
/ "src"
/ "components"
/ "shell"
/ "WorkbenchNavigation.tsx"
).read_text(encoding="utf-8")
app = read_feature("shell")
navigation = read_feature("shell")
assert "type WorkspaceKey" in app
assert "workspaceNavItems" in app
@@ -1,6 +1,7 @@
from __future__ import annotations
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -13,9 +14,7 @@ def test_data_workspace_panels_use_operator_friendly_cards_and_forms() -> None:
area_panel = (ROOT / "frontend" / "src" / "components" / "project" / "AreaPanel.tsx").read_text(
encoding="utf-8"
)
dataset_panel = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetPanel.tsx").read_text(
encoding="utf-8"
)
dataset_panel = read_feature("datasets")
assert "compact-form" in project_panel
assert "entity-card-active" in project_panel
@@ -28,18 +27,14 @@ def test_data_workspace_panels_use_operator_friendly_cards_and_forms() -> None:
def test_map_and_ai_workspaces_use_task_blocks_not_raw_stacks() -> None:
map_workspace = (ROOT / "frontend" / "src" / "components" / "map" / "MapWorkspace.tsx").read_text(
encoding="utf-8"
)
map_workspace = read_feature("map_workspace")
detection_lab = "\n".join(
(
(ROOT / "frontend" / "src" / "components" / "detection" / "DetectionLab.tsx").read_text(encoding="utf-8"),
(ROOT / "frontend" / "src" / "components" / "detection" / "DetectionModelManagement.tsx").read_text(encoding="utf-8"),
)
)
segmentation_lab = (
ROOT / "frontend" / "src" / "components" / "segmentation" / "SegmentationLab.tsx"
).read_text(encoding="utf-8")
segmentation_lab = read_feature("segmentation")
styles = (ROOT / "frontend" / "src" / "styles" / "app.css").read_text(encoding="utf-8")
assert "map-toolbar" in map_workspace
@@ -1,4 +1,5 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -19,9 +20,7 @@ def test_quality_panel_uses_workbench_summary_and_cards() -> None:
def test_export_center_uses_artifact_actions_and_cards() -> None:
export_center = (ROOT / "frontend" / "src" / "components" / "exports" / "ExportCenter.tsx").read_text(
encoding="utf-8"
)
export_center = read_feature("exports")
export_preview = (ROOT / "frontend" / "src" / "components" / "exports" / "ExportPreview.tsx").read_text(
encoding="utf-8"
)
@@ -1,11 +1,12 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
def test_app_wires_tabbed_workbench_inspector() -> None:
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
app = read_feature("shell")
assert "from './components/inspector/WorkbenchInspector'" in app
assert "<WorkbenchInspector" in app
@@ -35,9 +36,7 @@ def test_workbench_inspector_exposes_context_dataset_quality_and_ai_tabs() -> No
def test_dataset_detail_props_remain_exported_for_inspector_reuse() -> None:
dataset_panel = (
ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetDetailPanel.tsx"
).read_text(encoding="utf-8")
dataset_panel = read_feature("datasets")
assert "export interface DatasetDetailPanelProps" in dataset_panel
assert 'className="dataset-detail-panel"' in dataset_panel
@@ -1,13 +1,12 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
def test_dataset_panel_exposes_map_and_export_quick_actions() -> None:
panel = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetPanel.tsx").read_text(
encoding="utf-8"
)
panel = read_feature("datasets")
assert "selectedDatasetId" in panel
assert "dataset-card-active" in panel
@@ -29,7 +28,7 @@ def test_data_workspace_keeps_catalog_wide_enough_for_populated_state() -> None:
def test_shell_preserves_workspace_width_on_standard_desktop_viewports() -> None:
css = (ROOT / "frontend" / "src" / "styles" / "app.css").read_text(encoding="utf-8")
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
app = read_feature("shell")
assert "grid-template-columns: 12.5rem minmax(0, 1fr) 21rem" in css
assert "@media (max-width: 1360px)" in css
@@ -40,7 +39,7 @@ def test_shell_preserves_workspace_width_on_standard_desktop_viewports() -> None
def test_app_wires_dataset_quick_actions_to_existing_workspaces() -> None:
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
app = read_feature("shell")
assert "const openDatasetInMap = (dataset: DatasetCreateResponse) => {" in app
assert "loadDatasetDetails(selectedProjectId, dataset)" in app
@@ -1,6 +1,7 @@
from __future__ import annotations
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -11,14 +12,7 @@ def test_frontend_shell_has_atlas_workbench_contracts() -> None:
css = (ROOT / "frontend" / "src" / "styles" / "atlas-workbench.css").read_text(
encoding="utf-8"
)
navigation = (
ROOT
/ "frontend"
/ "src"
/ "components"
/ "shell"
/ "WorkbenchNavigation.tsx"
).read_text(encoding="utf-8")
navigation = read_feature("shell")
assert "workspace-command-bar" not in app
assert "workspace-nav-cluster" not in app
@@ -36,15 +30,9 @@ def test_primary_panels_use_empty_state_components() -> None:
project_panel = (ROOT / "frontend" / "src" / "components" / "project" / "ProjectPanel.tsx").read_text(
encoding="utf-8"
)
dataset_panel = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetPanel.tsx").read_text(
encoding="utf-8"
)
detection_lab = (ROOT / "frontend" / "src" / "components" / "detection" / "DetectionLab.tsx").read_text(
encoding="utf-8"
)
segmentation_lab = (
ROOT / "frontend" / "src" / "components" / "segmentation" / "SegmentationLab.tsx"
).read_text(encoding="utf-8")
dataset_panel = read_feature("datasets")
detection_lab = read_feature("detection")
segmentation_lab = read_feature("segmentation")
assert "empty-state" in project_panel
assert "empty-state" in dataset_panel
@@ -1,16 +1,15 @@
from __future__ import annotations
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
def test_map_workspace_exposes_layer_provenance_and_feature_summary() -> None:
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
map_workspace = (ROOT / "frontend" / "src" / "components" / "map" / "MapWorkspace.tsx").read_text(
encoding="utf-8"
)
app = read_feature("shell")
map_workspace = read_feature("map_workspace")
css = (ROOT / "frontend" / "src" / "styles" / "app.css").read_text(encoding="utf-8")
assert "mapLayerSourceLabel" in app
@@ -24,9 +23,7 @@ def test_map_workspace_exposes_layer_provenance_and_feature_summary() -> None:
def test_map_workspace_has_clear_empty_result_layer_guidance() -> None:
map_workspace = (ROOT / "frontend" / "src" / "components" / "map" / "MapWorkspace.tsx").read_text(
encoding="utf-8"
)
map_workspace = read_feature("map_workspace")
assert "Geen actieve vector- of resultaatlaag" in map_workspace
assert "Open een databron, beeldanalyse, segmentatie of veranderingsresultaat om het hier te tekenen." in map_workspace
@@ -1,13 +1,12 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
def test_export_center_surfaces_handoff_readiness_context() -> None:
export_center = (ROOT / "frontend" / "src" / "components" / "exports" / "ExportCenter.tsx").read_text(
encoding="utf-8"
)
export_center = read_feature("exports")
assert 'className="handoff-summary-card"' in export_center
assert 'className="handoff-readiness-grid"' in export_center
@@ -1,13 +1,12 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
def test_map_empty_state_surfaces_ready_vector_dataset_actions() -> None:
map_workspace = (ROOT / "frontend" / "src" / "components" / "map" / "MapWorkspace.tsx").read_text(
encoding="utf-8"
)
map_workspace = read_feature("map_workspace")
assert "availableMapDatasets" in map_workspace
assert "onOpenDatasetInMap" in map_workspace
@@ -18,7 +17,7 @@ def test_map_empty_state_surfaces_ready_vector_dataset_actions() -> None:
def test_app_passes_available_vector_datasets_to_map_workspace() -> None:
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
app = read_feature("shell")
assert "availableMapDatasets" in app
assert "datasets.filter((dataset) => isVectorDatasetType(dataset.dataset_type) && dataset.status === 'ready')" in app
@@ -1,13 +1,12 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
def test_dataset_panel_surfaces_role_summary_and_badges() -> None:
dataset_panel = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetPanel.tsx").read_text(
encoding="utf-8"
)
dataset_panel = read_feature("datasets")
assert "roleSummaries" in dataset_panel
assert "dataset-role-summary-grid" in dataset_panel
@@ -23,9 +22,7 @@ def test_dataset_panel_surfaces_role_summary_and_badges() -> None:
def test_dataset_cards_expose_scan_friendly_source_and_crs_context() -> None:
dataset_panel = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetPanel.tsx").read_text(
encoding="utf-8"
)
dataset_panel = read_feature("datasets")
assert "dataset-card-kicker" in dataset_panel
assert "Bron: {dataset.source_name ?? dataset.source}" in dataset_panel
@@ -1,13 +1,12 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
def test_dataset_panel_explains_recommended_actions() -> None:
dataset_panel = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetPanel.tsx").read_text(
encoding="utf-8"
)
dataset_panel = read_feature("datasets")
assert "datasetActionHint" in dataset_panel
assert "dataset-action-hint" in dataset_panel
@@ -17,9 +16,7 @@ def test_dataset_panel_explains_recommended_actions() -> None:
def test_dataset_buttons_have_scan_friendly_action_copy() -> None:
dataset_panel = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetPanel.tsx").read_text(
encoding="utf-8"
)
dataset_panel = read_feature("datasets")
assert "dataset-action-grid" in dataset_panel
assert "Bekijken" in dataset_panel
@@ -1,4 +1,5 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -32,7 +33,7 @@ def test_quality_panel_surfaces_candidate_reference_handoff_summary() -> None:
def test_app_passes_quality_dataset_context() -> None:
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
app = read_feature("shell")
assert "availableVectorDatasets.filter((item) => item.dataset_role !== 'reference')" in app
assert "candidateDatasets={candidateDatasets}" in app
@@ -1,13 +1,12 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
def test_quality_panel_promotes_core_metrics_before_raw_metric_list() -> None:
quality_panel = (
ROOT / "frontend" / "src" / "components" / "quality" / "QualityResultsPanel.tsx"
).read_text(encoding="utf-8")
quality_panel = read_feature("quality")
assert "CORE_METRIC_ORDER" in quality_panel
assert "precision" in quality_panel
@@ -21,9 +20,7 @@ def test_quality_panel_promotes_core_metrics_before_raw_metric_list() -> None:
def test_quality_panel_renders_metric_evidence_cards_and_raw_metrics() -> None:
quality_panel = (
ROOT / "frontend" / "src" / "components" / "quality" / "QualityResultsPanel.tsx"
).read_text(encoding="utf-8")
quality_panel = read_feature("quality")
assert "quality-metric-grid" in quality_panel
assert "quality-metric-card" in quality_panel
@@ -1,13 +1,12 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
def test_quality_panel_adds_result_filters_and_density_limit() -> None:
quality_panel = (
ROOT / "frontend" / "src" / "components" / "quality" / "QualityResultsPanel.tsx"
).read_text(encoding="utf-8")
quality_panel = read_feature("quality")
assert "useState" in quality_panel
assert "qualityStatusFilter" in quality_panel
@@ -1,4 +1,5 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -20,12 +21,8 @@ def test_data_and_map_mobile_polish_css_contracts() -> None:
def test_data_and_map_components_keep_existing_workflow_markup() -> None:
dataset_panel = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetPanel.tsx").read_text(
encoding="utf-8"
)
map_workspace = (ROOT / "frontend" / "src" / "components" / "map" / "MapWorkspace.tsx").read_text(
encoding="utf-8"
)
dataset_panel = read_feature("datasets")
map_workspace = read_feature("map_workspace")
assert 'className="dataset-upload-form"' in dataset_panel
assert 'className="file-input-label"' in dataset_panel
@@ -1,4 +1,5 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -27,9 +28,7 @@ def test_detection_and_segmentation_keep_ai_lab_workflow_markup() -> None:
(ROOT / "frontend" / "src" / "components" / "detection" / "DetectionModelManagement.tsx").read_text(encoding="utf-8"),
)
)
segmentation_lab = (
ROOT / "frontend" / "src" / "components" / "segmentation" / "SegmentationLab.tsx"
).read_text(encoding="utf-8")
segmentation_lab = read_feature("segmentation")
for source in (detection_lab, segmentation_lab):
assert 'className="model-list"' in source
@@ -1,4 +1,5 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -23,9 +24,7 @@ def test_export_and_system_mobile_density_css_contracts() -> None:
def test_export_and_provider_components_keep_workflow_markup() -> None:
export_center = (ROOT / "frontend" / "src" / "components" / "exports" / "ExportCenter.tsx").read_text(
encoding="utf-8"
)
export_center = read_feature("exports")
provider_panel = (ROOT / "frontend" / "src" / "components" / "providers" / "ProviderPanel.tsx").read_text(
encoding="utf-8"
)
@@ -1,4 +1,5 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -24,18 +25,10 @@ def test_inspector_mobile_density_css_contracts() -> None:
def test_inspector_components_keep_mobile_tool_markup() -> None:
inspector = (ROOT / "frontend" / "src" / "components" / "inspector" / "WorkbenchInspector.tsx").read_text(
encoding="utf-8"
)
dataset_detail = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetDetailPanel.tsx").read_text(
encoding="utf-8"
)
raster_controls = (ROOT / "frontend" / "src" / "components" / "datasets" / "RasterControls.tsx").read_text(
encoding="utf-8"
)
vector_controls = (ROOT / "frontend" / "src" / "components" / "datasets" / "VectorControls.tsx").read_text(
encoding="utf-8"
)
inspector = read_feature("shell")
dataset_detail = read_feature("datasets")
raster_controls = read_feature("datasets")
vector_controls = read_feature("datasets")
assert 'className="workbench-inspector-panel"' in inspector
assert 'className="inspector-action-bar"' in inspector
@@ -1,4 +1,5 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -19,15 +20,8 @@ def test_global_focus_visible_contracts_are_defined() -> None:
def test_primary_navigation_has_keyboard_labels() -> None:
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
navigation = (
ROOT
/ "frontend"
/ "src"
/ "components"
/ "shell"
/ "WorkbenchNavigation.tsx"
).read_text(encoding="utf-8")
app = read_feature("shell")
navigation = read_feature("shell")
assert 'aria-label={`Open ${item.label}: ${item.description}`}' in navigation
assert "title={item.description}" in navigation
@@ -39,9 +33,7 @@ def test_primary_navigation_has_keyboard_labels() -> None:
def test_inspector_tabs_are_bound_to_tab_panels() -> None:
inspector = (ROOT / "frontend" / "src" / "components" / "inspector" / "WorkbenchInspector.tsx").read_text(
encoding="utf-8"
)
inspector = read_feature("shell")
assert "const activeTabId = `inspector-tab-${activeTab}`" in inspector
assert "const activePanelId = `inspector-panel-${activeTab}`" in inspector
@@ -1,4 +1,5 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -19,9 +20,7 @@ def test_dataset_operation_form_css_contracts() -> None:
def test_raster_controls_expose_readable_operation_groups() -> None:
raster_controls = (ROOT / "frontend" / "src" / "components" / "datasets" / "RasterControls.tsx").read_text(
encoding="utf-8"
)
raster_controls = read_feature("datasets")
assert 'className="dataset-tool-heading"' in raster_controls
assert 'className="dataset-tool-helper"' in raster_controls
@@ -35,9 +34,7 @@ def test_raster_controls_expose_readable_operation_groups() -> None:
def test_vector_controls_expose_readable_operation_groups() -> None:
vector_controls = (ROOT / "frontend" / "src" / "components" / "datasets" / "VectorControls.tsx").read_text(
encoding="utf-8"
)
vector_controls = read_feature("datasets")
assert 'className="dataset-tool-heading"' in vector_controls
assert 'className="dataset-tool-helper"' in vector_controls
@@ -1,4 +1,5 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -18,12 +19,8 @@ def test_result_state_css_contracts() -> None:
def test_quality_and_export_panels_use_result_state_blocks() -> None:
quality_panel = (ROOT / "frontend" / "src" / "components" / "quality" / "QualityResultsPanel.tsx").read_text(
encoding="utf-8"
)
export_center = (ROOT / "frontend" / "src" / "components" / "exports" / "ExportCenter.tsx").read_text(
encoding="utf-8"
)
quality_panel = read_feature("quality")
export_center = read_feature("exports")
assert 'className="result-state result-state-error"' in quality_panel
assert 'className="result-state result-state-empty"' in quality_panel
@@ -33,12 +30,8 @@ def test_quality_and_export_panels_use_result_state_blocks() -> None:
def test_ai_labs_use_result_state_blocks() -> None:
detection_lab = (ROOT / "frontend" / "src" / "components" / "detection" / "DetectionLab.tsx").read_text(
encoding="utf-8"
)
segmentation_lab = (
ROOT / "frontend" / "src" / "components" / "segmentation" / "SegmentationLab.tsx"
).read_text(encoding="utf-8")
detection_lab = read_feature("detection")
segmentation_lab = read_feature("segmentation")
for content in (detection_lab, segmentation_lab):
assert 'className="result-state result-state-loading"' in content
@@ -1,21 +1,15 @@
from __future__ import annotations
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
def test_workbench_shell_has_skip_link_and_main_focus_target() -> None:
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
navigation = (
ROOT
/ "frontend"
/ "src"
/ "components"
/ "shell"
/ "WorkbenchNavigation.tsx"
).read_text(encoding="utf-8")
app = read_feature("shell")
navigation = read_feature("shell")
assert 'className="skip-link"' in app
assert 'href="#workspace-main"' in app
@@ -1,13 +1,14 @@
from __future__ import annotations
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
def test_overview_uses_named_hierarchy_regions() -> None:
app = (ROOT / "frontend" / "src" / "components" / "overview" / "OverviewWorkspace.tsx").read_text(encoding="utf-8")
app = read_feature("shell")
assert 'className="overview-action-copy"' in app
assert 'className="quick-action-grid overview-quick-actions"' in app
@@ -1,6 +1,7 @@
from __future__ import annotations
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -25,9 +26,7 @@ def test_project_and_area_panels_expose_selected_summary_regions() -> None:
def test_dataset_panel_separates_selected_upload_and_catalog_regions() -> None:
dataset_panel = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetPanel.tsx").read_text(
encoding="utf-8"
)
dataset_panel = read_feature("datasets")
assert "const selectedDataset = datasets.find" in dataset_panel
assert 'className="data-selection-summary data-selection-summary-dataset"' in dataset_panel
@@ -1,15 +1,14 @@
from __future__ import annotations
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
def test_map_workspace_exposes_structured_surfaces() -> None:
map_workspace = (ROOT / "frontend" / "src" / "components" / "map" / "MapWorkspace.tsx").read_text(
encoding="utf-8"
)
map_workspace = read_feature("map_workspace")
assert 'className="map-workspace-shell"' in map_workspace
assert 'className="map-context-summary"' in map_workspace
@@ -21,9 +20,7 @@ def test_map_workspace_exposes_structured_surfaces() -> None:
def test_map_workspace_summary_uses_current_layer_and_selection_state() -> None:
map_workspace = (ROOT / "frontend" / "src" / "components" / "map" / "MapWorkspace.tsx").read_text(
encoding="utf-8"
)
map_workspace = read_feature("map_workspace")
assert "const selectedMapArea = areas.find" in map_workspace
assert "selectedMapArea?.name ?? 'Geen gebied geselecteerd'" in map_workspace
@@ -1,15 +1,14 @@
from __future__ import annotations
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
def test_quality_results_panel_exposes_structured_surfaces() -> None:
panel = (ROOT / "frontend" / "src" / "components" / "quality" / "QualityResultsPanel.tsx").read_text(
encoding="utf-8"
)
panel = read_feature("quality")
assert "'quality-results-panel quality-results-panel-empty' : 'quality-results-panel'" in panel
assert 'className="quality-results-shell"' in panel
@@ -26,9 +25,7 @@ def test_quality_results_panel_exposes_structured_surfaces() -> None:
def test_quality_results_panel_preserves_existing_refresh_filter_and_history_state() -> None:
panel = (ROOT / "frontend" / "src" / "components" / "quality" / "QualityResultsPanel.tsx").read_text(
encoding="utf-8"
)
panel = read_feature("quality")
assert "onRefresh" in panel
assert "qualityStatusFilter" in panel
@@ -1,6 +1,7 @@
from __future__ import annotations
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -27,9 +28,7 @@ def test_detection_lab_exposes_structured_surfaces() -> None:
def test_segmentation_lab_exposes_structured_surfaces() -> None:
lab = (ROOT / "frontend" / "src" / "components" / "segmentation" / "SegmentationLab.tsx").read_text(
encoding="utf-8"
)
lab = read_feature("segmentation")
assert 'className="workspace-panel ai-lab-shell segmentation-lab-shell"' in lab
assert 'className="ai-lab-model-surface"' in lab
@@ -44,12 +43,8 @@ def test_segmentation_lab_exposes_structured_surfaces() -> None:
def test_ai_lab_preserves_existing_detection_and_segmentation_controls() -> None:
detection = (ROOT / "frontend" / "src" / "components" / "detection" / "DetectionLab.tsx").read_text(
encoding="utf-8"
)
segmentation = (ROOT / "frontend" / "src" / "components" / "segmentation" / "SegmentationLab.tsx").read_text(
encoding="utf-8"
)
detection = read_feature("detection")
segmentation = read_feature("segmentation")
assert "onRunDetection" in detection
assert "onLoadResults" in detection
@@ -1,15 +1,14 @@
from __future__ import annotations
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
def test_export_center_exposes_final_handoff_surfaces() -> None:
export_center = (ROOT / "frontend" / "src" / "components" / "exports" / "ExportCenter.tsx").read_text(
encoding="utf-8"
)
export_center = read_feature("exports")
assert 'className="export-center"' in export_center
assert 'className="export-center-shell"' in export_center
@@ -40,9 +39,7 @@ def test_provider_panel_exposes_final_system_surfaces() -> None:
def test_export_system_preserves_existing_workflow_controls() -> None:
export_center = (ROOT / "frontend" / "src" / "components" / "exports" / "ExportCenter.tsx").read_text(
encoding="utf-8"
)
export_center = read_feature("exports")
provider_panel = (ROOT / "frontend" / "src" / "components" / "providers" / "ProviderPanel.tsx").read_text(
encoding="utf-8"
)
@@ -1,13 +1,14 @@
from __future__ import annotations
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
def test_overview_exposes_end_to_end_workflow_guidance() -> None:
overview = (ROOT / "frontend" / "src" / "components" / "overview" / "OverviewWorkspace.tsx").read_text(encoding="utf-8")
overview = read_feature("shell")
assert 'aria-label="Voortgang van de werkstroom"' in overview
assert 'className="workflow-guidance-panel"' in overview
@@ -21,8 +22,8 @@ def test_overview_exposes_end_to_end_workflow_guidance() -> None:
def test_workflow_guidance_routes_to_existing_workspaces() -> None:
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
overview = (ROOT / "frontend" / "src" / "components" / "overview" / "OverviewWorkspace.tsx").read_text(encoding="utf-8")
app = read_feature("shell")
overview = read_feature("shell")
assert "target: 'data'" in overview
assert "target: 'map'" in overview
@@ -45,7 +46,7 @@ def test_workflow_guidance_has_responsive_contracts() -> None:
def test_workflow_guidance_complete_state_and_map_copy_are_precise() -> None:
overview = (ROOT / "frontend" / "src" / "components" / "overview" / "OverviewWorkspace.tsx").read_text(encoding="utf-8")
overview = read_feature("shell")
assert "workflowComplete" in overview
assert "Klaar om te delen" in overview
@@ -55,8 +56,8 @@ def test_workflow_guidance_complete_state_and_map_copy_are_precise() -> None:
def test_workflow_guidance_map_and_export_steps_reuse_dataset_context() -> None:
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
overview = (ROOT / "frontend" / "src" / "components" / "overview" / "OverviewWorkspace.tsx").read_text(encoding="utf-8")
app = read_feature("shell")
overview = read_feature("shell")
assert "openWorkflowGuidanceStep" in app
assert "target === 'map'" in app
@@ -1,14 +1,12 @@
from pathlib import Path
from tests.frontend_contract import assert_calls, assert_mentions, assert_wired
from tests.frontend_contract import assert_calls, assert_mentions, assert_wired, read_feature
ROOT = Path(__file__).resolve().parents[2]
def test_export_center_groups_latest_handoff_artifacts_by_type() -> None:
export_center = (ROOT / "frontend" / "src" / "components" / "exports" / "ExportCenter.tsx").read_text(
encoding="utf-8"
)
export_center = read_feature("exports")
assert "latestHandoffArtifacts" in export_center
assert "handoff" in export_center.casefold()
@@ -23,9 +21,7 @@ def test_export_center_groups_latest_handoff_artifacts_by_type() -> None:
def test_export_center_latest_artifact_cards_keep_existing_actions() -> None:
export_center = (ROOT / "frontend" / "src" / "components" / "exports" / "ExportCenter.tsx").read_text(
encoding="utf-8"
)
export_center = read_feature("exports")
assert "getLatestExportByType" in export_center
assert "const item = artifact.item" in export_center
@@ -1,13 +1,12 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
def test_quality_results_panel_exposes_selected_check_drilldown() -> None:
panel = (ROOT / "frontend" / "src" / "components" / "quality" / "QualityResultsPanel.tsx").read_text(
encoding="utf-8"
)
panel = read_feature("quality")
assert "selectedQualityCheckId" in panel
assert "selectedQualityCheck" in panel
@@ -23,9 +22,7 @@ def test_quality_results_panel_exposes_selected_check_drilldown() -> None:
def test_quality_results_panel_surfaces_false_positive_negative_evidence() -> None:
panel = (ROOT / "frontend" / "src" / "components" / "quality" / "QualityResultsPanel.tsx").read_text(
encoding="utf-8"
)
panel = read_feature("quality")
assert "Onterecht gevonden" in panel
assert "Gemiste objecten" in panel
@@ -1,13 +1,12 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
def test_raster_controls_expose_pipeline_readiness_and_handoff() -> None:
raster_controls = (ROOT / "frontend" / "src" / "components" / "datasets" / "RasterControls.tsx").read_text(
encoding="utf-8"
)
raster_controls = read_feature("datasets")
assert "rasterReadinessItems" in raster_controls
assert "rasterGuardrailItems" in raster_controls
@@ -1,11 +1,12 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
def test_dataset_workflow_selects_useful_default_dataset_after_project_load() -> None:
hook = (ROOT / "frontend" / "src" / "hooks" / "useDatasetWorkflow.ts").read_text(encoding="utf-8")
hook = read_feature("datasets")
assert "defaultDataset" in hook
assert "!selectedDatasetId" in hook
@@ -15,12 +16,8 @@ def test_dataset_workflow_selects_useful_default_dataset_after_project_load() ->
def test_ai_labs_explain_missing_raster_input_before_disabled_runs() -> None:
detection_lab = (ROOT / "frontend" / "src" / "components" / "detection" / "DetectionLab.tsx").read_text(
encoding="utf-8"
)
segmentation_lab = (ROOT / "frontend" / "src" / "components" / "segmentation" / "SegmentationLab.tsx").read_text(
encoding="utf-8"
)
detection_lab = read_feature("detection")
segmentation_lab = read_feature("segmentation")
assert "Geen luchtbeeld beschikbaar in deze werkruimte." in detection_lab
assert "Voeg hieronder een gegeorefereerde GeoTIFF toe." in detection_lab
@@ -1,4 +1,5 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
@@ -19,7 +20,7 @@ def test_demo_workflow_contract_includes_raster_fixture_dataset() -> None:
def test_demo_workflow_frontend_uses_raster_fixture_for_ai_labs() -> None:
types = (ROOT / "frontend" / "src" / "types.ts").read_text(encoding="utf-8")
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
app = read_feature("shell")
hook = (ROOT / "frontend" / "src" / "hooks" / "useDemoWorkflow.ts").read_text(encoding="utf-8")
assert "raster_dataset_id?: string | null" in types
@@ -1,14 +1,15 @@
from pathlib import Path
from tests.frontend_contract import read_feature
ROOT = Path(__file__).resolve().parents[2]
def test_raster_tile_manifest_is_visible_and_can_handoff_to_detection_lab() -> None:
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
hook = (ROOT / "frontend" / "src" / "hooks" / "useDatasetWorkflow.ts").read_text(encoding="utf-8")
detail_panel = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetDetailPanel.tsx").read_text(encoding="utf-8")
raster_controls = (ROOT / "frontend" / "src" / "components" / "datasets" / "RasterControls.tsx").read_text(encoding="utf-8")
app = read_feature("shell")
hook = read_feature("datasets")
detail_panel = read_feature("datasets")
raster_controls = read_feature("datasets")
assert "latestRasterTileManifestPath" in hook
assert "extractRasterTileManifestPath" in hook