Test utilities
ChatTestCase ¶
Base class for testing handlers against a mocked signal-cli-rest-api.
Call setup() from a fixture, register handlers on self.signal_bot and
decorate test methods with mock_chat.
Messages come from the test group (group_id, group_name) unless built
with one of the private new_* classmethods.
download_attachment_mock
instance-attribute
¶
download_attachment_mock: AsyncMock
Stub for downloading received attachments; returns empty base64 content.
receipts_mock
instance-attribute
¶
receipts_mock: AsyncMock
Stub for sending read/viewed receipts; called with a Receipt request.
remote_delete_mock
instance-attribute
¶
remote_delete_mock: RemoteDeleteMock
Stub for deleting sent messages (bot.messages.remote_delete).
send_mock
instance-attribute
¶
send_mock: SendMock
Stub for sending messages (bot.messages.send, context.send, ...).
signal_bot
instance-attribute
¶
signal_bot: SignalBot
The bot mock_chat feeds messages to; set by setup().
start_typing_mock
instance-attribute
¶
start_typing_mock: AsyncMock
Stub for showing the typing indicator.
stop_typing_mock
instance-attribute
¶
stop_typing_mock: AsyncMock
Stub for hiding the typing indicator.
make_bot ¶
make_bot() -> SignalBot
Build the bot under test; called by setup().
Override it when the bot is built by your own code, e.g. an application
object that creates its SignalBot internally, and return that
SignalBot (keeping a reference to the wrapper on self if tests need
it). Use self.config for a configuration pointing at the mocked
service. Assigning self.signal_bot directly works too.
Source code in src/signalbot/test_utils/chat_testing.py
new_edit_message
classmethod
¶
new_edit_message(
text: str,
*,
source_uuid: str,
target_sent_timestamp: int,
timestamp: int | None = None
) -> Envelope
A direct message from source_uuid editing their earlier message sent
at target_sent_timestamp; it is received as an
EditMessage by DataMessageHandlers.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The new text of the message. |
required |
source_uuid
|
str
|
The sender's uuid, i.e. the author of the edited message. |
required |
target_sent_timestamp
|
int
|
The timestamp of the message being edited. |
required |
timestamp
|
int | None
|
The timestamp of the edit; a fresh, unique one if |
None
|
Source code in src/signalbot/test_utils/chat_testing.py
new_message
classmethod
¶
A text message sent in the test group (ChatTestCase.group_id) by the
bot's own account.
This is what mock_chat turns plain str messages into.
Source code in src/signalbot/test_utils/chat_testing.py
new_private_message
classmethod
¶
new_private_message(
text: str | None,
*,
source_uuid: str | None = None,
timestamp: int | None = None,
quote: dict | None = None,
attachments: list[dict] | None = None,
view_once: bool = False
) -> Envelope
A direct (one-on-one) message to the bot, so message.is_private() is
true and it reaches handlers registered with groups=False.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str | None
|
The message text. |
required |
source_uuid
|
str | None
|
The sender's uuid; a random uuid4 if |
None
|
timestamp
|
int | None
|
The message timestamp in milliseconds; a fresh, unique one
if |
None
|
quote
|
dict | None
|
The quoted message in signal-cli's raw format, e.g.
|
None
|
attachments
|
list[dict] | None
|
Attachments in signal-cli's raw format, e.g.
|
None
|
view_once
|
bool
|
Whether the message is a view-once message. |
False
|
Source code in src/signalbot/test_utils/chat_testing.py
new_reaction_message
classmethod
¶
A reaction with emoji, sent in the test group by the bot's own
account.
Source code in src/signalbot/test_utils/chat_testing.py
new_remote_delete
classmethod
¶
new_remote_delete(
*,
source_uuid: str,
target_sent_timestamp: int,
timestamp: int | None = None
) -> Envelope
A direct message from source_uuid deleting their earlier message sent
at target_sent_timestamp; it is received by RemoteDeleteHandlers as a
RemoteDelete whose timestamp is
target_sent_timestamp.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source_uuid
|
str
|
The sender's uuid, i.e. the author of the deleted message. |
required |
target_sent_timestamp
|
int
|
The timestamp of the message being deleted. |
required |
timestamp
|
int | None
|
The timestamp of the delete itself; a fresh, unique one if
|
None
|
Source code in src/signalbot/test_utils/chat_testing.py
setup ¶
Create the bot under test as self.signal_bot (see make_bot).
Call it from a fixture, then register handlers on self.signal_bot.
Envelope ¶
Bases: str
A raw signal-cli-rest-api JSON envelope, exactly as received over the websocket.
mock_chat and
ReceiveMock.define feed an
Envelope to the bot untouched, whereas a plain str is treated as the text
of a group message and wrapped with
ChatTestCase.new_message.
Build envelopes with the ChatTestCase.new_* classmethods, or wrap your own
JSON with Envelope(json.dumps(...)).
SendMock ¶
SendMock(**kwargs: object)
Bases: _FirstArgResultsMock
Stub for sending messages.
Each call returns one response per recipient, each with a fresh, strictly
increasing timestamp (FIRST_TIMESTAMP, then +1 per response), so the
SentMessages a handler gets back can be
told apart, e.g. to match later edits, remote deletes or quotes. Setting
return_value explicitly overrides this.
Source code in src/signalbot/test_utils/chat_testing.py
ReactMock ¶
RemoteDeleteMock ¶
RemoteDeleteMock(**kwargs: object)
Bases: _FirstArgResultsMock
Stub for deleting sent messages.
Each call returns a fresh, strictly increasing timestamp (FIRST_TIMESTAMP,
then +1 per call). Setting return_value explicitly overrides this.
Source code in src/signalbot/test_utils/chat_testing.py
ReceiveMock ¶
Bases: MagicMock
define ¶
Make receive() yield messages: an
Envelope is yielded as-is, a plain str
is wrapped with ChatTestCase.new_message.
Source code in src/signalbot/test_utils/chat_testing.py
mock_chat ¶
Run the bot on messages before the decorated ChatTestCase test runs.
Each message is either an Envelope, fed to
the bot as-is, or a plain str, which becomes a group text message (see
ChatTestCase.new_message).
Before the test body runs, the signal-cli-rest-api calls are stubbed (see the
*_mock attributes on ChatTestCase), the bot
is initialised (ready handlers run, but no background producer/consumer
tasks are started) and every message is dispatched to the registered
handlers, which run to completion one at a time. The test body then inspects
the stubs, e.g. self.send_mock.results().