Files
ai-job-search/tests/test_html_report_command.py
T
Yuan Chen 848eddbecc feat(html-report): add /html-report command for application tracker dashboard (#131)
Self-contained HTML dashboard generated from job_search_tracker.csv and the application archives: stat cards, status/sector/channel/funnel charts as hand-generated inline SVG (no CDN, fully offline), HTML-escaped interpolation throughout, and a filterable applications table. Includes Python guards for the command file and the reports/ gitignore rule.
2026-07-16 21:48:59 +02:00

80 lines
2.6 KiB
Python

"""Tests for the /html-report command and its gitignore rule.
Mirrors the pattern in test_security_guards.py: one class that verifies
properties of the real repo, testing the things CI would catch if the
command file or gitignore rule were wrong.
"""
import subprocess
import sys
import unittest
from pathlib import Path
try:
import yaml # noqa: F401 - only probing availability for the lint integration test
_HAVE_YAML = True
except ImportError:
_HAVE_YAML = False
REPO_ROOT = Path(__file__).resolve().parent.parent
COMMAND_FILE = REPO_ROOT / ".claude" / "commands" / "html-report.md"
LINT_SCRIPT = REPO_ROOT / "tools" / "lint_skills.py"
GITIGNORE = REPO_ROOT / ".gitignore"
class HtmlReportCommandFileTests(unittest.TestCase):
"""Structural checks on the command file itself."""
def test_command_file_exists(self):
self.assertTrue(COMMAND_FILE.exists(), f"{COMMAND_FILE} not found")
def test_command_file_starts_with_correct_header(self):
"""lint_skills.py rejects command files that don't start with '# /<name>'."""
text = COMMAND_FILE.read_text(encoding="utf-8")
first_line = text.lstrip().splitlines()[0]
self.assertTrue(
first_line.startswith("# /html-report"),
f"Command file must start with '# /html-report', got: {first_line!r}",
)
def test_command_file_is_non_empty(self):
text = COMMAND_FILE.read_text(encoding="utf-8").strip()
self.assertGreater(len(text), 100, "Command file appears suspiciously short")
class HtmlReportGitignoreTests(unittest.TestCase):
"""reports/ must be gitignored — it holds personal generated output."""
def test_reports_folder_is_gitignored(self):
rules = {line.strip() for line in GITIGNORE.read_text(encoding="utf-8").splitlines()}
self.assertIn(
"reports/",
rules,
"reports/ must be listed in .gitignore — generated dashboards are personal output",
)
@unittest.skipUnless(
_HAVE_YAML,
"PyYAML not installed (the CI Python-test job omits it; the lint job runs lint_skills.py directly)",
)
class HtmlReportLintIntegrationTests(unittest.TestCase):
"""lint_skills.py must pass after the command is added."""
def test_lint_passes_on_real_repo(self):
result = subprocess.run(
[sys.executable, str(LINT_SCRIPT)],
capture_output=True,
text=True,
)
self.assertEqual(
result.returncode,
0,
f"lint_skills.py failed:\n{result.stdout}{result.stderr}",
)
self.assertIn("OK", result.stdout)
if __name__ == "__main__":
unittest.main()