feat: compose stable product surfaces
Module Package Release / publish-packages (push) Successful in 13s
Module Package Release / publish-packages (push) Successful in 13s
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
from dataclasses import replace
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.testclient import TestClient
|
||||
@@ -10,7 +11,9 @@ from govoplan_core.core.modules import (
|
||||
FrontendModule,
|
||||
FrontendRoute,
|
||||
ModuleManifest,
|
||||
ProductAvailabilityExplanation,
|
||||
ProductAreaContribution,
|
||||
ProductSurfaceContribution,
|
||||
QuickAccessTool,
|
||||
)
|
||||
from govoplan_core.core.registry import PlatformRegistry, RegistryError
|
||||
@@ -49,6 +52,26 @@ def presentation_manifest() -> ModuleManifest:
|
||||
surface_ids=("example.route.main",),
|
||||
),
|
||||
),
|
||||
product_surfaces=(
|
||||
ProductSurfaceContribution(
|
||||
id="work.examples",
|
||||
module_id="example",
|
||||
label="Examples",
|
||||
description="Review and update governed examples.",
|
||||
icon="list-checks",
|
||||
entry_path="/work/examples",
|
||||
route_path="/example",
|
||||
surface_ids=("example.route.main",),
|
||||
presentations=("task", "reader"),
|
||||
unavailable=ProductAvailabilityExplanation(
|
||||
reason="authorization",
|
||||
title="Examples are unavailable",
|
||||
description="Your current responsibility does not include examples.",
|
||||
resolution="Ask the responsible administrator to review your assignment.",
|
||||
responsible_role="Access administrator",
|
||||
),
|
||||
),
|
||||
),
|
||||
quick_access_tools=(
|
||||
QuickAccessTool(
|
||||
id="example.summary",
|
||||
@@ -121,6 +144,16 @@ class PresentationContractTests(unittest.TestCase):
|
||||
frontend = response.json()["modules"][0]["frontend"]
|
||||
self.assertEqual("1", frontend["presentation_contract_version"])
|
||||
self.assertEqual("work", frontend["product_areas"][0]["id"])
|
||||
product_surface = frontend["product_surfaces"][0]
|
||||
self.assertEqual("1", product_surface["contract_version"])
|
||||
self.assertEqual("work.examples", product_surface["id"])
|
||||
self.assertEqual("/work/examples", product_surface["entry_path"])
|
||||
self.assertEqual("/example", product_surface["route_path"])
|
||||
self.assertEqual(["task", "reader"], product_surface["presentations"])
|
||||
self.assertEqual(
|
||||
"authorization",
|
||||
product_surface["unavailable"]["reason"],
|
||||
)
|
||||
self.assertEqual("example.summary", frontend["quick_access_tools"][0]["id"])
|
||||
self.assertEqual("1", frontend["quick_access_tools"][0]["contract_version"])
|
||||
self.assertEqual(
|
||||
@@ -132,6 +165,61 @@ class PresentationContractTests(unittest.TestCase):
|
||||
frontend["quick_access_tools"][0]["help_context_id"],
|
||||
)
|
||||
|
||||
def test_registry_rejects_product_surface_without_owner_route(self) -> None:
|
||||
manifest = presentation_manifest()
|
||||
frontend = manifest.frontend
|
||||
assert frontend is not None
|
||||
surface = frontend.product_surfaces[0]
|
||||
invalid = ModuleManifest(
|
||||
id=manifest.id,
|
||||
name=manifest.name,
|
||||
version=manifest.version,
|
||||
frontend=FrontendModule(
|
||||
module_id=manifest.id,
|
||||
routes=frontend.routes,
|
||||
product_surfaces=(
|
||||
ProductSurfaceContribution(
|
||||
id=surface.id,
|
||||
module_id=surface.module_id,
|
||||
label=surface.label,
|
||||
description=surface.description,
|
||||
icon=surface.icon,
|
||||
entry_path=surface.entry_path,
|
||||
route_path="/missing",
|
||||
surface_ids=surface.surface_ids,
|
||||
unavailable=surface.unavailable,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
registry = PlatformRegistry()
|
||||
registry.register(invalid)
|
||||
|
||||
with self.assertRaisesRegex(RegistryError, "unknown owner route"):
|
||||
registry.validate()
|
||||
|
||||
def test_registry_rejects_product_alias_that_shadows_a_route(self) -> None:
|
||||
manifest = presentation_manifest()
|
||||
frontend = manifest.frontend
|
||||
assert frontend is not None
|
||||
surface = frontend.product_surfaces[0]
|
||||
invalid = replace(
|
||||
manifest,
|
||||
frontend=replace(
|
||||
frontend,
|
||||
routes=(
|
||||
*frontend.routes,
|
||||
FrontendRoute(path="/shortcut", component="ShortcutPage"),
|
||||
),
|
||||
product_surfaces=(replace(surface, aliases=("/shortcut",)),),
|
||||
),
|
||||
)
|
||||
registry = PlatformRegistry()
|
||||
registry.register(invalid)
|
||||
|
||||
with self.assertRaisesRegex(RegistryError, "collides with a concrete route"):
|
||||
registry.validate()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user