SharedDocsLib/tests/test_server.py
2026-08-09 17:59:49 +00:00

117 lines
4.2 KiB
Python

import base64
import io
import json
import os
import runpy
import zipfile
from fastapi.testclient import TestClient
from docslib import HeaderButton
from docslib.components import H1, Image, P
from docslib.hooks import Page
from docslib.server import create_app
def test_all_endpoints_and_self_contained_build(tmp_path):
assets = tmp_path / "assets"
assets.mkdir()
image_bytes = b"not-a-real-png-but-good-enough-for-encoding"
(assets / "hero.png").write_bytes(image_bytes)
custom_css = tmp_path / "inject.css"
custom_css.write_text(".content { --custom-test: yes; }", encoding="utf-8")
@Page("1.1", "Child")
def child():
return P("Second page")
@Page("1.", "Home")
def home():
return [H1("Welcome"), Image("hero.png", "Hero")]
app = create_app(
title="Test docs",
assets_dir=assets,
custom_css=custom_css,
manifest_path="http://127.0.0.1:9000/",
header_buttons=[
HeaderButton("Home", home),
HeaderButton.local("Child", "Child", section="1"),
HeaderButton.external("Source", "https://example.com"),
{"label": "Download", "href": "/index.zip"},
],
)
client = TestClient(app)
manifest_response = client.get("/manifest.json")
assert manifest_response.status_code == 200
manifest = manifest_response.json()
assert [page["number"] for page in manifest["pages"]] == ["1", "1.1"]
assert manifest["assets"]["hero.png"]["data"] == base64.b64encode(image_bytes).decode()
assert len(manifest["revision"]) == 20
assert manifest["ui"]["header_buttons"] == [
{"label": "Home", "page": "1"},
{"label": "Child", "page": "1.1"},
{"label": "Source", "href": "https://example.com", "target": "_blank"},
{"label": "Download", "href": "/index.zip"},
]
assert manifest_response.headers["cache-control"] == "no-store"
html_response = client.get("/index.html")
html = html_response.text
assert html_response.status_code == 200
assert "http://127.0.0.1:9000/manifest.json" in html
assert ".content { --custom-test: yes; }" in html
assert "indexedDB.open" in html
assert "link.dataset.page = button.page" in html
assert 'class="brand-mark"' not in html
assert ">Knowledge base<" not in html
assert ">Search<" not in html
assert ">Ctrl K<" not in html
assert ">Up to date<" not in html
assert "manifestIdentity" in html
assert "100dvh" in html
assert "100vh" not in html
assert "html, body { width: 100%; height: 100dvh" in html
assert "overflow-y: auto" in html
assert "document.body.append(elements.headerActions)" in html
assert "elements.workspace.scrollTo" in html
assert "--bg: #000000" in html
assert "--accent: #ffffff" in html
assert 'id="header-actions"' in html
assert 'id="actions-overlay"' in html
assert "<script src=" not in html
assert "<link rel=" not in html
zip_response = client.get("/index.zip")
assert zip_response.status_code == 200
with zipfile.ZipFile(io.BytesIO(zip_response.content)) as archive:
assert archive.namelist() == ["index.html"]
assert archive.read("index.html") == html_response.content
assert client.get("/live").status_code == 404
def test_live_preview_reloads_a_changed_main_source(tmp_path):
source = tmp_path / "docs.py"
source.write_text(
'from docslib.hooks import Page\n@Page("1", "Live")\ndef page(): return "<p>one</p>"\n',
encoding="utf-8",
)
runpy.run_path(str(source), run_name="__main__")
client = TestClient(create_app(live_preview=True))
initial = client.get("/manifest.json").json()
assert "one" in initial["pages"][0]["content"]
source.write_text(
'from docslib.hooks import Page\n@Page("1", "Live")\ndef page(): return "<p>two</p>"\n',
encoding="utf-8",
)
stat = source.stat()
os.utime(source, ns=(stat.st_atime_ns, stat.st_mtime_ns + 1_000_000_000))
live = client.get("/live").json()
assert live["changed"] is True
assert live["error"] is None
assert live["revision"] != initial["revision"]
assert "two" in client.get("/manifest.json").json()["pages"][0]["content"]