diff --git a/api/tests/unit_tests/core/workflow/test_human_input_adapter.py b/api/tests/unit_tests/core/workflow/test_human_input_adapter.py index 1e8ee1d5240..1ce4a7a1d50 100644 --- a/api/tests/unit_tests/core/workflow/test_human_input_adapter.py +++ b/api/tests/unit_tests/core/workflow/test_human_input_adapter.py @@ -4,10 +4,12 @@ import pytest from pydantic import BaseModel from core.workflow.human_input_adapter import ( + BoundRecipient, DeliveryMethodType, EmailDeliveryConfig, EmailDeliveryMethod, EmailRecipients, + ExternalRecipient, InstantMessageDeliveryMethod, InstantMessageProvider, InstantMessageRecipientType, @@ -24,7 +26,7 @@ from graphon.nodes.base.variable_template_parser import VariableTemplateParser from graphon.runtime import VariablePool -def test_render_body_template_replaces_variable_values(): +def test_render_body_template_replaces_variable_values() -> None: config = EmailDeliveryConfig( recipients=EmailRecipients(), subject="Subject", @@ -38,14 +40,14 @@ def test_render_body_template_replaces_variable_values(): assert result == "Hello World https://example.com" -def test_render_markdown_body_renders_markdown_to_html(): +def test_render_markdown_body_renders_markdown_to_html() -> None: rendered = EmailDeliveryConfig.render_markdown_body("**Bold** and [link](https://example.com)") assert "Bold" in rendered assert 'link' in rendered -def test_render_markdown_body_sanitizes_unsafe_html(): +def test_render_markdown_body_sanitizes_unsafe_html() -> None: rendered = EmailDeliveryConfig.render_markdown_body( 'Click' ) @@ -57,7 +59,7 @@ def test_render_markdown_body_sanitizes_unsafe_html(): assert "Click" in rendered -def test_render_markdown_body_sanitizes_markdown_link_with_javascript_href(): +def test_render_markdown_body_sanitizes_markdown_link_with_javascript_href() -> None: rendered = EmailDeliveryConfig.render_markdown_body("[bad](javascript:alert(1)) and [ok](https://example.com)") assert "javascript:" not in rendered @@ -65,7 +67,7 @@ def test_render_markdown_body_sanitizes_markdown_link_with_javascript_href(): assert 'ok' in rendered -def test_render_markdown_body_does_not_allow_raw_html_tags(): +def test_render_markdown_body_does_not_allow_raw_html_tags() -> None: rendered = EmailDeliveryConfig.render_markdown_body("raw html and **markdown**") assert "" not in rendered @@ -73,7 +75,7 @@ def test_render_markdown_body_does_not_allow_raw_html_tags(): assert "markdown" in rendered -def test_render_markdown_body_supports_table_syntax(): +def test_render_markdown_body_supports_table_syntax() -> None: rendered = EmailDeliveryConfig.render_markdown_body("| h1 | h2 |\n| --- | ---: |\n| v1 | v2 |") assert "" in rendered @@ -83,7 +85,7 @@ def test_render_markdown_body_supports_table_syntax(): assert "style=" not in rendered -def test_sanitize_subject_removes_crlf(): +def test_sanitize_subject_removes_crlf() -> None: sanitized = EmailDeliveryConfig.sanitize_subject("Notice\r\nBCC:attacker@example.com") assert "\r" not in sanitized @@ -91,7 +93,7 @@ def test_sanitize_subject_removes_crlf(): assert sanitized == "Notice BCC:attacker@example.com" -def test_sanitize_subject_removes_html_tags(): +def test_sanitize_subject_removes_html_tags() -> None: sanitized = EmailDeliveryConfig.sanitize_subject("Alert") assert "<" not in sanitized @@ -169,9 +171,14 @@ def test_parse_human_input_delivery_methods_normalizes_legacy_recipient_keys() - ) assert len(methods) == 1 - assert methods[0].config.recipients.include_bound_group is True - assert methods[0].config.recipients.items[0].reference_id == "user-1" - assert methods[0].config.recipients.items[1].email == "external@example.com" + config = methods[0].config + assert isinstance(config, EmailDeliveryConfig) + assert config.recipients.include_bound_group is True + bound_recipient, external_recipient = config.recipients.items + assert isinstance(bound_recipient, BoundRecipient) + assert isinstance(external_recipient, ExternalRecipient) + assert bound_recipient.reference_id == "user-1" + assert external_recipient.email == "external@example.com" def test_parse_human_input_delivery_methods_returns_empty_for_non_lists() -> None: @@ -373,7 +380,7 @@ def test_adapt_node_config_for_graph_rewrites_nested_node_data() -> None: def test_adapt_human_input_node_data_for_graph_accepts_models() -> None: class _NodeModel(BaseModel): - delivery_methods: list[dict] + delivery_methods: list[dict[str, object]] normalized = adapt_human_input_node_data_for_graph( _NodeModel( @@ -390,11 +397,6 @@ def test_adapt_human_input_node_data_for_graph_accepts_models() -> None: assert normalized["delivery_methods"][0]["type"] == DeliveryMethodType.WEBAPP -def test_adapt_human_input_node_data_for_graph_rejects_non_mappings() -> None: - with pytest.raises(TypeError, match="human-input node data must be a mapping"): - adapt_human_input_node_data_for_graph(123) - - def test_adapt_human_input_node_data_for_graph_preserves_non_mapping_methods() -> None: normalized = adapt_human_input_node_data_for_graph( { @@ -478,15 +480,7 @@ def test_webapp_delivery_method_uses_empty_selector_set() -> None: assert method.extract_variable_selectors() == () -def test_adapt_node_data_for_graph_rejects_non_mappings() -> None: - with pytest.raises(TypeError, match="node data must be a mapping"): - adapt_node_data_for_graph(123) - - -def test_adapt_node_config_for_graph_rejects_non_mapping_and_preserves_raw_data() -> None: - with pytest.raises(TypeError, match="node config must be a mapping"): - adapt_node_config_for_graph(123) - +def test_adapt_node_config_for_graph_preserves_raw_data() -> None: assert adapt_node_config_for_graph({"data": "raw"}) == {"data": "raw"} diff --git a/api/tests/unit_tests/pyrefly.toml b/api/tests/unit_tests/pyrefly.toml index 4f8b5a9d1ae..213ebe27ef7 100644 --- a/api/tests/unit_tests/pyrefly.toml +++ b/api/tests/unit_tests/pyrefly.toml @@ -199,7 +199,6 @@ project-excludes = [ "../e2e_tests/contracts/core/workflow/nodes/http_request/test_http_request_executor.py", "../e2e_tests/contracts/core/workflow/nodes/http_request/test_http_request_node.py", "core/workflow/nodes/human_input/test_entities.py", - "core/workflow/test_human_input_adapter.py", "core/workflow/nodes/knowledge_index/test_knowledge_index_node.py", "core/workflow/nodes/knowledge_retrieval/test_knowledge_retrieval_node.py", "../helpers/unit/core/workflow/nodes/list_operator/node_spec.py",