from unittest.mock import MagicMock, patch import pytest from scrapegraphai.graphs.search_graph import SearchGraph class TestSearchGraph: """Test class for SearchGraph""" @pytest.mark.parametrize( "urls", [["https://example.com", "https://test.com"], [], ["https://single-url.com"]], ) @patch("scrapegraphai.graphs.search_graph.BaseGraph") @patch("scrapegraphai.graphs.abstract_graph.AbstractGraph._create_llm") def test_get_considered_urls(self, mock_create_llm, mock_base_graph, urls): """ Test that get_considered_urls returns the correct list of URLs considered during the search process. """ # Arrange prompt = "Test prompt" config = {"llm": {"model": "test-model"}} # Mock the _create_llm method to return a MagicMock mock_create_llm.return_value = MagicMock() # Mock the execute method to set the final_state mock_base_graph.return_value.execute.return_value = ({"urls": urls}, {}) # Act search_graph = SearchGraph(prompt, config) search_graph.run() # Assert assert search_graph.get_considered_urls() == urls @patch("scrapegraphai.graphs.search_graph.BaseGraph") @patch("scrapegraphai.graphs.abstract_graph.AbstractGraph._create_llm") def test_run_no_answer_found(self, mock_create_llm, mock_base_graph): """ Test that the run() method returns "No answer found." when the final state doesn't contain an "answer" key. """ # Arrange prompt = "Test prompt" config = {"llm": {"model": "test-model"}} # Mock the _create_llm method to return a MagicMock mock_create_llm.return_value = MagicMock() # Mock the execute method to set the final_state without an "answer" key mock_base_graph.return_value.execute.return_value = ({"urls": []}, {}) # Act search_graph = SearchGraph(prompt, config) result = search_graph.run() # Assert assert result == "No answer found." @patch("scrapegraphai.graphs.search_graph.SearchInternetNode") @patch("scrapegraphai.graphs.search_graph.GraphIteratorNode") @patch("scrapegraphai.graphs.search_graph.MergeAnswersNode") @patch("scrapegraphai.graphs.search_graph.BaseGraph") @patch("scrapegraphai.graphs.abstract_graph.AbstractGraph._create_llm") def test_max_results_config( self, mock_create_llm, mock_base_graph, mock_merge_answers, mock_graph_iterator, mock_search_internet, ): """ Test that the max_results parameter from the config is correctly passed to the SearchInternetNode. """ # Arrange prompt = "Test prompt" max_results = 5 config = {"llm": {"model": "test-model"}, "max_results": max_results} # Act SearchGraph(prompt, config) # Assert mock_search_internet.assert_called_once() call_args = mock_search_internet.call_args assert call_args.kwargs["node_config"]["max_results"] == max_results @patch("scrapegraphai.graphs.search_graph.SearchInternetNode") @patch("scrapegraphai.graphs.search_graph.GraphIteratorNode") @patch("scrapegraphai.graphs.search_graph.MergeAnswersNode") @patch("scrapegraphai.graphs.search_graph.BaseGraph") @patch("scrapegraphai.graphs.abstract_graph.AbstractGraph._create_llm") def test_custom_search_engine_config( self, mock_create_llm, mock_base_graph, mock_merge_answers, mock_graph_iterator, mock_search_internet, ): """ Test that the custom search_engine parameter from the config is correctly passed to the SearchInternetNode. """ # Arrange prompt = "Test prompt" custom_search_engine = "custom_engine" config = {"llm": {"model": "test-model"}, "search_engine": custom_search_engine} # Act SearchGraph(prompt, config) # Assert mock_search_internet.assert_called_once() call_args = mock_search_internet.call_args assert call_args.kwargs["node_config"]["search_engine"] == custom_search_engine