feat: enforce hard test-tier requirement across all DevPlace workflow agents and feature-builder docs

Update the feature-builder agent prompt, test-maintainer agent, and all four workflow JS files (devii-tool, endpoint, feature, job-service) to codify the DevPlace test standard as a non-optional project requirement: one test file per endpoint, directory tree mirroring the URL/source path, split into three tiers (unit, api, e2e). Add explicit Test phases to devii-tool, endpoint, feature, and job-service workflows, and embed tier-specific test instructions (path mapping, fixture choice, coverage scope) directly in each workflow's meta description and TESTS constant.
This commit is contained in:
2026-06-15 12:10:14 +00:00
parent 3c7527988e
commit e1874f9b6a
71 changed files with 2198 additions and 145 deletions
View File
+63
View File
@@ -0,0 +1,63 @@
# retoor <retoor@molodetz.nl>
from playwright.sync_api import expect
from tests.e2e.post import create_post
def _post_comment(page, body):
textarea = page.locator(".comment-form textarea[name='content']")
textarea.fill(body)
page.locator(".comment-form button:has-text('Post')").click()
comment = page.locator(f".comment-text:has-text('{body}')")
expect(comment).to_be_visible()
return comment
def _delete_comment(page, body):
wrapper = page.locator(f".comment:has(.comment-text:has-text('{body}'))").last
wrapper.locator(".comment-action-btn:has-text('Delete')").click()
page.locator(".dialog-overlay.visible .dialog-confirm").click()
def test_delete_comment_removes_it(alice):
page, _ = alice
create_post(page, "fun", "Post for delete scroll removal")
comment = _post_comment(page, "Comment that will be deleted")
_delete_comment(page, "Comment that will be deleted")
expect(comment).to_have_count(0)
def test_delete_comment_scrolls_to_previous_comment(alice):
page, _ = alice
create_post(page, "devlog", "Post for delete scroll anchor")
for index in range(6):
_post_comment(page, f"Scroll anchor comment {index}")
target = "Scroll anchor comment 5"
previous = "Scroll anchor comment 4"
previous_wrapper = page.locator(
f".comment:has(.comment-text:has-text('{previous}'))"
).last
anchor_top = previous_wrapper.evaluate(
"el => el.getBoundingClientRect().top + window.scrollY"
)
page.evaluate("window.scrollTo(0, document.body.scrollHeight)")
_delete_comment(page, target)
expect(page.locator(f".comment-text:has-text('{target}')")).to_have_count(0)
page.wait_for_function(
"expected => Math.abs(window.scrollY - expected) < 120",
arg=anchor_top,
)
expect(previous_wrapper).to_be_visible()
def test_delete_only_comment_scrolls_without_error(alice):
page, _ = alice
create_post(page, "random", "Post for delete only comment")
_post_comment(page, "Sole comment to delete")
page.evaluate("window.scrollTo(0, document.body.scrollHeight)")
_delete_comment(page, "Sole comment to delete")
expect(page.locator(".comment-text:has-text('Sole comment to delete')")).to_have_count(0)
assert page.evaluate("window.scrollY") >= 0
+54
View File
@@ -0,0 +1,54 @@
# retoor <retoor@molodetz.nl>
from playwright.sync_api import expect
from tests.conftest import BASE_URL
from tests.e2e.post import create_post
def _post_comment(page, body):
textarea = page.locator(".comment-form textarea[name='content']")
textarea.fill(body)
page.locator(".comment-form button:has-text('Post')").click()
comment = page.locator(f".comment-text:has-text('{body}')")
expect(comment).to_be_visible()
return comment
def test_inline_edit_own_comment(alice):
page, _ = alice
create_post(page, "devlog", "Post for inline comment edit")
comment = _post_comment(page, "Original comment body")
edit_btn = page.locator(".comment-action-btn:has-text('Edit')").last
expect(edit_btn).to_be_visible()
edit_btn.click()
edit_textarea = page.locator(".comment-edit-form textarea[name='content']")
expect(edit_textarea).to_be_visible()
expect(edit_textarea).to_have_value("Original comment body")
edit_textarea.fill("Edited comment body")
page.locator(".comment-edit-form button:has-text('Save')").click()
expect(page.locator(".comment-text:has-text('Edited comment body')")).to_be_visible()
expect(page.locator(".comment-text:has-text('Original comment body')")).to_have_count(0)
def test_cancel_inline_edit(alice):
page, _ = alice
create_post(page, "fun", "Post for cancel edit")
_post_comment(page, "Keep this body")
page.locator(".comment-action-btn:has-text('Edit')").last.click()
edit_textarea = page.locator(".comment-edit-form textarea[name='content']")
expect(edit_textarea).to_be_visible()
edit_textarea.fill("Discarded body")
page.locator(".comment-edit-form button:has-text('Cancel')").click()
expect(page.locator(".comment-edit-form")).to_have_count(0)
expect(page.locator(".comment-text:has-text('Keep this body')")).to_be_visible()
def test_non_owner_sees_no_edit_button(alice, bob):
page, _ = alice
create_post(page, "random", "Post owned by alice")
_post_comment(page, "Alice only comment")
post_url = page.url
bob_page, _ = bob
bob_page.goto(post_url, wait_until="domcontentloaded")
expect(bob_page.locator(".comment-text:has-text('Alice only comment')")).to_be_visible()
expect(bob_page.locator(".comment-action-btn:has-text('Edit')")).to_have_count(0)
+44
View File
@@ -569,6 +569,50 @@ def test_feed_top_authors(alice):
assert page.is_visible("text=Top Authors")
def _resources_panel(page):
return page.locator(".sidebar-card .sidebar-section").filter(
has=page.locator(".sidebar-heading:has-text('Resources')")
)
def test_feed_resources_panel_visible(alice):
page, user = alice
page.goto(f"{BASE_URL}/feed", wait_until="domcontentloaded")
panel = _resources_panel(page)
panel.wait_for(state="visible")
expect(panel.locator(".sidebar-heading")).to_have_text("Resources")
expect(panel.locator("a.sidebar-link:has-text('Docs')")).to_be_visible()
expect(panel.locator("a.sidebar-link:has-text('Issues')")).to_be_visible()
expect(panel.locator("a.sidebar-link[data-devii-open]")).to_be_visible()
def test_feed_resources_docs_link(alice):
page, user = alice
page.goto(f"{BASE_URL}/feed", wait_until="domcontentloaded")
docs = _resources_panel(page).locator("a.sidebar-link:has-text('Docs')")
assert docs.get_attribute("href") == "/docs"
docs.click()
page.wait_for_url(f"{BASE_URL}/docs", wait_until="domcontentloaded")
def test_feed_resources_issues_link(alice):
page, user = alice
page.goto(f"{BASE_URL}/feed", wait_until="domcontentloaded")
issues = _resources_panel(page).locator("a.sidebar-link:has-text('Issues')")
assert issues.get_attribute("href") == "/issues"
issues.click()
page.wait_for_url(f"{BASE_URL}/issues", wait_until="domcontentloaded")
def test_feed_resources_devii_opens_assistant(alice):
page, user = alice
page.goto(f"{BASE_URL}/feed", wait_until="domcontentloaded")
devii = _resources_panel(page).locator("a.sidebar-link[data-devii-open]")
expect(devii).to_be_visible()
assert devii.get_attribute("href") == "/devii/"
expect(devii).to_have_text(re.compile("Devii"))
def test_feed_daily_topic(alice):
page, user = alice
page.goto(f"{BASE_URL}/feed", wait_until="domcontentloaded")
+64
View File
@@ -249,3 +249,67 @@ def test_landing_page_has_unique_title(page, app_server):
page.goto(f"{BASE_URL}/", wait_until="domcontentloaded")
title = page.title()
assert title and "DevPlace" in title
def _help_section(page):
return page.locator("section.landing-help")
def test_landing_build_with_us_section(page, app_server):
page.goto(f"{BASE_URL}/", wait_until="domcontentloaded")
section = _help_section(page)
section.wait_for(state="visible", timeout=5000)
assert section.locator("h2:has-text('Build With Us')").is_visible()
assert section.locator(".landing-help-intro").is_visible()
def test_landing_help_docs_card(page, app_server):
page.goto(f"{BASE_URL}/", wait_until="domcontentloaded")
section = _help_section(page)
section.wait_for(state="visible", timeout=5000)
link = section.locator(".landing-help-card:has-text('Documentation') a.landing-help-link")
assert link.get_attribute("href") == "/docs/index.html"
def test_landing_help_api_reference_links(page, app_server):
page.goto(f"{BASE_URL}/", wait_until="domcontentloaded")
section = _help_section(page)
section.wait_for(state="visible", timeout=5000)
card = section.locator(".landing-help-card:has-text('API Reference')")
assert card.locator("a:has-text('Swagger UI')").get_attribute("href") == "/swagger"
assert card.locator("a:has-text('OpenAPI JSON')").get_attribute("href") == "/openapi.json"
def test_landing_help_issue_tracker_link(page, app_server):
page.goto(f"{BASE_URL}/", wait_until="domcontentloaded")
section = _help_section(page)
section.wait_for(state="visible", timeout=5000)
link = section.locator(".landing-help-card:has-text('Contribute') a.landing-help-link")
assert link.get_attribute("href") == "/issues"
def test_landing_help_devii_card_explained(page, app_server):
page.goto(f"{BASE_URL}/", wait_until="domcontentloaded")
section = _help_section(page)
section.wait_for(state="visible", timeout=5000)
card = section.locator(".landing-help-card:has-text('Meet Devii')")
assert card.locator("h3:has-text('Meet Devii')").is_visible()
assert "AI developer" in card.locator("p").first.text_content()
assert card.locator("a.landing-help-link").get_attribute("href") == "/devii/"
def test_landing_help_launch_devii_button(page, app_server):
page.goto(f"{BASE_URL}/", wait_until="domcontentloaded")
section = _help_section(page)
section.wait_for(state="visible", timeout=5000)
button = section.locator("button.landing-help-cta[data-devii-open]")
assert button.is_visible()
assert "Launch Devii" in button.text_content()
def test_landing_launch_devii_opens_terminal(page, app_server):
page.goto(f"{BASE_URL}/", wait_until="domcontentloaded")
section = _help_section(page)
section.wait_for(state="visible", timeout=5000)
section.locator("button.landing-help-cta[data-devii-open]").click()
page.locator("devii-terminal").wait_for(state="attached", timeout=5000)