Files
aiturk-hermes-ide/tests/skills/test_publish_site_skill.py
T

144 lines
4.9 KiB
Python

"""Tests for the optional-skills/web-development/publish-site skill.
Structural + internal-consistency checks only (stdlib + pytest, no network).
"""
import re
from pathlib import Path
import pytest
REPO = Path(__file__).resolve().parents[2]
SKILL_DIR = REPO / "optional-skills" / "web-development" / "publish-site"
SKILL_MD = SKILL_DIR / "SKILL.md"
VALID_PLATFORMS = {"linux", "macos", "windows"}
@pytest.fixture(scope="module")
def skill_text() -> str:
return SKILL_MD.read_text(encoding="utf-8")
@pytest.fixture(scope="module")
def frontmatter(skill_text: str) -> dict:
"""Parse the YAML frontmatter with stdlib only (flat key: value fields)."""
m = re.match(r"^---\n(.*?)\n---\n", skill_text, re.DOTALL)
assert m, "SKILL.md must open with '---' delimited YAML frontmatter"
fm: dict[str, str] = {}
for line in m.group(1).splitlines():
if line.startswith((" ", "\t")) or ":" not in line:
continue # nested metadata keys — not needed here
key, _, value = line.partition(":")
fm[key.strip()] = value.strip()
return fm
def test_skill_file_exists():
assert SKILL_MD.is_file(), f"missing {SKILL_MD}"
def test_frontmatter_parses(frontmatter: dict):
assert frontmatter.get("name") == "publish-site"
assert frontmatter.get("version"), "version field required"
assert frontmatter.get("license") == "MIT"
assert "Hermes Agent" in frontmatter.get("author", "")
def test_description_length_and_period(frontmatter: dict):
desc = frontmatter.get("description", "").strip().strip('"')
assert desc, "no description field"
assert len(desc) <= 60, f"description is {len(desc)} chars (>60): {desc!r}"
assert desc.endswith("."), "description must end with a period"
def test_platforms_list_valid(frontmatter: dict):
raw = frontmatter.get("platforms", "")
platforms = [p.strip() for p in raw.strip("[]").split(",") if p.strip()]
assert platforms, "platforms list must be non-empty"
assert set(platforms) <= VALID_PLATFORMS, f"invalid platforms: {platforms}"
# gh/wrangler/netlify are all cross-platform — the skill keeps all three.
assert set(platforms) == VALID_PLATFORMS
def test_required_sections_present(skill_text: str):
for heading in (
"## When to Use",
"## Prerequisites",
"## How to Run",
"## Quick Reference",
"## Procedure",
"## Pitfalls",
"## Verification",
):
assert heading in skill_text, f"missing section: {heading}"
def test_no_dangling_skill_view_references(skill_text: str):
"""Every skill_view(name='...') reference must target a shipped skill."""
targets = re.findall(r"skill_view\(\s*name\s*=\s*['\"]([^'\"]+)['\"]", skill_text)
for name in targets:
hits = list((REPO / "skills").glob(f"**/{name}/SKILL.md")) + list(
(REPO / "optional-skills").glob(f"**/{name}/SKILL.md")
)
assert hits, f"skill_view reference to non-shipped skill: {name}"
def test_referenced_sibling_skills_ship(skill_text: str):
"""Prose-referenced companion skills must exist in the shipped trees."""
for name in ("cloudflare-temporary-deploy",):
if name in skill_text:
hits = list((REPO / "skills").glob(f"**/{name}/SKILL.md")) + list(
(REPO / "optional-skills").glob(f"**/{name}/SKILL.md")
)
assert hits, f"referenced skill does not ship: {name}"
def test_provider_ladder_documented(skill_text: str):
"""All three rungs of the provider ladder with their deploy commands."""
assert "gh repo create" in skill_text
assert "gh-pages" in skill_text
assert "wrangler@latest pages deploy" in skill_text
assert "netlify deploy --prod" in skill_text
def test_version_before_deploy_discipline(skill_text: str):
assert "git tag" in skill_text, "deploys must be tagged"
assert "Never deploy uncommitted files" in skill_text
def test_rollback_documented(skill_text: str):
assert "Rollback" in skill_text
assert re.search(r"git checkout deploy-", skill_text), "rollback must redeploy a previous tag"
def test_secrets_never_in_repo(skill_text: str):
assert "NEVER commit secrets" in skill_text
assert ".gitignore" in skill_text
def test_spa_404_pitfall_documented(skill_text: str):
assert "404.html" in skill_text
assert "_redirects" in skill_text
def test_verification_uses_real_http_check(skill_text: str):
assert "%{http_code}" in skill_text
assert "200" in skill_text
assert "deploy log alone" in skill_text
def test_preview_before_deploy(skill_text: str):
assert "http.server" in skill_text
assert "cloudflared tunnel --url" in skill_text
assert "trycloudflare.com" in skill_text
def test_category_description_exists():
desc = REPO / "optional-skills" / "web-development" / "DESCRIPTION.md"
assert desc.is_file(), "optional web-development category needs a DESCRIPTION.md"
if __name__ == "__main__":
raise SystemExit(pytest.main([__file__, "-q"]))