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:
@@ -22,20 +22,77 @@ ROOT = Path(__file__).resolve().parents[2]
|
|||||||
FRONTEND_SRC = ROOT / "frontend" / "src"
|
FRONTEND_SRC = ROOT / "frontend" / "src"
|
||||||
|
|
||||||
|
|
||||||
# The map workspace is one feature split across several modules: the container
|
# A feature is one behaviour spread over several modules: a container, its
|
||||||
# component, its domain layer and its pure helpers. A contract belongs to the
|
# hooks, its domain layer, its pure helpers. A contract belongs to the feature,
|
||||||
# feature, not to whichever file currently holds it, so splitting a 4.000-line
|
# not to whichever file currently holds it, so moving code between siblings
|
||||||
# component must not red the suite.
|
# must not red the suite. Missing entries are skipped, so a group survives a
|
||||||
MAP_WORKSPACE_SOURCES = (
|
# module being split further, renamed or merged back.
|
||||||
"components/map/MapWorkspace.tsx",
|
#
|
||||||
"components/map/mapWorkspaceThemes.ts",
|
# Use these for *positive* contracts ("this is wired"). A negative contract
|
||||||
"components/map/mapWorkspaceUtils.ts",
|
# ("this component performs no transport") is a statement about one file and
|
||||||
"hooks/useMapImageOverlays.ts",
|
# must keep reading that file, or widening it would quietly weaken the check.
|
||||||
"hooks/useMapRectangleSelection.ts",
|
FEATURE_SOURCES: dict[str, tuple[str, ...]] = {
|
||||||
"hooks/useFullGisWorkflow.ts",
|
"map_workspace": (
|
||||||
"components/map/MapExplorerView.tsx",
|
"components/map/MapWorkspace.tsx",
|
||||||
"components/map/MapAdvancedWorkbench.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:
|
def read_frontend(relative_path: str) -> str:
|
||||||
@@ -59,10 +116,22 @@ def read_frontend_area(*relative_paths: str) -> str:
|
|||||||
return chr(10).join(parts)
|
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:
|
def read_map_workspace() -> str:
|
||||||
"""The whole map workspace feature, whichever modules it is split into."""
|
"""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:
|
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_wired(source, "analyzeSelection")
|
||||||
assert_calls(source, "analyzeSelection", first_argument="bbox")
|
assert_calls(source, "analyzeSelection", first_argument="bbox")
|
||||||
assert_mentions(source, "AREAIDFORSELECTION")
|
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)}"
|
||||||
|
)
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ from app.models import Area, Dataset, Project
|
|||||||
from app.schemas.coverage import CoverageBBox
|
from app.schemas.coverage import CoverageBBox
|
||||||
from app.services.coverage_registry_service import CoverageRegistryService, THEMES, ZONES
|
from app.services.coverage_registry_service import CoverageRegistryService, THEMES, ZONES
|
||||||
from app.services.vector_feature_service import VectorFeatureService
|
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:
|
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:
|
def test_frontend_prefers_materialized_national_workspace_and_resolves_drawn_bbox() -> None:
|
||||||
root = Path(__file__).parents[2]
|
root = Path(__file__).parents[2]
|
||||||
focus = (root / "frontend" / "src" / "config" / "primaryFocus.ts").read_text(encoding="utf-8")
|
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")
|
workspace_hook = read_feature("shell")
|
||||||
coverage_hook = (root / "frontend" / "src" / "hooks" / "useCoverageResolver.ts").read_text(encoding="utf-8")
|
coverage_hook = read_feature("map_workspace")
|
||||||
map_workspace = read_map_workspace()
|
map_workspace = read_map_workspace()
|
||||||
|
|
||||||
assert "Belgium and North Sea Workbench" in focus
|
assert "Belgium and North Sea Workbench" in focus
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
from pathlib import Path
|
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]
|
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:
|
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()
|
map_workspace = read_map_workspace()
|
||||||
geo_map = (ROOT / "frontend" / "src" / "components" / "GeoMap.tsx").read_text(
|
geo_map = (ROOT / "frontend" / "src" / "components" / "GeoMap.tsx").read_text(
|
||||||
encoding="utf-8"
|
encoding="utf-8"
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
def test_raster_tile_manifest_can_handoff_to_segmentation_lab() -> None:
|
def test_raster_tile_manifest_can_handoff_to_segmentation_lab() -> None:
|
||||||
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
|
app = read_feature("shell")
|
||||||
hook = (ROOT / "frontend" / "src" / "hooks" / "useSegmentationWorkflow.ts").read_text(encoding="utf-8")
|
hook = read_feature("segmentation")
|
||||||
detail_panel = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetDetailPanel.tsx").read_text(encoding="utf-8")
|
detail_panel = read_feature("datasets")
|
||||||
raster_controls = (ROOT / "frontend" / "src" / "components" / "datasets" / "RasterControls.tsx").read_text(encoding="utf-8")
|
raster_controls = read_feature("datasets")
|
||||||
segmentation_lab = (ROOT / "frontend" / "src" / "components" / "segmentation" / "SegmentationLab.tsx").read_text(
|
segmentation_lab = read_feature("segmentation")
|
||||||
encoding="utf-8",
|
|
||||||
)
|
|
||||||
|
|
||||||
assert "segmentationTileManifestPath" in hook
|
assert "segmentationTileManifestPath" in hook
|
||||||
assert "setSegmentationTileManifestPath" in hook
|
assert "setSegmentationTileManifestPath" in hook
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
def test_detection_lab_exposes_run_readiness_contract() -> None:
|
def test_detection_lab_exposes_run_readiness_contract() -> None:
|
||||||
lab = (ROOT / "frontend" / "src" / "components" / "detection" / "DetectionLab.tsx").read_text(
|
lab = read_feature("detection")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert "selectedDetectionModel = detectionModels.find" in lab
|
assert "selectedDetectionModel = detectionModels.find" in lab
|
||||||
assert "detectionRequiresTileManifest = selectedDetectionModelId === 'yolo-configured'" 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:
|
def test_segmentation_lab_exposes_run_readiness_contract() -> None:
|
||||||
lab = (ROOT / "frontend" / "src" / "components" / "segmentation" / "SegmentationLab.tsx").read_text(
|
lab = read_feature("segmentation")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert "segmentationHasDataset" in lab
|
assert "segmentationHasDataset" in lab
|
||||||
assert "segmentationHasTileManifest = segmentationTileManifestPath.trim().length > 0" in lab
|
assert "segmentationHasTileManifest = segmentationTileManifestPath.trim().length > 0" in lab
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
def test_detection_lab_distinguishes_configured_model_from_ui_runnable_action() -> None:
|
def test_detection_lab_distinguishes_configured_model_from_ui_runnable_action() -> None:
|
||||||
lab = (ROOT / "frontend" / "src" / "components" / "detection" / "DetectionLab.tsx").read_text(
|
lab = read_feature("detection")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert "detectionModelUiRunnable" in lab
|
assert "detectionModelUiRunnable" in lab
|
||||||
assert "selectedDetectionModelId !== 'manual-fixture-detector'" 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:
|
def test_segmentation_lab_distinguishes_configured_model_from_ui_runnable_action() -> None:
|
||||||
lab = (ROOT / "frontend" / "src" / "components" / "segmentation" / "SegmentationLab.tsx").read_text(
|
lab = read_feature("segmentation")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert "segmentationModelUiRunnable" in lab
|
assert "segmentationModelUiRunnable" in lab
|
||||||
assert "selectedSegmentationModelId !== 'fixture-segmenter'" in lab
|
assert "selectedSegmentationModelId !== 'fixture-segmenter'" in lab
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pathlib import Path
|
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]
|
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:
|
def test_geomap_highlights_selected_feature_layer() -> None:
|
||||||
geomap = (ROOT / "frontend" / "src" / "components" / "GeoMap.tsx").read_text(encoding="utf-8")
|
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 "selectedFeature?: GeoJSON.Feature | null" in geomap
|
||||||
assert "selected-feature" 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.core.errors import AppError
|
||||||
from app.models import Dataset, VectorFeature
|
from app.models import Dataset, VectorFeature
|
||||||
from app.services.vector_feature_service import VectorFeatureService
|
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]
|
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:
|
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()
|
map_workspace = read_map_workspace()
|
||||||
geomap = (ROOT / "frontend" / "src" / "components" / "GeoMap.tsx").read_text(encoding="utf-8")
|
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")
|
||||||
extract_hook = (ROOT / "frontend" / "src" / "hooks" / "useMapSelectionExtract.ts").read_text(encoding="utf-8")
|
extract_hook = read_feature("map_workspace")
|
||||||
theme_hook = (ROOT / "frontend" / "src" / "hooks" / "useMapThemeSelectionInsights.ts").read_text(encoding="utf-8")
|
theme_hook = read_feature("map_workspace")
|
||||||
|
|
||||||
assert "selectVectorFeatures" in api_client
|
assert "selectVectorFeatures" in api_client
|
||||||
assert "Area selection" in map_workspace
|
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.export_service import ExportService
|
||||||
from app.services.storage_service import StorageService
|
from app.services.storage_service import StorageService
|
||||||
from app.services.vector_feature_service import VectorFeatureService
|
from app.services.vector_feature_service import VectorFeatureService
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
def test_frontend_exposes_map_selection_export_action() -> None:
|
||||||
types = (ROOT / "frontend" / "src" / "types.ts").read_text(encoding="utf-8")
|
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")
|
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")
|
export_hook = read_feature("exports")
|
||||||
map_workspace = (ROOT / "frontend" / "src" / "components" / "map" / "MapWorkspace.tsx").read_text(encoding="utf-8")
|
map_workspace = read_feature("map_workspace")
|
||||||
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
|
app = read_feature("shell")
|
||||||
|
|
||||||
assert "'vector_selection'" in types
|
assert "'vector_selection'" in types
|
||||||
assert "bbox?: VectorSelectionBBox" in exports_api
|
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.storage_service import StorageService
|
||||||
from app.services.vector_feature_service import VectorFeatureService
|
from app.services.vector_feature_service import VectorFeatureService
|
||||||
from app.services.vector_operations_service import VectorOperationsService
|
from app.services.vector_operations_service import VectorOperationsService
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
def test_frontend_exposes_map_selection_derive_action() -> None:
|
||||||
types = (ROOT / "frontend" / "src" / "types.ts").read_text(encoding="utf-8")
|
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")
|
datasets_api = read_feature("datasets")
|
||||||
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
|
app = read_feature("shell")
|
||||||
map_workspace = (ROOT / "frontend" / "src" / "components" / "map" / "MapWorkspace.tsx").read_text(encoding="utf-8")
|
map_workspace = read_feature("map_workspace")
|
||||||
|
|
||||||
assert "VectorSelectionDeriveRequest" in types
|
assert "VectorSelectionDeriveRequest" in types
|
||||||
assert "deriveVectorSelection" in datasets_api
|
assert "deriveVectorSelection" in datasets_api
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
def test_map_selection_qa_shortcut_uses_existing_qa_workflow_contract() -> None:
|
||||||
hook_path = ROOT / "frontend" / "src" / "hooks" / "useMapSelectionQa.ts"
|
hook_path = ROOT / "frontend" / "src" / "hooks" / "useMapSelectionQa.ts"
|
||||||
app = (ROOT / "frontend" / "src" / "App.tsx").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")
|
map_workspace = read_feature("map_workspace")
|
||||||
|
|
||||||
assert hook_path.exists()
|
assert hook_path.exists()
|
||||||
hook = hook_path.read_text(encoding="utf-8")
|
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.main import app
|
||||||
from app.models import QualityCheck, VectorFeature
|
from app.models import QualityCheck, VectorFeature
|
||||||
from app.services.quality_evidence_service import QualityEvidenceService
|
from app.services.quality_evidence_service import QualityEvidenceService
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
class FakeQuery:
|
class FakeQuery:
|
||||||
@@ -169,7 +170,7 @@ def test_frontend_quality_evidence_overlay_contract_is_wired() -> None:
|
|||||||
|
|
||||||
root = Path(__file__).resolve().parents[2]
|
root = Path(__file__).resolve().parents[2]
|
||||||
geo_map = (root / "frontend" / "src" / "components" / "GeoMap.tsx").read_text(encoding="utf-8")
|
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")
|
qa_api = (root / "frontend" / "src" / "services" / "api" / "qa.ts").read_text(encoding="utf-8")
|
||||||
|
|
||||||
assert "qaEvidenceData" in geo_map
|
assert "qaEvidenceData" in geo_map
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from pathlib import Path
|
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]
|
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:
|
def test_map_workspace_can_select_persisted_database_layer_and_run_query() -> None:
|
||||||
map_workspace = read_map_workspace()
|
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")
|
styles = (REPO_ROOT / "frontend/src/styles/app.css").read_text(encoding="utf-8")
|
||||||
|
|
||||||
assert "map-database-layer-select" in map_workspace
|
assert "map-database-layer-select" in map_workspace
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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"),
|
(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")
|
api = (ROOT / "frontend" / "src" / "services" / "api" / "detection.ts").read_text(encoding="utf-8")
|
||||||
types = (ROOT / "frontend" / "src" / "types.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 "Technische YOLO-runtimecontrole" in lab
|
||||||
assert "torch_version" 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"),
|
(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")
|
api = (ROOT / "frontend" / "src" / "services" / "api" / "detection.ts").read_text(encoding="utf-8")
|
||||||
types = (ROOT / "frontend" / "src" / "types.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(
|
provider_panel = (ROOT / "frontend" / "src" / "components" / "providers" / "ProviderPanel.tsx").read_text(
|
||||||
encoding="utf-8"
|
encoding="utf-8"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
def test_raster_workflow_exposes_structured_tile_manifest_handoff() -> None:
|
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")
|
types = (ROOT / "frontend" / "src" / "types.ts").read_text(encoding="utf-8")
|
||||||
|
|
||||||
assert "interface RasterTileHandoff" in types
|
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:
|
def test_raster_controls_show_manifest_details_and_ai_handoff_action() -> None:
|
||||||
controls = (ROOT / "frontend" / "src" / "components" / "datasets" / "RasterControls.tsx").read_text(
|
controls = read_feature("datasets")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert "latestRasterTileManifest" in controls
|
assert "latestRasterTileManifest" in controls
|
||||||
assert "Aantal tegels" in controls
|
assert "Aantal tegels" in controls
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
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")
|
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 "applyDetectionOperatorProfile" in hook
|
||||||
assert "setSelectedDetectionModelId('yolo-configured')" in hook
|
assert "setSelectedDetectionModelId('yolo-configured')" in hook
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
def test_long_context_names_remain_compact_and_inspectable() -> None:
|
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 = (
|
status = (
|
||||||
ROOT / "frontend" / "src" / "components" / "WorkbenchStatusStrip.tsx"
|
ROOT / "frontend" / "src" / "components" / "WorkbenchStatusStrip.tsx"
|
||||||
).read_text(encoding="utf-8")
|
).read_text(encoding="utf-8")
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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(
|
map_source = (ROOT / "frontend" / "src" / "components" / "GeoMap.tsx").read_text(
|
||||||
encoding="utf-8"
|
encoding="utf-8"
|
||||||
)
|
)
|
||||||
navigation = (
|
navigation = read_feature("shell")
|
||||||
ROOT
|
|
||||||
/ "frontend"
|
|
||||||
/ "src"
|
|
||||||
/ "components"
|
|
||||||
/ "shell"
|
|
||||||
/ "WorkbenchNavigation.tsx"
|
|
||||||
).read_text(encoding="utf-8")
|
|
||||||
|
|
||||||
assert "NATIONAL_WORKSPACE_PROJECT_NAME = 'Belgium and North Sea Workbench'" in focus
|
assert "NATIONAL_WORKSPACE_PROJECT_NAME = 'Belgium and North Sea Workbench'" in focus
|
||||||
assert "NATIONAL_WORKSPACE_REGION = 'Belgie en Belgische Noordzee'" in focus
|
assert "NATIONAL_WORKSPACE_REGION = 'Belgie en Belgische Noordzee'" in focus
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
def test_workbench_uses_grouped_navigation_and_optional_inspector() -> None:
|
||||||
app = read("frontend/src/App.tsx")
|
app = read_feature("shell")
|
||||||
inspector = read("frontend/src/components/inspector/WorkbenchInspector.tsx")
|
inspector = read_feature("shell")
|
||||||
|
|
||||||
assert "import './styles/premium.css'" in app
|
assert "import './styles/premium.css'" in app
|
||||||
assert "const workspaceNavGroups" 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:
|
def test_data_creation_forms_are_progressively_disclosed() -> None:
|
||||||
project = read("frontend/src/components/project/ProjectPanel.tsx")
|
project = read("frontend/src/components/project/ProjectPanel.tsx")
|
||||||
area = read("frontend/src/components/project/AreaPanel.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")
|
css = read("frontend/src/styles/premium.css")
|
||||||
|
|
||||||
assert '<details className="data-panel-form-block technical-management-block">' in project
|
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:
|
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")
|
css = read("frontend/src/styles/premium.css")
|
||||||
|
|
||||||
control_index = map_workspace.index('className="map-control-surface"')
|
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"),
|
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")
|
css = read("frontend/src/styles/premium.css")
|
||||||
|
|
||||||
assert '<details className="ai-lab-model-surface" aria-label="Technische modelmogelijkheden">' in detection
|
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.models import VectorFeature
|
||||||
from app.services.vector_feature_service import VectorFeatureService
|
from app.services.vector_feature_service import VectorFeatureService
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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")
|
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")
|
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")
|
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_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 "py_compile scripts/provision_mol_municipality_workspace.py" in readiness
|
||||||
assert "COPY scripts/provision_mol_municipality_workspace.py" in dockerfile
|
assert "COPY scripts/provision_mol_municipality_workspace.py" in dockerfile
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import pytest
|
|||||||
from pydantic import ValidationError
|
from pydantic import ValidationError
|
||||||
|
|
||||||
from app.schemas.operations import VectorSelectionBBox, VectorSelectionRequest
|
from app.schemas.operations import VectorSelectionBBox, VectorSelectionRequest
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
def test_large_vector_delivery_uses_existing_postgis_bbox_contract() -> None:
|
||||||
config = (ROOT / "frontend" / "src" / "config" / "vectorDelivery.ts").read_text(encoding="utf-8")
|
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")
|
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_FEATURE_THRESHOLD = 5_000" in config
|
||||||
assert "VECTOR_VIEWPORT_MIN_ZOOM = 14" 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:
|
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")
|
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 "useViewportVectorLayer" in app
|
||||||
assert "fitMapDataOnChange={!viewportVectorLayerActive}" in app
|
assert "fitMapDataOnChange={!viewportVectorLayerActive}" in app
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
def test_map_source_mode_keeps_database_layers_distinct_from_analysis_results() -> None:
|
def test_map_source_mode_keeps_database_layers_distinct_from_analysis_results() -> None:
|
||||||
app = (ROOT / "frontend/src/App.tsx").read_text(encoding="utf-8")
|
app = read_feature("shell")
|
||||||
workspace = (ROOT / "frontend/src/components/map/MapWorkspace.tsx").read_text(encoding="utf-8")
|
workspace = read_feature("map_workspace")
|
||||||
|
|
||||||
assert "const [mapContentMode, setMapContentMode]" in app
|
assert "const [mapContentMode, setMapContentMode]" in app
|
||||||
assert "mapContentMode === 'analysis' && analysisMapLayerAvailable" in app
|
assert "mapContentMode === 'analysis' && analysisMapLayerAvailable" in app
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
from pathlib import Path
|
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]
|
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:
|
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()
|
workspace = read_map_workspace()
|
||||||
|
|
||||||
assert "useState<WorkspaceKey>('map')" in app
|
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:
|
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 datasetDetailRequestSequence = useRef(0)" in workflow
|
||||||
assert "const detailRequestId = ++datasetDetailRequestSequence.current" in workflow
|
assert "const detailRequestId = ++datasetDetailRequestSequence.current" in workflow
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ from pathlib import Path
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
from shapely.geometry import Polygon, shape
|
from shapely.geometry import Polygon, shape
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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"),
|
(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/geographic_scopes.py" in dockerfile
|
||||||
assert "COPY scripts/provision_geographic_scope.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:
|
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")
|
bootstrap = read_feature("shell")
|
||||||
project_workspace = (ROOT / "frontend/src/hooks/useProjectWorkspace.ts").read_text(encoding="utf-8")
|
project_workspace = read_feature("shell")
|
||||||
map_state = (ROOT / "frontend/src/hooks/useMapWorkspaceState.ts").read_text(encoding="utf-8")
|
map_state = read_feature("map_workspace")
|
||||||
dataset_workflow = (ROOT / "frontend/src/hooks/useDatasetWorkflow.ts").read_text(encoding="utf-8")
|
dataset_workflow = read_feature("datasets")
|
||||||
|
|
||||||
selected_project_branch = bootstrap.split("if (!selectedProjectId)", maxsplit=1)[1]
|
selected_project_branch = bootstrap.split("if (!selectedProjectId)", maxsplit=1)[1]
|
||||||
assert "resetProjectData()" in selected_project_branch
|
assert "resetProjectData()" in selected_project_branch
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from pathlib import Path
|
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]
|
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:
|
def test_cancelled_selection_requests_cannot_restore_stale_results() -> None:
|
||||||
selection_hook = read("frontend/src/hooks/useMapSelectionExtract.ts")
|
selection_hook = read_feature("map_workspace")
|
||||||
themes_hook = read("frontend/src/hooks/useMapThemeSelectionInsights.ts")
|
themes_hook = read_feature("map_workspace")
|
||||||
|
|
||||||
assert "const requestSequence = useRef(0)" in selection_hook
|
assert "const requestSequence = useRef(0)" in selection_hook
|
||||||
assert "requestSequence.current += 1\n setMapSelectionBbox(null)" in selection_hook
|
assert "requestSequence.current += 1\n setMapSelectionBbox(null)" in selection_hook
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
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"):
|
for label in ("Kaart", "Bronnen", "Kwaliteit", "Beeldanalyse", "Downloads"):
|
||||||
assert f"label: '{label}'" in app
|
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:
|
def test_technical_projects_and_metadata_are_progressively_disclosed() -> None:
|
||||||
projects = read("frontend/src/components/project/ProjectPanel.tsx")
|
projects = read("frontend/src/components/project/ProjectPanel.tsx")
|
||||||
areas = read("frontend/src/components/project/AreaPanel.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")
|
dataset_names = read("frontend/src/lib/datasetDisplay.ts")
|
||||||
|
|
||||||
assert "TECHNICAL_PROJECT_PATTERN" in projects
|
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:
|
def test_configured_yolo_and_active_asset_are_selected_without_hiding_limitations() -> None:
|
||||||
hook = read("frontend/src/hooks/useDetectionWorkflow.ts")
|
hook = read_feature("detection")
|
||||||
lab = read("frontend/src/components/detection/DetectionLab.tsx")
|
lab = read_feature("detection")
|
||||||
|
|
||||||
assert "useState('yolo-configured')" in hook
|
assert "useState('yolo-configured')" in hook
|
||||||
assert "useState(0.15)" 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:
|
def test_visible_ai_and_quality_labels_are_end_user_facing() -> None:
|
||||||
profiles = read("frontend/src/components/detection/detectionProfiles.ts")
|
profiles = read_feature("detection")
|
||||||
quality = read("frontend/src/components/quality/QualityResultsPanel.tsx")
|
quality = read_feature("quality")
|
||||||
export_preview = read("frontend/src/components/exports/ExportPreview.tsx")
|
export_preview = read("frontend/src/components/exports/ExportPreview.tsx")
|
||||||
providers = read("frontend/src/components/providers/ProviderPanel.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.models import Dataset
|
||||||
from app.services.vector_feature_service import VectorFeatureService
|
from app.services.vector_feature_service import VectorFeatureService
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
def test_end_user_dataset_sources_are_human_readable() -> None:
|
||||||
display = (ROOT / "frontend/src/lib/datasetDisplay.ts").read_text(encoding="utf-8")
|
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")
|
workspace = read_feature("map_workspace")
|
||||||
catalog = (ROOT / "frontend/src/components/datasets/DatasetPanel.tsx").read_text(encoding="utf-8")
|
catalog = read_feature("datasets")
|
||||||
status = (ROOT / "frontend/src/components/WorkbenchStatusStrip.tsx").read_text(encoding="utf-8")
|
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")
|
detection = read_feature("detection")
|
||||||
exports = (ROOT / "frontend/src/components/exports/ExportCenter.tsx").read_text(encoding="utf-8")
|
exports = read_feature("exports")
|
||||||
|
|
||||||
assert "department_omgeving_land_use: 'Departement Omgeving'" in display
|
assert "department_omgeving_land_use: 'Departement Omgeving'" in display
|
||||||
assert "statbel: 'Statbel'" in display
|
assert "statbel: 'Statbel'" in display
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
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 "prepareAndRunDetection" in hook
|
||||||
assert "datasetsApi.rasterTile" 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:
|
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 "uploadDetectionRaster" in hook
|
||||||
assert "datasetsApi.upload" 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:
|
def test_detection_lab_hides_manifest_plumbing_and_exposes_map_first_result_flow() -> None:
|
||||||
lab = read("frontend/src/components/detection/DetectionLab.tsx")
|
lab = read_feature("detection")
|
||||||
app = read("frontend/src/App.tsx")
|
app = read_feature("shell")
|
||||||
|
|
||||||
assert "Gebouwen zoeken en op kaart tonen" in lab
|
assert "Gebouwen zoeken en op kaart tonen" in lab
|
||||||
assert 'aria-label="Luchtbeeld toevoegen"' 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:
|
def test_detection_qa_remains_persisted_and_primary_not_parallel() -> None:
|
||||||
lab = read("frontend/src/components/detection/DetectionLab.tsx")
|
lab = read_feature("detection")
|
||||||
hook = read("frontend/src/hooks/useDetectionWorkflow.ts")
|
hook = read_feature("detection")
|
||||||
|
|
||||||
assert 'aria-label="Kwaliteitscontrole gebouwdetectie"' in lab
|
assert 'aria-label="Kwaliteitscontrole gebouwdetectie"' in lab
|
||||||
assert "als kwaliteitscontrole in de database bewaard" 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:
|
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 "analysisMapLayerActive && mapFeatureCollection" in app
|
||||||
assert "`${mapLayerLabel} · controle vereist`" 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.models import Area, Dataset, DatasetVersion, Job, Project, SourceRegistry, SourceSnapshot
|
||||||
from app.schemas.orthophoto import OrthophotoAcquireRequest
|
from app.schemas.orthophoto import OrthophotoAcquireRequest
|
||||||
from app.services.orthophoto_acquisition_service import OrthophotoAcquisitionService
|
from app.services.orthophoto_acquisition_service import OrthophotoAcquisitionService
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
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")
|
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 "useMapOrthophotoAnalysis" in app_source
|
||||||
assert "onRunOrthophotoAnalysis={mapOrthophotoAnalysis.run}" in app_source
|
assert "onRunOrthophotoAnalysis={mapOrthophotoAnalysis.run}" in app_source
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ from app.schemas.detection_review import (
|
|||||||
DetectionReviewUpsert,
|
DetectionReviewUpsert,
|
||||||
)
|
)
|
||||||
from app.services.detection_review_service import DetectionReviewService
|
from app.services.detection_review_service import DetectionReviewService
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
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")
|
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")
|
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
|
assert "MAP_BUILDING_QA_IOU_THRESHOLD = 0.25" in hook
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
def test_app_wires_map_workbench_component() -> None:
|
||||||
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
|
app = read_feature("shell")
|
||||||
component = (ROOT / "frontend" / "src" / "components" / "map" / "MapWorkspace.tsx").read_text(encoding="utf-8")
|
component = read_feature("map_workspace")
|
||||||
|
|
||||||
assert "mapLayerVisible" in app
|
assert "mapLayerVisible" in app
|
||||||
assert "mapLayerOpacity" in app
|
assert "mapLayerOpacity" in app
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from uuid import uuid4
|
|||||||
from app.models import Dataset
|
from app.models import Dataset
|
||||||
from app.schemas.operations import VectorSelectionSummary
|
from app.schemas.operations import VectorSelectionSummary
|
||||||
from app.services.vector_feature_service import VectorFeatureService
|
from app.services.vector_feature_service import VectorFeatureService
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).parents[2]
|
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:
|
def test_future_regional_imports_persist_semantic_aggregation_configuration() -> None:
|
||||||
buildings = (ROOT / "scripts/provision_regional_grb_buildings.py").read_text(encoding="utf-8")
|
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")
|
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 '"method": "intersection_area"' in buildings
|
||||||
assert '"label": "Bebouwde grondoppervlakte"' 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.schemas.assistant import AssistantContextMetric, AssistantModelRead, AssistantQueryRequest, AssistantStatus, AssistantTemporalSeries
|
||||||
from app.services.geo_assistant_service import GeoAssistantService
|
from app.services.geo_assistant_service import GeoAssistantService
|
||||||
from app.services.temporal_analysis_service import TemporalAnalysisService
|
from app.services.temporal_analysis_service import TemporalAnalysisService
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
def test_frontend_exposes_source_inventory_timeline_and_ai_window() -> None:
|
||||||
app = (ROOT / "frontend/src/App.tsx").read_text(encoding="utf-8")
|
app = read_feature("shell")
|
||||||
workspace = (ROOT / "frontend/src/components/map/MapWorkspace.tsx").read_text(encoding="utf-8")
|
workspace = read_feature("map_workspace")
|
||||||
catalog = (ROOT / "frontend/src/components/datasets/SourceCatalogPanel.tsx").read_text(encoding="utf-8")
|
catalog = read_feature("datasets")
|
||||||
assistant_hook = (ROOT / "frontend/src/hooks/useGeoAssistant.ts").read_text(encoding="utf-8")
|
assistant_hook = (ROOT / "frontend/src/hooks/useGeoAssistant.ts").read_text(encoding="utf-8")
|
||||||
|
|
||||||
assert "SourceCatalogPanel" in app
|
assert "SourceCatalogPanel" in app
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import sys
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from shapely.geometry import box
|
from shapely.geometry import box
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
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 "DATASET_PAGE_SIZE = 200" in client
|
||||||
assert "offset < (total ?? 0)" 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.models import Dataset
|
||||||
from app.schemas.operations import VectorSelectionSummary
|
from app.schemas.operations import VectorSelectionSummary
|
||||||
from app.services.vector_feature_service import VectorFeatureService
|
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]
|
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")
|
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")
|
service = (ROOT / "backend" / "app" / "services" / "vector_feature_service.py").read_text(encoding="utf-8")
|
||||||
map_workspace = read_map_workspace()
|
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 "COPY scripts/provision_mol_bwk_natura2000.py" in dockerfile
|
||||||
assert "py_compile scripts/provision_mol_bwk_natura2000.py" in readiness
|
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.models import Dataset
|
||||||
from app.schemas.operations import VectorSelectionSummary
|
from app.schemas.operations import VectorSelectionSummary
|
||||||
from app.services.vector_feature_service import VectorFeatureService
|
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]
|
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")
|
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")
|
readiness = (ROOT / "scripts" / "run_readiness_check.sh").read_text(encoding="utf-8")
|
||||||
map_workspace = read_map_workspace()
|
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")
|
dataset_display = (ROOT / "frontend" / "src" / "lib" / "datasetDisplay.ts").read_text(encoding="utf-8")
|
||||||
|
|
||||||
assert "/datasets/upload" in operator
|
assert "/datasets/upload" in operator
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ from app.models import Area, Dataset, DatasetVersion, Job, Project, SourceRegist
|
|||||||
from app.schemas.dhmv import DhmvAcquireRequest, TerrainPartitionSelectionRequest, TerrainSelectionRequest
|
from app.schemas.dhmv import DhmvAcquireRequest, TerrainPartitionSelectionRequest, TerrainSelectionRequest
|
||||||
from app.services.dhmv_acquisition_service import DhmvAcquisitionService
|
from app.services.dhmv_acquisition_service import DhmvAcquisitionService
|
||||||
from app.services.terrain_analysis_service import TerrainAnalysisService
|
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]
|
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"
|
ROOT / "frontend" / "src" / "lib" / "datasetCapabilities.ts"
|
||||||
).read_text(encoding="utf-8")
|
).read_text(encoding="utf-8")
|
||||||
map_source = read_map_workspace()
|
map_source = read_map_workspace()
|
||||||
hook_source = (ROOT / "frontend" / "src" / "hooks" / "useMapSelectionExtract.ts").read_text(encoding="utf-8")
|
hook_source = read_feature("map_workspace")
|
||||||
service_source = (ROOT / "frontend" / "src" / "services" / "api" / "datasets.ts").read_text(encoding="utf-8")
|
service_source = read_feature("datasets")
|
||||||
|
|
||||||
assert "digitaal_vlaanderen_dhmv" in capabilities_source
|
assert "digitaal_vlaanderen_dhmv" in capabilities_source
|
||||||
assert "isMapRasterDataset" 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.models import Dataset
|
||||||
from app.schemas.operations import VectorSelectionSummary
|
from app.schemas.operations import VectorSelectionSummary
|
||||||
from app.services.vector_feature_service import VectorFeatureService
|
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]
|
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")
|
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")
|
readiness = (ROOT / "scripts/run_readiness_check.sh").read_text(encoding="utf-8")
|
||||||
workspace = read_map_workspace()
|
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")
|
display = (ROOT / "frontend/src/lib/datasetDisplay.ts").read_text(encoding="utf-8")
|
||||||
|
|
||||||
assert "/datasets/upload" in operator
|
assert "/datasets/upload" in operator
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ from pathlib import Path
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
from shapely.geometry import box, mapping, shape
|
from shapely.geometry import box, mapping, shape
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
def test_regional_historical_operator_is_packaged_and_release_checked() -> None:
|
||||||
dockerfile = (ROOT / "deploy/unraid/Dockerfile.all-in-one").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")
|
readiness = (ROOT / "scripts/run_readiness_check.sh").read_text(encoding="utf-8")
|
||||||
app = (ROOT / "frontend/src/App.tsx").read_text(encoding="utf-8")
|
app = read_feature("shell")
|
||||||
workspace = (ROOT / "frontend/src/components/map/MapWorkspace.tsx").read_text(encoding="utf-8")
|
workspace = read_feature("map_workspace")
|
||||||
|
|
||||||
assert "COPY scripts/provision_regional_historical_landuse.py" in dockerfile
|
assert "COPY scripts/provision_regional_historical_landuse.py" in dockerfile
|
||||||
assert "py_compile scripts/provision_regional_historical_landuse.py" in readiness
|
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.models import Area
|
||||||
from app.services.area_service import AreaService
|
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:
|
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:
|
def test_frontend_wires_selected_area_map_overlay_contract() -> None:
|
||||||
root = __import__("pathlib").Path(__file__).resolve().parents[2]
|
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")
|
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")
|
area_panel = (root / "frontend" / "src" / "components" / "project" / "AreaPanel.tsx").read_text(encoding="utf-8")
|
||||||
|
|
||||||
assert "selectedMapAreaId" in app
|
assert "selectedMapAreaId" in app
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ from shapely.geometry import box, mapping, shape
|
|||||||
|
|
||||||
from app.models import Dataset
|
from app.models import Dataset
|
||||||
from app.services.vector_feature_service import VectorFeatureService
|
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]
|
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")
|
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")
|
service = (ROOT / "backend/app/services/vector_feature_service.py").read_text(encoding="utf-8")
|
||||||
workspace = read_map_workspace()
|
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")
|
model = (ROOT / "backend/app/models/entities.py").read_text(encoding="utf-8")
|
||||||
migration = (
|
migration = (
|
||||||
ROOT / "backend/alembic/versions/202607160001_vector_feature_municipality_index.py"
|
ROOT / "backend/alembic/versions/202607160001_vector_feature_municipality_index.py"
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
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")
|
styles = (ROOT / "frontend/src/styles/app.css").read_text(encoding="utf-8")
|
||||||
|
|
||||||
assert "Welke vragen kan GeoIntel beantwoorden?" in catalog
|
assert "Welke vragen kan GeoIntel beantwoorden?" in catalog
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from pathlib import Path
|
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]
|
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:
|
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()
|
workspace = read_map_workspace()
|
||||||
hook = (ROOT / "frontend/src/hooks/useMapThemeSelectionInsights.ts").read_text(encoding="utf-8")
|
hook = read_feature("map_workspace")
|
||||||
api = (ROOT / "frontend/src/services/api/datasets.ts").read_text(encoding="utf-8")
|
api = read_feature("datasets")
|
||||||
|
|
||||||
assert "regionalScopeSelected" in workspace
|
assert "regionalScopeSelected" in workspace
|
||||||
assert "rasterPartitionsForDataset" in workspace
|
assert "rasterPartitionsForDataset" in workspace
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ from types import SimpleNamespace
|
|||||||
|
|
||||||
from app.models import Dataset, DatasetVersion
|
from app.models import Dataset, DatasetVersion
|
||||||
from app.services.source_freshness_service import SourceFreshnessService
|
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)
|
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")
|
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")
|
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")
|
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")
|
app = read_feature("shell")
|
||||||
api = (root / "frontend" / "src" / "services" / "api" / "datasets.ts").read_text(encoding="utf-8")
|
api = read_feature("datasets")
|
||||||
|
|
||||||
assert "Request(endpoint" in script
|
assert "Request(endpoint" in script
|
||||||
assert "method=\"POST\"" not in script
|
assert "method=\"POST\"" not in script
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
def test_frontend_wires_v1_workbench_status_strip() -> None:
|
def test_frontend_wires_v1_workbench_status_strip() -> None:
|
||||||
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
|
app = read_feature("shell")
|
||||||
overview = (ROOT / "frontend" / "src" / "components" / "overview" / "OverviewWorkspace.tsx").read_text(encoding="utf-8")
|
overview = read_feature("shell")
|
||||||
component = (ROOT / "frontend" / "src" / "components" / "WorkbenchStatusStrip.tsx").read_text(encoding="utf-8")
|
component = (ROOT / "frontend" / "src" / "components" / "WorkbenchStatusStrip.tsx").read_text(encoding="utf-8")
|
||||||
css = (ROOT / "frontend" / "src" / "styles" / "app.css").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 pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
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")
|
styles = read("frontend/src/styles/app.css")
|
||||||
|
|
||||||
assert 'className="geo-theme-result-value"' in workspace
|
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:
|
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}-analysis.json" in workspace
|
||||||
assert "activeTheme.id}-selection.geojson" 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:
|
def test_completed_analysis_hands_off_to_ai_and_downloads_responsively() -> None:
|
||||||
app = read("frontend/src/App.tsx")
|
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")
|
styles = read("frontend/src/styles/app.css")
|
||||||
|
|
||||||
assert "onOpenAssistant: () => void" in workspace
|
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.source_registry_service import SourceRegistryService
|
||||||
from app.services.temporal_analysis_service import TemporalAnalysisService
|
from app.services.temporal_analysis_service import TemporalAnalysisService
|
||||||
from app.services.thematic_raster_analysis_service import ThematicRasterAnalysisService
|
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:
|
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:
|
def test_frontend_persists_map_result_before_opening_downloads() -> None:
|
||||||
root = Path(__file__).resolve().parents[2]
|
root = Path(__file__).resolve().parents[2]
|
||||||
workspace = read_map_workspace()
|
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")
|
api = (root / "frontend/src/services/api/exports.ts").read_text(encoding="utf-8")
|
||||||
|
|
||||||
assert "persistActiveResultAndOpenDownloads" in workspace
|
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:
|
def test_frontend_fetches_canonical_workspace_outside_default_project_page() -> None:
|
||||||
root = Path(__file__).resolve().parents[2]
|
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")
|
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
|
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:
|
def test_theme_failures_name_the_source_and_reason() -> None:
|
||||||
root = Path(__file__).resolve().parents[2]
|
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]?.dataset?.name" in hook
|
||||||
assert "queries[index]?.acquisition?.displayName" 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:
|
def test_workspace_navigation_resets_the_actual_scroll_container() -> None:
|
||||||
root = Path(__file__).resolve().parents[2]
|
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 "const workbenchMainRef = useRef<HTMLElement | null>(null)" in app
|
||||||
assert "workbenchMainRef.current?.scrollTo({ top: 0, left: 0 })" 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:
|
def test_quality_scores_have_plain_language_interpretation() -> None:
|
||||||
root = Path(__file__).resolve().parents[2]
|
root = Path(__file__).resolve().parents[2]
|
||||||
quality = (root / "frontend/src/components/quality/QualityResultsPanel.tsx").read_text(encoding="utf-8")
|
quality = read_feature("quality")
|
||||||
detection = (root / "frontend/src/components/detection/DetectionLab.tsx").read_text(encoding="utf-8")
|
detection = read_feature("detection")
|
||||||
|
|
||||||
assert "Laatste score (0-1)" in quality
|
assert "Laatste score (0-1)" in quality
|
||||||
assert "Bruikbaar na controle" 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:
|
def test_detection_lab_only_receives_operational_imagery_rasters() -> None:
|
||||||
root = Path(__file__).resolve().parents[2]
|
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")
|
capability_source = (root / "frontend/src/lib/datasetCapabilities.ts").read_text(encoding="utf-8")
|
||||||
|
|
||||||
assert "department_omgeving_thematic_raster" in capability_source
|
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:
|
def test_download_workspace_surfaces_map_results_in_plain_dutch() -> None:
|
||||||
root = Path(__file__).resolve().parents[2]
|
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 "Gebiedsanalyse (JSON)" in exports
|
||||||
assert "Historische vergelijking (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.main import app
|
||||||
from app.schemas.project import ProjectRead, ProjectUpdate
|
from app.schemas.project import ProjectRead, ProjectUpdate
|
||||||
from app.services.project_service import ProjectService
|
from app.services.project_service import ProjectService
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
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")
|
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")
|
detection_lab = read_feature("detection")
|
||||||
segmentation_lab = (ROOT / "frontend/src/components/segmentation/SegmentationLab.tsx").read_text(encoding="utf-8")
|
segmentation_lab = read_feature("segmentation")
|
||||||
map_workspace = (ROOT / "frontend/src/components/map/MapWorkspace.tsx").read_text(encoding="utf-8")
|
map_workspace = read_feature("map_workspace")
|
||||||
premium_css = (ROOT / "frontend/src/styles/premium.css").read_text(encoding="utf-8")
|
premium_css = (ROOT / "frontend/src/styles/premium.css").read_text(encoding="utf-8")
|
||||||
|
|
||||||
assert "OverviewWorkspace" in app_source
|
assert "OverviewWorkspace" in app_source
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ if str(SCRIPTS) not in sys.path:
|
|||||||
sys.path.insert(0, str(SCRIPTS))
|
sys.path.insert(0, str(SCRIPTS))
|
||||||
|
|
||||||
import provision_flanders_geographic_scope as flanders_scope # noqa: E402
|
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:
|
class BinaryResponse:
|
||||||
@@ -433,9 +433,7 @@ def test_frontend_bounds_large_area_and_dataset_catalogs() -> None:
|
|||||||
area_panel = (
|
area_panel = (
|
||||||
ROOT / "frontend" / "src" / "components" / "project" / "AreaPanel.tsx"
|
ROOT / "frontend" / "src" / "components" / "project" / "AreaPanel.tsx"
|
||||||
).read_text(encoding="utf-8")
|
).read_text(encoding="utf-8")
|
||||||
dataset_panel = (
|
dataset_panel = read_feature("datasets")
|
||||||
ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetPanel.tsx"
|
|
||||||
).read_text(encoding="utf-8")
|
|
||||||
|
|
||||||
assert "const AREA_CATALOG_PAGE_SIZE = 12" in area_panel
|
assert "const AREA_CATALOG_PAGE_SIZE = 12" in area_panel
|
||||||
assert "{catalogOpen ? (" 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:
|
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")
|
index = (ROOT / "frontend" / "index.html").read_text(encoding="utf-8")
|
||||||
focus = (
|
focus = (
|
||||||
ROOT / "frontend" / "src" / "config" / "primaryFocus.ts"
|
ROOT / "frontend" / "src" / "config" / "primaryFocus.ts"
|
||||||
).read_text(encoding="utf-8")
|
).read_text(encoding="utf-8")
|
||||||
map_workspace = read_map_workspace()
|
map_workspace = read_map_workspace()
|
||||||
theme_hook = (
|
theme_hook = read_feature("map_workspace")
|
||||||
ROOT / "frontend" / "src" / "hooks" / "useMapThemeSelectionInsights.ts"
|
dataset_api = read_feature("datasets")
|
||||||
).read_text(encoding="utf-8")
|
|
||||||
dataset_api = (
|
|
||||||
ROOT / "frontend" / "src" / "services" / "api" / "datasets.ts"
|
|
||||||
).read_text(encoding="utf-8")
|
|
||||||
|
|
||||||
assert "isPartitionedBathymetry" in map_workspace
|
assert "isPartitionedBathymetry" in map_workspace
|
||||||
assert "regionalPartitionedThemeActive" in map_workspace
|
assert "regionalPartitionedThemeActive" in map_workspace
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from pathlib import Path
|
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]
|
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:
|
def test_flanders_workspace_exposes_governed_thematic_products_on_demand() -> None:
|
||||||
workspace = read_map_workspace()
|
workspace = read_map_workspace()
|
||||||
product_hook = read("frontend/src/hooks/useOfficialMapProducts.ts")
|
product_hook = read_feature("map_workspace")
|
||||||
selection_hook = read("frontend/src/hooks/useMapThemeSelectionInsights.ts")
|
selection_hook = read_feature("map_workspace")
|
||||||
api = read("frontend/src/services/api/datasets.ts")
|
api = read_feature("datasets")
|
||||||
|
|
||||||
assert "activeScopeProject?.name === FLANDERS_WORKSPACE_PROJECT_NAME" in workspace
|
assert "activeScopeProject?.name === FLANDERS_WORKSPACE_PROJECT_NAME" in workspace
|
||||||
assert "new Map<DataThemeId, OnDemandMapProduct>" 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:
|
def test_selection_reads_and_bounded_acquires_all_relevant_themes() -> None:
|
||||||
workspace = read_map_workspace()
|
workspace = read_map_workspace()
|
||||||
app = read("frontend/src/App.tsx")
|
app = read_feature("shell")
|
||||||
selection_hook = read("frontend/src/hooks/useMapThemeSelectionInsights.ts")
|
selection_hook = read_feature("map_workspace")
|
||||||
|
|
||||||
# Selection reads the active theme; the loop form is incidental.
|
# Selection reads the active theme; the loop form is incidental.
|
||||||
assert_wired(workspace, "activeTheme")
|
assert_wired(workspace, "activeTheme")
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ from pathlib import Path
|
|||||||
|
|
||||||
from app.schemas.flood_hazard import FloodHazardAcquireRequest
|
from app.schemas.flood_hazard import FloodHazardAcquireRequest
|
||||||
from app.schemas.operations import VectorSelectionBBox
|
from app.schemas.operations import VectorSelectionBBox
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
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.listThematicRasterProducts" in hook
|
||||||
assert "datasetsApi.listDhmvProducts" 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:
|
def test_map_selection_can_acquire_dhmv_and_flood_hazard_products() -> None:
|
||||||
selection_hook = read("frontend/src/hooks/useMapThemeSelectionInsights.ts")
|
selection_hook = read_feature("map_workspace")
|
||||||
workspace = read("frontend/src/components/map/MapWorkspace.tsx")
|
workspace = read_feature("map_workspace")
|
||||||
|
|
||||||
for acquisition_kind in (
|
for acquisition_kind in (
|
||||||
"'thematic_raster'",
|
"'thematic_raster'",
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ from app.models import Area, Dataset, Job, Project
|
|||||||
from app.schemas.grb import GrbAcquireRequest
|
from app.schemas.grb import GrbAcquireRequest
|
||||||
from app.services.dataset_service import DatasetService
|
from app.services.dataset_service import DatasetService
|
||||||
from app.services.grb_acquisition_service import GrbAcquisitionService
|
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]
|
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:
|
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")
|
selection_hook = read_feature("map_workspace")
|
||||||
catalog_hook = (ROOT / "frontend/src/hooks/useOfficialMapProducts.ts").read_text(encoding="utf-8")
|
catalog_hook = read_feature("map_workspace")
|
||||||
workspace = read_map_workspace()
|
workspace = read_map_workspace()
|
||||||
contracts = (ROOT / "docs/API_CONTRACTS.md").read_text(encoding="utf-8")
|
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.dataset_service import DatasetService
|
||||||
from app.services.official_vector_acquisition_service import OfficialVectorAcquisitionService
|
from app.services.official_vector_acquisition_service import OfficialVectorAcquisitionService
|
||||||
from app.services.thematic_raster_acquisition_service import ThematicRasterAcquisitionService
|
from app.services.thematic_raster_acquisition_service import ThematicRasterAcquisitionService
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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 acquire_response.json()["data"]["job_type"] == "vector.official.acquire"
|
||||||
assert any(isinstance(item, Job) for item in db.added)
|
assert any(isinstance(item, Job) for item in db.added)
|
||||||
|
|
||||||
selection_hook = (ROOT / "frontend/src/hooks/useMapThemeSelectionInsights.ts").read_text(encoding="utf-8")
|
selection_hook = read_feature("map_workspace")
|
||||||
catalog_hook = (ROOT / "frontend/src/hooks/useOfficialMapProducts.ts").read_text(encoding="utf-8")
|
catalog_hook = read_feature("map_workspace")
|
||||||
workspace = (ROOT / "frontend/src/components/map/MapWorkspace.tsx").read_text(encoding="utf-8")
|
workspace = (ROOT / "frontend/src/components/map/MapWorkspace.tsx").read_text(encoding="utf-8")
|
||||||
assert "datasetsApi.acquireOfficialVector" in selection_hook
|
assert "datasetsApi.acquireOfficialVector" in selection_hook
|
||||||
assert "datasetsApi.listOfficialVectorProducts" in catalog_hook
|
assert "datasetsApi.listOfficialVectorProducts" in catalog_hook
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
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.listModels" in hook
|
||||||
assert "detectionApi.listRuns" 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:
|
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.listModels" in hook
|
||||||
assert "segmentationApi.listRuns" in hook
|
assert "segmentationApi.listRuns" in hook
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
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.listProjectExports" in hook
|
||||||
assert "exportsApi.exportGeojson" 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:
|
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.listQualityChecks" in hook
|
||||||
assert "qaApi.runQa" 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:
|
def test_app_still_wires_quality_results_and_export_center() -> None:
|
||||||
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
|
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
|
||||||
quality_panel = (
|
quality_panel = read_feature("quality")
|
||||||
ROOT / "frontend" / "src" / "components" / "quality" / "QualityResultsPanel.tsx"
|
|
||||||
).read_text(encoding="utf-8")
|
|
||||||
|
|
||||||
assert "<QualityResultsPanel" in app
|
assert "<QualityResultsPanel" in app
|
||||||
assert "onRefresh={() => loadQualityChecks()}" in app
|
assert "onRefresh={() => loadQualityChecks()}" in app
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
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.upload" in hook
|
||||||
assert "datasetsApi.getContent" 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:
|
def test_app_still_wires_dataset_ui_callbacks() -> None:
|
||||||
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
|
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
|
||||||
dataset_panel = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetPanel.tsx").read_text(
|
dataset_panel = read_feature("datasets")
|
||||||
encoding="utf-8"
|
detail_panel = read_feature("datasets")
|
||||||
)
|
|
||||||
detail_panel = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetDetailPanel.tsx").read_text(
|
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert "<DatasetPanel" in app
|
assert "<DatasetPanel" in app
|
||||||
assert "onUploadDataset={uploadDataset}" in app
|
assert "onUploadDataset={uploadDataset}" in app
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
@@ -8,9 +9,7 @@ ROOT = Path(__file__).resolve().parents[2]
|
|||||||
|
|
||||||
def test_app_uses_dataset_presentational_components() -> None:
|
def test_app_uses_dataset_presentational_components() -> None:
|
||||||
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
|
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
|
||||||
inspector = (
|
inspector = read_feature("shell")
|
||||||
ROOT / "frontend" / "src" / "components" / "inspector" / "WorkbenchInspector.tsx"
|
|
||||||
).read_text(encoding="utf-8")
|
|
||||||
|
|
||||||
assert "from './components/datasets/DatasetPanel'" in app
|
assert "from './components/datasets/DatasetPanel'" in app
|
||||||
assert "from './components/inspector/WorkbenchInspector'" 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:
|
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 "Eigen bronbestand toevoegen" in panel
|
||||||
assert "Metadata vernieuwen" 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:
|
def test_dataset_detail_panel_composes_raster_and_vector_controls() -> None:
|
||||||
detail_panel = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetDetailPanel.tsx").read_text(
|
detail_panel = read_feature("datasets")
|
||||||
encoding="utf-8"
|
raster_controls = read_feature("datasets")
|
||||||
)
|
vector_controls = read_feature("datasets")
|
||||||
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"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert "<RasterControls" in detail_panel
|
assert "<RasterControls" in detail_panel
|
||||||
assert "<VectorControls" in detail_panel
|
assert "<VectorControls" in detail_panel
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
def test_workbench_bootstrap_hook_owns_entrypoint_effects() -> None:
|
||||||
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
|
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 "loadProjects().catch(() => null)" not in app
|
||||||
assert "loadDetectionResults().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:
|
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 "DEMO_PROJECT_NAME = 'GeoIntel Demo - Building QA'" in hook
|
||||||
assert "pickInitialProjectId" 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:
|
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 "areaFeatureCollection" in hook
|
||||||
assert "mapFeatureCollection" 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:
|
def test_area_selection_fallbacks_live_with_owning_hooks() -> None:
|
||||||
dataset_hook = (ROOT / "frontend" / "src" / "hooks" / "useDatasetWorkflow.ts").read_text(encoding="utf-8")
|
dataset_hook = read_feature("datasets")
|
||||||
map_hook = (ROOT / "frontend" / "src" / "hooks" / "useMapWorkspaceState.ts").read_text(encoding="utf-8")
|
map_hook = read_feature("map_workspace")
|
||||||
|
|
||||||
assert "setSelectedClipAreaId(areas[0].id)" in dataset_hook
|
assert "setSelectedClipAreaId(areas[0].id)" in dataset_hook
|
||||||
assert "setSelectedMapAreaId(areas[0].id)" in map_hook
|
assert "setSelectedMapAreaId(areas[0].id)" in map_hook
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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(
|
area_panel = (ROOT / "frontend" / "src" / "components" / "project" / "AreaPanel.tsx").read_text(
|
||||||
encoding="utf-8"
|
encoding="utf-8"
|
||||||
)
|
)
|
||||||
map_workspace = (ROOT / "frontend" / "src" / "components" / "map" / "MapWorkspace.tsx").read_text(
|
map_workspace = read_feature("map_workspace")
|
||||||
encoding="utf-8"
|
dataset_panel = read_feature("datasets")
|
||||||
)
|
quality_panel = read_feature("quality")
|
||||||
dataset_panel = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetPanel.tsx").read_text(
|
export_center = read_feature("exports")
|
||||||
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"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert 'data-testid="project-panel"' in project_panel
|
assert 'data-testid="project-panel"' in project_panel
|
||||||
assert 'data-testid={`project-select-${project.id}`}' in project_panel
|
assert 'data-testid={`project-select-${project.id}`}' in project_panel
|
||||||
|
|||||||
@@ -1,21 +1,15 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
def test_app_uses_task_based_workbench_shell() -> None:
|
def test_app_uses_task_based_workbench_shell() -> None:
|
||||||
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
|
app = read_feature("shell")
|
||||||
navigation = (
|
navigation = read_feature("shell")
|
||||||
ROOT
|
|
||||||
/ "frontend"
|
|
||||||
/ "src"
|
|
||||||
/ "components"
|
|
||||||
/ "shell"
|
|
||||||
/ "WorkbenchNavigation.tsx"
|
|
||||||
).read_text(encoding="utf-8")
|
|
||||||
|
|
||||||
assert "type WorkspaceKey" in app
|
assert "type WorkspaceKey" in app
|
||||||
assert "workspaceNavItems" in app
|
assert "workspaceNavItems" in app
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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(
|
area_panel = (ROOT / "frontend" / "src" / "components" / "project" / "AreaPanel.tsx").read_text(
|
||||||
encoding="utf-8"
|
encoding="utf-8"
|
||||||
)
|
)
|
||||||
dataset_panel = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetPanel.tsx").read_text(
|
dataset_panel = read_feature("datasets")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert "compact-form" in project_panel
|
assert "compact-form" in project_panel
|
||||||
assert "entity-card-active" 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:
|
def test_map_and_ai_workspaces_use_task_blocks_not_raw_stacks() -> None:
|
||||||
map_workspace = (ROOT / "frontend" / "src" / "components" / "map" / "MapWorkspace.tsx").read_text(
|
map_workspace = read_feature("map_workspace")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
detection_lab = "\n".join(
|
detection_lab = "\n".join(
|
||||||
(
|
(
|
||||||
(ROOT / "frontend" / "src" / "components" / "detection" / "DetectionLab.tsx").read_text(encoding="utf-8"),
|
(ROOT / "frontend" / "src" / "components" / "detection" / "DetectionLab.tsx").read_text(encoding="utf-8"),
|
||||||
(ROOT / "frontend" / "src" / "components" / "detection" / "DetectionModelManagement.tsx").read_text(encoding="utf-8"),
|
(ROOT / "frontend" / "src" / "components" / "detection" / "DetectionModelManagement.tsx").read_text(encoding="utf-8"),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
segmentation_lab = (
|
segmentation_lab = read_feature("segmentation")
|
||||||
ROOT / "frontend" / "src" / "components" / "segmentation" / "SegmentationLab.tsx"
|
|
||||||
).read_text(encoding="utf-8")
|
|
||||||
styles = (ROOT / "frontend" / "src" / "styles" / "app.css").read_text(encoding="utf-8")
|
styles = (ROOT / "frontend" / "src" / "styles" / "app.css").read_text(encoding="utf-8")
|
||||||
|
|
||||||
assert "map-toolbar" in map_workspace
|
assert "map-toolbar" in map_workspace
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
def test_export_center_uses_artifact_actions_and_cards() -> None:
|
||||||
export_center = (ROOT / "frontend" / "src" / "components" / "exports" / "ExportCenter.tsx").read_text(
|
export_center = read_feature("exports")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
export_preview = (ROOT / "frontend" / "src" / "components" / "exports" / "ExportPreview.tsx").read_text(
|
export_preview = (ROOT / "frontend" / "src" / "components" / "exports" / "ExportPreview.tsx").read_text(
|
||||||
encoding="utf-8"
|
encoding="utf-8"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
def test_app_wires_tabbed_workbench_inspector() -> None:
|
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 "from './components/inspector/WorkbenchInspector'" in app
|
||||||
assert "<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:
|
def test_dataset_detail_props_remain_exported_for_inspector_reuse() -> None:
|
||||||
dataset_panel = (
|
dataset_panel = read_feature("datasets")
|
||||||
ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetDetailPanel.tsx"
|
|
||||||
).read_text(encoding="utf-8")
|
|
||||||
|
|
||||||
assert "export interface DatasetDetailPanelProps" in dataset_panel
|
assert "export interface DatasetDetailPanelProps" in dataset_panel
|
||||||
assert 'className="dataset-detail-panel"' in dataset_panel
|
assert 'className="dataset-detail-panel"' in dataset_panel
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
def test_dataset_panel_exposes_map_and_export_quick_actions() -> None:
|
def test_dataset_panel_exposes_map_and_export_quick_actions() -> None:
|
||||||
panel = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetPanel.tsx").read_text(
|
panel = read_feature("datasets")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert "selectedDatasetId" in panel
|
assert "selectedDatasetId" in panel
|
||||||
assert "dataset-card-active" 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:
|
def test_shell_preserves_workspace_width_on_standard_desktop_viewports() -> None:
|
||||||
css = (ROOT / "frontend" / "src" / "styles" / "app.css").read_text(encoding="utf-8")
|
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 "grid-template-columns: 12.5rem minmax(0, 1fr) 21rem" in css
|
||||||
assert "@media (max-width: 1360px)" 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:
|
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 "const openDatasetInMap = (dataset: DatasetCreateResponse) => {" in app
|
||||||
assert "loadDatasetDetails(selectedProjectId, dataset)" in app
|
assert "loadDatasetDetails(selectedProjectId, dataset)" in app
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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(
|
css = (ROOT / "frontend" / "src" / "styles" / "atlas-workbench.css").read_text(
|
||||||
encoding="utf-8"
|
encoding="utf-8"
|
||||||
)
|
)
|
||||||
navigation = (
|
navigation = read_feature("shell")
|
||||||
ROOT
|
|
||||||
/ "frontend"
|
|
||||||
/ "src"
|
|
||||||
/ "components"
|
|
||||||
/ "shell"
|
|
||||||
/ "WorkbenchNavigation.tsx"
|
|
||||||
).read_text(encoding="utf-8")
|
|
||||||
|
|
||||||
assert "workspace-command-bar" not in app
|
assert "workspace-command-bar" not in app
|
||||||
assert "workspace-nav-cluster" 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(
|
project_panel = (ROOT / "frontend" / "src" / "components" / "project" / "ProjectPanel.tsx").read_text(
|
||||||
encoding="utf-8"
|
encoding="utf-8"
|
||||||
)
|
)
|
||||||
dataset_panel = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetPanel.tsx").read_text(
|
dataset_panel = read_feature("datasets")
|
||||||
encoding="utf-8"
|
detection_lab = read_feature("detection")
|
||||||
)
|
segmentation_lab = read_feature("segmentation")
|
||||||
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")
|
|
||||||
|
|
||||||
assert "empty-state" in project_panel
|
assert "empty-state" in project_panel
|
||||||
assert "empty-state" in dataset_panel
|
assert "empty-state" in dataset_panel
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
def test_map_workspace_exposes_layer_provenance_and_feature_summary() -> None:
|
def test_map_workspace_exposes_layer_provenance_and_feature_summary() -> None:
|
||||||
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
|
app = read_feature("shell")
|
||||||
map_workspace = (ROOT / "frontend" / "src" / "components" / "map" / "MapWorkspace.tsx").read_text(
|
map_workspace = read_feature("map_workspace")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
css = (ROOT / "frontend" / "src" / "styles" / "app.css").read_text(encoding="utf-8")
|
css = (ROOT / "frontend" / "src" / "styles" / "app.css").read_text(encoding="utf-8")
|
||||||
|
|
||||||
assert "mapLayerSourceLabel" in app
|
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:
|
def test_map_workspace_has_clear_empty_result_layer_guidance() -> None:
|
||||||
map_workspace = (ROOT / "frontend" / "src" / "components" / "map" / "MapWorkspace.tsx").read_text(
|
map_workspace = read_feature("map_workspace")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert "Geen actieve vector- of resultaatlaag" in 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
|
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 pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
def test_export_center_surfaces_handoff_readiness_context() -> None:
|
def test_export_center_surfaces_handoff_readiness_context() -> None:
|
||||||
export_center = (ROOT / "frontend" / "src" / "components" / "exports" / "ExportCenter.tsx").read_text(
|
export_center = read_feature("exports")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert 'className="handoff-summary-card"' in export_center
|
assert 'className="handoff-summary-card"' in export_center
|
||||||
assert 'className="handoff-readiness-grid"' in export_center
|
assert 'className="handoff-readiness-grid"' in export_center
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
def test_map_empty_state_surfaces_ready_vector_dataset_actions() -> None:
|
def test_map_empty_state_surfaces_ready_vector_dataset_actions() -> None:
|
||||||
map_workspace = (ROOT / "frontend" / "src" / "components" / "map" / "MapWorkspace.tsx").read_text(
|
map_workspace = read_feature("map_workspace")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert "availableMapDatasets" in map_workspace
|
assert "availableMapDatasets" in map_workspace
|
||||||
assert "onOpenDatasetInMap" 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:
|
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 "availableMapDatasets" in app
|
||||||
assert "datasets.filter((dataset) => isVectorDatasetType(dataset.dataset_type) && dataset.status === 'ready')" in app
|
assert "datasets.filter((dataset) => isVectorDatasetType(dataset.dataset_type) && dataset.status === 'ready')" in app
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
def test_dataset_panel_surfaces_role_summary_and_badges() -> None:
|
def test_dataset_panel_surfaces_role_summary_and_badges() -> None:
|
||||||
dataset_panel = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetPanel.tsx").read_text(
|
dataset_panel = read_feature("datasets")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert "roleSummaries" in dataset_panel
|
assert "roleSummaries" in dataset_panel
|
||||||
assert "dataset-role-summary-grid" 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:
|
def test_dataset_cards_expose_scan_friendly_source_and_crs_context() -> None:
|
||||||
dataset_panel = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetPanel.tsx").read_text(
|
dataset_panel = read_feature("datasets")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert "dataset-card-kicker" in dataset_panel
|
assert "dataset-card-kicker" in dataset_panel
|
||||||
assert "Bron: {dataset.source_name ?? dataset.source}" in dataset_panel
|
assert "Bron: {dataset.source_name ?? dataset.source}" in dataset_panel
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
def test_dataset_panel_explains_recommended_actions() -> None:
|
def test_dataset_panel_explains_recommended_actions() -> None:
|
||||||
dataset_panel = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetPanel.tsx").read_text(
|
dataset_panel = read_feature("datasets")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert "datasetActionHint" in dataset_panel
|
assert "datasetActionHint" in dataset_panel
|
||||||
assert "dataset-action-hint" 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:
|
def test_dataset_buttons_have_scan_friendly_action_copy() -> None:
|
||||||
dataset_panel = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetPanel.tsx").read_text(
|
dataset_panel = read_feature("datasets")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert "dataset-action-grid" in dataset_panel
|
assert "dataset-action-grid" in dataset_panel
|
||||||
assert "Bekijken" in dataset_panel
|
assert "Bekijken" in dataset_panel
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
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 "availableVectorDatasets.filter((item) => item.dataset_role !== 'reference')" in app
|
||||||
assert "candidateDatasets={candidateDatasets}" in app
|
assert "candidateDatasets={candidateDatasets}" in app
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
def test_quality_panel_promotes_core_metrics_before_raw_metric_list() -> None:
|
def test_quality_panel_promotes_core_metrics_before_raw_metric_list() -> None:
|
||||||
quality_panel = (
|
quality_panel = read_feature("quality")
|
||||||
ROOT / "frontend" / "src" / "components" / "quality" / "QualityResultsPanel.tsx"
|
|
||||||
).read_text(encoding="utf-8")
|
|
||||||
|
|
||||||
assert "CORE_METRIC_ORDER" in quality_panel
|
assert "CORE_METRIC_ORDER" in quality_panel
|
||||||
assert "precision" 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:
|
def test_quality_panel_renders_metric_evidence_cards_and_raw_metrics() -> None:
|
||||||
quality_panel = (
|
quality_panel = read_feature("quality")
|
||||||
ROOT / "frontend" / "src" / "components" / "quality" / "QualityResultsPanel.tsx"
|
|
||||||
).read_text(encoding="utf-8")
|
|
||||||
|
|
||||||
assert "quality-metric-grid" in quality_panel
|
assert "quality-metric-grid" in quality_panel
|
||||||
assert "quality-metric-card" in quality_panel
|
assert "quality-metric-card" in quality_panel
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
def test_quality_panel_adds_result_filters_and_density_limit() -> None:
|
def test_quality_panel_adds_result_filters_and_density_limit() -> None:
|
||||||
quality_panel = (
|
quality_panel = read_feature("quality")
|
||||||
ROOT / "frontend" / "src" / "components" / "quality" / "QualityResultsPanel.tsx"
|
|
||||||
).read_text(encoding="utf-8")
|
|
||||||
|
|
||||||
assert "useState" in quality_panel
|
assert "useState" in quality_panel
|
||||||
assert "qualityStatusFilter" in quality_panel
|
assert "qualityStatusFilter" in quality_panel
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
def test_data_and_map_components_keep_existing_workflow_markup() -> None:
|
||||||
dataset_panel = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetPanel.tsx").read_text(
|
dataset_panel = read_feature("datasets")
|
||||||
encoding="utf-8"
|
map_workspace = read_feature("map_workspace")
|
||||||
)
|
|
||||||
map_workspace = (ROOT / "frontend" / "src" / "components" / "map" / "MapWorkspace.tsx").read_text(
|
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert 'className="dataset-upload-form"' in dataset_panel
|
assert 'className="dataset-upload-form"' in dataset_panel
|
||||||
assert 'className="file-input-label"' in dataset_panel
|
assert 'className="file-input-label"' in dataset_panel
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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"),
|
(ROOT / "frontend" / "src" / "components" / "detection" / "DetectionModelManagement.tsx").read_text(encoding="utf-8"),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
segmentation_lab = (
|
segmentation_lab = read_feature("segmentation")
|
||||||
ROOT / "frontend" / "src" / "components" / "segmentation" / "SegmentationLab.tsx"
|
|
||||||
).read_text(encoding="utf-8")
|
|
||||||
|
|
||||||
for source in (detection_lab, segmentation_lab):
|
for source in (detection_lab, segmentation_lab):
|
||||||
assert 'className="model-list"' in source
|
assert 'className="model-list"' in source
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
def test_export_and_provider_components_keep_workflow_markup() -> None:
|
||||||
export_center = (ROOT / "frontend" / "src" / "components" / "exports" / "ExportCenter.tsx").read_text(
|
export_center = read_feature("exports")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
provider_panel = (ROOT / "frontend" / "src" / "components" / "providers" / "ProviderPanel.tsx").read_text(
|
provider_panel = (ROOT / "frontend" / "src" / "components" / "providers" / "ProviderPanel.tsx").read_text(
|
||||||
encoding="utf-8"
|
encoding="utf-8"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
def test_inspector_components_keep_mobile_tool_markup() -> None:
|
||||||
inspector = (ROOT / "frontend" / "src" / "components" / "inspector" / "WorkbenchInspector.tsx").read_text(
|
inspector = read_feature("shell")
|
||||||
encoding="utf-8"
|
dataset_detail = read_feature("datasets")
|
||||||
)
|
raster_controls = read_feature("datasets")
|
||||||
dataset_detail = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetDetailPanel.tsx").read_text(
|
vector_controls = read_feature("datasets")
|
||||||
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"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert 'className="workbench-inspector-panel"' in inspector
|
assert 'className="workbench-inspector-panel"' in inspector
|
||||||
assert 'className="inspector-action-bar"' in inspector
|
assert 'className="inspector-action-bar"' in inspector
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
def test_primary_navigation_has_keyboard_labels() -> None:
|
||||||
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
|
app = read_feature("shell")
|
||||||
navigation = (
|
navigation = read_feature("shell")
|
||||||
ROOT
|
|
||||||
/ "frontend"
|
|
||||||
/ "src"
|
|
||||||
/ "components"
|
|
||||||
/ "shell"
|
|
||||||
/ "WorkbenchNavigation.tsx"
|
|
||||||
).read_text(encoding="utf-8")
|
|
||||||
|
|
||||||
assert 'aria-label={`Open ${item.label}: ${item.description}`}' in navigation
|
assert 'aria-label={`Open ${item.label}: ${item.description}`}' in navigation
|
||||||
assert "title={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:
|
def test_inspector_tabs_are_bound_to_tab_panels() -> None:
|
||||||
inspector = (ROOT / "frontend" / "src" / "components" / "inspector" / "WorkbenchInspector.tsx").read_text(
|
inspector = read_feature("shell")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert "const activeTabId = `inspector-tab-${activeTab}`" in inspector
|
assert "const activeTabId = `inspector-tab-${activeTab}`" in inspector
|
||||||
assert "const activePanelId = `inspector-panel-${activeTab}`" in inspector
|
assert "const activePanelId = `inspector-panel-${activeTab}`" in inspector
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
def test_raster_controls_expose_readable_operation_groups() -> None:
|
||||||
raster_controls = (ROOT / "frontend" / "src" / "components" / "datasets" / "RasterControls.tsx").read_text(
|
raster_controls = read_feature("datasets")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert 'className="dataset-tool-heading"' in raster_controls
|
assert 'className="dataset-tool-heading"' in raster_controls
|
||||||
assert 'className="dataset-tool-helper"' 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:
|
def test_vector_controls_expose_readable_operation_groups() -> None:
|
||||||
vector_controls = (ROOT / "frontend" / "src" / "components" / "datasets" / "VectorControls.tsx").read_text(
|
vector_controls = read_feature("datasets")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert 'className="dataset-tool-heading"' in vector_controls
|
assert 'className="dataset-tool-heading"' in vector_controls
|
||||||
assert 'className="dataset-tool-helper"' in vector_controls
|
assert 'className="dataset-tool-helper"' in vector_controls
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
def test_quality_and_export_panels_use_result_state_blocks() -> None:
|
||||||
quality_panel = (ROOT / "frontend" / "src" / "components" / "quality" / "QualityResultsPanel.tsx").read_text(
|
quality_panel = read_feature("quality")
|
||||||
encoding="utf-8"
|
export_center = read_feature("exports")
|
||||||
)
|
|
||||||
export_center = (ROOT / "frontend" / "src" / "components" / "exports" / "ExportCenter.tsx").read_text(
|
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert 'className="result-state result-state-error"' in quality_panel
|
assert 'className="result-state result-state-error"' in quality_panel
|
||||||
assert 'className="result-state result-state-empty"' 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:
|
def test_ai_labs_use_result_state_blocks() -> None:
|
||||||
detection_lab = (ROOT / "frontend" / "src" / "components" / "detection" / "DetectionLab.tsx").read_text(
|
detection_lab = read_feature("detection")
|
||||||
encoding="utf-8"
|
segmentation_lab = read_feature("segmentation")
|
||||||
)
|
|
||||||
segmentation_lab = (
|
|
||||||
ROOT / "frontend" / "src" / "components" / "segmentation" / "SegmentationLab.tsx"
|
|
||||||
).read_text(encoding="utf-8")
|
|
||||||
|
|
||||||
for content in (detection_lab, segmentation_lab):
|
for content in (detection_lab, segmentation_lab):
|
||||||
assert 'className="result-state result-state-loading"' in content
|
assert 'className="result-state result-state-loading"' in content
|
||||||
|
|||||||
@@ -1,21 +1,15 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
def test_workbench_shell_has_skip_link_and_main_focus_target() -> None:
|
def test_workbench_shell_has_skip_link_and_main_focus_target() -> None:
|
||||||
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
|
app = read_feature("shell")
|
||||||
navigation = (
|
navigation = read_feature("shell")
|
||||||
ROOT
|
|
||||||
/ "frontend"
|
|
||||||
/ "src"
|
|
||||||
/ "components"
|
|
||||||
/ "shell"
|
|
||||||
/ "WorkbenchNavigation.tsx"
|
|
||||||
).read_text(encoding="utf-8")
|
|
||||||
|
|
||||||
assert 'className="skip-link"' in app
|
assert 'className="skip-link"' in app
|
||||||
assert 'href="#workspace-main"' in app
|
assert 'href="#workspace-main"' in app
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
def test_overview_uses_named_hierarchy_regions() -> None:
|
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="overview-action-copy"' in app
|
||||||
assert 'className="quick-action-grid overview-quick-actions"' in app
|
assert 'className="quick-action-grid overview-quick-actions"' in app
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
def test_dataset_panel_separates_selected_upload_and_catalog_regions() -> None:
|
||||||
dataset_panel = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetPanel.tsx").read_text(
|
dataset_panel = read_feature("datasets")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert "const selectedDataset = datasets.find" in dataset_panel
|
assert "const selectedDataset = datasets.find" in dataset_panel
|
||||||
assert 'className="data-selection-summary data-selection-summary-dataset"' in dataset_panel
|
assert 'className="data-selection-summary data-selection-summary-dataset"' in dataset_panel
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
def test_map_workspace_exposes_structured_surfaces() -> None:
|
def test_map_workspace_exposes_structured_surfaces() -> None:
|
||||||
map_workspace = (ROOT / "frontend" / "src" / "components" / "map" / "MapWorkspace.tsx").read_text(
|
map_workspace = read_feature("map_workspace")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert 'className="map-workspace-shell"' in map_workspace
|
assert 'className="map-workspace-shell"' in map_workspace
|
||||||
assert 'className="map-context-summary"' 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:
|
def test_map_workspace_summary_uses_current_layer_and_selection_state() -> None:
|
||||||
map_workspace = (ROOT / "frontend" / "src" / "components" / "map" / "MapWorkspace.tsx").read_text(
|
map_workspace = read_feature("map_workspace")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert "const selectedMapArea = areas.find" in map_workspace
|
assert "const selectedMapArea = areas.find" in map_workspace
|
||||||
assert "selectedMapArea?.name ?? 'Geen gebied geselecteerd'" in map_workspace
|
assert "selectedMapArea?.name ?? 'Geen gebied geselecteerd'" in map_workspace
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
def test_quality_results_panel_exposes_structured_surfaces() -> None:
|
def test_quality_results_panel_exposes_structured_surfaces() -> None:
|
||||||
panel = (ROOT / "frontend" / "src" / "components" / "quality" / "QualityResultsPanel.tsx").read_text(
|
panel = read_feature("quality")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert "'quality-results-panel quality-results-panel-empty' : 'quality-results-panel'" in panel
|
assert "'quality-results-panel quality-results-panel-empty' : 'quality-results-panel'" in panel
|
||||||
assert 'className="quality-results-shell"' 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:
|
def test_quality_results_panel_preserves_existing_refresh_filter_and_history_state() -> None:
|
||||||
panel = (ROOT / "frontend" / "src" / "components" / "quality" / "QualityResultsPanel.tsx").read_text(
|
panel = read_feature("quality")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert "onRefresh" in panel
|
assert "onRefresh" in panel
|
||||||
assert "qualityStatusFilter" in panel
|
assert "qualityStatusFilter" in panel
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
def test_segmentation_lab_exposes_structured_surfaces() -> None:
|
||||||
lab = (ROOT / "frontend" / "src" / "components" / "segmentation" / "SegmentationLab.tsx").read_text(
|
lab = read_feature("segmentation")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert 'className="workspace-panel ai-lab-shell segmentation-lab-shell"' in lab
|
assert 'className="workspace-panel ai-lab-shell segmentation-lab-shell"' in lab
|
||||||
assert 'className="ai-lab-model-surface"' 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:
|
def test_ai_lab_preserves_existing_detection_and_segmentation_controls() -> None:
|
||||||
detection = (ROOT / "frontend" / "src" / "components" / "detection" / "DetectionLab.tsx").read_text(
|
detection = read_feature("detection")
|
||||||
encoding="utf-8"
|
segmentation = read_feature("segmentation")
|
||||||
)
|
|
||||||
segmentation = (ROOT / "frontend" / "src" / "components" / "segmentation" / "SegmentationLab.tsx").read_text(
|
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert "onRunDetection" in detection
|
assert "onRunDetection" in detection
|
||||||
assert "onLoadResults" in detection
|
assert "onLoadResults" in detection
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
def test_export_center_exposes_final_handoff_surfaces() -> None:
|
def test_export_center_exposes_final_handoff_surfaces() -> None:
|
||||||
export_center = (ROOT / "frontend" / "src" / "components" / "exports" / "ExportCenter.tsx").read_text(
|
export_center = read_feature("exports")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert 'className="export-center"' in export_center
|
assert 'className="export-center"' in export_center
|
||||||
assert 'className="export-center-shell"' 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:
|
def test_export_system_preserves_existing_workflow_controls() -> None:
|
||||||
export_center = (ROOT / "frontend" / "src" / "components" / "exports" / "ExportCenter.tsx").read_text(
|
export_center = read_feature("exports")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
provider_panel = (ROOT / "frontend" / "src" / "components" / "providers" / "ProviderPanel.tsx").read_text(
|
provider_panel = (ROOT / "frontend" / "src" / "components" / "providers" / "ProviderPanel.tsx").read_text(
|
||||||
encoding="utf-8"
|
encoding="utf-8"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
def test_overview_exposes_end_to_end_workflow_guidance() -> None:
|
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 'aria-label="Voortgang van de werkstroom"' in overview
|
||||||
assert 'className="workflow-guidance-panel"' 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:
|
def test_workflow_guidance_routes_to_existing_workspaces() -> None:
|
||||||
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
|
app = read_feature("shell")
|
||||||
overview = (ROOT / "frontend" / "src" / "components" / "overview" / "OverviewWorkspace.tsx").read_text(encoding="utf-8")
|
overview = read_feature("shell")
|
||||||
|
|
||||||
assert "target: 'data'" in overview
|
assert "target: 'data'" in overview
|
||||||
assert "target: 'map'" 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:
|
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 "workflowComplete" in overview
|
||||||
assert "Klaar om te delen" 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:
|
def test_workflow_guidance_map_and_export_steps_reuse_dataset_context() -> None:
|
||||||
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
|
app = read_feature("shell")
|
||||||
overview = (ROOT / "frontend" / "src" / "components" / "overview" / "OverviewWorkspace.tsx").read_text(encoding="utf-8")
|
overview = read_feature("shell")
|
||||||
|
|
||||||
assert "openWorkflowGuidanceStep" in app
|
assert "openWorkflowGuidanceStep" in app
|
||||||
assert "target === 'map'" in app
|
assert "target === 'map'" in app
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
from pathlib import Path
|
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]
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
def test_export_center_groups_latest_handoff_artifacts_by_type() -> None:
|
def test_export_center_groups_latest_handoff_artifacts_by_type() -> None:
|
||||||
export_center = (ROOT / "frontend" / "src" / "components" / "exports" / "ExportCenter.tsx").read_text(
|
export_center = read_feature("exports")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert "latestHandoffArtifacts" in export_center
|
assert "latestHandoffArtifacts" in export_center
|
||||||
assert "handoff" in export_center.casefold()
|
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:
|
def test_export_center_latest_artifact_cards_keep_existing_actions() -> None:
|
||||||
export_center = (ROOT / "frontend" / "src" / "components" / "exports" / "ExportCenter.tsx").read_text(
|
export_center = read_feature("exports")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert "getLatestExportByType" in export_center
|
assert "getLatestExportByType" in export_center
|
||||||
assert "const item = artifact.item" in export_center
|
assert "const item = artifact.item" in export_center
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
def test_quality_results_panel_exposes_selected_check_drilldown() -> None:
|
def test_quality_results_panel_exposes_selected_check_drilldown() -> None:
|
||||||
panel = (ROOT / "frontend" / "src" / "components" / "quality" / "QualityResultsPanel.tsx").read_text(
|
panel = read_feature("quality")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert "selectedQualityCheckId" in panel
|
assert "selectedQualityCheckId" in panel
|
||||||
assert "selectedQualityCheck" 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:
|
def test_quality_results_panel_surfaces_false_positive_negative_evidence() -> None:
|
||||||
panel = (ROOT / "frontend" / "src" / "components" / "quality" / "QualityResultsPanel.tsx").read_text(
|
panel = read_feature("quality")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert "Onterecht gevonden" in panel
|
assert "Onterecht gevonden" in panel
|
||||||
assert "Gemiste objecten" in panel
|
assert "Gemiste objecten" in panel
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
def test_raster_controls_expose_pipeline_readiness_and_handoff() -> None:
|
def test_raster_controls_expose_pipeline_readiness_and_handoff() -> None:
|
||||||
raster_controls = (ROOT / "frontend" / "src" / "components" / "datasets" / "RasterControls.tsx").read_text(
|
raster_controls = read_feature("datasets")
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert "rasterReadinessItems" in raster_controls
|
assert "rasterReadinessItems" in raster_controls
|
||||||
assert "rasterGuardrailItems" in raster_controls
|
assert "rasterGuardrailItems" in raster_controls
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
def test_dataset_workflow_selects_useful_default_dataset_after_project_load() -> None:
|
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 "defaultDataset" in hook
|
||||||
assert "!selectedDatasetId" 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:
|
def test_ai_labs_explain_missing_raster_input_before_disabled_runs() -> None:
|
||||||
detection_lab = (ROOT / "frontend" / "src" / "components" / "detection" / "DetectionLab.tsx").read_text(
|
detection_lab = read_feature("detection")
|
||||||
encoding="utf-8"
|
segmentation_lab = read_feature("segmentation")
|
||||||
)
|
|
||||||
segmentation_lab = (ROOT / "frontend" / "src" / "components" / "segmentation" / "SegmentationLab.tsx").read_text(
|
|
||||||
encoding="utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert "Geen luchtbeeld beschikbaar in deze werkruimte." in detection_lab
|
assert "Geen luchtbeeld beschikbaar in deze werkruimte." in detection_lab
|
||||||
assert "Voeg hieronder een gegeorefereerde GeoTIFF toe." in detection_lab
|
assert "Voeg hieronder een gegeorefereerde GeoTIFF toe." in detection_lab
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
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:
|
def test_demo_workflow_frontend_uses_raster_fixture_for_ai_labs() -> None:
|
||||||
types = (ROOT / "frontend" / "src" / "types.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")
|
||||||
hook = (ROOT / "frontend" / "src" / "hooks" / "useDemoWorkflow.ts").read_text(encoding="utf-8")
|
hook = (ROOT / "frontend" / "src" / "hooks" / "useDemoWorkflow.ts").read_text(encoding="utf-8")
|
||||||
|
|
||||||
assert "raster_dataset_id?: string | null" in types
|
assert "raster_dataset_id?: string | null" in types
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from tests.frontend_contract import read_feature
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
def test_raster_tile_manifest_is_visible_and_can_handoff_to_detection_lab() -> None:
|
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")
|
app = read_feature("shell")
|
||||||
hook = (ROOT / "frontend" / "src" / "hooks" / "useDatasetWorkflow.ts").read_text(encoding="utf-8")
|
hook = read_feature("datasets")
|
||||||
detail_panel = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetDetailPanel.tsx").read_text(encoding="utf-8")
|
detail_panel = read_feature("datasets")
|
||||||
raster_controls = (ROOT / "frontend" / "src" / "components" / "datasets" / "RasterControls.tsx").read_text(encoding="utf-8")
|
raster_controls = read_feature("datasets")
|
||||||
|
|
||||||
assert "latestRasterTileManifestPath" in hook
|
assert "latestRasterTileManifestPath" in hook
|
||||||
assert "extractRasterTileManifestPath" in hook
|
assert "extractRasterTileManifestPath" in hook
|
||||||
|
|||||||
Reference in New Issue
Block a user