fix: address code review issues in flow-to-library sync
- Fix sync trigger: only fire on publish transition, not every PUT - Add TestSyncOnPublish integration tests (2 tests, 16 total passing) - Add group_label to frontend StepContent interface - Guard Library Visibility select to procedure_step nodes only - Block API edits to flow-synced steps (400 read-only guard) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -138,3 +138,79 @@ class TestExtractStepsForSync:
|
||||
}
|
||||
results = list(extract_steps_for_sync(tree_structure, tree_type='maintenance'))
|
||||
assert len(results) == 1
|
||||
|
||||
|
||||
class TestSyncOnPublish:
|
||||
"""Integration tests — sync triggered by publishing a tree."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_publishing_procedural_tree_creates_library_steps(
|
||||
self, client, auth_headers
|
||||
):
|
||||
# Create a procedural tree with two steps
|
||||
tree_resp = await client.post("/api/v1/trees", json={
|
||||
"name": "Test Procedure",
|
||||
"tree_type": "procedural",
|
||||
"status": "draft",
|
||||
"tree_structure": {
|
||||
"steps": [
|
||||
{"id": "step_1", "type": "procedure_step",
|
||||
"title": "First step", "description": "Do this first"},
|
||||
{"id": "step_2", "type": "procedure_step",
|
||||
"title": "Second step", "description": "Do this second"},
|
||||
{"id": "end_1", "type": "procedure_end", "title": "Done"},
|
||||
]
|
||||
}
|
||||
}, headers=auth_headers)
|
||||
assert tree_resp.status_code == 201
|
||||
tree_id = tree_resp.json()["id"]
|
||||
|
||||
# Publish the tree
|
||||
pub_resp = await client.put(f"/api/v1/trees/{tree_id}", json={"status": "published"}, headers=auth_headers)
|
||||
assert pub_resp.status_code == 200
|
||||
|
||||
# Check library has synced entries
|
||||
lib_resp = await client.get("/api/v1/steps", headers=auth_headers)
|
||||
assert lib_resp.status_code == 200
|
||||
steps = lib_resp.json()
|
||||
synced = [s for s in steps if s.get("is_flow_synced")]
|
||||
assert len(synced) == 2
|
||||
titles = {s["title"] for s in synced}
|
||||
assert "First step" in titles
|
||||
assert "Second step" in titles
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_republishing_updates_existing_library_steps(
|
||||
self, client, auth_headers
|
||||
):
|
||||
# Create a draft tree first, then publish
|
||||
tree_resp = await client.post("/api/v1/trees", json={
|
||||
"name": "Update Test",
|
||||
"tree_type": "procedural",
|
||||
"status": "draft",
|
||||
"tree_structure": {"steps": [
|
||||
{"id": "step_1", "type": "procedure_step",
|
||||
"title": "Original title", "description": "Original desc"},
|
||||
{"id": "end_1", "type": "procedure_end", "title": "Done"},
|
||||
]}
|
||||
}, headers=auth_headers)
|
||||
tree_id = tree_resp.json()["id"]
|
||||
first_pub = await client.put(f"/api/v1/trees/{tree_id}", json={"status": "published"}, headers=auth_headers)
|
||||
assert first_pub.status_code == 200
|
||||
|
||||
# Republish with updated step title
|
||||
second_pub = await client.put(f"/api/v1/trees/{tree_id}", json={
|
||||
"tree_structure": {"steps": [
|
||||
{"id": "step_1", "type": "procedure_step",
|
||||
"title": "Updated title", "description": "Updated desc"},
|
||||
{"id": "end_1", "type": "procedure_end", "title": "Done"},
|
||||
]},
|
||||
"status": "published"
|
||||
}, headers=auth_headers)
|
||||
assert second_pub.status_code == 200
|
||||
|
||||
# Check library shows updated title (not a duplicate)
|
||||
lib_resp = await client.get("/api/v1/steps", headers=auth_headers)
|
||||
synced = [s for s in lib_resp.json() if s.get("is_flow_synced")]
|
||||
assert len(synced) == 1
|
||||
assert synced[0]["title"] == "Updated title"
|
||||
|
||||
Reference in New Issue
Block a user