feat: add canonical workflow prompt library to web UI (Closes #428)
Expose short copy/paste operator prompts on /prompts derived from canonical workflow files with workflow path and SHA-256 hash. Adds JSON export at /api/prompts, copy buttons, and tests. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
"""Tests for web UI prompt library (#428)."""
|
||||
import sys
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
||||
|
||||
from starlette.testclient import TestClient
|
||||
|
||||
from webui.app import create_app
|
||||
from webui.prompt_library import load_prompt_library, prompt_to_dict
|
||||
|
||||
|
||||
class TestWebuiPromptLibrary(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.client = TestClient(create_app())
|
||||
|
||||
def test_library_has_required_prompts(self):
|
||||
entries = load_prompt_library()
|
||||
slugs = {entry.slug for entry in entries}
|
||||
self.assertEqual(
|
||||
slugs,
|
||||
{
|
||||
"review-pr",
|
||||
"work-issue",
|
||||
"create-issue",
|
||||
"comment-issue",
|
||||
"cleanup",
|
||||
"audit",
|
||||
"onboarding",
|
||||
},
|
||||
)
|
||||
|
||||
def test_workflow_entries_include_hash_and_task_mode(self):
|
||||
review = next(e for e in load_prompt_library() if e.slug == "review-pr")
|
||||
self.assertEqual(
|
||||
review.workflow_path,
|
||||
"skills/llm-project-workflow/workflows/review-merge-pr.md",
|
||||
)
|
||||
self.assertEqual(review.task_mode, "review-merge-pr")
|
||||
self.assertIsNotNone(review.workflow_hash)
|
||||
self.assertGreater(len(review.workflow_hash), 12)
|
||||
self.assertIn("eligible open PR", review.prompt_text)
|
||||
|
||||
def test_comment_issue_defers_to_workflow(self):
|
||||
comment = next(e for e in load_prompt_library() if e.slug == "comment-issue")
|
||||
self.assertIn("comment_issue", comment.prompt_text)
|
||||
self.assertIn("create-issue", comment.workflow_path)
|
||||
self.assertIn("§16", comment.source_note)
|
||||
|
||||
def test_prompts_page_renders_cards_and_copy_buttons(self):
|
||||
response = self.client.get("/prompts")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
text = response.text
|
||||
self.assertIn("Prompt library", text)
|
||||
self.assertIn("review-merge-pr.md", text)
|
||||
self.assertIn("Copy prompt", text)
|
||||
self.assertIn('data-copy-target="prompt-review-pr"', text)
|
||||
self.assertNotIn("child issue", text.lower())
|
||||
|
||||
def test_api_prompts_json(self):
|
||||
response = self.client.get("/api/prompts")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
data = response.json()
|
||||
self.assertEqual(data["count"], 7)
|
||||
self.assertEqual(len(data["prompts"]), 7)
|
||||
first = data["prompts"][0]
|
||||
self.assertIn("slug", first)
|
||||
self.assertIn("prompt_text", first)
|
||||
self.assertIn("workflow_path", first)
|
||||
self.assertIn("workflow_hash", first)
|
||||
|
||||
def test_prompt_to_dict_round_trip(self):
|
||||
entry = load_prompt_library()[0]
|
||||
payload = prompt_to_dict(entry)
|
||||
self.assertEqual(payload["slug"], entry.slug)
|
||||
self.assertEqual(payload["prompt_text"], entry.prompt_text)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -30,12 +30,17 @@ class TestWebuiSkeleton(unittest.TestCase):
|
||||
self.assertIn("Read-only MVP", response.text)
|
||||
|
||||
def test_route_stubs_render(self):
|
||||
for path in ("/prompts", "/runtime", "/audit"):
|
||||
for path in ("/runtime", "/audit"):
|
||||
with self.subTest(path=path):
|
||||
response = self.client.get(path)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn("child issue", response.text.lower())
|
||||
|
||||
def test_prompts_is_implemented(self):
|
||||
response = self.client.get("/prompts")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn("Prompt library", response.text)
|
||||
|
||||
def test_projects_is_implemented(self):
|
||||
response = self.client.get("/projects")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
Reference in New Issue
Block a user