tests/gateway/test_wecom.py::TestWeComRequirements::test_returns_false_without_aiohttp tests/gateway/test_wecom.py::TestWeComRequirements::test_returns_false_without_httpx tests/gateway/test_wecom.py::TestWeComRequirements::test_returns_true_when_available tests/gateway/test_wecom.py::TestWeComAdapterInit::test_declares_non_editable_message_capability tests/gateway/test_wecom.py::TestWeComAdapterInit::test_reads_config_from_extra tests/gateway/test_wecom.py::TestWeComAdapterInit::test_falls_back_to_env_vars tests/gateway/test_wecom.py::TestWeComConnect::test_connect_records_missing_credentials tests/gateway/test_wecom.py::TestWeComConnect::test_connect_records_handshake_failure_details tests/gateway/test_wecom.py::TestWeComQrScan::test_qr_scan_timeout_uses_monotonic_clock tests/gateway/test_wecom.py::TestWeComReplyMode::test_send_uses_passive_reply_markdown_when_reply_context_exists tests/gateway/test_wecom.py::TestWeComReplyMode::test_send_image_file_uses_passive_reply_media_when_reply_context_exists tests/gateway/test_wecom.py::TestExtractText::test_extracts_plain_text tests/gateway/test_wecom.py::TestExtractText::test_extracts_mixed_text tests/gateway/test_wecom.py::TestExtractText::test_extracts_voice_and_quote tests/gateway/test_wecom.py::TestCallbackDispatch::test_dispatch_accepts_new_and_legacy_callback_cmds[aibot_msg_callback] tests/gateway/test_wecom.py::TestCallbackDispatch::test_dispatch_accepts_new_and_legacy_callback_cmds[aibot_callback] tests/gateway/test_wecom.py::TestPolicyHelpers::test_dm_allowlist tests/gateway/test_wecom.py::TestPolicyHelpers::test_dm_allowlist_honors_env_only_allowed_users tests/gateway/test_wecom.py::TestPolicyHelpers::test_dm_allowlist_extra_takes_precedence_over_env tests/gateway/test_wecom.py::TestPolicyHelpers::test_group_allowlist_and_per_group_sender_allowlist tests/gateway/test_wecom.py::TestMediaHelpers::test_detect_wecom_media_type tests/gateway/test_wecom.py::TestMediaHelpers::test_voice_non_amr_downgrades_to_file tests/gateway/test_wecom.py::TestMediaHelpers::test_oversized_file_is_rejected tests/gateway/test_wecom.py::TestMediaHelpers::test_decrypt_file_bytes_round_trip tests/gateway/test_wecom.py::TestMediaHelpers::test_load_outbound_media_rejects_placeholder_path tests/gateway/test_wecom.py::TestMediaUpload::test_upload_media_bytes_uses_sdk_sequence tests/gateway/test_wecom.py::TestMediaUpload::test_download_remote_bytes_rejects_large_content_length tests/gateway/test_wecom.py::TestMediaUpload::test_cache_media_decrypts_url_payload_before_writing tests/gateway/test_wecom.py::TestSend::test_send_uses_proactive_payload tests/gateway/test_wecom.py::TestSend::test_send_reports_wecom_errors tests/gateway/test_wecom.py::TestSend::test_send_image_falls_back_to_text_for_remote_url tests/gateway/test_wecom.py::TestSend::test_send_voice_sends_caption_and_downgrade_note tests/gateway/test_wecom.py::TestInboundMessages::test_on_message_builds_event tests/gateway/test_wecom.py::TestInboundMessages::test_on_message_preserves_quote_context tests/gateway/test_wecom.py::TestInboundMessages::test_on_message_respects_group_policy tests/gateway/test_wecom.py::TestWeComZombieSessionFix::test_adapter_generates_stable_device_id_per_instance tests/gateway/test_wecom.py::TestWeComZombieSessionFix::test_different_adapter_instances_get_distinct_device_ids tests/gateway/test_wecom.py::TestWeComZombieSessionFix::test_open_connection_includes_device_id_in_subscribe tests/gateway/test_wecom.py::TestWeComZombieSessionFix::test_on_message_caches_last_req_id_per_chat tests/gateway/test_wecom.py::TestWeComZombieSessionFix::test_on_message_does_not_cache_blocked_sender_req_id tests/gateway/test_wecom.py::TestWeComZombieSessionFix::test_remember_chat_req_id_is_bounded tests/gateway/test_wecom.py::TestWeComZombieSessionFix::test_remember_chat_req_id_ignores_empty_values tests/gateway/test_wecom.py::TestWeComZombieSessionFix::test_proactive_group_send_falls_back_to_cached_req_id tests/gateway/test_wecom.py::TestWeComZombieSessionFix::test_proactive_send_without_cached_req_id_uses_app_cmd_send tests/gateway/test_wecom.py::TestTextBatchFlushRace::test_superseded_task_does_not_pop_or_process_event tests/gateway/test_wecom.py::TestTextBatchFlushRace::test_active_task_processes_event_normally