133 lines
4.4 KiB
Python
133 lines
4.4 KiB
Python
|
|
"""Issue B — wikilinks with redlinks + cross-project resolution."""
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
from fastapi.testclient import TestClient
|
||
|
|
|
||
|
|
from atocore.engineering.service import (
|
||
|
|
create_entity,
|
||
|
|
init_engineering_schema,
|
||
|
|
)
|
||
|
|
from atocore.engineering.wiki import (
|
||
|
|
_resolve_wikilink,
|
||
|
|
_wikilink_transform,
|
||
|
|
render_entity,
|
||
|
|
render_new_entity_form,
|
||
|
|
render_project,
|
||
|
|
)
|
||
|
|
from atocore.main import app
|
||
|
|
from atocore.models.database import init_db
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.fixture
|
||
|
|
def env(tmp_data_dir, tmp_path, monkeypatch):
|
||
|
|
registry_path = tmp_path / "test-registry.json"
|
||
|
|
registry_path.write_text('{"projects": []}', encoding="utf-8")
|
||
|
|
monkeypatch.setenv("ATOCORE_PROJECT_REGISTRY_PATH", str(registry_path))
|
||
|
|
from atocore import config
|
||
|
|
config.settings = config.Settings()
|
||
|
|
init_db()
|
||
|
|
init_engineering_schema()
|
||
|
|
yield tmp_data_dir
|
||
|
|
|
||
|
|
|
||
|
|
def test_resolve_wikilink_same_project_is_live(env):
|
||
|
|
tower = create_entity(entity_type="component", name="Tower", project="p05")
|
||
|
|
href, cls, _ = _resolve_wikilink("Tower", current_project="p05")
|
||
|
|
assert href == f"/wiki/entities/{tower.id}"
|
||
|
|
assert cls == "wikilink"
|
||
|
|
|
||
|
|
|
||
|
|
def test_resolve_wikilink_missing_is_redlink(env):
|
||
|
|
href, cls, suffix = _resolve_wikilink("DoesNotExist", current_project="p05")
|
||
|
|
assert "/wiki/new" in href
|
||
|
|
assert "name=DoesNotExist" in href
|
||
|
|
assert cls == "redlink"
|
||
|
|
|
||
|
|
|
||
|
|
def test_resolve_wikilink_cross_project_indicator(env):
|
||
|
|
other = create_entity(entity_type="material", name="Invar", project="p06")
|
||
|
|
href, cls, suffix = _resolve_wikilink("Invar", current_project="p05")
|
||
|
|
assert href == f"/wiki/entities/{other.id}"
|
||
|
|
assert "wikilink-cross" in cls
|
||
|
|
assert "in p06" in suffix
|
||
|
|
|
||
|
|
|
||
|
|
def test_resolve_wikilink_case_insensitive(env):
|
||
|
|
tower = create_entity(entity_type="component", name="Tower", project="p05")
|
||
|
|
href, cls, _ = _resolve_wikilink("tower", current_project="p05")
|
||
|
|
assert href == f"/wiki/entities/{tower.id}"
|
||
|
|
assert cls == "wikilink"
|
||
|
|
|
||
|
|
|
||
|
|
def test_transform_replaces_brackets_with_anchor(env):
|
||
|
|
create_entity(entity_type="component", name="Base Plate", project="p05")
|
||
|
|
out = _wikilink_transform("See [[Base Plate]] for details.", current_project="p05")
|
||
|
|
assert '<a href="/wiki/entities/' in out
|
||
|
|
assert 'class="wikilink"' in out
|
||
|
|
assert "[[Base Plate]]" not in out
|
||
|
|
|
||
|
|
|
||
|
|
def test_transform_redlink_for_missing(env):
|
||
|
|
out = _wikilink_transform("Mentions [[Ghost]] nowhere.", current_project="p05")
|
||
|
|
assert 'class="redlink"' in out
|
||
|
|
assert "/wiki/new?name=Ghost" in out
|
||
|
|
|
||
|
|
|
||
|
|
def test_transform_alias_syntax(env):
|
||
|
|
tower = create_entity(entity_type="component", name="Tower", project="p05")
|
||
|
|
out = _wikilink_transform("The [[Tower|big tower]] is tall.", current_project="p05")
|
||
|
|
assert f'href="/wiki/entities/{tower.id}"' in out
|
||
|
|
assert ">big tower<" in out
|
||
|
|
|
||
|
|
|
||
|
|
def test_render_entity_description_has_redlink(env):
|
||
|
|
a = create_entity(
|
||
|
|
entity_type="component",
|
||
|
|
name="EntityA",
|
||
|
|
project="p05",
|
||
|
|
description="This depends on [[MissingPart]] which does not exist.",
|
||
|
|
)
|
||
|
|
html = render_entity(a.id)
|
||
|
|
assert 'class="redlink"' in html
|
||
|
|
assert "/wiki/new?name=MissingPart" in html
|
||
|
|
|
||
|
|
|
||
|
|
def test_regression_redlink_becomes_live_once_target_created(env):
|
||
|
|
a = create_entity(
|
||
|
|
entity_type="component",
|
||
|
|
name="EntityA",
|
||
|
|
project="p05",
|
||
|
|
description="Connected to [[EntityB]].",
|
||
|
|
)
|
||
|
|
# Pre-create: redlink.
|
||
|
|
html_before = render_entity(a.id)
|
||
|
|
assert 'class="redlink"' in html_before
|
||
|
|
|
||
|
|
b = create_entity(entity_type="component", name="EntityB", project="p05")
|
||
|
|
html_after = render_entity(a.id)
|
||
|
|
assert 'class="redlink"' not in html_after
|
||
|
|
assert f"/wiki/entities/{b.id}" in html_after
|
||
|
|
|
||
|
|
|
||
|
|
def test_new_entity_form_prefills_name():
|
||
|
|
html = render_new_entity_form(name="FreshEntity", project="p05")
|
||
|
|
assert 'value="FreshEntity"' in html
|
||
|
|
assert 'value="p05"' in html
|
||
|
|
assert "entity_type" in html
|
||
|
|
assert 'method="post"' not in html # JS-driven
|
||
|
|
|
||
|
|
|
||
|
|
def test_wiki_new_route_renders(env):
|
||
|
|
client = TestClient(app)
|
||
|
|
r = client.get("/wiki/new?name=NewThing&project=p05")
|
||
|
|
assert r.status_code == 200
|
||
|
|
assert "NewThing" in r.text
|
||
|
|
assert "Create entity" in r.text
|
||
|
|
|
||
|
|
|
||
|
|
def test_wiki_new_url_escapes_special_chars(env):
|
||
|
|
# "steel (likely)" is the kind of awkward name AKC produces
|
||
|
|
href, cls, _ = _resolve_wikilink("steel (likely)", current_project="p05")
|
||
|
|
assert cls == "redlink"
|
||
|
|
assert "name=steel%20%28likely%29" in href
|