Files
kleinanzeigen-bot/tests/unit/test_web_scraping_mixin_remoteobject.py

131 lines
5.2 KiB
Python

# SPDX-FileCopyrightText: © Jens Bergmann and contributors
# SPDX-License-Identifier: AGPL-3.0-or-later
# SPDX-ArtifactOfProjectHomePage: https://github.com/Second-Hand-Friends/kleinanzeigen-bot/
"""Unit tests for web_scraping_mixin.py RemoteObject handling."""
from unittest.mock import AsyncMock, Mock, patch
import pytest
from kleinanzeigen_bot.utils.web_scraping_mixin import WebScrapingMixin
class TestWebExecuteRemoteObjectHandling:
"""Test web_execute method with nodriver 0.47+ RemoteObject behavior."""
@pytest.mark.asyncio
async def test_web_execute_remoteobject_with_deep_serialized_value(self) -> None:
"""Test web_execute with RemoteObject that has deep_serialized_value."""
mixin = WebScrapingMixin()
# Mock RemoteObject with deep_serialized_value
mock_remote_object = Mock()
mock_remote_object.deep_serialized_value = Mock()
mock_remote_object.deep_serialized_value.value = [
["key1", "value1"],
["key2", "value2"]
]
# Mock the page evaluation to return our RemoteObject
with patch.object(mixin, "page") as mock_page:
mock_page.evaluate = AsyncMock(return_value = mock_remote_object)
result = await mixin.web_execute("window.test")
# Should convert the RemoteObject to a dict
assert result == {"key1": "value1", "key2": "value2"}
@pytest.mark.asyncio
async def test_web_execute_remoteobject_with_none_deep_serialized_value(self) -> None:
"""Test web_execute with RemoteObject that has None deep_serialized_value."""
mixin = WebScrapingMixin()
# Mock RemoteObject with None deep_serialized_value
mock_remote_object = Mock()
mock_remote_object.deep_serialized_value = None
with patch.object(mixin, "page") as mock_page:
mock_page.evaluate = AsyncMock(return_value = mock_remote_object)
result = await mixin.web_execute("window.test")
# Should return the original RemoteObject
assert result is mock_remote_object
@pytest.mark.asyncio
async def test_web_execute_remoteobject_with_non_list_serialized_data(self) -> None:
"""Test web_execute with RemoteObject that has non-list serialized data."""
mixin = WebScrapingMixin()
# Mock RemoteObject with non-list serialized data
mock_remote_object = Mock()
mock_remote_object.deep_serialized_value = Mock()
mock_remote_object.deep_serialized_value.value = {"direct": "dict"}
with patch.object(mixin, "page") as mock_page:
mock_page.evaluate = AsyncMock(return_value = mock_remote_object)
result = await mixin.web_execute("window.test")
# Should return the serialized data directly
assert result == {"direct": "dict"}
@pytest.mark.asyncio
async def test_web_execute_remoteobject_with_none_serialized_data(self) -> None:
"""Test web_execute with RemoteObject that has None serialized data."""
mixin = WebScrapingMixin()
# Mock RemoteObject with None serialized data
mock_remote_object = Mock()
mock_remote_object.deep_serialized_value = Mock()
mock_remote_object.deep_serialized_value.value = None
with patch.object(mixin, "page") as mock_page:
mock_page.evaluate = AsyncMock(return_value = mock_remote_object)
result = await mixin.web_execute("window.test")
# Should return the original RemoteObject
assert result is mock_remote_object
@pytest.mark.asyncio
async def test_web_execute_regular_result(self) -> None:
"""Test web_execute with regular result (no RemoteObject)."""
mixin = WebScrapingMixin()
# Mock regular result (no deep_serialized_value attribute)
mock_result = {"regular": "dict"}
with patch.object(mixin, "page") as mock_page:
mock_page.evaluate = AsyncMock(return_value = mock_result)
result = await mixin.web_execute("window.test")
# Should return the result unchanged
assert result == mock_result
@pytest.mark.asyncio
async def test_web_execute_remoteobject_conversion_exception(self) -> None:
"""Test web_execute with RemoteObject that raises exception during conversion."""
mixin = WebScrapingMixin()
# Mock RemoteObject that will raise an exception when trying to convert to dict
mock_remote_object = Mock()
mock_deep_serialized = Mock()
# Create a list-like object that raises an exception when dict() is called on it
class ExceptionRaisingList(list[str]):
def __iter__(self) -> None: # type: ignore[override]
raise ValueError("Simulated conversion error")
mock_deep_serialized.value = ExceptionRaisingList([["key", "value"]]) # type: ignore[list-item]
mock_remote_object.deep_serialized_value = mock_deep_serialized
with patch.object(mixin, "page") as mock_page:
mock_page.evaluate = AsyncMock(return_value = mock_remote_object)
result = await mixin.web_execute("window.test")
# Should return the original RemoteObject when conversion fails
assert result is mock_remote_object