feat: enhance APIRequestComponent with new output methods (#7148)
* ✨ (Research Translation Loop.spec.ts): Increase timeout value by a factor of 3 for better reliability in waiting for element to appear ✨ (chatInputOutputUser-shard-1.spec.ts): Increase timeout value by a factor of 3 for better reliability in waiting for element to appear * 🐛 (typescript_test.yml): adjust the maximum shard count to 10 to prevent exceeding the limit and optimize test execution. * 🐛 (chatInputOutputUser-shard-1.spec.ts): increase timeout for waiting for "built successfully" text to improve test reliability * ⬆️ (typescript_test.yml): increase maximum shard count to 15 for better test distribution ♻️ (Portfolio Website Code Generator.spec.ts): refactor test assertions to improve readability and maintainability * 🐛 (typescript_test.yml): adjust the maximum shard count to 10 to prevent exceeding the limit of parallel test executions * 🔧 (typescript_test.yml): Increase maximum shard count to 15 for better test distribution efficiency 🐛 (chatInputOutputUser-shard-1.spec.ts): Update timeout values for page element waits to prevent premature failures due to timing issues * templates adjustments * travel planning fix * Update Travel Planning Agents.json * fix templates * ♻️ (Youtube Analysis.spec.ts): remove unused imports and cleanup code for better readability and maintainability * json fix * fix: update simple agent template (#7081) * Update Simple Agent.json * Update Simple Agent.json * feat: update search agent template agent component (#7082) * update agent component with the latest changes * Update Search agent.json * Update Search agent.json * feat: enhance APIRequestComponent with new output methods - Refactored output methods to include `as_data` and `as_message` for better data handling. - Updated existing output method from `make_requests` to `as_data` for consistency. - Improved metadata handling by merging dictionary results and storing non-dict results as 'data'. - Added detailed docstrings for new methods to clarify their functionality. * added the updated test class * [autofix.ci] apply automated fixes * 📝 (ContentBlockDisplay.tsx): wrap headerIcon element in a span with data-testid attribute for better accessibility 📝 (DurationDisplay.tsx): add data-testid attribute to the duration display element for testing purposes 📝 (Simple Agent.spec.ts, Social Media Agent.spec.ts, generalBugs-shard-9.spec.ts): update test assertions to improve readability and accuracy 📝 (chatInputOutput.spec.ts): add a skip test annotation and a todo comment for further investigation * ✨ (typescript_test.yml): Add support for a new development suite in the test workflow ✨ (frontend): Add support for a new development suite in multiple test files * 🔧 (.github/workflows/typescript_test.yml): ensure that the SUITES variable is valid JSON format to prevent errors and improve reliability * ✨ (inputFileComponent/index.tsx): Refactor InputFileComponent to wrap Button component in a div for better structure and readability 🔧 (Vector Store.spec.ts): Add initialGPTsetup function to set up GPT environment variables for tests 🔧 (Vector Store.spec.ts): Refactor test to use initialGPTsetup function and improve readability 🔧 (add-new-api-keys.ts): Refactor addNewApiKeys function to handle multiple openai_api_key inputs 🔧 (remove-old-api-keys.ts): Refactor removeOldApiKeys function to click on the correct remove-icon-badge element * ✨ Add support for running tests in serial mode with a delay between each test 🔧 Configure tests to run with a 3-second delay between each test run 🔧 Add a 7-second delay before starting tests in userSettings.spec.ts 🔧 Add a 3-second delay before the second event delivery mode test in withEventDeliveryModes.ts * 📝 (userSettings.spec.ts): remove unnecessary console log message to improve test readability and maintainability * 📝 (deploy-dropdown.tsx): Add data-testid attribute to shareable-playground element ✨ (index.tsx): Add useGetTypes hook to fetch types data when component is fetched 🔧 (publish-flow.spec.ts): Increase timeout for page.waitForSelector and page.waitForTimeout 🔧 (Vector Store.spec.ts): Refactor code to wait for dropdown to appear and be visible 🔧 (files-page.spec.ts): Refactor tests to run serially with a delay between each test and add comments to improve readability * ✨ Add useGetTypes hook to fetch types data and support caching with checkCache option 🔧 Refactor useGetTypes hook to accept options object with checkCache property 🔧 Refactor useGetTypes hook to conditionally return cached data if available 🔧 Refactor useGetTypes hook to fetch types data with force_refresh query parameter 🔧 Refactor useGetTypes hook to handle errors and set types data 🔧 Refactor useGetTypes hook to improve query function and options handling 🔧 Refactor useGetTypes hook to optimize query function and options handling 🔧 Refactor useGetTypes hook to improve caching logic and error handling 🔧 Refactor useGetTypes hook to enhance caching mechanism and error handling 🔧 Refactor useGetTypes hook to improve data fetching and error handling 🔧 Refactor useGetTypes hook to optimize data fetching and error handling * ✨ (Vector Store.spec.ts): Remove unnecessary loadingOptions check and expectation ♻️ (withEventDeliveryModes.ts): Refactor withEventDeliveryModes function to accept a timeout parameter for better flexibility * ⚡️ (Vector Store.spec.ts): increase timeout for page.waitForTimeout from 2000ms to 10000ms to improve test stability and reliability * update pokedex agent template * ✨ (publish-flow.spec.ts): Remove unnecessary development tag from test description ✨ (Simple Agent.spec.ts, Social Media Agent.spec.ts): Remove unnecessary development tag from test description ✨ (Vector Store.spec.ts): Change withEventDeliveryModes to test for better test organization 🔧 (chatInputOutput.spec.ts): Refactor test description and remove unnecessary development tag ✨ (files-page.spec.ts): Remove unnecessary development tag from test descriptions ✨ (userSettings.spec.ts): Remove unnecessary development tag from test description * formatting json * ✨ (Vector Store.spec.ts): Add new integration test withEventDeliveryModes for Vector Store RAG 🔧 (Vector Store.spec.ts): Update timeout values in test functions to improve test performance and reliability * 📝 (Text Sentiment Analysis.json): Update JSON file to have consistent formatting and structure for output_types and inputTypes arrays 📝 (Text Sentiment Analysis.spec.ts): Refactor integration test for Text Sentiment Analysis to improve readability and maintainability * ✨ (PageComponent/index.tsx): Update minZoom and maxZoom values for better user experience 🐛 (upload-file.ts): Fix missing await keyword before clicking on an element * 🐛 (PageComponent/index.tsx): fix minZoom value to 0.2 for consistency with fitViewOptions and improve user experience * ✨ (dropdownComponent.spec.ts): add delay before checking dropdown value to ensure it has updated properly ✨ (dropdownComponent.spec.ts): add delay before interacting with more options modal to ensure it has loaded ✨ (floatComponent.spec.ts): add delay after clicking add button to wait for API request to complete --------- Co-authored-by: cristhianzl <cristhian.lousa@gmail.com> Co-authored-by: Edwin Jose <edwin.jose@datastax.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
ec78119b3a
commit
44254206b8
30 changed files with 1183 additions and 727 deletions
|
|
@ -1,6 +1,5 @@
|
|||
import tempfile
|
||||
from pathlib import Path
|
||||
from unittest.mock import Mock
|
||||
from unittest.mock import patch
|
||||
|
||||
import aiofiles
|
||||
import aiofiles.os
|
||||
|
|
@ -8,172 +7,306 @@ import httpx
|
|||
import pytest
|
||||
import respx
|
||||
from httpx import Response
|
||||
from langflow.components import data
|
||||
from langflow.components.data import APIRequestComponent
|
||||
from langflow.schema import Data, DataFrame, Message
|
||||
|
||||
from tests.base import ComponentTestBaseWithoutClient
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def api_request():
|
||||
# This fixture provides an instance of APIRequest for each test case
|
||||
return data.APIRequestComponent()
|
||||
class TestAPIRequestComponent(ComponentTestBaseWithoutClient):
|
||||
@pytest.fixture
|
||||
def component_class(self):
|
||||
"""Return the component class to test."""
|
||||
return APIRequestComponent
|
||||
|
||||
@pytest.fixture
|
||||
def default_kwargs(self):
|
||||
"""Return the default kwargs for the component."""
|
||||
return {
|
||||
"urls": ["https://example.com/api/test"],
|
||||
"method": "GET",
|
||||
"headers": [],
|
||||
"body": [],
|
||||
"timeout": 5,
|
||||
"follow_redirects": True,
|
||||
"save_to_file": False,
|
||||
"include_httpx_metadata": False,
|
||||
"use_curl": False,
|
||||
"curl": "",
|
||||
}
|
||||
|
||||
def test_parse_curl(api_request):
|
||||
# Arrange
|
||||
field_value = (
|
||||
"curl -X GET https://example.com/api/test -H 'Content-Type: application/json' -d '{\"key\": \"value\"}'"
|
||||
)
|
||||
build_config = {
|
||||
"method": {"value": ""},
|
||||
"urls": {"value": []},
|
||||
"headers": {},
|
||||
"body": {},
|
||||
}
|
||||
# Act
|
||||
new_build_config = api_request.parse_curl(field_value, build_config.copy())
|
||||
@pytest.fixture
|
||||
def file_names_mapping(self):
|
||||
"""Return an empty list since this component doesn't have version-specific files."""
|
||||
return []
|
||||
|
||||
# Assert
|
||||
assert new_build_config["method"]["value"] == "GET"
|
||||
assert new_build_config["urls"]["value"] == ["https://example.com/api/test"]
|
||||
assert new_build_config["headers"]["value"] == [{"key": "Content-Type", "value": "application/json"}]
|
||||
assert new_build_config["body"]["value"] == [{"key": "key", "value": "value"}]
|
||||
@pytest.fixture
|
||||
async def component(self, component_class, default_kwargs):
|
||||
"""Return a component instance."""
|
||||
return component_class(**default_kwargs)
|
||||
|
||||
async def test_parse_curl(self, component):
|
||||
# Test basic curl command parsing
|
||||
curl_cmd = (
|
||||
"curl -X GET https://example.com/api/test -H 'Content-Type: application/json' -d '{\"key\": \"value\"}'"
|
||||
)
|
||||
build_config = {
|
||||
"method": {"value": ""},
|
||||
"urls": {"value": []},
|
||||
"headers": {},
|
||||
"body": {},
|
||||
}
|
||||
new_build_config = component.parse_curl(curl_cmd, build_config.copy())
|
||||
|
||||
# HTTPx Metadata testing
|
||||
@pytest.mark.parametrize(
|
||||
("include_metadata", "expected_properties"),
|
||||
[
|
||||
(False, {"source", "result"}),
|
||||
(True, {"source", "result", "headers", "status_code", "response_headers", "redirection_history"}),
|
||||
],
|
||||
)
|
||||
@respx.mock
|
||||
async def test_httpx_metadata_behavior(api_request, include_metadata, expected_properties):
|
||||
# Mocking a successful GET request with headers and a redirection
|
||||
url = "https://example.com/api/test"
|
||||
redirected_url = "https://example.com/api/redirect"
|
||||
response_content = {"key": "value"}
|
||||
respx.get(url).mock(return_value=Response(303, headers={"Location": redirected_url}))
|
||||
respx.get(redirected_url).mock(
|
||||
return_value=Response(200, json=response_content, headers={"Custom-Header": "HeaderValue"})
|
||||
)
|
||||
assert new_build_config["method"]["value"] == "GET"
|
||||
assert new_build_config["urls"]["value"] == ["https://example.com/api/test"]
|
||||
assert new_build_config["headers"]["value"] == [{"key": "Content-Type", "value": "application/json"}]
|
||||
assert new_build_config["body"]["value"] == [{"key": "key", "value": "value"}]
|
||||
|
||||
# Make the request
|
||||
result = await api_request.make_request(
|
||||
client=httpx.AsyncClient(),
|
||||
method="GET",
|
||||
url=url,
|
||||
save_to_file=False,
|
||||
include_httpx_metadata=include_metadata,
|
||||
)
|
||||
@respx.mock
|
||||
async def test_make_request_success(self, component):
|
||||
# Test successful request with JSON response
|
||||
url = "https://example.com/api/test"
|
||||
response_data = {"key": "value"}
|
||||
respx.get(url).mock(return_value=Response(200, json=response_data))
|
||||
|
||||
# Check returned metadata
|
||||
metadata = result.data
|
||||
assert set(metadata.keys()) == expected_properties, f"Unexpected properties: {set(metadata.keys())}"
|
||||
|
||||
if include_metadata:
|
||||
# Validate individual fields
|
||||
assert metadata["source"] == url
|
||||
assert metadata["headers"] is None
|
||||
assert metadata["status_code"] == 200
|
||||
assert metadata["response_headers"]["custom-header"] == "HeaderValue"
|
||||
|
||||
# Validate redirection history
|
||||
assert metadata["redirection_history"] == [{"url": redirected_url, "status_code": 303}], (
|
||||
"Redirection history is incorrect"
|
||||
result = await component.make_request(
|
||||
client=httpx.AsyncClient(),
|
||||
method="GET",
|
||||
url=url,
|
||||
)
|
||||
|
||||
# Validate result
|
||||
assert metadata["result"] == response_content, "Response content mismatch"
|
||||
assert isinstance(result, Data)
|
||||
assert result.data["source"] == url
|
||||
assert "key" in result.data
|
||||
assert result.data["key"] == "value"
|
||||
|
||||
@respx.mock
|
||||
async def test_make_request_with_metadata(self, component):
|
||||
# Test request with metadata included
|
||||
url = "https://example.com/api/test"
|
||||
headers = {"Custom-Header": "Value"}
|
||||
response_data = {"key": "value"}
|
||||
respx.get(url).mock(return_value=Response(200, json=response_data, headers=headers))
|
||||
|
||||
# Save to File testing
|
||||
@pytest.mark.parametrize(
|
||||
("save_to_file", "expected_properties"),
|
||||
[
|
||||
(False, {"source", "result"}),
|
||||
(True, {"source", "file_path"}),
|
||||
],
|
||||
)
|
||||
@respx.mock
|
||||
async def test_save_to_file_behavior(api_request, save_to_file, expected_properties):
|
||||
# Mocking a successful GET request with a response body
|
||||
url = "https://example.com/api/test"
|
||||
response_content = "Test response content"
|
||||
respx.get(url).mock(return_value=Response(200, content=response_content))
|
||||
result = await component.make_request(
|
||||
client=httpx.AsyncClient(),
|
||||
method="GET",
|
||||
url=url,
|
||||
include_httpx_metadata=True,
|
||||
)
|
||||
|
||||
# Make the request
|
||||
result = await api_request.make_request(
|
||||
client=httpx.AsyncClient(),
|
||||
method="GET",
|
||||
url=url,
|
||||
save_to_file=save_to_file,
|
||||
)
|
||||
assert isinstance(result, Data)
|
||||
assert result.data["source"] == url
|
||||
assert result.data["status_code"] == 200
|
||||
assert result.data["response_headers"]["custom-header"] == "Value"
|
||||
|
||||
# Check returned metadata
|
||||
metadata = result.data
|
||||
assert set(metadata.keys()) == expected_properties, (
|
||||
f"Unexpected properties: {set(metadata.keys())}. Raw result: {result.data}"
|
||||
)
|
||||
@respx.mock
|
||||
async def test_make_request_save_to_file(self, component):
|
||||
# Test saving response to file
|
||||
url = "https://example.com/api/test"
|
||||
content = "Test content"
|
||||
respx.get(url).mock(return_value=Response(200, text=content))
|
||||
|
||||
if save_to_file:
|
||||
# Validate that file_path exists in metadata
|
||||
assert "file_path" in metadata, "file_path is missing in metadata"
|
||||
file_path = metadata["file_path"]
|
||||
result = await component.make_request(
|
||||
client=httpx.AsyncClient(),
|
||||
method="GET",
|
||||
url=url,
|
||||
save_to_file=True,
|
||||
)
|
||||
|
||||
# Validate that the file exists and its content matches the response
|
||||
assert await aiofiles.os.path.exists(file_path), "Saved file does not exist"
|
||||
assert isinstance(result, Data)
|
||||
assert "file_path" in result.data
|
||||
file_path = Path(result.data["file_path"])
|
||||
|
||||
# Use async file operations
|
||||
assert await aiofiles.os.path.exists(file_path)
|
||||
async with aiofiles.open(file_path) as f:
|
||||
file_content = await f.read()
|
||||
assert file_content == response_content, "File content does not match response content"
|
||||
saved_content = await f.read()
|
||||
assert saved_content == content
|
||||
|
||||
# Cleanup the file
|
||||
# Cleanup using async operation
|
||||
await aiofiles.os.remove(file_path)
|
||||
else:
|
||||
# Validate that result exists in metadata
|
||||
assert "result" in metadata, "result is missing in metadata"
|
||||
assert metadata["result"] == response_content.encode("utf-8"), "Response content mismatch in metadata"
|
||||
|
||||
@respx.mock
|
||||
async def test_make_request_binary_response(self, component):
|
||||
# Test handling binary response
|
||||
url = "https://example.com/api/binary"
|
||||
binary_content = b"Binary content"
|
||||
headers = {"Content-Type": "application/octet-stream"}
|
||||
respx.get(url).mock(return_value=Response(200, content=binary_content, headers=headers))
|
||||
|
||||
async def test_response_info_binary_content(api_request):
|
||||
response = Mock()
|
||||
response.headers = {"Content-Type": "application/octet-stream"}
|
||||
is_binary, file_path = await api_request._response_info(response, with_file_path=False)
|
||||
assert is_binary is True
|
||||
assert file_path is None
|
||||
result = await component.make_request(
|
||||
client=httpx.AsyncClient(),
|
||||
method="GET",
|
||||
url=url,
|
||||
)
|
||||
|
||||
assert isinstance(result, Data)
|
||||
assert result.data["source"] == url
|
||||
assert result.data["data"] == binary_content
|
||||
|
||||
async def test_response_info_non_binary_content(api_request):
|
||||
response = Mock()
|
||||
response.headers = {"Content-Type": "text/plain"}
|
||||
is_binary, file_path = await api_request._response_info(response, with_file_path=False)
|
||||
assert is_binary is False
|
||||
assert file_path is None
|
||||
@respx.mock
|
||||
async def test_make_request_timeout(self, component):
|
||||
# Test request timeout
|
||||
url = "https://example.com/api/test"
|
||||
respx.get(url).mock(side_effect=httpx.TimeoutException("Request timed out"))
|
||||
|
||||
result = await component.make_request(
|
||||
client=httpx.AsyncClient(),
|
||||
method="GET",
|
||||
url=url,
|
||||
timeout=1,
|
||||
)
|
||||
|
||||
async def test_response_info_filename_from_content_disposition(api_request):
|
||||
response = Mock()
|
||||
response.headers = {
|
||||
"Content-Disposition": 'attachment; filename="thisfile.txt"',
|
||||
"Content-Type": "text/plain",
|
||||
}
|
||||
response.request = Mock()
|
||||
response.request.url = "https://example.com/testfile"
|
||||
assert isinstance(result, Data)
|
||||
assert result.data["status_code"] == 408
|
||||
assert result.data["error"] == "Request timed out"
|
||||
|
||||
is_binary, file_path = await api_request._response_info(response, with_file_path=True)
|
||||
@respx.mock
|
||||
async def test_make_request_with_redirects(self, component):
|
||||
# Test handling redirects
|
||||
url = "https://example.com/api/test"
|
||||
redirect_url = "https://example.com/api/redirect"
|
||||
final_data = {"key": "value"}
|
||||
|
||||
assert is_binary is False
|
||||
assert file_path.parent == Path(tempfile.gettempdir()) / "APIRequestComponent"
|
||||
assert file_path.name.endswith("thisfile.txt")
|
||||
respx.get(url).mock(return_value=Response(303, headers={"Location": redirect_url}))
|
||||
respx.get(redirect_url).mock(return_value=Response(200, json=final_data))
|
||||
|
||||
result = await component.make_request(
|
||||
client=httpx.AsyncClient(),
|
||||
method="GET",
|
||||
url=url,
|
||||
include_httpx_metadata=True,
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
async def test_response_info_default_filename(api_request):
|
||||
response = Mock()
|
||||
response.headers = {"Content-Type": "text/plain"}
|
||||
response.request = Mock()
|
||||
response.request.url = "https://example.com/testfile"
|
||||
assert isinstance(result, Data)
|
||||
assert result.data["source"] == url
|
||||
assert result.data["status_code"] == 200
|
||||
assert result.data["redirection_history"] == [{"url": redirect_url, "status_code": 303}]
|
||||
|
||||
is_binary, file_path = await api_request._response_info(response, with_file_path=True)
|
||||
async def test_process_headers(self, component):
|
||||
# Test header processing
|
||||
headers_list = [
|
||||
{"key": "Content-Type", "value": "application/json"},
|
||||
{"key": "Authorization", "value": "Bearer token"},
|
||||
]
|
||||
processed = component._process_headers(headers_list)
|
||||
assert processed == {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer token",
|
||||
}
|
||||
|
||||
assert is_binary is False
|
||||
assert file_path.parent == Path(tempfile.gettempdir()) / "APIRequestComponent"
|
||||
assert file_path.name.endswith("testfile.txt")
|
||||
# Test invalid headers
|
||||
assert component._process_headers(None) == {}
|
||||
assert component._process_headers([{"invalid": "format"}]) == {}
|
||||
|
||||
async def test_process_body(self, component):
|
||||
# Test body processing
|
||||
# Test dictionary body
|
||||
dict_body = {"key": "value", "nested": {"inner": "value"}}
|
||||
assert component._process_body(dict_body) == dict_body
|
||||
|
||||
# Test string body
|
||||
json_str = '{"key": "value"}'
|
||||
assert component._process_body(json_str) == {"key": "value"}
|
||||
|
||||
# Test list body
|
||||
list_body = [{"key": "key1", "value": "value1"}, {"key": "key2", "value": "value2"}]
|
||||
assert component._process_body(list_body) == {"key1": "value1", "key2": "value2"}
|
||||
|
||||
# Test invalid body
|
||||
assert component._process_body(None) == {}
|
||||
assert component._process_body([{"invalid": "format"}]) == {}
|
||||
|
||||
async def test_add_query_params(self, component):
|
||||
# Test query parameter handling
|
||||
url = "https://example.com/api/test"
|
||||
params = {"param1": "value1", "param2": "value2"}
|
||||
result = component.add_query_params(url, params)
|
||||
assert "param1=value1" in result
|
||||
assert "param2=value2" in result
|
||||
|
||||
# Test with existing query params
|
||||
url_with_params = "https://example.com/api/test?existing=true"
|
||||
result = component.add_query_params(url_with_params, params)
|
||||
assert "existing=true" in result
|
||||
assert "param1=value1" in result
|
||||
assert "param2=value2" in result
|
||||
|
||||
async def test_output_formats(self, component):
|
||||
# Test different output formats
|
||||
with patch.object(component, "make_requests") as mock_make_requests:
|
||||
mock_make_requests.return_value = [Data(data={"key": "value"})]
|
||||
|
||||
# Test DataFrame output
|
||||
df_result = await component.as_dataframe()
|
||||
assert isinstance(df_result, DataFrame)
|
||||
|
||||
# Test Message output
|
||||
msg_result = await component.as_message()
|
||||
assert isinstance(msg_result, Message)
|
||||
|
||||
# Test Data output
|
||||
data_result = await component.as_data()
|
||||
assert isinstance(data_result, Data)
|
||||
assert isinstance(data_result.data["output"], list)
|
||||
|
||||
async def test_invalid_urls(self, component):
|
||||
# Test invalid URL handling
|
||||
component.urls = ["not_a_valid_url"]
|
||||
with pytest.raises(ValueError, match="Invalid URLs provided"):
|
||||
await component.make_requests()
|
||||
|
||||
async def test_update_build_config(self, component):
|
||||
# Test build config updates
|
||||
build_config = {
|
||||
"method": {"value": "GET", "advanced": False},
|
||||
"urls": {"value": [], "advanced": False},
|
||||
"headers": {"value": [], "advanced": True},
|
||||
"body": {"value": [], "advanced": True},
|
||||
"use_curl": {"value": False, "advanced": False},
|
||||
"curl": {"value": "", "advanced": True},
|
||||
"timeout": {"value": 5, "advanced": True},
|
||||
"follow_redirects": {"value": True, "advanced": True},
|
||||
"save_to_file": {"value": False, "advanced": True},
|
||||
"include_httpx_metadata": {"value": False, "advanced": True},
|
||||
"query_params": {"value": {}, "advanced": True},
|
||||
}
|
||||
|
||||
# Test curl mode update
|
||||
updated = component.update_build_config(
|
||||
build_config=build_config.copy(), field_value=True, field_name="use_curl"
|
||||
)
|
||||
assert updated["curl"]["advanced"] is False
|
||||
assert updated["urls"]["advanced"] is True
|
||||
|
||||
# Test method update
|
||||
updated = component.update_build_config(
|
||||
build_config=build_config.copy(), field_value="POST", field_name="method"
|
||||
)
|
||||
assert updated["body"]["advanced"] is False
|
||||
|
||||
@respx.mock
|
||||
async def test_error_handling(self, component):
|
||||
# Test various error scenarios
|
||||
url = "https://example.com/api/test"
|
||||
|
||||
# Test connection error
|
||||
respx.get(url).mock(side_effect=httpx.ConnectError("Connection failed"))
|
||||
result = await component.make_request(
|
||||
client=httpx.AsyncClient(),
|
||||
method="GET",
|
||||
url=url,
|
||||
)
|
||||
assert result.data["status_code"] == 500
|
||||
assert "Connection failed" in result.data["error"]
|
||||
|
||||
# Test invalid method
|
||||
with pytest.raises(ValueError, match="Unsupported method"):
|
||||
await component.make_request(
|
||||
client=httpx.AsyncClient(),
|
||||
method="INVALID",
|
||||
url=url,
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue