diff --git a/src/test/test_link_preview.py b/src/test/test_link_preview.py
new file mode 100644
index 0000000..5ba3d6b
--- /dev/null
+++ b/src/test/test_link_preview.py
@@ -0,0 +1,152 @@
+"""Unit tests for the link-preview page (get_preview / get_preview_image)."""
+
+import html
+import re
+
+import pytest
+
+from vfbquery import link_preview
+
+
+def _neuron():
+ return {
+ "Id": "VFB_jrchjrch",
+ "Name": "5-HTPLP01_R",
+ "IsIndividual": True,
+ "IsClass": False,
+ "Meta": {
+ "Description": "",
+ "Comment": "tracing status-Roughly traced, cropped-False",
+ "Types": "[adult glutamatergic neuron](FBbt_00058220);[adult serotonergic PLP neuron](FBbt_00110925)",
+ },
+ "Technique": ["Hemibrain-Reconstruction"],
+ "Tags": ["Adult", "Nervous_system"],
+ "Images": {
+ "VFB_00101567": [
+ {"id": "VFB_00101384", "thumbnail": "https://www.virtualflybrain.org/data/VFB/i/jrch/jrch/VFB_00101384/thumbnail.png"},
+ {"id": "VFB_00101385", "thumbnail": "https://x/second.png"},
+ ]
+ },
+ }
+
+
+def _class_with_example():
+ return {
+ "Id": "FBbt_00003748",
+ "Name": "medulla",
+ "IsClass": True,
+ "IsIndividual": False,
+ "Meta": {"Description": "The second optic neuropil, [see](FBbt_00003701) *the* lobula."},
+ "Images": {},
+ "Examples": {"VFB_00017894": [{"id": "VFB_00030624", "thumbnail": "https://x/medulla.png"}]},
+ }
+
+
+# --- id validation -----------------------------------------------------------
+
+@pytest.mark.parametrize("value", ["FBbt_00003748", "VFB_jrchjrch", "VFBexp_FBtp0000001", "GO_0001872"])
+def test_is_term_id_accepts_vfb_shapes(value):
+ assert link_preview.is_term_id(value)
+
+
+@pytest.mark.parametrize("value", ["", None, "medulla", "'
+ info["Meta"]["Description"] = "a & b < c"
+ page = link_preview.render_preview_html(info)
+ assert "