mirror of
https://github.com/Rainyy21/lol_discordbot
synced 2026-10-10 23:50:32 -04:00
fix some bug that doesn't let user to sign in and connect with discord, added some test
This commit is contained in:
@@ -82,3 +82,71 @@ Traceback (most recent call last):
|
|||||||
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/aiohttp/connector.py", line 1327, in _wrap_create_connection
|
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/aiohttp/connector.py", line 1327, in _wrap_create_connection
|
||||||
raise ClientConnectorCertificateError(req.connection_key, exc) from exc
|
raise ClientConnectorCertificateError(req.connection_key, exc) from exc
|
||||||
aiohttp.client_exceptions.ClientConnectorCertificateError: Cannot connect to host discord.com:443 ssl:True [SSLCertVerificationError: (1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1018)')]
|
aiohttp.client_exceptions.ClientConnectorCertificateError: Cannot connect to host discord.com:443 ssl:True [SSLCertVerificationError: (1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1018)')]
|
||||||
|
2026-04-22 00:50:03,180 [WARNING] discord.client: PyNaCl is not installed, voice will NOT be supported
|
||||||
|
2026-04-22 00:50:03,181 [WARNING] discord.client: davey is not installed, voice will NOT be supported
|
||||||
|
2026-04-22 00:50:03,182 [INFO] discord.client: logging in using static token
|
||||||
|
2026-04-22 00:50:03,704 [INFO] bot: ✅ Loaded extension: commands.login
|
||||||
|
2026-04-22 00:50:03,708 [ERROR] bot: ❌ Failed to load commands.profile: Extension 'commands.profile' raised an error: NameError: name 'discord' is not defined
|
||||||
|
2026-04-22 00:50:03,714 [INFO] bot: ✅ Loaded extension: commands.recent
|
||||||
|
2026-04-22 00:50:03,910 [INFO] bot: 🔄 Slash commands synced
|
||||||
|
2026-04-22 00:50:04,352 [WARNING] bot: ⚠️ Bot disconnected from Discord
|
||||||
|
2026-04-22 00:54:47,504 [WARNING] discord.client: PyNaCl is not installed, voice will NOT be supported
|
||||||
|
2026-04-22 00:54:47,505 [WARNING] discord.client: davey is not installed, voice will NOT be supported
|
||||||
|
2026-04-22 00:54:47,506 [INFO] discord.client: logging in using static token
|
||||||
|
2026-04-22 00:54:47,891 [INFO] bot: ✅ Loaded extension: commands.login
|
||||||
|
2026-04-22 00:54:47,899 [INFO] bot: ✅ Loaded extension: commands.profile
|
||||||
|
2026-04-22 00:54:47,900 [INFO] bot: ✅ Loaded extension: commands.recent
|
||||||
|
2026-04-22 00:54:48,183 [INFO] bot: 🔄 Slash commands synced
|
||||||
|
2026-04-22 00:54:48,576 [WARNING] bot: ⚠️ Bot disconnected from Discord
|
||||||
|
2026-04-22 01:02:58,262 [WARNING] discord.client: PyNaCl is not installed, voice will NOT be supported
|
||||||
|
2026-04-22 01:02:58,263 [WARNING] discord.client: davey is not installed, voice will NOT be supported
|
||||||
|
2026-04-22 01:02:58,264 [INFO] discord.client: logging in using static token
|
||||||
|
2026-04-22 01:02:58,661 [INFO] bot: ✅ Loaded extension: commands.login
|
||||||
|
2026-04-22 01:02:58,661 [INFO] bot: ✅ Loaded extension: commands.profile
|
||||||
|
2026-04-22 01:02:58,663 [INFO] bot: ✅ Loaded extension: commands.recent
|
||||||
|
2026-04-22 01:02:58,798 [INFO] bot: 🔄 Slash commands synced
|
||||||
|
2026-04-22 01:03:01,276 [INFO] discord.gateway: Shard ID None has connected to Gateway (Session ID: 8ffd3e5eaf4edabab0603b0294b5b94f).
|
||||||
|
2026-04-22 01:03:03,284 [INFO] bot: ✅ Logged in as league of legend bot#3877 (ID: 1494467149186465862)
|
||||||
|
2026-04-22 01:03:03,284 [INFO] bot: Guilds : 1
|
||||||
|
2026-04-22 01:03:03,285 [INFO] bot: Ping : 42ms
|
||||||
|
2026-04-22 01:03:32,882 [ERROR] discord.app_commands.tree: Ignoring exception in command tree
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/discord/app_commands/tree.py", line 1138, in wrapper
|
||||||
|
await self._call(interaction)
|
||||||
|
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/discord/app_commands/tree.py", line 1270, in _call
|
||||||
|
command, options = self._get_app_command_options(data)
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
|
||||||
|
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/discord/app_commands/tree.py", line 1174, in _get_app_command_options
|
||||||
|
raise CommandNotFound(name, parents)
|
||||||
|
discord.app_commands.errors.CommandNotFound: Application command 'ping' not found
|
||||||
|
2026-04-22 01:03:53,411 [ERROR] discord.app_commands.tree: Ignoring exception in command 'login'
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/discord/app_commands/tree.py", line 1302, in _call
|
||||||
|
await command._invoke_with_namespace(interaction, namespace)
|
||||||
|
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/discord/app_commands/commands.py", line 883, in _invoke_with_namespace
|
||||||
|
transformed_values = await self._transform_arguments(interaction, namespace)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/discord/app_commands/commands.py", line 847, in _transform_arguments
|
||||||
|
raise CommandSignatureMismatch(self) from None
|
||||||
|
discord.app_commands.errors.CommandSignatureMismatch: The signature for command 'login' is different from the one provided by Discord. This can happen because either your code is out of date or you have not synced the commands with Discord, causing the mismatch in data. It is recommended to sync the command tree to fix this issue.
|
||||||
|
2026-04-22 03:20:37,191 [WARNING] discord.client: PyNaCl is not installed, voice will NOT be supported
|
||||||
|
2026-04-22 03:20:37,192 [WARNING] discord.client: davey is not installed, voice will NOT be supported
|
||||||
|
2026-04-22 03:20:37,193 [INFO] discord.client: logging in using static token
|
||||||
|
2026-04-22 03:20:37,715 [INFO] bot: ✅ Loaded extension: commands.login
|
||||||
|
2026-04-22 03:20:37,726 [INFO] bot: ✅ Loaded extension: commands.profile
|
||||||
|
2026-04-22 03:20:37,731 [INFO] bot: ✅ Loaded extension: commands.recent
|
||||||
|
2026-04-22 03:20:37,899 [INFO] bot: 🔄 Slash commands synced
|
||||||
|
2026-04-22 03:20:38,668 [INFO] discord.gateway: Shard ID None has connected to Gateway (Session ID: c6e5a2c0cdf32e5c69cdbabeed40a2d4).
|
||||||
|
2026-04-22 03:20:40,672 [INFO] bot: ✅ Logged in as league of legend bot#3877 (ID: 1494467149186465862)
|
||||||
|
2026-04-22 03:20:40,674 [INFO] bot: Guilds : 1
|
||||||
|
2026-04-22 03:20:40,674 [INFO] bot: Ping : 45ms
|
||||||
|
2026-04-22 03:21:03,101 [ERROR] discord.app_commands.tree: Ignoring exception in command 'login'
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/discord/app_commands/tree.py", line 1302, in _call
|
||||||
|
await command._invoke_with_namespace(interaction, namespace)
|
||||||
|
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/discord/app_commands/commands.py", line 883, in _invoke_with_namespace
|
||||||
|
transformed_values = await self._transform_arguments(interaction, namespace)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/discord/app_commands/commands.py", line 847, in _transform_arguments
|
||||||
|
raise CommandSignatureMismatch(self) from None
|
||||||
|
discord.app_commands.errors.CommandSignatureMismatch: The signature for command 'login' is different from the one provided by Discord. This can happen because either your code is out of date or you have not synced the commands with Discord, causing the mismatch in data. It is recommended to sync the command tree to fix this issue.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ from discord.ext import commands, tasks
|
|||||||
import asyncio
|
import asyncio
|
||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
from datetime import datetime
|
from datetime import datetime, timezone
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
@@ -52,8 +52,19 @@ class LoLBot(commands.Bot):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error(f"❌ Failed to load {ext}: {e}")
|
log.error(f"❌ Failed to load {ext}: {e}")
|
||||||
|
|
||||||
|
# If SERVER_ID is provided, sync specifically to that guild for instant updates
|
||||||
|
guild_id = os.getenv("SERVER_ID")
|
||||||
|
if guild_id:
|
||||||
|
try:
|
||||||
|
guild = discord.Object(id=int(guild_id))
|
||||||
|
self.tree.copy_global_to(guild=guild)
|
||||||
|
await self.tree.sync(guild=guild)
|
||||||
|
log.info(f"🔄 Slash commands synced to guild {guild_id}")
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f"❌ Failed to sync to guild {guild_id}: {e}")
|
||||||
|
|
||||||
await self.tree.sync()
|
await self.tree.sync()
|
||||||
log.info("🔄 Slash commands synced")
|
log.info("🔄 Global slash commands synced")
|
||||||
|
|
||||||
async def on_ready(self):
|
async def on_ready(self):
|
||||||
log.info(f"✅ Logged in as {self.user} (ID: {self.user.id})")
|
log.info(f"✅ Logged in as {self.user} (ID: {self.user.id})")
|
||||||
@@ -127,11 +138,17 @@ bot = LoLBot()
|
|||||||
|
|
||||||
@bot.command(name="sync")
|
@bot.command(name="sync")
|
||||||
@commands.is_owner()
|
@commands.is_owner()
|
||||||
async def sync(ctx):
|
async def sync(ctx, guild: str = None):
|
||||||
"""Force re-sync slash commands (owner only)."""
|
"""Force re-sync slash commands. Use 'guild' to sync to current guild."""
|
||||||
await bot.tree.sync()
|
if guild == "guild":
|
||||||
await ctx.send("✅ Slash commands synced.")
|
bot.tree.copy_global_to(guild=ctx.guild)
|
||||||
log.info("🔄 Manual sync triggered")
|
await bot.tree.sync(guild=ctx.guild)
|
||||||
|
await ctx.send(f"✅ Slash commands synced to **{ctx.guild.name}**.")
|
||||||
|
log.info(f"🔄 Manual sync triggered for guild {ctx.guild.id}")
|
||||||
|
else:
|
||||||
|
await bot.tree.sync()
|
||||||
|
await ctx.send("✅ Global slash commands synced (may take an hour).")
|
||||||
|
log.info("🔄 Manual global sync triggered")
|
||||||
|
|
||||||
|
|
||||||
@bot.command(name="reload")
|
@bot.command(name="reload")
|
||||||
@@ -147,17 +164,17 @@ async def reload(ctx, extension: str):
|
|||||||
log.error(f"Reload failed for {extension}: {e}")
|
log.error(f"Reload failed for {extension}: {e}")
|
||||||
|
|
||||||
|
|
||||||
@bot.command(name="ping")
|
@bot.tree.command(name="ping", description="Check bot latency")
|
||||||
async def ping(ctx):
|
async def ping(interaction: discord.Interaction):
|
||||||
"""Check bot latency."""
|
"""Check bot latency."""
|
||||||
await ctx.send(f"🏓 Pong! `{round(bot.latency * 1000)}ms`")
|
await interaction.response.send_message(f"🏓 Pong! `{round(bot.latency * 1000)}ms`")
|
||||||
|
|
||||||
|
|
||||||
@bot.command(name="status")
|
@bot.command(name="status")
|
||||||
@commands.is_owner()
|
@commands.is_owner()
|
||||||
async def status(ctx):
|
async def status(ctx):
|
||||||
"""Show bot status info (owner only)."""
|
"""Show bot status info (owner only)."""
|
||||||
uptime = datetime.utcnow() - bot.start_time if hasattr(bot, "start_time") else "N/A"
|
uptime = datetime.now(timezone.utc) - bot.start_time if hasattr(bot, "start_time") else "N/A"
|
||||||
embed = discord.Embed(title="🤖 Bot Status", color=0x1A78C2)
|
embed = discord.Embed(title="🤖 Bot Status", color=0x1A78C2)
|
||||||
embed.add_field(name="📡 Ping", value=f"{round(bot.latency * 1000)}ms", inline=True)
|
embed.add_field(name="📡 Ping", value=f"{round(bot.latency * 1000)}ms", inline=True)
|
||||||
embed.add_field(name="🏠 Guilds", value=str(len(bot.guilds)), inline=True)
|
embed.add_field(name="🏠 Guilds", value=str(len(bot.guilds)), inline=True)
|
||||||
@@ -175,7 +192,7 @@ async def main():
|
|||||||
return
|
return
|
||||||
|
|
||||||
async with bot:
|
async with bot:
|
||||||
bot.start_time = datetime.utcnow()
|
bot.start_time = datetime.now(timezone.utc)
|
||||||
await bot.start(token)
|
await bot.start(token)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
2026-04-22 00:54:47,504 [WARNING] discord.client: PyNaCl is not installed, voice will NOT be supported
|
||||||
|
2026-04-22 00:54:47,505 [WARNING] discord.client: davey is not installed, voice will NOT be supported
|
||||||
|
/Users/simonzheng/Documents/vscode/lolBot/bot.py:178: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC).
|
||||||
|
bot.start_time = datetime.utcnow()
|
||||||
|
2026-04-22 00:54:47,506 [INFO] discord.client: logging in using static token
|
||||||
|
2026-04-22 00:54:47,891 [INFO] bot: ✅ Loaded extension: commands.login
|
||||||
|
2026-04-22 00:54:47,899 [INFO] bot: ✅ Loaded extension: commands.profile
|
||||||
|
2026-04-22 00:54:47,900 [INFO] bot: ✅ Loaded extension: commands.recent
|
||||||
|
2026-04-22 00:54:48,183 [INFO] bot: 🔄 Slash commands synced
|
||||||
|
2026-04-22 00:54:48,576 [WARNING] bot: ⚠️ Bot disconnected from Discord
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "/Users/simonzheng/Documents/vscode/lolBot/bot.py", line 182, in <module>
|
||||||
|
asyncio.run(main())
|
||||||
|
~~~~~~~~~~~^^^^^^^^
|
||||||
|
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/asyncio/runners.py", line 194, in run
|
||||||
|
return runner.run(main)
|
||||||
|
~~~~~~~~~~^^^^^^
|
||||||
|
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/asyncio/runners.py", line 118, in run
|
||||||
|
return self._loop.run_until_complete(task)
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
|
||||||
|
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/asyncio/base_events.py", line 720, in run_until_complete
|
||||||
|
return future.result()
|
||||||
|
~~~~~~~~~~~~~^^
|
||||||
|
File "/Users/simonzheng/Documents/vscode/lolBot/bot.py", line 179, in main
|
||||||
|
await bot.start(token)
|
||||||
|
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/discord/client.py", line 851, in start
|
||||||
|
await self.connect(reconnect=reconnect)
|
||||||
|
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/discord/client.py", line 775, in connect
|
||||||
|
raise PrivilegedIntentsRequired(exc.shard_id) from None
|
||||||
|
discord.errors.PrivilegedIntentsRequired: Shard ID None is requesting privileged intents that have not been explicitly enabled in the developer portal. It is recommended to go to https://discord.com/developers/applications/ and explicitly enable the privileged intents within your application's page. If this is not possible, then consider disabling the privileged intents instead.
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
+11
-3
@@ -11,9 +11,7 @@ class LoginCog(commands.Cog):
|
|||||||
def __init__(self, bot):
|
def __init__(self, bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
|
|
||||||
@app_commands.command(name="login", description="Link your Riot account")
|
async def _handle_login(self, interaction: discord.Interaction, summoner: str):
|
||||||
@app_commands.describe(summoner="Your Riot ID (e.g. Name#TAG)")
|
|
||||||
async def login(self, interaction: discord.Interaction, summoner: str):
|
|
||||||
await interaction.response.defer(ephemeral=True)
|
await interaction.response.defer(ephemeral=True)
|
||||||
|
|
||||||
if "#" not in summoner:
|
if "#" not in summoner:
|
||||||
@@ -53,6 +51,16 @@ class LoginCog(commands.Cog):
|
|||||||
ephemeral=True
|
ephemeral=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@app_commands.command(name="login", description="Link your Riot account")
|
||||||
|
@app_commands.describe(summoner="Your Riot ID (e.g. Name#TAG)")
|
||||||
|
async def login(self, interaction: discord.Interaction, summoner: str):
|
||||||
|
await self._handle_login(interaction, summoner)
|
||||||
|
|
||||||
|
@app_commands.command(name="signin", description="Link your Riot account")
|
||||||
|
@app_commands.describe(summoner="Your Riot ID (e.g. Name#TAG)")
|
||||||
|
async def signin(self, interaction: discord.Interaction, summoner: str):
|
||||||
|
await self._handle_login(interaction, summoner)
|
||||||
|
|
||||||
|
|
||||||
async def setup(bot):
|
async def setup(bot):
|
||||||
await bot.add_cog(LoginCog(bot))
|
await bot.add_cog(LoginCog(bot))
|
||||||
|
|||||||
+2
-1
@@ -1,3 +1,4 @@
|
|||||||
|
import discord
|
||||||
from discord import app_commands
|
from discord import app_commands
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
import aiohttp
|
import aiohttp
|
||||||
@@ -23,7 +24,7 @@ class ProfileCog(commands.Cog):
|
|||||||
#check if user login
|
#check if user login
|
||||||
if not user:
|
if not user:
|
||||||
await interaction.followup.send(
|
await interaction.followup.send(
|
||||||
"❌ You haven't linked your Riot account yet. Use `/login` first."
|
"❌ You haven't linked your Riot account yet. Use `/signin` first."
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -30,7 +30,7 @@ class RecentCog(commands.Cog):
|
|||||||
#check if user
|
#check if user
|
||||||
if not user:
|
if not user:
|
||||||
await interaction.followup.send(
|
await interaction.followup.send(
|
||||||
"❌ You haven't linked your account yet. Use `/login` first."
|
"❌ You haven't linked your account yet. Use `/signin` first."
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@@ -67,7 +67,7 @@ async def get_rank(summoner_id: str) -> dict | None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def get_match_ids(puuid: str, cont: int = 5) -> dict | None:
|
async def get_match_ids(puuid: str, count: int = 5) -> dict | None:
|
||||||
return await riot_get(
|
return await riot_get(
|
||||||
f"https://{CLUSTER}.api.riotgames.com"
|
f"https://{CLUSTER}.api.riotgames.com"
|
||||||
f"/lol/match/v5/matches/by-puuid/{puuid}/ids?count={count}"
|
f"/lol/match/v5/matches/by-puuid/{puuid}/ids?count={count}"
|
||||||
|
|||||||
@@ -0,0 +1,120 @@
|
|||||||
|
import unittest
|
||||||
|
import asyncio
|
||||||
|
from unittest.mock import AsyncMock, MagicMock, patch
|
||||||
|
import discord
|
||||||
|
from commands.login import LoginCog
|
||||||
|
from commands.profile import ProfileCog
|
||||||
|
from commands.recent import RecentCog
|
||||||
|
|
||||||
|
class TestCommands(unittest.IsolatedAsyncioTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.bot = MagicMock()
|
||||||
|
self.login_cog = LoginCog(self.bot)
|
||||||
|
self.profile_cog = ProfileCog(self.bot)
|
||||||
|
self.recent_cog = RecentCog(self.bot)
|
||||||
|
|
||||||
|
async def test_login_success(self):
|
||||||
|
interaction = AsyncMock(spec=discord.Interaction)
|
||||||
|
interaction.user.id = 12345
|
||||||
|
interaction.response.defer = AsyncMock()
|
||||||
|
interaction.followup.send = AsyncMock()
|
||||||
|
|
||||||
|
with patch("commands.login.save_user") as mock_save, \
|
||||||
|
patch("aiohttp.ClientSession.get") as mock_get:
|
||||||
|
|
||||||
|
# Mock Riot Account API response
|
||||||
|
mock_resp = AsyncMock()
|
||||||
|
mock_resp.status = 200
|
||||||
|
mock_resp.json.return_value = {"puuid": "fake_puuid"}
|
||||||
|
mock_get.return_value.__aenter__.return_value = mock_resp
|
||||||
|
|
||||||
|
await self.login_cog.login.callback(self.login_cog, interaction, "TestUser#TAG")
|
||||||
|
|
||||||
|
interaction.response.defer.assert_called_once()
|
||||||
|
mock_save.assert_called_once_with("12345", "fake_puuid", "TestUser", "TAG")
|
||||||
|
interaction.followup.send.assert_called_once()
|
||||||
|
self.assertIn("Linked **TestUser#TAG**", interaction.followup.send.call_args[0][0])
|
||||||
|
|
||||||
|
async def test_login_not_found(self):
|
||||||
|
interaction = AsyncMock(spec=discord.Interaction)
|
||||||
|
interaction.response.defer = AsyncMock()
|
||||||
|
interaction.followup.send = AsyncMock()
|
||||||
|
|
||||||
|
with patch("aiohttp.ClientSession.get") as mock_get:
|
||||||
|
mock_resp = AsyncMock()
|
||||||
|
mock_resp.status = 404
|
||||||
|
mock_get.return_value.__aenter__.return_value = mock_resp
|
||||||
|
|
||||||
|
await self.login_cog.login.callback(self.login_cog, interaction, "NonExistent#TAG")
|
||||||
|
|
||||||
|
interaction.followup.send.assert_called_once()
|
||||||
|
self.assertIn("Summoner not found", interaction.followup.send.call_args[0][0])
|
||||||
|
|
||||||
|
async def test_profile_not_linked(self):
|
||||||
|
interaction = AsyncMock(spec=discord.Interaction)
|
||||||
|
interaction.user.id = 12345
|
||||||
|
interaction.response.defer = AsyncMock()
|
||||||
|
interaction.followup.send = AsyncMock()
|
||||||
|
|
||||||
|
with patch("commands.profile.get_user", return_value=None):
|
||||||
|
await self.profile_cog.profile.callback(self.profile_cog, interaction)
|
||||||
|
|
||||||
|
interaction.followup.send.assert_called_once()
|
||||||
|
self.assertIn("haven't linked your Riot account", interaction.followup.send.call_args[0][0])
|
||||||
|
|
||||||
|
async def test_profile_success(self):
|
||||||
|
interaction = AsyncMock(spec=discord.Interaction)
|
||||||
|
interaction.user.id = 12345
|
||||||
|
interaction.response.defer = AsyncMock()
|
||||||
|
interaction.followup.send = AsyncMock()
|
||||||
|
|
||||||
|
# (discord_id, puuid, game_name, tag_line)
|
||||||
|
mock_user = ("12345", "fake_puuid", "TestUser", "TAG")
|
||||||
|
|
||||||
|
with patch("commands.profile.get_user", return_value=mock_user), \
|
||||||
|
patch("commands.profile.fetch") as mock_fetch:
|
||||||
|
|
||||||
|
# Mock Summoner Data
|
||||||
|
mock_fetch.side_effect = [
|
||||||
|
{"id": "summoner_id", "summonerLevel": 100}, # Summoner info
|
||||||
|
[{"queueType": "RANKED_SOLO_5x5", "tier": "GOLD", "rank": "I", "leaguePoints": 50, "wins": 10, "losses": 5}] # League info
|
||||||
|
]
|
||||||
|
|
||||||
|
await self.profile_cog.profile.callback(self.profile_cog, interaction)
|
||||||
|
|
||||||
|
interaction.followup.send.assert_called_once()
|
||||||
|
embed = interaction.followup.send.call_args[1]["embed"]
|
||||||
|
self.assertEqual(embed.title, "📊 TestUser#TAG")
|
||||||
|
self.assertIn("Gold I", embed.fields[1].value)
|
||||||
|
|
||||||
|
async def test_recent_success(self):
|
||||||
|
interaction = AsyncMock(spec=discord.Interaction)
|
||||||
|
interaction.user.id = 12345
|
||||||
|
interaction.response.defer = AsyncMock()
|
||||||
|
interaction.followup.send = AsyncMock()
|
||||||
|
|
||||||
|
mock_user = ("12345", "fake_puuid", "TestUser", "TAG")
|
||||||
|
|
||||||
|
with patch("commands.recent.get_user", return_value=mock_user), \
|
||||||
|
patch("commands.recent.fetch") as mock_fetch, \
|
||||||
|
patch("commands.recent.fetch_all") as mock_fetch_all:
|
||||||
|
|
||||||
|
mock_fetch.return_value = ["match1"]
|
||||||
|
mock_fetch_all.return_value = [{
|
||||||
|
"metadata": {"matchId": "match1"},
|
||||||
|
"info": {
|
||||||
|
"participants": [{"puuid": "fake_puuid", "win": True, "championName": "Lux", "kills": 10, "deaths": 2, "assists": 15, "totalMinionsKilled": 100, "neutralMinionsKilled": 10}],
|
||||||
|
"gameDuration": 1800,
|
||||||
|
"queueId": 420
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
|
||||||
|
await self.recent_cog.recent.callback(self.recent_cog, interaction, count=1)
|
||||||
|
|
||||||
|
interaction.followup.send.assert_called_once()
|
||||||
|
embeds = interaction.followup.send.call_args[1]["embeds"]
|
||||||
|
self.assertEqual(len(embeds), 1)
|
||||||
|
self.assertIn("Victory — Lux", embeds[0].title)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
Reference in New Issue
Block a user