"""Phase 2 tests: kirche CustomInput* library + intake fixture flow.""" import json import sys from pathlib import Path from lfx.custom import Component REPO_ROOT = Path(__file__).resolve().parent.parent.parent sys.path.insert(0, str(REPO_ROOT / "backend" / "components")) from kirche.form_inputs import CustomInputForm # noqa: E402 FIXTURES = Path(__file__).parent / "fixtures" / "flows" FORM_FIELDS = [ "full_name", "notes", "password", "age", "amount", "newsletter", "department", "topics", "satisfaction", "attachment", ] def test_component_contract(): assert issubclass(CustomInputForm, Component) assert CustomInputForm.display_name.startswith("CustomInput") inputs = {i.name: i for i in CustomInputForm.inputs} # Ten form fields plus the hidden run-envelope plumbing input. assert sorted(n for n in inputs if n != "form_values") == sorted(FORM_FIELDS) assert inputs["form_values"].show is False outputs = {o.name: o for o in CustomInputForm.outputs} assert set(outputs) == {"form_data"} def test_collect_merges_submitted_values_over_defaults(): from lfx.schema.message import Message form = CustomInputForm() default = json.loads(form.collect().text) assert default["full_name"] == "" assert default["department"] == "Music" assert isinstance(form.collect(), Message) form.form_values = json.dumps({"full_name": "Maria", "age": 41}) merged = json.loads(form.collect().text) assert merged["full_name"] == "Maria" assert merged["age"] == 41 assert merged["department"] == "Music" # default kept # Run envelope shape {"payload": {...}} unwraps like the other components. form.form_values = json.dumps({"payload": {"notes": "hi"}}) assert json.loads(form.collect().text)["notes"] == "hi" form.form_values = "not json" assert json.loads(form.collect().text)["full_name"] == "" def test_intake_fixture_shape(): doc = json.loads((FIXTURES / "intake_form.json").read_text()) nodes = {n["id"]: n for n in doc["data"]["nodes"]} form = nodes["CustomInputForm-intake"] assert form["data"]["type"] == "CustomInputForm" assert form["data"]["node"]["display_name"].startswith("CustomInput") template = form["data"]["node"]["template"] for field in FORM_FIELDS: assert field in template, field assert template["form_values"]["show"] is False assert len(template["code"]["value"]) > 200 edges = {(e["source"], e["target"]) for e in doc["data"]["edges"]} assert ("ChatInput-entry", "CustomInputForm-intake") in edges assert ("CustomInputForm-intake", "ChatOutput-collected") in edges async def test_intake_deploy_and_run_with_values(client, lfx_server): doc = json.loads((FIXTURES / "intake_form.json").read_text()) created = await client.post("/api/flows", json={"name": "intake-e2e"}) assert created.status_code == 201, created.text flow_id = created.json()["id"] version = await client.post( f"/api/flows/{flow_id}/versions", json={"langflow_json": doc, "author": "test"}, ) assert version.status_code == 201, version.text deployed = await client.post(f"/api/flows/{flow_id}/versions/1/deploy") assert deployed.status_code == 200, deployed.text run = await client.post( f"/api/flows/{flow_id}/run", json={"input": {"full_name": "Maria Muster", "age": 41}}, ) assert run.status_code == 200, run.text assert run.json()["status"] == "completed" result = json.loads(run.json()["output"]["result"]) assert result["full_name"] == "Maria Muster" assert result["age"] == 41 assert result["department"] == "Music" # default preserved