mirror of
https://github.com/discordeno/discordeno.git
synced 2026-05-31 16:00:07 +00:00
fix tests and cache bugs
This commit is contained in:
32
src/bot.ts
32
src/bot.ts
@@ -253,11 +253,11 @@ export async function startBot(bot: Bot) {
|
||||
// SETUP
|
||||
bot.utils = createUtils({});
|
||||
bot.transformers = createTransformers(bot.transformers || {});
|
||||
bot.helpers = createHelpers(bot.helpers || {});
|
||||
bot.helpers = createHelpers(bot);
|
||||
|
||||
// START REST
|
||||
bot.rest = createRestManager({ token: bot.token, debug: bot.events.debug });
|
||||
if (!bot.botGatewayData) bot.botGatewayData = await bot.helpers.getGatewayBot(bot);
|
||||
if (!bot.botGatewayData) bot.botGatewayData = await bot.helpers.getGatewayBot();
|
||||
|
||||
// START WS
|
||||
bot.gateway = createGatewayManager({
|
||||
@@ -629,7 +629,24 @@ export interface Helpers {
|
||||
suppressEmbeds: typeof helpers.suppressEmbeds;
|
||||
}
|
||||
|
||||
export function createHelpers(options: Partial<Helpers>) {
|
||||
export function createHelpers(
|
||||
bot: Bot,
|
||||
customHelpers?: Partial<Helpers>,
|
||||
): FinalHelpers {
|
||||
const converted = {} as FinalHelpers;
|
||||
for (const [name, fun] of Object.entries({ ...createBaseHelpers(customHelpers || {}) })) {
|
||||
// @ts-ignore - TODO: make the types better
|
||||
converted[name as keyof FinalHelpers] = (
|
||||
...args: RemoveFirstFromTuple<Parameters<typeof fun>>
|
||||
) =>
|
||||
// @ts-ignore - TODO: make the types better
|
||||
fun(bot, ...args);
|
||||
}
|
||||
|
||||
return converted;
|
||||
}
|
||||
|
||||
export function createBaseHelpers(options: Partial<Helpers>) {
|
||||
return {
|
||||
addDiscoverySubcategory: options.addDiscoverySubcategory || helpers.addDiscoverySubcategory,
|
||||
addReaction: options.addReaction || helpers.addReaction,
|
||||
@@ -1236,3 +1253,12 @@ export function createBotGatewayHandlers(
|
||||
INTEGRATION_DELETE: options.INTEGRATION_DELETE ?? handlers.handleIntegrationDelete,
|
||||
};
|
||||
}
|
||||
|
||||
export type RemoveFirstFromTuple<T extends any[]> = T["length"] extends 0 ? []
|
||||
: ((...b: T) => void) extends (a: any, ...b: infer I) => void ? I
|
||||
: [];
|
||||
export type FinalHelpers = {
|
||||
[K in keyof Helpers]: (
|
||||
...args: RemoveFirstFromTuple<Parameters<Helpers[K]>>
|
||||
) => ReturnType<Helpers[K]>;
|
||||
};
|
||||
27
src/cache.ts
27
src/cache.ts
@@ -1,14 +1,9 @@
|
||||
import { Bot } from "./bot.ts";
|
||||
import type { DiscordenoChannel } from "./transformers/channel.ts";
|
||||
import type { DiscordenoGuild } from "./transformers/guild.ts";
|
||||
import type { DiscordenoMember, DiscordenoUser } from "./transformers/member.ts";
|
||||
import type { DiscordenoMessage } from "./transformers/message.ts";
|
||||
import { DiscordenoPresence } from "./transformers/presence.ts";
|
||||
import { PresenceUpdate } from "./types/activity/presence_update.ts";
|
||||
import { Channel } from "./types/channels/channel.ts";
|
||||
import { GuildMember } from "./types/members/guild_member.ts";
|
||||
import { Message } from "./types/messages/message.ts";
|
||||
import { SnakeCasedPropertiesDeep } from "./types/util.ts";
|
||||
import { Collection } from "./util/collection.ts";
|
||||
|
||||
export function createCache(
|
||||
@@ -33,7 +28,7 @@ export function createCache(
|
||||
throw new Error("Async cache requires a tableCreator to be passed.");
|
||||
}
|
||||
|
||||
return {
|
||||
const cache = {
|
||||
guilds: tableCreator("guilds"),
|
||||
users: tableCreator("users"),
|
||||
members: tableCreator("members"),
|
||||
@@ -44,10 +39,14 @@ export function createCache(
|
||||
unavailableGuilds: tableCreator("unavailableGuilds"),
|
||||
executedSlashCommands: new Set(),
|
||||
} as AsyncCache;
|
||||
|
||||
cache.execute = createExecute(cache);
|
||||
|
||||
return cache;
|
||||
}
|
||||
if (!tableCreator) tableCreator = createTable;
|
||||
|
||||
return {
|
||||
const cache = {
|
||||
guilds: tableCreator("guilds"),
|
||||
users: tableCreator("users"),
|
||||
members: tableCreator("members"),
|
||||
@@ -58,6 +57,10 @@ export function createCache(
|
||||
unavailableGuilds: tableCreator("unavailableGuilds"),
|
||||
executedSlashCommands: new Set(),
|
||||
} as Cache;
|
||||
|
||||
cache.execute = createExecute(cache);
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
export type CachedDiscordenoUser = DiscordenoUser & { guilds: Map<bigint, GuildMember> };
|
||||
@@ -180,7 +183,15 @@ export function createExecute(cache: Cache | AsyncCache): CacheExecutor {
|
||||
};
|
||||
}
|
||||
|
||||
export type TableNames = "channels" | "users" | "guilds" | "messages" | "presences" | "threads" | "unavailableGuilds" | "members";
|
||||
export type TableNames =
|
||||
| "channels"
|
||||
| "users"
|
||||
| "guilds"
|
||||
| "messages"
|
||||
| "presences"
|
||||
| "threads"
|
||||
| "unavailableGuilds"
|
||||
| "members";
|
||||
|
||||
// function messageSweeper(bot: Bot, message: DiscordenoMessage) {
|
||||
// // DM messages aren't needed
|
||||
|
||||
@@ -25,5 +25,5 @@ export async function cloneChannel(bot: Bot, channelId: bigint, reason?: string)
|
||||
};
|
||||
|
||||
//Create the channel (also handles permissions)
|
||||
return await bot.helpers.createChannel(bot, channelToClone.guildId!, createChannelOptions, reason);
|
||||
return await bot.helpers.createChannel(channelToClone.guildId!, createChannelOptions, reason);
|
||||
}
|
||||
|
||||
@@ -98,14 +98,14 @@ function processEditChannelQueue(bot: Bot) {
|
||||
if (!details) return;
|
||||
|
||||
await bot.helpers
|
||||
.editChannel(bot, details.channelId, details.options)
|
||||
.editChannel(details.channelId, details.options)
|
||||
.then((result) => details.resolve(result))
|
||||
.catch(details.reject);
|
||||
const secondDetails = request.items.shift();
|
||||
if (!secondDetails) return;
|
||||
|
||||
await bot.helpers
|
||||
.editChannel(bot, secondDetails.channelId, secondDetails.options)
|
||||
.editChannel(secondDetails.channelId, secondDetails.options)
|
||||
.then((result) => secondDetails.resolve(result))
|
||||
.catch(secondDetails.reject);
|
||||
return;
|
||||
|
||||
@@ -2,5 +2,5 @@ import type { Bot } from "../../../bot.ts";
|
||||
|
||||
/** Sets a thread channel to be archived. */
|
||||
export async function archiveThread(bot: Bot, threadId: bigint) {
|
||||
return await bot.helpers.editThread(bot, threadId, { archived: true });
|
||||
return await bot.helpers.editThread(threadId, { archived: true });
|
||||
}
|
||||
|
||||
@@ -2,5 +2,5 @@ import type { Bot } from "../../../bot.ts";
|
||||
|
||||
/** Sets a thread channel to be unarchived. */
|
||||
export async function unarchiveThread(bot: Bot, threadId: bigint) {
|
||||
return await bot.helpers.editThread(bot, threadId, { archived: false });
|
||||
return await bot.helpers.editThread(threadId, { archived: false });
|
||||
}
|
||||
|
||||
@@ -2,5 +2,5 @@ import type { Bot } from "../../../bot.ts";
|
||||
|
||||
/** Sets a thread channel to be unlocked. */
|
||||
export async function unlockThread(bot: Bot, threadId: bigint) {
|
||||
return await bot.helpers.editThread(bot, threadId, { locked: false });
|
||||
return await bot.helpers.editThread(threadId, { locked: false });
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ export async function createGuild(bot: Bot, options: CreateGuild) {
|
||||
// MANUALLY CACHE THE GUILD
|
||||
await bot.cache.guilds.set(guild.id, guild);
|
||||
// MANUALLY CACHE THE BOT
|
||||
await bot.helpers.getMember(bot, guild.id, bot.id);
|
||||
await bot.helpers.getMember(guild.id, bot.id);
|
||||
|
||||
return guild;
|
||||
}
|
||||
|
||||
@@ -2,5 +2,5 @@ import type { Bot } from "../../bot.ts";
|
||||
|
||||
/** Kicks a member from a voice channel */
|
||||
export function disconnectMember(bot: Bot, guildId: bigint, memberId: bigint) {
|
||||
return bot.helpers.editMember(bot, guildId, memberId, { channelId: null });
|
||||
return bot.helpers.editMember(guildId, memberId, { channelId: null });
|
||||
}
|
||||
|
||||
@@ -8,5 +8,5 @@ import type { Bot } from "../../bot.ts";
|
||||
* @param channelId id of channel to move user to (if they are connected to voice)
|
||||
*/
|
||||
export function moveMember(bot: Bot, guildId: bigint, memberId: bigint, channelId: bigint) {
|
||||
return bot.helpers.editMember(bot, guildId, memberId, { channelId });
|
||||
return bot.helpers.editMember(guildId, memberId, { channelId });
|
||||
}
|
||||
|
||||
@@ -25,5 +25,5 @@ export async function sendDirectMessage(bot: Bot, memberId: bigint, content: str
|
||||
}
|
||||
|
||||
// If it does exist try sending a message to this user
|
||||
return await bot.helpers.sendMessage(bot, dmChannel.id, content);
|
||||
return await bot.helpers.sendMessage(dmChannel.id, content);
|
||||
}
|
||||
|
||||
@@ -9,11 +9,11 @@ export async function addReactions(
|
||||
ordered = false
|
||||
) {
|
||||
if (!ordered) {
|
||||
await Promise.all(reactions.map((reaction) => bot.helpers.addReaction(bot, channelId, messageId, reaction)));
|
||||
await Promise.all(reactions.map((reaction) => bot.helpers.addReaction(channelId, messageId, reaction)));
|
||||
} else {
|
||||
for (const reaction of reactions) {
|
||||
bot.events.debug("Running for of loop in addReactions function.");
|
||||
await bot.helpers.addReaction(bot, channelId, messageId, reaction);
|
||||
await bot.helpers.addReaction(channelId, messageId, reaction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// import { cacheHandlers } from "../../cache.ts";
|
||||
import { DiscordChannelTypes } from "../../types/channels/channel_types.ts";
|
||||
import { Errors } from "../../types/discordeno/errors.ts";
|
||||
import { DiscordAllowedMentionsTypes } from "../../types/messages/allowed_mentions_types.ts";
|
||||
@@ -6,8 +5,6 @@ import type { CreateMessage } from "../../types/messages/create_message.ts";
|
||||
import type { Message } from "../../types/messages/message.ts";
|
||||
import type { PermissionStrings } from "../../types/permissions/permission_strings.ts";
|
||||
import type { Bot } from "../../bot.ts";
|
||||
import type { SnakeCasedPropertiesDeep } from "../../types/util.ts";
|
||||
import { Embed } from "../../types/embeds/embed.ts";
|
||||
|
||||
/** Send a message to the channel. Requires SEND_MESSAGES permission. */
|
||||
export async function sendMessage(bot: Bot, channelId: bigint, content: string | CreateMessage) {
|
||||
|
||||
@@ -49,7 +49,7 @@ export async function dispatchRequirements(bot: Bot, data: DiscordGatewayPayload
|
||||
bot.events.debug(`[DISPATCH] New Guild ID has appeared: ${id} in ${data.t} event`);
|
||||
|
||||
const rawGuild = (await bot.helpers
|
||||
.getGuild(bot, id, {
|
||||
.getGuild(id, {
|
||||
counts: true,
|
||||
addToCache: false,
|
||||
})
|
||||
@@ -63,8 +63,8 @@ export async function dispatchRequirements(bot: Bot, data: DiscordGatewayPayload
|
||||
bot.events.debug(`[DISPATCH] Guild ID ${id} has been found. ${rawGuild.name}`);
|
||||
|
||||
const [channels, botMember] = await Promise.all([
|
||||
bot.helpers.getChannels(bot, id, false),
|
||||
bot.helpers.getMember(bot, id, bot.id, { force: true }),
|
||||
bot.helpers.getChannels(id, false),
|
||||
bot.helpers.getMember(id, bot.id, { force: true }),
|
||||
]).catch((error) => {
|
||||
bot.events.debug(error);
|
||||
return [];
|
||||
|
||||
42
tests/messages/deleteMessage.ts
Normal file
42
tests/messages/deleteMessage.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { Bot } from "../../src/bot.ts";
|
||||
import { assertExists } from "../deps.ts";
|
||||
import { delayUntil } from "../utils.ts";
|
||||
|
||||
async function ifItFailsBlameWolf(bot: Bot, channelId: bigint, reason?: string) {
|
||||
const message = await bot.helpers.sendMessage(channelId, "Hello World!");
|
||||
|
||||
// Assertions
|
||||
assertExists(message);
|
||||
// Delay the execution by 5 seconds to allow MESSAGE_CREATE event to be processed
|
||||
await delayUntil(10000, () => bot.cache.messages.has(message.id));
|
||||
// Make sure the message was created.
|
||||
if (!bot.cache.messages.has(message.id)) {
|
||||
throw new Error("The message seemed to be sent but it was not cached. Reason: ${reason}");
|
||||
}
|
||||
|
||||
// Delete the message now
|
||||
await bot.helpers.deleteMessage(channelId, message.id, reason);
|
||||
|
||||
// Wait 5 seconds to give it time for MESSAGE_DELETE event
|
||||
await delayUntil(10000, () => !bot.cache.messages.has(message.id));
|
||||
// Make sure it is gone from cache
|
||||
if (bot.cache.messages.has(message.id)) {
|
||||
throw new Error("The message should have been deleted but it is still in cache.");
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteMessageWithoutReasonTest(bot: Bot, channelId: bigint, t: Deno.TestContext) {
|
||||
console.log("⏳ [message] delete a message without a reason.");
|
||||
|
||||
await ifItFailsBlameWolf(bot, channelId);
|
||||
|
||||
console.log("✅ [message] delete a message without a reason.");
|
||||
}
|
||||
|
||||
export async function deleteMessageWithReasonTest(bot: Bot, channelId: bigint, t: Deno.TestContext) {
|
||||
console.log("⏳ [message] delete a message with a reason.");
|
||||
|
||||
await ifItFailsBlameWolf(bot, channelId, "with a reason");
|
||||
|
||||
console.log("✅ [message] delete a message with a reason.");
|
||||
}
|
||||
32
tests/mod.ts
32
tests/mod.ts
@@ -1,27 +1,33 @@
|
||||
// import { TOKEN } from "../configs.ts";
|
||||
import { TOKEN } from "../configs.ts";
|
||||
import { createBot, createEventHandlers, DiscordChannelTypes, startBot, stopBot } from "../mod.ts";
|
||||
import { assertEquals, assertExists } from "./deps.ts";
|
||||
import { deleteMessageWithReasonTest } from "./messages/deleteMessage.ts";
|
||||
import { deleteMessageWithoutReasonTest } from "./messages/deleteMessage.ts";
|
||||
import { delayUntil } from "./utils.ts";
|
||||
|
||||
Deno.test("[Bot] - Starting Tests", async (t) => {
|
||||
let startedAt = 0;
|
||||
const bot = createBot({
|
||||
// token: TOKEN || Deno.env.get("DISCORD_TOKEN"),
|
||||
token: Deno.env.get("DISCORD_TOKEN")!,
|
||||
token: TOKEN || Deno.env.get("DISCORD_TOKEN"),
|
||||
// token: Deno.env.get("DISCORD_TOKEN")!,
|
||||
// TEST BOT
|
||||
botId: 770381961553510451n,
|
||||
// DD bot
|
||||
// botId: 675412054529540107n,
|
||||
events: createEventHandlers({
|
||||
ready: () => {
|
||||
startedAt = Date.now();
|
||||
},
|
||||
debug: console.log,
|
||||
// debug: console.log,
|
||||
}),
|
||||
intents: [],
|
||||
intents: ["Guilds", "GuildMessages"],
|
||||
cache: {
|
||||
isAsync: false,
|
||||
},
|
||||
});
|
||||
|
||||
await startBot(bot);
|
||||
|
||||
// Delay the execution to allow READY events to be processed
|
||||
await delayUntil(10000, () => Boolean(startedAt));
|
||||
console.log("Bot online");
|
||||
@@ -29,15 +35,15 @@ Deno.test("[Bot] - Starting Tests", async (t) => {
|
||||
// DELETE GUILDS IF LESS THAN 10 SERVERS AS SAFETY MEASURE
|
||||
if (bot.cache.guilds.size() <= 10) {
|
||||
bot.cache.guilds.forEach(async (guild) => {
|
||||
if (guild.ownerId === bot.id) await bot.helpers.deleteGuild(bot, guild.id);
|
||||
})
|
||||
if (guild.ownerId === bot.id) await bot.helpers.deleteGuild(guild.id);
|
||||
});
|
||||
}
|
||||
|
||||
// Delay the execution to allow delete guilds to be processed
|
||||
await delayUntil(10000, () => Boolean(startedAt));
|
||||
|
||||
// CREATE ONE GUILD SO WE CAN REUSE LATER TO SAVE RATE LIMITS
|
||||
const guild = await bot.helpers.createGuild(bot, { name: "Discordeno Test" });
|
||||
const guild = await bot.helpers.createGuild({ name: "Discordeno Test" });
|
||||
|
||||
// Assertions
|
||||
assertExists(guild);
|
||||
@@ -53,7 +59,7 @@ Deno.test("[Bot] - Starting Tests", async (t) => {
|
||||
|
||||
// CHANNEL TESTS GROUPED
|
||||
await t.step("Channel related tests", async (t) => {
|
||||
const channel = await bot.helpers.createChannel(bot, guild.id, { name: "Discordeno-test" });
|
||||
const channel = await bot.helpers.createChannel(guild.id, { name: "Discordeno-test" });
|
||||
|
||||
// Assertions
|
||||
assertExists(channel);
|
||||
@@ -61,7 +67,7 @@ Deno.test("[Bot] - Starting Tests", async (t) => {
|
||||
|
||||
// ALL MESSAGE RELATED TESTS THAT DEPEND ON AN EXISTING CHANNEL
|
||||
await t.step("Message related tests", async (t) => {
|
||||
const message = await bot.helpers.sendMessage(bot, channel.id, "Testing");
|
||||
const message = await bot.helpers.sendMessage(channel.id, "Testing");
|
||||
|
||||
// Assertions
|
||||
assertExists(message);
|
||||
@@ -72,6 +78,12 @@ Deno.test("[Bot] - Starting Tests", async (t) => {
|
||||
if (!bot.cache.messages.has(message.id)) {
|
||||
throw new Error("The message seemed to be sent but it was not cached.");
|
||||
}
|
||||
|
||||
// CONDUCT ALL TESTS RELATED TO A MESSAGE HERE
|
||||
await Promise.all([
|
||||
deleteMessageWithoutReasonTest(bot, channel.id, t),
|
||||
deleteMessageWithReasonTest(bot, channel.id, t),
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user