Skip to content

Commit cdd631a

Browse files
committed
test: integrate DirectMessage type safety tests into tests.py
- Add ClientDirectMessageTypesTestCase to tests.py following CONTRIBUTING.md requirements - Test that DirectMessage and DirectThread fields use structured Pydantic models instead of raw dictionaries - Remove separate test file test_type_improvements.py to align with unittest framework requirements - Includes tests for MessageReactions, MessageLink, VisualMedia, LastSeenInfo, ClipsMetadata models - Validates datetime compatibility and backward compatibility with dict-style access
1 parent eda766e commit cdd631a

File tree

2 files changed

+174
-195
lines changed

2 files changed

+174
-195
lines changed

test_type_improvements.py

Lines changed: 0 additions & 195 deletions
This file was deleted.

tests.py

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,6 +1121,180 @@ def test_direct_thread_by_participants(self):
11211121
pass
11221122

11231123

1124+
class ClientDirectMessageTypesTestCase(ClientPrivateTestCase):
1125+
"""Test that DirectMessage and DirectThread fields use structured Pydantic models instead of raw dictionaries"""
1126+
1127+
def test_direct_message_reactions_model(self):
1128+
"""Test that DirectMessage.reactions field uses MessageReactions model"""
1129+
from instagrapi.types import MessageReactions, MessageReaction
1130+
from datetime import datetime
1131+
1132+
# Get some direct messages
1133+
threads = self.cl.direct_threads(amount=5)
1134+
if not threads:
1135+
self.skipTest("No direct threads available for testing")
1136+
1137+
for thread in threads:
1138+
messages = self.cl.direct_messages(thread.id, amount=10)
1139+
for message in messages:
1140+
if message.reactions:
1141+
# Test that reactions field is now a MessageReactions object
1142+
self.assertIsInstance(message.reactions, MessageReactions)
1143+
1144+
# Test that reactions have proper structure
1145+
if hasattr(message.reactions, 'emojis') and message.reactions.emojis:
1146+
for emoji_reaction in message.reactions.emojis:
1147+
self.assertIsInstance(emoji_reaction, MessageReaction)
1148+
self.assertIsInstance(emoji_reaction.emoji, str)
1149+
self.assertIsInstance(emoji_reaction.sender_id, str)
1150+
self.assertIsInstance(emoji_reaction.timestamp, datetime)
1151+
1152+
# Test backward compatibility - should still work as dict
1153+
if hasattr(message.reactions, 'likes_count'):
1154+
self.assertIsInstance(message.reactions.likes_count, int)
1155+
1156+
return # Found one message with reactions, test passed
1157+
1158+
def test_direct_message_link_model(self):
1159+
"""Test that DirectMessage.link field uses MessageLink model"""
1160+
from instagrapi.types import MessageLink, LinkContext
1161+
1162+
# Get some direct messages
1163+
threads = self.cl.direct_threads(amount=5)
1164+
if not threads:
1165+
self.skipTest("No direct threads available for testing")
1166+
1167+
for thread in threads:
1168+
messages = self.cl.direct_messages(thread.id, amount=10)
1169+
for message in messages:
1170+
if message.link:
1171+
# Test that link field is now a MessageLink object
1172+
self.assertIsInstance(message.link, MessageLink)
1173+
1174+
# Test that link has proper structure
1175+
if hasattr(message.link, 'text'):
1176+
self.assertIsInstance(message.link.text, str)
1177+
1178+
if hasattr(message.link, 'link_context') and message.link.link_context:
1179+
self.assertIsInstance(message.link.link_context, LinkContext)
1180+
if hasattr(message.link.link_context, 'link_url'):
1181+
self.assertIsInstance(message.link.link_context.link_url, str)
1182+
1183+
return # Found one message with link, test passed
1184+
1185+
def test_direct_message_visual_media_model(self):
1186+
"""Test that DirectMessage.visual_media field uses VisualMedia model"""
1187+
from instagrapi.types import VisualMedia, VisualMediaContent
1188+
1189+
# Get some direct messages
1190+
threads = self.cl.direct_threads(amount=5)
1191+
if not threads:
1192+
self.skipTest("No direct threads available for testing")
1193+
1194+
for thread in threads:
1195+
messages = self.cl.direct_messages(thread.id, amount=10)
1196+
for message in messages:
1197+
if message.visual_media:
1198+
# Test that visual_media field is now a VisualMedia object
1199+
self.assertIsInstance(message.visual_media, VisualMedia)
1200+
1201+
# Test that visual_media has proper structure
1202+
if hasattr(message.visual_media, 'media') and message.visual_media.media:
1203+
self.assertIsInstance(message.visual_media.media, VisualMediaContent)
1204+
1205+
return # Found one message with visual media, test passed
1206+
1207+
def test_direct_thread_last_seen_at_model(self):
1208+
"""Test that DirectThread.last_seen_at field uses LastSeenInfo model"""
1209+
from instagrapi.types import LastSeenInfo
1210+
from datetime import datetime
1211+
1212+
# Get some direct threads
1213+
threads = self.cl.direct_threads(amount=5)
1214+
if not threads:
1215+
self.skipTest("No direct threads available for testing")
1216+
1217+
for thread in threads:
1218+
if thread.last_seen_at:
1219+
# Test that last_seen_at is now a dict of LastSeenInfo objects
1220+
for user_id, seen_info in thread.last_seen_at.items():
1221+
self.assertIsInstance(user_id, str)
1222+
self.assertIsInstance(seen_info, LastSeenInfo)
1223+
1224+
# Test structure of LastSeenInfo
1225+
if hasattr(seen_info, 'timestamp'):
1226+
self.assertIsInstance(seen_info.timestamp, datetime)
1227+
if hasattr(seen_info, 'created_at'):
1228+
self.assertIsInstance(seen_info.created_at, datetime)
1229+
1230+
return # Found one thread with last_seen_at, test passed
1231+
1232+
def test_direct_message_clips_metadata_model(self):
1233+
"""Test that DirectMessage.clips_metadata field uses ClipsMetadata model"""
1234+
from instagrapi.types import ClipsMetadata
1235+
1236+
# Get some direct messages
1237+
threads = self.cl.direct_threads(amount=5)
1238+
if not threads:
1239+
self.skipTest("No direct threads available for testing")
1240+
1241+
for thread in threads:
1242+
messages = self.cl.direct_messages(thread.id, amount=10)
1243+
for message in messages:
1244+
if message.clips_metadata:
1245+
# Test that clips_metadata field is now a ClipsMetadata object
1246+
self.assertIsInstance(message.clips_metadata, ClipsMetadata)
1247+
1248+
return # Found one message with clips metadata, test passed
1249+
1250+
def test_thread_is_seen_datetime_compatibility(self):
1251+
"""Test that DirectThread.is_seen() works with datetime objects"""
1252+
from datetime import datetime
1253+
1254+
# Get some direct threads
1255+
threads = self.cl.direct_threads(amount=5)
1256+
if not threads:
1257+
self.skipTest("No direct threads available for testing")
1258+
1259+
for thread in threads:
1260+
if thread.last_seen_at:
1261+
# Test that is_seen method works with datetime objects
1262+
user_id = str(self.cl.user_id)
1263+
try:
1264+
is_seen = thread.is_seen(user_id)
1265+
self.assertIsInstance(is_seen, bool)
1266+
return # Successfully tested is_seen method
1267+
except Exception as e:
1268+
self.fail(f"is_seen() method failed with datetime objects: {e}")
1269+
1270+
def test_backward_compatibility_dict_access(self):
1271+
"""Test that dict-style access patterns still work for backward compatibility"""
1272+
# Get some direct messages
1273+
threads = self.cl.direct_threads(amount=5)
1274+
if not threads:
1275+
self.skipTest("No direct threads available for testing")
1276+
1277+
for thread in threads:
1278+
messages = self.cl.direct_messages(thread.id, amount=10)
1279+
for message in messages:
1280+
# Test that we can still access fields as if they were dicts
1281+
# This should work due to our Pydantic model structure
1282+
try:
1283+
if message.reactions:
1284+
# Should work even though it's now a Pydantic model
1285+
likes_count = getattr(message.reactions, 'likes_count', 0)
1286+
self.assertIsInstance(likes_count, int)
1287+
1288+
if message.link:
1289+
# Should work even though it's now a Pydantic model
1290+
link_text = getattr(message.link, 'text', '')
1291+
self.assertIsInstance(link_text, str)
1292+
1293+
return # Successfully tested backward compatibility
1294+
except Exception as e:
1295+
self.fail(f"Backward compatibility test failed: {e}")
1296+
1297+
11241298
class ClientAccountTestCase(ClientPrivateTestCase):
11251299
def test_account_edit(self):
11261300
# current

0 commit comments

Comments
 (0)