mirror of
https://github.com/discordeno/discordeno.git
synced 2026-06-16 11:28:15 +00:00
more stuff
This commit is contained in:
@@ -1,2 +1,2 @@
|
|||||||
export { serve } from "https://deno.land/std@0.90.0/http/server.ts";
|
export { serve } from "https://deno.land/std@0.90.0/http/server.ts";
|
||||||
export { verify } from "https://esm.sh/@evan/wasm@0.0.50/target/ed25519/deno.js";
|
export { verify } from "https://unpkg.com/@evan/wasm@0.0.50/target/ed25519/deno.js";
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ export async function processQueue(id: string) {
|
|||||||
if (!queue) return;
|
if (!queue) return;
|
||||||
|
|
||||||
while (queue.length) {
|
while (queue.length) {
|
||||||
|
console.log("process queue");
|
||||||
// IF THE BOT IS GLOBALLY RATELIMITED TRY AGAIN
|
// IF THE BOT IS GLOBALLY RATELIMITED TRY AGAIN
|
||||||
if (rest.globallyRateLimited) {
|
if (rest.globallyRateLimited) {
|
||||||
setTimeout(() => processQueue(id), 1000);
|
setTimeout(() => processQueue(id), 1000);
|
||||||
@@ -36,16 +37,15 @@ export async function processQueue(id: string) {
|
|||||||
// EXECUTE THE REQUEST
|
// EXECUTE THE REQUEST
|
||||||
|
|
||||||
// IF THIS IS A GET REQUEST, CHANGE THE BODY TO QUERY PARAMETERS
|
// IF THIS IS A GET REQUEST, CHANGE THE BODY TO QUERY PARAMETERS
|
||||||
const query = queuedRequest.request.method.toUpperCase() === "GET" &&
|
const query =
|
||||||
|
queuedRequest.request.method.toUpperCase() === "GET" &&
|
||||||
queuedRequest.payload.body
|
queuedRequest.payload.body
|
||||||
? Object.entries(queuedRequest.payload.body)
|
? Object.entries(queuedRequest.payload.body)
|
||||||
.map(
|
.map(
|
||||||
([key, value]) =>
|
([key, value]) =>
|
||||||
`${encodeURIComponent(key)}=${
|
`${encodeURIComponent(key)}=${encodeURIComponent(
|
||||||
encodeURIComponent(
|
value as string
|
||||||
value as string,
|
)}`
|
||||||
)
|
|
||||||
}`,
|
|
||||||
)
|
)
|
||||||
.join("&")
|
.join("&")
|
||||||
: "";
|
: "";
|
||||||
@@ -60,13 +60,13 @@ export async function processQueue(id: string) {
|
|||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
urlToUse,
|
urlToUse,
|
||||||
rest.createRequestBody(queuedRequest),
|
rest.createRequestBody(queuedRequest)
|
||||||
);
|
);
|
||||||
|
|
||||||
rest.eventHandlers.fetched(queuedRequest.payload);
|
rest.eventHandlers.fetched(queuedRequest.payload);
|
||||||
const bucketIdFromHeaders = rest.processRequestHeaders(
|
const bucketIdFromHeaders = rest.processRequestHeaders(
|
||||||
queuedRequest.request.url,
|
queuedRequest.request.url,
|
||||||
response.headers,
|
response.headers
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.status < 200 || response.status >= 400) {
|
if (response.status < 200 || response.status >= 400) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { SnakeCasedPropertiesDeep } from "../util.ts";
|
import { SnakeCasedPropertiesDeep } from "../util.ts";
|
||||||
import { DiscordVisibilityTypes } from "./visibility_types.ts";
|
import { DiscordVisibilityTypes } from "./visibility_types.ts";
|
||||||
import { Integration } from "../guilds/integration.ts";
|
import { Integration } from "../integration/integration.ts";
|
||||||
|
|
||||||
export interface Connection {
|
export interface Connection {
|
||||||
/** id of the connection account */
|
/** id of the connection account */
|
||||||
|
|||||||
+2
-2
@@ -59,11 +59,11 @@ export const formatImageURL = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
function camelToSnakeCase(text: string) {
|
function camelToSnakeCase(text: string) {
|
||||||
return text.replace(/Id|[A-Z]/g, ($1) => `_${$1.toLowerCase()}`);
|
return text.replace(/[A-Z]/g, ($1) => `_${$1.toLowerCase()}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function snakeToCamelCase(text: string) {
|
function snakeToCamelCase(text: string) {
|
||||||
return text.replace(/_id|([-_][a-z])/gi, ($1) =>
|
return text.replace(/([-_][a-z])/gi, ($1) =>
|
||||||
$1.toUpperCase().replace("_", "")
|
$1.toUpperCase().replace("_", "")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,13 +4,15 @@ import { ws } from "./ws.ts";
|
|||||||
/** The handler to clean up shards that identified but never received a READY. */
|
/** The handler to clean up shards that identified but never received a READY. */
|
||||||
export async function cleanupLoadingShards() {
|
export async function cleanupLoadingShards() {
|
||||||
while (ws.loadingShards.size) {
|
while (ws.loadingShards.size) {
|
||||||
|
console.log("cls");
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
ws.loadingShards.forEach((loadingShard) => {
|
ws.loadingShards.forEach((loadingShard) => {
|
||||||
|
console.log(loadingShard);
|
||||||
// Not a minute yet. Max should be few seconds but do a minute to be safe.
|
// Not a minute yet. Max should be few seconds but do a minute to be safe.
|
||||||
if (now < loadingShard.startedAt + 60000) return;
|
if (now < loadingShard.startedAt + 60000) return;
|
||||||
|
|
||||||
loadingShard.reject(
|
loadingShard.reject(
|
||||||
`[Identify Failure] Shard ${loadingShard.shardId} has not received READY event in over a minute.`,
|
`[Identify Failure] Shard ${loadingShard.shardId} has not received READY event in over a minute.`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ export async function createShard(shardId: number) {
|
|||||||
|
|
||||||
socket.onclose = (event) => {
|
socket.onclose = (event) => {
|
||||||
ws.log("CLOSED", { shardId, payload: event });
|
ws.log("CLOSED", { shardId, payload: event });
|
||||||
|
if (event.code === 4009 && ["Resharded!", "Resuming the shard, closing old shard."].includes(event.reason)) {
|
||||||
|
return ws.log("CLOSED_RECONNECT", { shardId, payload: event });
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: ENUM FOR THESE CODES?
|
// TODO: ENUM FOR THESE CODES?
|
||||||
switch (event.code) {
|
switch (event.code) {
|
||||||
@@ -29,14 +32,13 @@ export async function createShard(shardId: number) {
|
|||||||
case 4013:
|
case 4013:
|
||||||
case 4014:
|
case 4014:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
event.reason || "Discord gave no reason! GG! You broke Discord!",
|
event.reason || "Discord gave no reason! GG! You broke Discord!"
|
||||||
);
|
);
|
||||||
// THESE ERRORS CAN NO BE RESUMED! THEY MUST RE-IDENTIFY!
|
// THESE ERRORS CAN NO BE RESUMED! THEY MUST RE-IDENTIFY!
|
||||||
case 4003:
|
case 4003:
|
||||||
case 4007:
|
case 4007:
|
||||||
case 4008:
|
case 4008:
|
||||||
case 4009:
|
case 4009:
|
||||||
ws.log("CLOSED_RECONNECT", { shardId, payload: event });
|
|
||||||
identify(shardId, ws.maxShards);
|
identify(shardId, ws.maxShards);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -15,10 +15,8 @@ export async function handleOnMessage(message: any, shardId: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (message instanceof Uint8Array) {
|
if (message instanceof Uint8Array) {
|
||||||
message = decompressWith(
|
message = decompressWith(message, 0, (slice: Uint8Array) =>
|
||||||
message,
|
ws.utf8decoder.decode(slice)
|
||||||
0,
|
|
||||||
(slice: Uint8Array) => ws.utf8decoder.decode(slice),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,7 +29,7 @@ export async function handleOnMessage(message: any, shardId: number) {
|
|||||||
case DiscordGatewayOpcodes.Hello:
|
case DiscordGatewayOpcodes.Hello:
|
||||||
ws.heartbeat(
|
ws.heartbeat(
|
||||||
shardId,
|
shardId,
|
||||||
(messageData.d as DiscordHeartbeat).heartbeat_interval,
|
(messageData.d as DiscordHeartbeat).heartbeat_interval
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case DiscordGatewayOpcodes.HeartbeatACK:
|
case DiscordGatewayOpcodes.HeartbeatACK:
|
||||||
@@ -80,8 +78,20 @@ export async function handleOnMessage(message: any, shardId: number) {
|
|||||||
shard.sessionId = (messageData.d as DiscordReady).session_id;
|
shard.sessionId = (messageData.d as DiscordReady).session_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
"shoulda deleted it",
|
||||||
|
shardId,
|
||||||
|
ws.loadingShards.has(shardId),
|
||||||
|
ws.loadingShards
|
||||||
|
);
|
||||||
ws.loadingShards.get(shardId)?.resolve(true);
|
ws.loadingShards.get(shardId)?.resolve(true);
|
||||||
ws.loadingShards.delete(shardId);
|
ws.loadingShards.delete(shardId);
|
||||||
|
console.log(
|
||||||
|
"shoulda deleted it",
|
||||||
|
shardId,
|
||||||
|
ws.loadingShards.has(shardId),
|
||||||
|
ws.loadingShards
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the sequence number if it is present
|
// Update the sequence number if it is present
|
||||||
|
|||||||
+2
-1
@@ -32,11 +32,12 @@ export async function identify(shardId: number, maxShards: number) {
|
|||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
op: DiscordGatewayOpcodes.Identify,
|
op: DiscordGatewayOpcodes.Identify,
|
||||||
d: { ...ws.identifyPayload, shard: [shardId, maxShards] },
|
d: { ...ws.identifyPayload, shard: [shardId, maxShards] },
|
||||||
}),
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
console.log("setting the shard loader");
|
||||||
ws.loadingShards.set(shardId, {
|
ws.loadingShards.set(shardId, {
|
||||||
shardId,
|
shardId,
|
||||||
resolve,
|
resolve,
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ export function spawnShards(firstShardId = 0) {
|
|||||||
let shardId = queue.shift();
|
let shardId = queue.shift();
|
||||||
|
|
||||||
while (shardId !== undefined) {
|
while (shardId !== undefined) {
|
||||||
|
console.log("spawn shards");
|
||||||
await ws.tellClusterToIdentify(clusterId as number, shardId, bucketId);
|
await ws.tellClusterToIdentify(clusterId as number, shardId, bucketId);
|
||||||
shardId = queue.shift();
|
shardId = queue.shift();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ export async function startGateway(options: StartGatewayOptions) {
|
|||||||
ws.identifyPayload.compress = options.compress;
|
ws.identifyPayload.compress = options.compress;
|
||||||
}
|
}
|
||||||
if (options.reshard) ws.reshard = options.reshard;
|
if (options.reshard) ws.reshard = options.reshard;
|
||||||
// Once an hour check if resharding is necessary
|
// TODO: Once an hour check if resharding is necessary
|
||||||
setInterval(ws.resharder, 1000 * 60 * 60);
|
// setInterval(ws.resharder, 1000 * 60 * 60);
|
||||||
|
|
||||||
ws.identifyPayload.intents = options.intents.reduce(
|
ws.identifyPayload.intents = options.intents.reduce(
|
||||||
(
|
(
|
||||||
|
|||||||
@@ -1,341 +0,0 @@
|
|||||||
import {
|
|
||||||
addReaction,
|
|
||||||
botId,
|
|
||||||
cache,
|
|
||||||
Channel,
|
|
||||||
channelOverwriteHasPermission,
|
|
||||||
createChannel,
|
|
||||||
createGuild,
|
|
||||||
createRole,
|
|
||||||
delay,
|
|
||||||
deleteChannel,
|
|
||||||
deleteMessage,
|
|
||||||
deleteRole,
|
|
||||||
deleteServer,
|
|
||||||
editChannel,
|
|
||||||
editRole,
|
|
||||||
getChannel,
|
|
||||||
getMessage,
|
|
||||||
getPins,
|
|
||||||
Guild,
|
|
||||||
OverwriteType,
|
|
||||||
pinMessage,
|
|
||||||
removeReaction,
|
|
||||||
Role,
|
|
||||||
sendMessage,
|
|
||||||
startBot,
|
|
||||||
unpinMessage,
|
|
||||||
} from "../mod.ts";
|
|
||||||
import { assertEquals, assertExists } from "./deps.ts";
|
|
||||||
|
|
||||||
// Default options for tests
|
|
||||||
export const defaultTestOptions: Partial<Deno.TestDefinition> = {
|
|
||||||
sanitizeOps: false,
|
|
||||||
sanitizeResources: false,
|
|
||||||
sanitizeExit: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Temporary data
|
|
||||||
export const tempData = {
|
|
||||||
guildId: "",
|
|
||||||
roleId: "",
|
|
||||||
channelId: "",
|
|
||||||
messageId: "",
|
|
||||||
};
|
|
||||||
|
|
||||||
// Main
|
|
||||||
Deno.test({
|
|
||||||
name: "[main] connect to gateway",
|
|
||||||
async fn() {
|
|
||||||
const token = Deno.env.get("DISCORD_TOKEN");
|
|
||||||
if (!token) throw new Error("Token is not provided");
|
|
||||||
|
|
||||||
await startBot({
|
|
||||||
token,
|
|
||||||
intents: ["GUILD_MESSAGES", "GUILDS"],
|
|
||||||
});
|
|
||||||
|
|
||||||
// Delay the execution by 5 seconds
|
|
||||||
await delay(5000);
|
|
||||||
|
|
||||||
// Assertions
|
|
||||||
assertExists(botId);
|
|
||||||
},
|
|
||||||
...defaultTestOptions,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Guild
|
|
||||||
|
|
||||||
Deno.test({
|
|
||||||
name: "[guild] create a new guild",
|
|
||||||
async fn() {
|
|
||||||
const guild = await createGuild({
|
|
||||||
name: "Discordeno Test",
|
|
||||||
}) as Guild;
|
|
||||||
|
|
||||||
// Assertions
|
|
||||||
assertExists(guild);
|
|
||||||
|
|
||||||
tempData.guildId = guild.id;
|
|
||||||
|
|
||||||
// Delay the execution by 5 seconds to allow GUILD_CREATE event to be processed
|
|
||||||
await delay(5000);
|
|
||||||
},
|
|
||||||
...defaultTestOptions,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Role
|
|
||||||
|
|
||||||
Deno.test({
|
|
||||||
name: "[role] create a role in a guild",
|
|
||||||
async fn() {
|
|
||||||
if (!tempData.guildId) {
|
|
||||||
throw new Error("guildId not present in temporary data");
|
|
||||||
}
|
|
||||||
|
|
||||||
const name = "Discordeno Test";
|
|
||||||
const role = await createRole(tempData.guildId, {
|
|
||||||
name,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Assertions
|
|
||||||
assertExists(role);
|
|
||||||
assertEquals(role.name, name);
|
|
||||||
|
|
||||||
tempData.roleId = role.id;
|
|
||||||
},
|
|
||||||
...defaultTestOptions,
|
|
||||||
});
|
|
||||||
|
|
||||||
Deno.test({
|
|
||||||
name: "[role] edit a role in a guild",
|
|
||||||
async fn() {
|
|
||||||
const name = "Discordeno Test Edited";
|
|
||||||
const color = 4320244;
|
|
||||||
const role = await editRole(tempData.guildId, tempData.roleId, {
|
|
||||||
name,
|
|
||||||
color,
|
|
||||||
hoist: false,
|
|
||||||
mentionable: false,
|
|
||||||
}) as Role;
|
|
||||||
|
|
||||||
// Assertions
|
|
||||||
assertExists(role);
|
|
||||||
assertEquals(role.name, name);
|
|
||||||
assertEquals(role.color, color);
|
|
||||||
assertEquals(role.hoist, false);
|
|
||||||
assertEquals(role.mentionable, false);
|
|
||||||
|
|
||||||
tempData.roleId = role.id;
|
|
||||||
},
|
|
||||||
...defaultTestOptions,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Channel
|
|
||||||
|
|
||||||
Deno.test({
|
|
||||||
name: "[channel] create a channel in a guild",
|
|
||||||
async fn() {
|
|
||||||
const channel = await createChannel(tempData.guildId, "test");
|
|
||||||
|
|
||||||
// Assertions
|
|
||||||
assertExists(channel);
|
|
||||||
|
|
||||||
tempData.channelId = channel.id;
|
|
||||||
},
|
|
||||||
...defaultTestOptions,
|
|
||||||
});
|
|
||||||
|
|
||||||
Deno.test({
|
|
||||||
name: "[channel] get a channel in a guild",
|
|
||||||
async fn() {
|
|
||||||
const channel = await getChannel(tempData.channelId);
|
|
||||||
|
|
||||||
// Assertions
|
|
||||||
assertExists(channel);
|
|
||||||
assertEquals(channel.id, tempData.channelId);
|
|
||||||
},
|
|
||||||
...defaultTestOptions,
|
|
||||||
});
|
|
||||||
|
|
||||||
Deno.test({
|
|
||||||
name: "[channel] edit a channel in a guild",
|
|
||||||
async fn() {
|
|
||||||
const channel = await editChannel(tempData.channelId, {
|
|
||||||
name: "discordeno-test-edited",
|
|
||||||
overwrites: [
|
|
||||||
{
|
|
||||||
id: tempData.roleId,
|
|
||||||
type: OverwriteType.ROLE,
|
|
||||||
allow: ["VIEW_CHANNEL", "SEND_MESSAGES"],
|
|
||||||
deny: ["USE_EXTERNAL_EMOJIS"],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}) as Channel;
|
|
||||||
|
|
||||||
// Wait 5s for CHANNEL_UPDATE to fire
|
|
||||||
await delay(5000);
|
|
||||||
|
|
||||||
// Assertions
|
|
||||||
assertExists(channel);
|
|
||||||
assertEquals(channel.name, "discordeno-test-edited");
|
|
||||||
},
|
|
||||||
...defaultTestOptions,
|
|
||||||
});
|
|
||||||
|
|
||||||
Deno.test({
|
|
||||||
name: "[channel] channel overwrite has permission",
|
|
||||||
fn() {
|
|
||||||
const channel = cache.channels.get(tempData.channelId);
|
|
||||||
if (!channel) throw new Error("Channel not found");
|
|
||||||
if (!channel.permissionOverwrites) {
|
|
||||||
throw new Error("permissionOverwrites not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
const hasPerm = channelOverwriteHasPermission(
|
|
||||||
tempData.guildId,
|
|
||||||
tempData.roleId,
|
|
||||||
channel.permissionOverwrites,
|
|
||||||
["VIEW_CHANNEL", "SEND_MESSAGES"],
|
|
||||||
);
|
|
||||||
const missingPerm = channelOverwriteHasPermission(
|
|
||||||
tempData.guildId,
|
|
||||||
tempData.roleId,
|
|
||||||
channel.permissionOverwrites,
|
|
||||||
["USE_EXTERNAL_EMOJIS"],
|
|
||||||
);
|
|
||||||
|
|
||||||
assertEquals(hasPerm, true);
|
|
||||||
assertEquals(missingPerm, false);
|
|
||||||
},
|
|
||||||
...defaultTestOptions,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Message
|
|
||||||
|
|
||||||
Deno.test({
|
|
||||||
name: "[message] send a message in a text channel",
|
|
||||||
async fn() {
|
|
||||||
const message = await sendMessage(tempData.channelId, {
|
|
||||||
embed: {
|
|
||||||
title: "Discordeno Test",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Assertions
|
|
||||||
assertExists(message);
|
|
||||||
assertEquals(message.embeds[0].title, "Discordeno Test");
|
|
||||||
|
|
||||||
tempData.messageId = message.id;
|
|
||||||
},
|
|
||||||
...defaultTestOptions,
|
|
||||||
});
|
|
||||||
|
|
||||||
Deno.test({
|
|
||||||
name: "[message] get a message in a guild",
|
|
||||||
async fn() {
|
|
||||||
const message = await getMessage(tempData.channelId, tempData.messageId);
|
|
||||||
|
|
||||||
// Assertions
|
|
||||||
assertExists(message);
|
|
||||||
assertEquals(message.embeds[0].title, "Discordeno Test");
|
|
||||||
},
|
|
||||||
...defaultTestOptions,
|
|
||||||
});
|
|
||||||
|
|
||||||
Deno.test({
|
|
||||||
name: "[message] pin a message in a channel",
|
|
||||||
async fn() {
|
|
||||||
await pinMessage(tempData.channelId, tempData.messageId);
|
|
||||||
},
|
|
||||||
...defaultTestOptions,
|
|
||||||
});
|
|
||||||
|
|
||||||
Deno.test({
|
|
||||||
name: "[message] get pinned message in a channel",
|
|
||||||
async fn() {
|
|
||||||
const [msg] = await getPins(tempData.channelId);
|
|
||||||
|
|
||||||
// Assertions
|
|
||||||
assertExists(msg);
|
|
||||||
assertEquals(msg.id, tempData.messageId);
|
|
||||||
assertEquals(msg.pinned, true);
|
|
||||||
},
|
|
||||||
...defaultTestOptions,
|
|
||||||
});
|
|
||||||
|
|
||||||
Deno.test({
|
|
||||||
name: "[message] unpin a message",
|
|
||||||
async fn() {
|
|
||||||
await unpinMessage(tempData.channelId, tempData.messageId);
|
|
||||||
},
|
|
||||||
...defaultTestOptions,
|
|
||||||
});
|
|
||||||
|
|
||||||
Deno.test({
|
|
||||||
name: "[message] add a reaction to a message",
|
|
||||||
async fn() {
|
|
||||||
// TODO: add tests for a guild emoji ― <:name:id>
|
|
||||||
|
|
||||||
await addReaction(tempData.channelId, tempData.messageId, "👍");
|
|
||||||
},
|
|
||||||
...defaultTestOptions,
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO(ayntee): add unit tests for getReactions()
|
|
||||||
|
|
||||||
Deno.test({
|
|
||||||
name: "[message] remove a reaction to a message",
|
|
||||||
async fn() {
|
|
||||||
await removeReaction(tempData.channelId, tempData.messageId, "👍");
|
|
||||||
},
|
|
||||||
...defaultTestOptions,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Cleanup
|
|
||||||
|
|
||||||
Deno.test({
|
|
||||||
name: "[message] delete a message by channel Id",
|
|
||||||
async fn() {
|
|
||||||
await deleteMessage(tempData.channelId, tempData.messageId);
|
|
||||||
},
|
|
||||||
...defaultTestOptions,
|
|
||||||
});
|
|
||||||
|
|
||||||
Deno.test({
|
|
||||||
name: "[channel] delete a channel in a guild",
|
|
||||||
async fn() {
|
|
||||||
await deleteChannel(tempData.guildId, tempData.channelId);
|
|
||||||
},
|
|
||||||
...defaultTestOptions,
|
|
||||||
});
|
|
||||||
|
|
||||||
Deno.test({
|
|
||||||
name: "[role] delete a role in a guild",
|
|
||||||
async fn() {
|
|
||||||
await deleteRole(tempData.guildId, tempData.roleId);
|
|
||||||
},
|
|
||||||
...defaultTestOptions,
|
|
||||||
});
|
|
||||||
|
|
||||||
Deno.test({
|
|
||||||
name: "[guild] delete a guild",
|
|
||||||
async fn() {
|
|
||||||
await deleteServer(tempData.guildId);
|
|
||||||
|
|
||||||
// TODO(ayntee): remove this weird shit lol
|
|
||||||
// TODO(ayntee): check if the GUILD_DELETE event is fired
|
|
||||||
tempData.guildId = "";
|
|
||||||
assertEquals(tempData.guildId, "");
|
|
||||||
},
|
|
||||||
...defaultTestOptions,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Forcefully exit the Deno process once all tests are done.
|
|
||||||
Deno.test({
|
|
||||||
name: "[main] exit the process forcefully",
|
|
||||||
fn() {
|
|
||||||
Deno.exit();
|
|
||||||
},
|
|
||||||
...defaultTestOptions,
|
|
||||||
});
|
|
||||||
+324
@@ -0,0 +1,324 @@
|
|||||||
|
import { botId, delay, startBot, ws } from "../mod.ts";
|
||||||
|
import { assertExists } from "./deps.ts";
|
||||||
|
|
||||||
|
// Set necessary settings
|
||||||
|
// Disables the logger which logs everything
|
||||||
|
ws.log = function (x: string, d: any) {
|
||||||
|
if (["RAW", "GUILD_CREATE", "HEARTBEATING_DETAILS"].includes(x)) return console.log(x);
|
||||||
|
console.log(x, d);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Default options for tests
|
||||||
|
export const defaultTestOptions: Partial<Deno.TestDefinition> = {
|
||||||
|
sanitizeOps: false,
|
||||||
|
sanitizeResources: false,
|
||||||
|
sanitizeExit: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Temporary data
|
||||||
|
export const tempData = {
|
||||||
|
guildId: "",
|
||||||
|
roleId: "",
|
||||||
|
channelId: "",
|
||||||
|
messageId: "",
|
||||||
|
};
|
||||||
|
|
||||||
|
// Main
|
||||||
|
Deno.test({
|
||||||
|
name: "[main] connect to gateway",
|
||||||
|
async fn() {
|
||||||
|
const token = Deno.env.get("DISCORD_TOKEN");
|
||||||
|
if (!token) throw new Error("Token is not provided");
|
||||||
|
|
||||||
|
await startBot({
|
||||||
|
token,
|
||||||
|
intents: ["GUILD_MESSAGES", "GUILDS"],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Delay the execution by 5 seconds
|
||||||
|
await delay(5000);
|
||||||
|
|
||||||
|
// Assertions
|
||||||
|
assertExists(botId);
|
||||||
|
},
|
||||||
|
...defaultTestOptions,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Guild
|
||||||
|
|
||||||
|
// Deno.test({
|
||||||
|
// name: "[guild] create a new guild",
|
||||||
|
// async fn() {
|
||||||
|
// const guild = await createGuild({
|
||||||
|
// name: "Discordeno Test",
|
||||||
|
// }) as Guild;
|
||||||
|
|
||||||
|
// // Assertions
|
||||||
|
// assertExists(guild);
|
||||||
|
|
||||||
|
// tempData.guildId = guild.id;
|
||||||
|
|
||||||
|
// // Delay the execution by 5 seconds to allow GUILD_CREATE event to be processed
|
||||||
|
// await delay(5000);
|
||||||
|
// },
|
||||||
|
// ...defaultTestOptions,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// // Role
|
||||||
|
|
||||||
|
// Deno.test({
|
||||||
|
// name: "[role] create a role in a guild",
|
||||||
|
// async fn() {
|
||||||
|
// if (!tempData.guildId) {
|
||||||
|
// throw new Error("guildId not present in temporary data");
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const name = "Discordeno Test";
|
||||||
|
// const role = await createRole(tempData.guildId, {
|
||||||
|
// name,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// // Assertions
|
||||||
|
// assertExists(role);
|
||||||
|
// assertEquals(role.name, name);
|
||||||
|
|
||||||
|
// tempData.roleId = role.id;
|
||||||
|
// },
|
||||||
|
// ...defaultTestOptions,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// Deno.test({
|
||||||
|
// name: "[role] edit a role in a guild",
|
||||||
|
// async fn() {
|
||||||
|
// const name = "Discordeno Test Edited";
|
||||||
|
// const color = 4320244;
|
||||||
|
// const role = await editRole(tempData.guildId, tempData.roleId, {
|
||||||
|
// name,
|
||||||
|
// color,
|
||||||
|
// hoist: false,
|
||||||
|
// mentionable: false,
|
||||||
|
// }) as Role;
|
||||||
|
|
||||||
|
// // Assertions
|
||||||
|
// assertExists(role);
|
||||||
|
// assertEquals(role.name, name);
|
||||||
|
// assertEquals(role.color, color);
|
||||||
|
// assertEquals(role.hoist, false);
|
||||||
|
// assertEquals(role.mentionable, false);
|
||||||
|
|
||||||
|
// tempData.roleId = role.id;
|
||||||
|
// },
|
||||||
|
// ...defaultTestOptions,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// // Channel
|
||||||
|
|
||||||
|
// Deno.test({
|
||||||
|
// name: "[channel] create a channel in a guild",
|
||||||
|
// async fn() {
|
||||||
|
// const channel = await createChannel(tempData.guildId, "test");
|
||||||
|
|
||||||
|
// // Assertions
|
||||||
|
// assertExists(channel);
|
||||||
|
|
||||||
|
// tempData.channelId = channel.id;
|
||||||
|
// },
|
||||||
|
// ...defaultTestOptions,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// Deno.test({
|
||||||
|
// name: "[channel] get a channel in a guild",
|
||||||
|
// async fn() {
|
||||||
|
// const channel = await getChannel(tempData.channelId);
|
||||||
|
|
||||||
|
// // Assertions
|
||||||
|
// assertExists(channel);
|
||||||
|
// assertEquals(channel.id, tempData.channelId);
|
||||||
|
// },
|
||||||
|
// ...defaultTestOptions,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// Deno.test({
|
||||||
|
// name: "[channel] edit a channel in a guild",
|
||||||
|
// async fn() {
|
||||||
|
// const channel = await editChannel(tempData.channelId, {
|
||||||
|
// name: "discordeno-test-edited",
|
||||||
|
// overwrites: [
|
||||||
|
// {
|
||||||
|
// id: tempData.roleId,
|
||||||
|
// type: OverwriteType.ROLE,
|
||||||
|
// allow: ["VIEW_CHANNEL", "SEND_MESSAGES"],
|
||||||
|
// deny: ["USE_EXTERNAL_EMOJIS"],
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// }) as Channel;
|
||||||
|
|
||||||
|
// // Wait 5s for CHANNEL_UPDATE to fire
|
||||||
|
// await delay(5000);
|
||||||
|
|
||||||
|
// // Assertions
|
||||||
|
// assertExists(channel);
|
||||||
|
// assertEquals(channel.name, "discordeno-test-edited");
|
||||||
|
// },
|
||||||
|
// ...defaultTestOptions,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// Deno.test({
|
||||||
|
// name: "[channel] channel overwrite has permission",
|
||||||
|
// fn() {
|
||||||
|
// const channel = cache.channels.get(tempData.channelId);
|
||||||
|
// if (!channel) throw new Error("Channel not found");
|
||||||
|
// if (!channel.permissionOverwrites) {
|
||||||
|
// throw new Error("permissionOverwrites not found");
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const hasPerm = channelOverwriteHasPermission(
|
||||||
|
// tempData.guildId,
|
||||||
|
// tempData.roleId,
|
||||||
|
// channel.permissionOverwrites,
|
||||||
|
// ["VIEW_CHANNEL", "SEND_MESSAGES"],
|
||||||
|
// );
|
||||||
|
// const missingPerm = channelOverwriteHasPermission(
|
||||||
|
// tempData.guildId,
|
||||||
|
// tempData.roleId,
|
||||||
|
// channel.permissionOverwrites,
|
||||||
|
// ["USE_EXTERNAL_EMOJIS"],
|
||||||
|
// );
|
||||||
|
|
||||||
|
// assertEquals(hasPerm, true);
|
||||||
|
// assertEquals(missingPerm, false);
|
||||||
|
// },
|
||||||
|
// ...defaultTestOptions,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// // Message
|
||||||
|
|
||||||
|
// Deno.test({
|
||||||
|
// name: "[message] send a message in a text channel",
|
||||||
|
// async fn() {
|
||||||
|
// const message = await sendMessage(tempData.channelId, {
|
||||||
|
// embed: {
|
||||||
|
// title: "Discordeno Test",
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
|
||||||
|
// // Assertions
|
||||||
|
// assertExists(message);
|
||||||
|
// assertEquals(message.embeds[0].title, "Discordeno Test");
|
||||||
|
|
||||||
|
// tempData.messageId = message.id;
|
||||||
|
// },
|
||||||
|
// ...defaultTestOptions,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// Deno.test({
|
||||||
|
// name: "[message] get a message in a guild",
|
||||||
|
// async fn() {
|
||||||
|
// const message = await getMessage(tempData.channelId, tempData.messageId);
|
||||||
|
|
||||||
|
// // Assertions
|
||||||
|
// assertExists(message);
|
||||||
|
// assertEquals(message.embeds[0].title, "Discordeno Test");
|
||||||
|
// },
|
||||||
|
// ...defaultTestOptions,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// Deno.test({
|
||||||
|
// name: "[message] pin a message in a channel",
|
||||||
|
// async fn() {
|
||||||
|
// await pinMessage(tempData.channelId, tempData.messageId);
|
||||||
|
// },
|
||||||
|
// ...defaultTestOptions,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// Deno.test({
|
||||||
|
// name: "[message] get pinned message in a channel",
|
||||||
|
// async fn() {
|
||||||
|
// const [msg] = await getPins(tempData.channelId);
|
||||||
|
|
||||||
|
// // Assertions
|
||||||
|
// assertExists(msg);
|
||||||
|
// assertEquals(msg.id, tempData.messageId);
|
||||||
|
// assertEquals(msg.pinned, true);
|
||||||
|
// },
|
||||||
|
// ...defaultTestOptions,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// Deno.test({
|
||||||
|
// name: "[message] unpin a message",
|
||||||
|
// async fn() {
|
||||||
|
// await unpinMessage(tempData.channelId, tempData.messageId);
|
||||||
|
// },
|
||||||
|
// ...defaultTestOptions,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// Deno.test({
|
||||||
|
// name: "[message] add a reaction to a message",
|
||||||
|
// async fn() {
|
||||||
|
// // TODO: add tests for a guild emoji ― <:name:id>
|
||||||
|
|
||||||
|
// await addReaction(tempData.channelId, tempData.messageId, "👍");
|
||||||
|
// },
|
||||||
|
// ...defaultTestOptions,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// // TODO(ayntee): add unit tests for getReactions()
|
||||||
|
|
||||||
|
// Deno.test({
|
||||||
|
// name: "[message] remove a reaction to a message",
|
||||||
|
// async fn() {
|
||||||
|
// await removeReaction(tempData.channelId, tempData.messageId, "👍");
|
||||||
|
// },
|
||||||
|
// ...defaultTestOptions,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// // Cleanup
|
||||||
|
|
||||||
|
// Deno.test({
|
||||||
|
// name: "[message] delete a message by channel Id",
|
||||||
|
// async fn() {
|
||||||
|
// await deleteMessage(tempData.channelId, tempData.messageId);
|
||||||
|
// },
|
||||||
|
// ...defaultTestOptions,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// Deno.test({
|
||||||
|
// name: "[channel] delete a channel in a guild",
|
||||||
|
// async fn() {
|
||||||
|
// await deleteChannel(tempData.guildId, tempData.channelId);
|
||||||
|
// },
|
||||||
|
// ...defaultTestOptions,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// Deno.test({
|
||||||
|
// name: "[role] delete a role in a guild",
|
||||||
|
// async fn() {
|
||||||
|
// await deleteRole(tempData.guildId, tempData.roleId);
|
||||||
|
// },
|
||||||
|
// ...defaultTestOptions,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// Deno.test({
|
||||||
|
// name: "[guild] delete a guild",
|
||||||
|
// async fn() {
|
||||||
|
// await deleteServer(tempData.guildId);
|
||||||
|
|
||||||
|
// // TODO(ayntee): remove this weird shit lol
|
||||||
|
// // TODO(ayntee): check if the GUILD_DELETE event is fired
|
||||||
|
// tempData.guildId = "";
|
||||||
|
// assertEquals(tempData.guildId, "");
|
||||||
|
// },
|
||||||
|
// ...defaultTestOptions,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// Forcefully exit the Deno process once all tests are done.
|
||||||
|
Deno.test({
|
||||||
|
name: "[main] exit the process forcefully",
|
||||||
|
fn() {
|
||||||
|
ws.shards.forEach((shard) => {
|
||||||
|
clearInterval(shard.heartbeat.intervalId);
|
||||||
|
shard.ws.close();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
...defaultTestOptions,
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user