Feature/12 create tests (#102)

* Fix tests

* Update coverage

* Remove unrequired mock files

* Add about command test

* Update about tests

* Ban command tests

* eval command tests

* Start help command tests

* Add help command tests

* Add kick command tests

* Mute command tests

* Poll command tests

* Add role command tests

Signed-off-by: Ethan Lane <ethan@vylpes.com>

* Add rules command tests

* Add unmute command tests

* Add warn command tests

* Add MemberEvents tests

* Add GuildMemberUpdate tests

Signed-off-by: Ethan Lane <ethan@vylpes.com>

* Add MessageEvents tests

* Add StringTools test

Signed-off-by: Ethan Lane <ethan@vylpes.com>

* Add embed tests

Signed-off-by: Ethan Lane <ethan@vylpes.com>

* Add GitHub Actions

Signed-off-by: Ethan Lane <ethan@vylpes.com>

* Move to tslint

Signed-off-by: Ethan Lane <ethan@vylpes.com>

* Remove tslint

Signed-off-by: Ethan Lane <ethan@vylpes.com>

* Remove linting script

Signed-off-by: Ethan Lane <ethan@vylpes.com>
This commit is contained in:
Vylpes 2022-01-30 17:03:36 +00:00 committed by GitHub
parent 2cc12d91be
commit f61c4c728a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
58 changed files with 6749 additions and 833 deletions

View file

@ -1,4 +1,5 @@
import { ICommandContext } from "../contracts/ICommandContext";
import ICommandReturnContext from "../contracts/ICommandReturnContext";
import PublicEmbed from "../helpers/embeds/PublicEmbed";
import { Command } from "../type/command";
@ -8,12 +9,17 @@ export default class About extends Command {
super._category = "General";
}
public override execute(context: ICommandContext) {
public override execute(context: ICommandContext): ICommandReturnContext {
const embed = new PublicEmbed(context, "About", "")
.addField("Version", process.env.BOT_VER)
.addField("Author", process.env.BOT_AUTHOR)
.addField("Date", process.env.BOT_DATE);
embed.SendToCurrentChannel();
return {
commandContext: context,
embeds: [embed]
};
}
}

View file

@ -4,6 +4,7 @@ import LogEmbed from "../helpers/embeds/LogEmbed";
import PublicEmbed from "../helpers/embeds/PublicEmbed";
import { Command } from "../type/command";
import { ICommandContext } from "../contracts/ICommandContext";
import ICommandReturnContext from "../contracts/ICommandReturnContext";
export default class Ban extends Command {
constructor() {
@ -15,13 +16,16 @@ export default class Ban extends Command {
];
}
public override async execute(context: ICommandContext) {
public override async execute(context: ICommandContext): Promise<ICommandReturnContext> {
const targetUser = context.message.mentions.users.first();
if (!targetUser) {
const embed = new ErrorEmbed(context, "User does not exist");
embed.SendToCurrentChannel();
return;
return {
commandContext: context,
embeds: [embed],
};
}
const targetMember = context.message.guild?.member(targetUser);
@ -29,7 +33,10 @@ export default class Ban extends Command {
if (!targetMember) {
const embed = new ErrorEmbed(context, "User is not in this server");
embed.SendToCurrentChannel();
return;
return {
commandContext: context,
embeds: [embed],
};
}
const reasonArgs = context.args;
@ -38,13 +45,19 @@ export default class Ban extends Command {
const reason = reasonArgs.join(" ");
if (!context.message.guild?.available) {
return;
return {
commandContext: context,
embeds: [],
};
}
if (!targetMember.bannable) {
const embed = new ErrorEmbed(context, ErrorMessages.InsufficientBotPermissions);
embed.SendToCurrentChannel();
return;
return {
commandContext: context,
embeds: [embed],
};
}
const logEmbed = new LogEmbed(context, "Member Banned");
@ -58,5 +71,10 @@ export default class Ban extends Command {
logEmbed.SendToModLogsChannel();
publicEmbed.SendToCurrentChannel();
return {
commandContext: context,
embeds: [logEmbed, publicEmbed],
};
}
}

View file

@ -3,6 +3,7 @@ import { TextChannel } from "discord.js";
import PublicEmbed from "../helpers/embeds/PublicEmbed";
import { Command } from "../type/command";
import { ICommandContext } from "../contracts/ICommandContext";
import ICommandReturnContext from "../contracts/ICommandReturnContext";
export default class Clear extends Command {
constructor() {
@ -14,11 +15,15 @@ export default class Clear extends Command {
];
}
public override async execute(context: ICommandContext) {
public override async execute(context: ICommandContext): Promise<ICommandReturnContext> {
if (context.args.length == 0) {
const errorEmbed = new ErrorEmbed(context, "Please specify an amount between 1 and 100");
errorEmbed.SendToCurrentChannel();
return;
return {
commandContext: context,
embeds: [errorEmbed]
};
}
const totalToClear = Number.parseInt(context.args[0]);
@ -26,12 +31,20 @@ export default class Clear extends Command {
if (!totalToClear || totalToClear <= 0 || totalToClear > 100) {
const errorEmbed = new ErrorEmbed(context, "Please specify an amount between 1 and 100");
errorEmbed.SendToCurrentChannel();
return;
return {
commandContext: context,
embeds: [errorEmbed]
};
}
await (context.message.channel as TextChannel).bulkDelete(totalToClear);
const embed = new PublicEmbed(context, "", `${totalToClear} message(s) were removed`);
embed.SendToCurrentChannel();
return {
commandContext: context,
embeds: [embed]
};
}
}

View file

@ -1,4 +1,5 @@
import { ICommandContext } from "../contracts/ICommandContext";
import ICommandReturnContext from "../contracts/ICommandReturnContext";
import ErrorEmbed from "../helpers/embeds/ErrorEmbed";
import PublicEmbed from "../helpers/embeds/PublicEmbed";
import { Command } from "../type/command";
@ -10,9 +11,12 @@ export default class Evaluate extends Command {
super._category = "Owner";
}
public override execute(context: ICommandContext) {
public override execute(context: ICommandContext): ICommandReturnContext {
if (context.message.author.id != process.env.BOT_OWNERID) {
return;
return {
commandContext: context,
embeds: []
};
}
const stmt = context.args;
@ -24,10 +28,20 @@ export default class Evaluate extends Command {
const embed = new PublicEmbed(context, "", result);
embed.SendToCurrentChannel();
return {
commandContext: context,
embeds: [embed]
};
}
catch (err: any) {
const errorEmbed = new ErrorEmbed(context, err);
errorEmbed.SendToCurrentChannel();
return {
commandContext: context,
embeds: [errorEmbed]
};
}
}
}

View file

@ -3,9 +3,10 @@ import { ICommandContext } from "../contracts/ICommandContext";
import ErrorEmbed from "../helpers/embeds/ErrorEmbed";
import PublicEmbed from "../helpers/embeds/PublicEmbed";
import StringTools from "../helpers/StringTools";
import ICommandReturnContext from "../contracts/ICommandReturnContext";
import { Command } from "../type/command";
interface ICommandData {
export interface ICommandData {
Exists: boolean;
Name?: string;
Category?: string;
@ -19,17 +20,17 @@ export default class Help extends Command {
super._category = "General";
}
public override execute(context: ICommandContext) {
public override execute(context: ICommandContext): ICommandReturnContext {
if (context.args.length == 0) {
this.SendAll(context);
return this.SendAll(context);
} else {
this.SendSingle(context);
return this.SendSingle(context);
}
}
private SendAll(context: ICommandContext) {
public SendAll(context: ICommandContext): ICommandReturnContext {
const allCommands = this.GetAllCommandData();
const cateogries = this.DetermineCategories(allCommands);
const cateogries = [...new Set(allCommands.map(x => x.Category!))];;
const embed = new PublicEmbed(context, "Commands", "");
@ -40,15 +41,24 @@ export default class Help extends Command {
});
embed.SendToCurrentChannel();
return {
commandContext: context,
embeds: [ embed ]
};
}
private SendSingle(context: ICommandContext) {
public SendSingle(context: ICommandContext): ICommandReturnContext {
const command = this.GetCommandData(context.args[0]);
if (!command.Exists) {
const errorEmbed = new ErrorEmbed(context, "Command does not exist");
errorEmbed.SendToCurrentChannel();
return;
return {
commandContext: context,
embeds: [ errorEmbed ]
};
}
const embed = new PublicEmbed(context, StringTools.Capitalise(command.Name!), "");
@ -56,9 +66,14 @@ export default class Help extends Command {
embed.addField("Required Roles", StringTools.Capitalise(command.Roles!.join(", ")) || "*none*");
embed.SendToCurrentChannel();
return {
commandContext: context,
embeds: [ embed ]
};
}
private GetAllCommandData(): ICommandData[] {
public GetAllCommandData(): ICommandData[] {
const result: ICommandData[] = [];
const folder = process.env.FOLDERS_COMMANDS!;
@ -82,7 +97,7 @@ export default class Help extends Command {
return result;
}
private GetCommandData(name: string): ICommandData {
public GetCommandData(name: string): ICommandData {
const folder = process.env.FOLDERS_COMMANDS!;
const path = `${process.cwd()}/${folder}/${name}.ts`;
@ -104,16 +119,4 @@ export default class Help extends Command {
return data;
}
private DetermineCategories(commands: ICommandData[]): string[] {
const result: string[] = [];
commands.forEach(cmd => {
if (!result.includes(cmd.Category!)) {
result.push(cmd.Category!);
}
});
return result;
}
}
}

View file

@ -1,5 +1,6 @@
import ErrorMessages from "../constants/ErrorMessages";
import { ICommandContext } from "../contracts/ICommandContext";
import ICommandReturnContext from "../contracts/ICommandReturnContext";
import ErrorEmbed from "../helpers/embeds/ErrorEmbed";
import LogEmbed from "../helpers/embeds/LogEmbed";
import PublicEmbed from "../helpers/embeds/PublicEmbed";
@ -15,13 +16,17 @@ export default class Kick extends Command {
];
}
public override async execute(context: ICommandContext) {
public override async execute(context: ICommandContext): Promise<ICommandReturnContext> {
const targetUser = context.message.mentions.users.first();
if (!targetUser) {
const embed = new ErrorEmbed(context, "User does not exist");
embed.SendToCurrentChannel();
return;
return {
commandContext: context,
embeds: [embed]
};
}
const targetMember = context.message.guild?.member(targetUser);
@ -29,7 +34,11 @@ export default class Kick extends Command {
if (!targetMember) {
const embed = new ErrorEmbed(context, "User is not in this server");
embed.SendToCurrentChannel();
return;
return {
commandContext: context,
embeds: [embed]
};
}
const reasonArgs = context.args;
@ -38,13 +47,20 @@ export default class Kick extends Command {
const reason = reasonArgs.join(" ");
if (!context.message.guild?.available) {
return;
return {
commandContext: context,
embeds: []
};
}
if (!targetMember.kickable) {
const embed = new ErrorEmbed(context, ErrorMessages.InsufficientBotPermissions);
embed.SendToCurrentChannel();
return;
return {
commandContext: context,
embeds: [embed]
};
}
const logEmbed = new LogEmbed(context, "Member Kicked");
@ -58,5 +74,10 @@ export default class Kick extends Command {
logEmbed.SendToModLogsChannel();
publicEmbed.SendToCurrentChannel();
return {
commandContext: context,
embeds: [logEmbed, publicEmbed]
};
}
}

View file

@ -1,5 +1,6 @@
import ErrorMessages from "../constants/ErrorMessages";
import { ICommandContext } from "../contracts/ICommandContext";
import ICommandReturnContext from "../contracts/ICommandReturnContext";
import ErrorEmbed from "../helpers/embeds/ErrorEmbed";
import LogEmbed from "../helpers/embeds/LogEmbed";
import PublicEmbed from "../helpers/embeds/PublicEmbed";
@ -15,13 +16,17 @@ export default class Mute extends Command {
];
}
public override async execute(context: ICommandContext) {
public override async execute(context: ICommandContext): Promise<ICommandReturnContext> {
const targetUser = context.message.mentions.users.first();
if (!targetUser) {
const embed = new ErrorEmbed(context, "User does not exist");
embed.SendToCurrentChannel();
return;
return {
commandContext: context,
embeds: [embed]
};
}
const targetMember = context.message.guild?.member(targetUser);
@ -29,7 +34,11 @@ export default class Mute extends Command {
if (!targetMember) {
const embed = new ErrorEmbed(context, "User is not in this server");
embed.SendToCurrentChannel();
return;
return {
commandContext: context,
embeds: [embed]
};
}
const reasonArgs = context.args;
@ -38,13 +47,20 @@ export default class Mute extends Command {
const reason = reasonArgs.join(" ");
if (!context.message.guild?.available) {
return;
return {
commandContext: context,
embeds: []
};
}
if (!targetMember.manageable) {
const embed = new ErrorEmbed(context, ErrorMessages.InsufficientBotPermissions);
embed.SendToCurrentChannel();
return;
return {
commandContext: context,
embeds: [embed]
};
}
const logEmbed = new LogEmbed(context, "Member Muted");
@ -60,12 +76,21 @@ export default class Mute extends Command {
if (!mutedRole) {
const embed = new ErrorEmbed(context, ErrorMessages.RoleNotFound);
embed.SendToCurrentChannel();
return;
return {
commandContext: context,
embeds: [embed]
};
}
await targetMember.roles.add(mutedRole, reason);
logEmbed.SendToModLogsChannel();
publicEmbed.SendToCurrentChannel();
return {
commandContext: context,
embeds: [logEmbed, publicEmbed]
};
}
}

View file

@ -1,4 +1,5 @@
import { ICommandContext } from "../contracts/ICommandContext";
import ICommandReturnContext from "../contracts/ICommandReturnContext";
import ErrorEmbed from "../helpers/embeds/ErrorEmbed";
import PublicEmbed from "../helpers/embeds/PublicEmbed";
import { Command } from "../type/command";
@ -10,14 +11,18 @@ export default class Poll extends Command {
super._category = "General";
}
public override async execute(context: ICommandContext) {
public override async execute(context: ICommandContext): Promise<ICommandReturnContext> {
const argsJoined = context.args.join(" ");
const argsSplit = argsJoined.split(";");
if (argsSplit.length < 3 || argsSplit.length > 10) {
const errorEmbed = new ErrorEmbed(context, "Usage: <title>;<option 1>;<option 2>... (separate options with semicolons), maximum of 9 options");
errorEmbed.SendToCurrentChannel();
return;
return {
commandContext: context,
embeds: [errorEmbed]
};
}
const title = argsSplit[0];
@ -53,5 +58,10 @@ export default class Poll extends Command {
if (context.message.deletable) {
await context.message.delete({ reason: "Poll command" });
}
return {
commandContext: context,
embeds: [embed]
};
}
}

View file

@ -3,6 +3,7 @@ import PublicEmbed from "../helpers/embeds/PublicEmbed";
import { Role as DiscordRole } from "discord.js";
import { Command } from "../type/command";
import { ICommandContext } from "../contracts/ICommandContext";
import ICommandReturnContext from "../contracts/ICommandReturnContext";
export default class Role extends Command {
constructor() {
@ -11,30 +12,39 @@ export default class Role extends Command {
super._category = "General";
}
public override execute(context: ICommandContext) {
public override async execute(context: ICommandContext) {
const roles = process.env.COMMANDS_ROLE_ROLES!.split(',');
if (context.args.length == 0) {
this.SendRolesList(context, roles);
} else {
this.ToggleRole(context, roles);
await this.ToggleRole(context, roles);
}
}
private SendRolesList(context: ICommandContext, roles: String[]) {
public SendRolesList(context: ICommandContext, roles: String[]): ICommandReturnContext {
const description = `Do ${process.env.BOT_PREFIX}role <role> to get the role!\n${roles.join('\n')}`;
const embed = new PublicEmbed(context, "Roles", description);
embed.SendToCurrentChannel();
return {
commandContext: context,
embeds: [embed]
};
}
private ToggleRole(context: ICommandContext, roles: String[]) {
public async ToggleRole(context: ICommandContext, roles: String[]): Promise<ICommandReturnContext> {
const requestedRole = context.args[0];
if (!roles.includes(requestedRole)) {
const errorEmbed = new ErrorEmbed(context, "This role isn't marked as assignable, to see a list of assignable roles, run this command without any parameters");
errorEmbed.SendToCurrentChannel();
return;
return {
commandContext: context,
embeds: [errorEmbed]
};
}
const assignRole = context.message.guild?.roles.cache.find(x => x.name == requestedRole);
@ -42,29 +52,48 @@ export default class Role extends Command {
if (!assignRole) {
const errorEmbed = new ErrorEmbed(context, "The current server doesn't have this role. Please contact the server's moderators");
errorEmbed.SendToCurrentChannel();
return;
return {
commandContext: context,
embeds: [errorEmbed]
};
}
const role = context.message.member?.roles.cache.find(x => x.name == requestedRole)
if (!role) {
this.AddRole(context, assignRole);
await this.AddRole(context, assignRole);
} else {
this.RemoveRole(context, assignRole);
await this.RemoveRole(context, assignRole);
}
return {
commandContext: context,
embeds: []
};
}
private async AddRole(context: ICommandContext, role: DiscordRole) {
public async AddRole(context: ICommandContext, role: DiscordRole): Promise<ICommandReturnContext> {
await context.message.member?.roles.add(role);
const embed = new PublicEmbed(context, "", `Gave role: ${role.name}`);
embed.SendToCurrentChannel();
return {
commandContext: context,
embeds: [embed]
};
}
private async RemoveRole(context: ICommandContext, role: DiscordRole) {
public async RemoveRole(context: ICommandContext, role: DiscordRole): Promise<ICommandReturnContext> {
await context.message.member?.roles.remove(role);
const embed = new PublicEmbed(context, "", `Removed role: ${role.name}`);
embed.SendToCurrentChannel();
return {
commandContext: context,
embeds: [embed]
};
}
}

View file

@ -1,5 +1,6 @@
import { existsSync, readFileSync } from "fs";
import { ICommandContext } from "../contracts/ICommandContext";
import ICommandReturnContext from "../contracts/ICommandReturnContext";
import ErrorEmbed from "../helpers/embeds/ErrorEmbed";
import PublicEmbed from "../helpers/embeds/PublicEmbed";
import { Command } from "../type/command";
@ -21,11 +22,15 @@ export default class Rules extends Command {
];
}
public override execute(context: ICommandContext) {
if (!existsSync(process.env.COMMANDS_RULES_FILE!)) {
public override execute(context: ICommandContext): ICommandReturnContext {
if (!existsSync(`${process.cwd()}/${process.env.COMMANDS_RULES_FILE!}`)) {
const errorEmbed = new ErrorEmbed(context, "Rules file doesn't exist");
errorEmbed.SendToCurrentChannel();
return;
return {
commandContext: context,
embeds: [errorEmbed]
};
}
const rulesFile = readFileSync(`${process.cwd()}/${process.env.COMMANDS_RULES_FILE}`).toString();
@ -43,5 +48,10 @@ export default class Rules extends Command {
});
embeds.forEach(x => x.SendToCurrentChannel());
return {
commandContext: context,
embeds: embeds
};
}
}

View file

@ -1,5 +1,6 @@
import ErrorMessages from "../constants/ErrorMessages";
import { ICommandContext } from "../contracts/ICommandContext";
import ICommandReturnContext from "../contracts/ICommandReturnContext";
import ErrorEmbed from "../helpers/embeds/ErrorEmbed";
import LogEmbed from "../helpers/embeds/LogEmbed";
import PublicEmbed from "../helpers/embeds/PublicEmbed";
@ -15,13 +16,17 @@ export default class Unmute extends Command {
];
}
public override async execute(context: ICommandContext) {
public override async execute(context: ICommandContext): Promise<ICommandReturnContext> {
const targetUser = context.message.mentions.users.first();
if (!targetUser) {
const embed = new ErrorEmbed(context, "User does not exist");
embed.SendToCurrentChannel();
return;
return {
commandContext: context,
embeds: [embed]
};
}
const targetMember = context.message.guild?.member(targetUser);
@ -29,7 +34,11 @@ export default class Unmute extends Command {
if (!targetMember) {
const embed = new ErrorEmbed(context, "User is not in this server");
embed.SendToCurrentChannel();
return;
return {
commandContext: context,
embeds: [embed]
};
}
const reasonArgs = context.args;
@ -38,13 +47,20 @@ export default class Unmute extends Command {
const reason = reasonArgs.join(" ");
if (!context.message.guild?.available) {
return;
return {
commandContext: context,
embeds: []
};
}
if (!targetMember.manageable) {
const embed = new ErrorEmbed(context, ErrorMessages.InsufficientBotPermissions);
embed.SendToCurrentChannel();
return;
return {
commandContext: context,
embeds: [embed]
};
}
const logEmbed = new LogEmbed(context, "Member Unmuted");
@ -60,12 +76,21 @@ export default class Unmute extends Command {
if (!mutedRole) {
const embed = new ErrorEmbed(context, ErrorMessages.RoleNotFound);
embed.SendToCurrentChannel();
return;
return {
commandContext: context,
embeds: [embed]
};
}
await targetMember.roles.remove(mutedRole, reason);
logEmbed.SendToModLogsChannel();
publicEmbed.SendToCurrentChannel();
return {
commandContext: context,
embeds: [logEmbed, publicEmbed]
};
}
}

View file

@ -1,4 +1,5 @@
import { ICommandContext } from "../contracts/ICommandContext";
import ICommandReturnContext from "../contracts/ICommandReturnContext";
import ErrorEmbed from "../helpers/embeds/ErrorEmbed";
import LogEmbed from "../helpers/embeds/LogEmbed";
import PublicEmbed from "../helpers/embeds/PublicEmbed";
@ -14,21 +15,29 @@ export default class Warn extends Command {
];
}
public override execute(context: ICommandContext) {
public override execute(context: ICommandContext): ICommandReturnContext {
const user = context.message.mentions.users.first();
if (!user) {
const errorEmbed = new ErrorEmbed(context, "Please specify a valid user");
const errorEmbed = new ErrorEmbed(context, "User does not exist");
errorEmbed.SendToCurrentChannel();
return;
return {
commandContext: context,
embeds: [errorEmbed]
};
}
const member = context.message.guild?.member(user);
if (!member) {
const errorEmbed = new ErrorEmbed(context, "Please specify a valid user");
const errorEmbed = new ErrorEmbed(context, "User is not in this server");
errorEmbed.SendToCurrentChannel();
return;
return {
commandContext: context,
embeds: [errorEmbed]
};
}
const reasonArgs = context.args;
@ -37,7 +46,10 @@ export default class Warn extends Command {
const reason = reasonArgs.join(" ");
if (!context.message.guild?.available) {
return;
return {
commandContext: context,
embeds: []
};
}
const logEmbed = new LogEmbed(context, "Member Warned");
@ -50,5 +62,10 @@ export default class Warn extends Command {
logEmbed.SendToModLogsChannel();
publicEmbed.SendToCurrentChannel();
return {
commandContext: context,
embeds: [logEmbed, publicEmbed]
};
}
}