test: cover WhatsApp read receipts
maintainer edit: add focused coverage for the new best-effort mark_read path and remove an unused helper argument.
This commit is contained in:
@@ -499,9 +499,7 @@ class WhatsAppChannel(BaseChannel):
|
||||
self._self_jids.add(jid)
|
||||
self._self_jids.add(_bare_jid(jid))
|
||||
|
||||
async def _send_read_receipt(
|
||||
self, client: Any, info: Any, source: Any, message_id: str
|
||||
) -> None:
|
||||
async def _send_read_receipt(self, client: Any, source: Any, message_id: str) -> None:
|
||||
"""Send a read receipt (blue double-check) for an incoming message.
|
||||
|
||||
Best-effort: any failure is logged at debug level and swallowed so it
|
||||
@@ -559,7 +557,7 @@ class WhatsAppChannel(BaseChannel):
|
||||
self._processed_message_ids.popitem(last=False)
|
||||
|
||||
# Mark the incoming message as read (blue double-check). Best-effort.
|
||||
await self._send_read_receipt(client, info, source, message_id)
|
||||
await self._send_read_receipt(client, source, message_id)
|
||||
|
||||
participant_jid = _normalize_jid(_safe_attr(source, "Sender"))
|
||||
sender_alt_jid = _normalize_jid(_safe_attr(source, "SenderAlt"))
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import types
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
|
||||
@@ -86,6 +88,23 @@ def _patch_neonize_api(monkeypatch) -> None:
|
||||
)
|
||||
|
||||
|
||||
def _patch_receipt_type(monkeypatch):
|
||||
neonize = types.ModuleType("neonize")
|
||||
utils = types.ModuleType("neonize.utils")
|
||||
enum = types.ModuleType("neonize.utils.enum")
|
||||
|
||||
class ReceiptType:
|
||||
READ = "read"
|
||||
|
||||
enum.ReceiptType = ReceiptType
|
||||
neonize.utils = utils
|
||||
utils.enum = enum
|
||||
monkeypatch.setitem(sys.modules, "neonize", neonize)
|
||||
monkeypatch.setitem(sys.modules, "neonize.utils", utils)
|
||||
monkeypatch.setitem(sys.modules, "neonize.utils.enum", enum)
|
||||
return ReceiptType
|
||||
|
||||
|
||||
class _FakeLoginClient:
|
||||
def __init__(self) -> None:
|
||||
self.handlers = {}
|
||||
@@ -301,6 +320,60 @@ async def test_group_sender_id_uses_participant_not_group_jid() -> None:
|
||||
assert kwargs["metadata"]["participant"] == "SENDERLID@lid"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_read_receipt_is_requested_once_after_dedup() -> None:
|
||||
ch = _make_channel()
|
||||
ch._send_read_receipt = AsyncMock()
|
||||
ch._handle_message = AsyncMock()
|
||||
client = SimpleNamespace(download_any=AsyncMock())
|
||||
event = _event(
|
||||
message=_Proto(conversation="hi"),
|
||||
sender=_jid("15551234567", "s.whatsapp.net"),
|
||||
)
|
||||
|
||||
await ch._handle_neonize_message(client, event)
|
||||
await ch._handle_neonize_message(client, event)
|
||||
|
||||
ch._send_read_receipt.assert_awaited_once_with(
|
||||
client,
|
||||
event.Info.MessageSource,
|
||||
"m1",
|
||||
)
|
||||
ch._handle_message.assert_awaited_once()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_send_read_receipt_uses_mark_read_and_swallows_failures(monkeypatch) -> None:
|
||||
receipt_type = _patch_receipt_type(monkeypatch)
|
||||
ch = _make_channel()
|
||||
source = _event(
|
||||
message=_Proto(conversation="hi"),
|
||||
sender=_jid("15551234567", "s.whatsapp.net"),
|
||||
).Info.MessageSource
|
||||
client = SimpleNamespace(
|
||||
mark_read=AsyncMock(),
|
||||
download_any=AsyncMock(),
|
||||
)
|
||||
|
||||
await ch._send_read_receipt(client, source, "m1")
|
||||
|
||||
client.mark_read.assert_awaited_once_with(
|
||||
"m1",
|
||||
chat=source.Chat,
|
||||
sender=source.Sender,
|
||||
receipt=receipt_type.READ,
|
||||
)
|
||||
|
||||
failing_client = SimpleNamespace(
|
||||
mark_read=AsyncMock(side_effect=RuntimeError("boom")),
|
||||
download_any=AsyncMock(),
|
||||
)
|
||||
|
||||
await ch._send_read_receipt(failing_client, source, "m2")
|
||||
|
||||
failing_client.mark_read.assert_awaited_once()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_lid_to_phone_cache_resolves_lid_only_messages() -> None:
|
||||
ch = _make_channel()
|
||||
|
||||
Reference in New Issue
Block a user