From 53a084b3b1f12fd5a7db8d4713047466c1ad1c8d Mon Sep 17 00:00:00 2001 From: Ethan Lane Date: Wed, 27 Mar 2024 10:40:42 +0000 Subject: [PATCH 1/8] Create add lobby tests --- src/commands/501231711271780357/Lobby/add.ts | 2 +- .../501231711271780357/Lobby/add.test.ts | 349 +++++++++++++++++- 2 files changed, 339 insertions(+), 12 deletions(-) diff --git a/src/commands/501231711271780357/Lobby/add.ts b/src/commands/501231711271780357/Lobby/add.ts index b30f736..41d60b8 100644 --- a/src/commands/501231711271780357/Lobby/add.ts +++ b/src/commands/501231711271780357/Lobby/add.ts @@ -53,6 +53,6 @@ export default class AddRole extends Command { const entity = new eLobby(channel.channel.id, role.role.id, cooldown.value as number, gameName.value as string); await entity.Save(eLobby, entity); - await interaction.reply(`Added \`${channel.name}\` as a new lobby channel with a cooldown of \`${cooldown.value} minutes \` and will ping \`${role.name}\` on use`); + await interaction.reply(`Added \`${channel.name}\` as a new lobby channel with a cooldown of \`${cooldown.value} minutes\` and will ping \`${role.name}\` on use`); } } \ No newline at end of file diff --git a/tests/commands/501231711271780357/Lobby/add.test.ts b/tests/commands/501231711271780357/Lobby/add.test.ts index 2809796..cd4eb83 100644 --- a/tests/commands/501231711271780357/Lobby/add.test.ts +++ b/tests/commands/501231711271780357/Lobby/add.test.ts @@ -1,5 +1,6 @@ -import { PermissionsBitField, SlashCommandBuilder, SlashCommandChannelOption, SlashCommandNumberOption, SlashCommandRoleOption, SlashCommandStringOption } from "discord.js"; +import { CommandInteraction, PermissionsBitField, SlashCommandBuilder, SlashCommandChannelOption, SlashCommandNumberOption, SlashCommandRoleOption, SlashCommandStringOption } from "discord.js"; import Add from "../../../../src/commands/501231711271780357/Lobby/add"; +import Lobby from "../../../../src/database/entities/501231711271780357/Lobby"; describe('constuctor', () => { test("EXPECT properties to be set", () => { @@ -42,23 +43,349 @@ describe('constuctor', () => { }); describe('execute', () => { - test.todo("EXPECT channel to be added to the lobby database table"); + test("EXPECT channel to be added to the lobby database table", async () => { + const channel = { + channel: { + id: "channelId", + }, + name: "channelName", + }; + const role = { + role: {}, + name: "roleName", + }; + const cooldown = { + value: "5", + }; + const gameName = { + value: "test", + }; - test.todo("GIVEN channel is null, EXPECT error"); + const interaction = { + options: { + get: jest.fn() + .mockReturnValueOnce(channel) + .mockReturnValueOnce(role) + .mockReturnValueOnce(cooldown) + .mockReturnValueOnce(gameName), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; - test.todo("GIVEN channel.channel is undefined, EXPECT error"); + Lobby.FetchOneByChannelId = jest.fn().mockReturnValue(null); + Lobby.prototype.Save = jest.fn(); - test.todo("GIVEN role is null, EXPECT error"); + const add = new Add(); + await add.execute(interaction); - test.todo("GIVEN role.role is undefined, EXPECT error"); + expect(interaction.options.get).toHaveBeenCalledTimes(4); + expect(interaction.options.get).toHaveBeenCalledWith("channel"); + expect(interaction.options.get).toHaveBeenCalledWith("role"); + expect(interaction.options.get).toHaveBeenCalledWith("cooldown"); + expect(interaction.options.get).toHaveBeenCalledWith("name"); - test.todo("GIVEN cooldown is null, EXPECT error"); + expect(Lobby.FetchOneByChannelId).toHaveBeenCalledTimes(1); + expect(Lobby.FetchOneByChannelId).toHaveBeenCalledWith("channelId"); - test.todo("GIVEN cooldown.value is undefined, EXPECT error"); + expect(Lobby.prototype.Save).toHaveBeenCalledTimes(1); - test.todo("GIVEN gameName is null, EXPECT error"); + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Added `channelName` as a new lobby channel with a cooldown of `5 minutes` and will ping `roleName` on use"); + }); - test.todo("GIVEN gameName.value is undefined, EXPECT error"); + test("GIVEN channel is null, EXPECT error", async () => { + const channel = null; + const role = { + role: {}, + name: "roleName", + }; + const cooldown = { + value: "5", + }; + const gameName = { + value: "test", + }; - test.todo("GIVEN channel has already been set up in the database, EXPECT error"); + const interaction = { + options: { + get: jest.fn() + .mockReturnValueOnce(channel) + .mockReturnValueOnce(role) + .mockReturnValueOnce(cooldown) + .mockReturnValueOnce(gameName), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + const add = new Add(); + await add.execute(interaction); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Fields are required."); + }); + + test("GIVEN channel.channel is undefined, EXPECT error", async () => { + const channel = { + channel: undefined, + }; + const role = { + role: {}, + name: "roleName", + }; + const cooldown = { + value: "5", + }; + const gameName = { + value: "test", + }; + + const interaction = { + options: { + get: jest.fn() + .mockReturnValueOnce(channel) + .mockReturnValueOnce(role) + .mockReturnValueOnce(cooldown) + .mockReturnValueOnce(gameName), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + const add = new Add(); + await add.execute(interaction); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Fields are required."); + }); + + test("GIVEN role is null, EXPECT error", async () => { + const channel = { + channel: {}, + }; + const role = null; + const cooldown = { + value: "5", + }; + const gameName = { + value: "test", + }; + + const interaction = { + options: { + get: jest.fn() + .mockReturnValueOnce(channel) + .mockReturnValueOnce(role) + .mockReturnValueOnce(cooldown) + .mockReturnValueOnce(gameName), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + const add = new Add(); + await add.execute(interaction); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Fields are required."); + }); + + test("GIVEN role.role is undefined, EXPECT error", async () => { + const channel = { + channel: {}, + }; + const role = { + role: undefined + }; + const cooldown = { + value: "5", + }; + const gameName = { + value: "test", + }; + + const interaction = { + options: { + get: jest.fn() + .mockReturnValueOnce(channel) + .mockReturnValueOnce(role) + .mockReturnValueOnce(cooldown) + .mockReturnValueOnce(gameName), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + const add = new Add(); + await add.execute(interaction); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Fields are required."); + }); + + test("GIVEN cooldown is null, EXPECT error", async () => { + const channel = { + channel: {}, + }; + const role = { + role: {}, + name: "roleName", + }; + const cooldown = null; + const gameName = { + value: "test", + }; + + const interaction = { + options: { + get: jest.fn() + .mockReturnValueOnce(channel) + .mockReturnValueOnce(role) + .mockReturnValueOnce(cooldown) + .mockReturnValueOnce(gameName), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + const add = new Add(); + await add.execute(interaction); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Fields are required."); + }); + + test("GIVEN cooldown.value is undefined, EXPECT error", async () => { + const channel = { + channel: {}, + }; + const role = { + role: {}, + name: "roleName", + }; + const cooldown = { + value: undefined, + }; + const gameName = { + value: "test", + }; + + const interaction = { + options: { + get: jest.fn() + .mockReturnValueOnce(channel) + .mockReturnValueOnce(role) + .mockReturnValueOnce(cooldown) + .mockReturnValueOnce(gameName), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + const add = new Add(); + await add.execute(interaction); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Fields are required."); + }); + + test("GIVEN gameName is null, EXPECT error", async () => { + const channel = { + channel: {}, + }; + const role = { + role: {}, + name: "roleName", + }; + const cooldown = { + value: "5", + }; + const gameName = null; + + const interaction = { + options: { + get: jest.fn() + .mockReturnValueOnce(channel) + .mockReturnValueOnce(role) + .mockReturnValueOnce(cooldown) + .mockReturnValueOnce(gameName), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + const add = new Add(); + await add.execute(interaction); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Fields are required."); + }); + + test("GIVEN gameName.value is undefined, EXPECT error", async () => { + const channel = { + channel: {}, + }; + const role = { + role: {}, + name: "roleName", + }; + const cooldown = { + value: "5", + }; + const gameName = { + value: undefined, + }; + + const interaction = { + options: { + get: jest.fn() + .mockReturnValueOnce(channel) + .mockReturnValueOnce(role) + .mockReturnValueOnce(cooldown) + .mockReturnValueOnce(gameName), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + const add = new Add(); + await add.execute(interaction); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Fields are required."); + }); + + test("GIVEN channel has already been set up in the database, EXPECT error", async () => { + const channel = { + channel: { + id: "channelId", + }, + name: "channelName", + }; + const role = { + role: {}, + name: "roleName", + }; + const cooldown = { + value: "5", + }; + const gameName = { + value: "test", + }; + + const interaction = { + options: { + get: jest.fn() + .mockReturnValueOnce(channel) + .mockReturnValueOnce(role) + .mockReturnValueOnce(cooldown) + .mockReturnValueOnce(gameName), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + Lobby.FetchOneByChannelId = jest.fn().mockReturnValue({}); + Lobby.prototype.Save = jest.fn(); + + const add = new Add(); + await add.execute(interaction); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("This channel has already been setup."); + + expect(Lobby.FetchOneByChannelId).toHaveBeenCalledTimes(1); + expect(Lobby.prototype.Save).not.toHaveBeenCalled(); + }); }); \ No newline at end of file From f770e3f4fc1b683b84f31b7db4e1bd701e3a0a9b Mon Sep 17 00:00:00 2001 From: Ethan Lane Date: Wed, 27 Mar 2024 11:01:18 +0000 Subject: [PATCH 2/8] Add list lobby tests --- .../501231711271780357/Lobby/list.test.ts | 79 ++++++++++++++++++- 1 file changed, 76 insertions(+), 3 deletions(-) diff --git a/tests/commands/501231711271780357/Lobby/list.test.ts b/tests/commands/501231711271780357/Lobby/list.test.ts index d58deed..ee6a0f8 100644 --- a/tests/commands/501231711271780357/Lobby/list.test.ts +++ b/tests/commands/501231711271780357/Lobby/list.test.ts @@ -1,9 +1,82 @@ +import { APIEmbedField, CommandInteraction, EmbedBuilder, PermissionsBitField, SlashCommandBuilder } from "discord.js"; +import List from "../../../../src/commands/501231711271780357/Lobby/list"; +import Lobby from "../../../../src/database/entities/501231711271780357/Lobby"; +import EmbedColours from "../../../../src/constants/EmbedColours"; + describe('constructor', () => { - test.todo("EXPECT properties to be set"); + test("EXPECT properties to be set", () => { + const list = new List(); + + expect(list.CommandBuilder).toBeDefined(); + + const commandBulder = list.CommandBuilder as SlashCommandBuilder; + + expect(commandBulder.name).toBe("listlobby"); + expect(commandBulder.description).toBe("Lists all channels set up as lobbies"); + expect(commandBulder.default_member_permissions).toBe(PermissionsBitField.Flags.ModerateMembers.toString()); + }); }); describe("execute", () => { - test.todo('EXPECT list of lobby channels to be sent'); + test('EXPECT list of lobby channels to be sent', async () => { + let repliedWith; - test.todo("GIVEN interaction.guild is null, EXPECT error"); + const interaction = { + guild: { + channels: { + cache: { + map: jest.fn().mockReturnValue([{ + id: "channelId", + }]), + } + } + }, + reply: jest.fn().mockImplementation((options) => { + repliedWith = options; + }), + } as unknown as CommandInteraction; + + Lobby.FetchOneByChannelId = jest.fn().mockReturnValue({ + Name: "lobbyName", + LastUsed: "lastUsed", + }); + + const list = new List(); + await list.execute(interaction); + + expect(Lobby.FetchOneByChannelId).toHaveBeenCalledTimes(1); + expect(Lobby.FetchOneByChannelId).toHaveBeenCalledWith("channelId"); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + + expect(repliedWith).toBeDefined(); + expect(repliedWith!.embeds).toBeDefined(); + expect(repliedWith!.embeds.length).toBe(1); + + const repliedEmbed: EmbedBuilder = repliedWith!.embeds[0]; + + expect(repliedEmbed.data.color).toBe(EmbedColours.Ok); + expect(repliedEmbed.data.title).toBe("Lobbies"); + expect(repliedEmbed.data.description).toBe("Channels: 1"); + expect(repliedEmbed.data.fields).toBeDefined(); + expect(repliedEmbed.data.fields!.length).toBe(1); + + const repliedEmbedField1: APIEmbedField = repliedEmbed.data.fields![0]; + + expect(repliedEmbedField1.name).toBe("# lobbyName"); + expect(repliedEmbedField1.value).toBe("Last Used: lastUsed"); + }); + + test("GIVEN interaction.guild is null, EXPECT error", async () => { + const interaction = { + guild: null, + reply: jest.fn(), + } as unknown as CommandInteraction; + + const list = new List(); + await list.execute(interaction); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Guild not found."); + }); }); \ No newline at end of file From 5e309620531f093289a5fa59f6e0b8b36b99cc3a Mon Sep 17 00:00:00 2001 From: Ethan Lane Date: Wed, 27 Mar 2024 11:31:32 +0000 Subject: [PATCH 3/8] Create lobby command tests --- .../501231711271780357/Lobby/lobby.test.ts | 109 +++++++++++++++++- 1 file changed, 104 insertions(+), 5 deletions(-) diff --git a/tests/commands/501231711271780357/Lobby/lobby.test.ts b/tests/commands/501231711271780357/Lobby/lobby.test.ts index 872a48b..4b2a287 100644 --- a/tests/commands/501231711271780357/Lobby/lobby.test.ts +++ b/tests/commands/501231711271780357/Lobby/lobby.test.ts @@ -1,13 +1,112 @@ +import { CommandInteraction, SlashCommandBuilder } from "discord.js"; +import Command from "../../../../src/commands/501231711271780357/Lobby/lobby"; +import Lobby from "../../../../src/database/entities/501231711271780357/Lobby"; + describe('constructor', () => { - test.todo("EXPECT properties to be set"); + test("EXPECT properties to be set", () => { + const lobby = new Command(); + + expect(lobby.CommandBuilder).toBeDefined(); + + const commandBuilder = lobby.CommandBuilder as SlashCommandBuilder; + + expect(commandBuilder.name).toBe("lobby"); + expect(commandBuilder.description).toBe("Attempt to organise a lobby"); + }); }); describe("execute", () => { - test.todo("EXPECT lobby command to announce a lobby setup"); + test("EXPECT lobby command to announce a lobby setup", async () => { + const interaction = { + user: "user", + channelId: "channelId", + reply: jest.fn(), + } as unknown as CommandInteraction; - test.todo("GIVEN interaction.channelId is null, EXPECT nothing to happen"); + const markAsUsed = jest.fn(); + const lobbySave = jest.fn(); - test.todo("GIVEN channel is not setup in the database as a lobby, EXPECT error"); + Lobby.FetchOneByChannelId = jest.fn().mockResolvedValue({ + Cooldown: 5, + LastUsed: new Date(2 * 60 * 1000), + Name: "gameName", + RoleId: "roleId", + MarkAsUsed: markAsUsed, + Save: lobbySave, + }); - test.todo("GIVEN lobby command was last used within the cooldown, EXPECT error"); + Date.now = jest.fn().mockReturnValue(10 * 60 * 1000); + + const lobby = new Command(); + await lobby.execute(interaction); + + expect(Lobby.FetchOneByChannelId).toHaveBeenCalledTimes(1); + expect(Lobby.FetchOneByChannelId).toHaveBeenCalledWith("channelId"); + + expect(Date.now).toHaveBeenCalledTimes(1); + + expect(markAsUsed).toHaveBeenCalledTimes(1); + + expect(lobbySave).toHaveBeenCalledTimes(1); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("user would like to organise a lobby of **gameName**! <@&roleId>"); + }); + + test("GIVEN interaction.channelId is null, EXPECT nothing to happen", async () => { + const interaction = { + channelId: null, + reply: jest.fn(), + } as unknown as CommandInteraction; + + const lobby = new Command(); + await lobby.execute(interaction); + + expect(interaction.reply).not.toHaveBeenCalled(); + }); + + test("GIVEN channel is not setup in the database as a lobby, EXPECT error", async () => { + const interaction = { + channelId: "channelId", + reply: jest.fn(), + } as unknown as CommandInteraction; + + Lobby.FetchOneByChannelId = jest.fn().mockResolvedValue(null); + + const lobby = new Command(); + await lobby.execute(interaction); + + expect(Lobby.FetchOneByChannelId).toHaveBeenCalledTimes(1); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("This channel is disabled from using the lobby command."); + }); + + test("GIVEN lobby command was last used within the cooldown, EXPECT error", async () => { + const interaction = { + user: "user", + channelId: "channelId", + reply: jest.fn(), + } as unknown as CommandInteraction; + + const markAsUsed = jest.fn(); + const lobbySave = jest.fn(); + + Lobby.FetchOneByChannelId = jest.fn().mockResolvedValue({ + Cooldown: 5, + LastUsed: new Date(2 * 60 * 1000), + Name: "gameName", + RoleId: "roleId", + MarkAsUsed: markAsUsed, + Save: lobbySave, + }); + + Date.now = jest.fn().mockReturnValue(5 * 60 * 1000); + + const lobby = new Command(); + await lobby.execute(interaction); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Requesting a lobby for this game is on cooldown! Please try again in **2 minutes**."); + }); }); \ No newline at end of file From 946422b2acbdb76171fc3b6f64cb3f841f192d6a Mon Sep 17 00:00:00 2001 From: Ethan Lane Date: Wed, 27 Mar 2024 11:51:26 +0000 Subject: [PATCH 4/8] Create remove lobby tests --- .../501231711271780357/Lobby/remove.test.ts | 113 +++++++++++++++++- 1 file changed, 108 insertions(+), 5 deletions(-) diff --git a/tests/commands/501231711271780357/Lobby/remove.test.ts b/tests/commands/501231711271780357/Lobby/remove.test.ts index f2c3af0..0ab6f0e 100644 --- a/tests/commands/501231711271780357/Lobby/remove.test.ts +++ b/tests/commands/501231711271780357/Lobby/remove.test.ts @@ -1,13 +1,116 @@ +import { CommandInteraction, PermissionsBitField, SlashCommandBuilder, SlashCommandChannelOption } from "discord.js"; +import Remove from "../../../../src/commands/501231711271780357/Lobby/remove"; +import Lobby from "../../../../src/database/entities/501231711271780357/Lobby"; +import BaseEntity from "../../../../src/contracts/BaseEntity"; + describe('constructor', () => { - test.todo("EXPECT properties to be set"); + test("EXPECT properties to be set", () => { + const remove = new Remove(); + + expect(remove.CommandBuilder).toBeDefined(); + + const commandBuilder = remove.CommandBuilder as SlashCommandBuilder; + + expect(commandBuilder.name).toBe("removelobby"); + expect(commandBuilder.description).toBe("Remove a lobby channel"); + expect(commandBuilder.default_member_permissions).toBe(PermissionsBitField.Flags.ModerateMembers.toString()); + expect(commandBuilder.options.length).toBe(1); + + const channelOption = commandBuilder.options[0] as SlashCommandChannelOption; + + expect(channelOption.name).toBe("channel"); + expect(channelOption.description).toBe("The channel"); + expect(channelOption.required).toBe(true); + }); }); describe("execute", () => { - test.todo("EXPECT channel to be removed from database"); + test("EXPECT channel to be removed from database", async () => { + const channel = { + channel: { + id: "channelId", + }, + }; - test.todo("GIVEN channel is null, EXPECT error"); + const interaction = { + options: { + get: jest.fn().mockReturnValue(channel), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; - test.todo("GIVEN channel.channel is undefined, EXPECT error"); + Lobby.FetchOneByChannelId = jest.fn().mockResolvedValue({}); + BaseEntity.Remove = jest.fn(); - test.todo("GIVEN channel is not set up as a lobby, EXPECT error"); + const remove = new Remove(); + await remove.execute(interaction); + + expect(Lobby.FetchOneByChannelId).toHaveBeenCalledTimes(1); + expect(Lobby.FetchOneByChannelId).toHaveBeenCalledWith("channelId"); + + expect(BaseEntity.Remove).toHaveBeenCalledTimes(1); + + expect(interaction.options.get).toHaveBeenCalledTimes(1); + expect(interaction.options.get).toHaveBeenCalledWith("channel"); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Removed <#channelId> from the list of lobby channels"); + }); + + test("GIVEN channel is null, EXPECT error", async () => { + const interaction = { + options: { + get: jest.fn().mockReturnValue(null), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + const remove = new Remove(); + await remove.execute(interaction); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Channel is required."); + }); + + test("GIVEN channel.channel is undefined, EXPECT error", async () => { + const channel = { + channel: undefined, + }; + + const interaction = { + options: { + get: jest.fn().mockReturnValue(channel), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + const remove = new Remove(); + await remove.execute(interaction); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Channel is required."); + }); + + test("GIVEN channel is not set up as a lobby, EXPECT error", async () => { + const channel = { + channel: { + id: "channelId", + }, + }; + + const interaction = { + options: { + get: jest.fn().mockReturnValue(channel), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + Lobby.FetchOneByChannelId = jest.fn().mockResolvedValue(null); + + const remove = new Remove(); + await remove.execute(interaction); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Channel not found."); + }); }); \ No newline at end of file From 00f6a60a4397c90fe930f7d4106f343accae393a Mon Sep 17 00:00:00 2001 From: Ethan Lane Date: Wed, 27 Mar 2024 12:27:20 +0000 Subject: [PATCH 5/8] Add entry command tests --- .../commands/501231711271780357/entry.test.ts | 108 +++++++++++++++++- 1 file changed, 103 insertions(+), 5 deletions(-) diff --git a/tests/commands/501231711271780357/entry.test.ts b/tests/commands/501231711271780357/entry.test.ts index 6556b8c..b9bde81 100644 --- a/tests/commands/501231711271780357/entry.test.ts +++ b/tests/commands/501231711271780357/entry.test.ts @@ -1,13 +1,111 @@ +import { CommandInteraction, EmbedBuilder, PermissionsBitField, SlashCommandBuilder } from "discord.js"; +import Entry from "../../../src/commands/501231711271780357/entry"; +import SettingsHelper from "../../../src/helpers/SettingsHelper"; +import EmbedColours from "../../../src/constants/EmbedColours"; + describe('constructor', () => { - test.todo("EXPECT properties to be set"); + test("EXPECT properties to be set", () => { + const entry = new Entry(); + + expect(entry.CommandBuilder).toBeDefined(); + + const commandBuilder = entry.CommandBuilder as SlashCommandBuilder; + + expect(commandBuilder.name).toBe("entry"); + expect(commandBuilder.description).toBe("Sends the entry embed"); + expect(commandBuilder.default_member_permissions).toBe(PermissionsBitField.Flags.ModerateMembers.toString()); + }); }); describe("execute", () => { - test.todo("EXPECT entry embed to be sent"); + test("EXPECT entry embed to be sent", async () => { + let sentWith; - test.todo("GIVEN interaction.guildId is null, EXPECT error"); + const interaction = { + guildId: "guildId", + channel: { + send: jest.fn().mockImplementation((options) => { + sentWith = options; + }), + }, + } as unknown as CommandInteraction; - test.todo("GIVEN interaction.channel is null, EXPECT error"); + SettingsHelper.GetSetting = jest.fn().mockResolvedValue("channelId"); - test.todo("GIVEN channels.rules setting is not set, EXPECT channel id to be defaulted"); + const entry = new Entry(); + await entry.execute(interaction); + + expect(SettingsHelper.GetSetting).toHaveBeenCalledTimes(1); + expect(SettingsHelper.GetSetting).toHaveBeenCalledWith("channels.rules", "guildId"); + + expect(interaction.channel!.send).toHaveBeenCalledTimes(1); + expect(sentWith).toBeDefined(); + expect(sentWith!.embeds).toBeDefined(); + expect(sentWith!.embeds.length).toBe(1); + + const embed = sentWith!.embeds[0] as EmbedBuilder; + + expect(embed.data.color).toBe(EmbedColours.Ok); + expect(embed.data.title).toBe("Welcome"); + expect(embed.data.description).toBe("Welcome to the server! Please make sure to read the rules in the <#channelId> channel and type the code found there in here to proceed to the main part of the server."); + }); + + test("GIVEN interaction.guildId is null, EXPECT error", async () => { + const interaction = { + guildId: null, + } as unknown as CommandInteraction; + + SettingsHelper.GetSetting = jest.fn(); + + const entry = new Entry(); + await entry.execute(interaction); + + expect(SettingsHelper.GetSetting).not.toHaveBeenCalled(); + }); + + test("GIVEN interaction.channel is null, EXPECT error", async () => { + const interaction = { + guildId: "guildId", + channel: null, + } as unknown as CommandInteraction; + + SettingsHelper.GetSetting = jest.fn(); + + const entry = new Entry(); + await entry.execute(interaction); + + expect(SettingsHelper.GetSetting).not.toHaveBeenCalled(); + }); + + test("GIVEN channels.rules setting is not set, EXPECT channel id to be defaulted", async () => { + let sentWith; + + const interaction = { + guildId: "guildId", + channel: { + send: jest.fn().mockImplementation((options) => { + sentWith = options; + }), + }, + } as unknown as CommandInteraction; + + SettingsHelper.GetSetting = jest.fn().mockResolvedValue(undefined); + + const entry = new Entry(); + await entry.execute(interaction); + + expect(SettingsHelper.GetSetting).toHaveBeenCalledTimes(1); + expect(SettingsHelper.GetSetting).toHaveBeenCalledWith("channels.rules", "guildId"); + + expect(interaction.channel!.send).toHaveBeenCalledTimes(1); + expect(sentWith).toBeDefined(); + expect(sentWith!.embeds).toBeDefined(); + expect(sentWith!.embeds.length).toBe(1); + + const embed = sentWith!.embeds[0] as EmbedBuilder; + + expect(embed.data.color).toBe(EmbedColours.Ok); + expect(embed.data.title).toBe("Welcome"); + expect(embed.data.description).toBe("Welcome to the server! Please make sure to read the rules in the <#rules> channel and type the code found there in here to proceed to the main part of the server."); + }); }); \ No newline at end of file From d5a5282371e3209ed2cd327abc91ac025e362db7 Mon Sep 17 00:00:00 2001 From: Ethan Lane Date: Wed, 27 Mar 2024 12:51:51 +0000 Subject: [PATCH 6/8] Create config tests --- tests/commands/Role/config.test.ts | 224 +++++++++++++++++++++++++++-- 1 file changed, 215 insertions(+), 9 deletions(-) diff --git a/tests/commands/Role/config.test.ts b/tests/commands/Role/config.test.ts index ac6c1c7..56ea2a9 100644 --- a/tests/commands/Role/config.test.ts +++ b/tests/commands/Role/config.test.ts @@ -1,21 +1,227 @@ +import { CommandInteraction, PermissionsBitField, SlashCommandBuilder, SlashCommandRoleOption } from "discord.js"; +import Config from "../../../src/commands/Role/config"; +import Role from "../../../src/database/entities/Role"; +import Server from "../../../src/database/entities/Server"; + describe('constructor', () => { - test.todo('EXPECT properties to be set'); + test('EXPECT properties to be set', () => { + const config = new Config(); + + expect(config.CommandBuilder).toBeDefined(); + + const commandBuilder = config.CommandBuilder as SlashCommandBuilder; + + expect(commandBuilder.name).toBe("configrole"); + expect(commandBuilder.description).toBe("Toggle your roles"); + expect(commandBuilder.default_member_permissions).toBe(PermissionsBitField.Flags.ManageRoles.toString()); + expect(commandBuilder.options.length).toBe(1); + + const roleOption = commandBuilder.options[0] as SlashCommandRoleOption; + + expect(roleOption.name).toBe("role"); + expect(roleOption.description).toBe("The role name"); + expect(roleOption.required).toBe(true); + }); }); describe("execute", () => { - test.todo("GIVEN role is marked as assignable, EXPECT role to be removed"); + test("GIVEN role is marked as assignable, EXPECT role to be removed", async () => { + const role = { + role: { + id: "roleId", + }, + }; - test.todo("GIVEN role is not marked as assignable, EXPECT role to be added"); + const interaction = { + guildId: "guildId", + guild: {}, + member: {}, + options: { + get: jest.fn().mockReturnValue(role), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; - test.todo("GIVEN interaction.guildId is null, EXPECT error"); + Role.FetchOneByRoleId = jest.fn().mockResolvedValue({}); + Role.Remove = jest.fn(); - test.todo("GIVEN interaction.guild is null, EXPECT error"); + const config = new Config(); + await config.execute(interaction); - test.todo("GIVEN interaction.member is null, EXPECT error"); + expect(Role.FetchOneByRoleId).toHaveBeenCalledTimes(1); + expect(Role.FetchOneByRoleId).toHaveBeenCalledWith("roleId"); - test.todo("GIVEN role is null, EXPECT error"); + expect(Role.Remove).toHaveBeenCalledTimes(1); - test.todo("GIVEN role.role is undefined, EXPECT error"); + expect(interaction.options.get).toHaveBeenCalledTimes(1); + expect(interaction.options.get).toHaveBeenCalledWith("role"); - test.todo("GIVEN server is not configured in the database, EXPECT error"); + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Removed role from configuration."); + }); + + test("GIVEN role is not marked as assignable, EXPECT role to be added", async () => { + let newRole: Role | undefined; + + const role = { + role: { + id: "roleId", + }, + }; + + const interaction = { + guildId: "guildId", + guild: {}, + member: {}, + options: { + get: jest.fn().mockReturnValue(role), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + Role.FetchOneByRoleId = jest.fn().mockResolvedValue(null); + Role.prototype.SetServer = jest.fn(); + Role.prototype.Save = jest.fn().mockImplementation((_, role) => { + newRole = role; + }); + + Server.FetchOneById = jest.fn().mockResolvedValue({}); + + const config = new Config(); + await config.execute(interaction); + + expect(Role.FetchOneByRoleId).toHaveBeenCalledTimes(1); + expect(Role.FetchOneByRoleId).toHaveBeenCalledWith("roleId"); + + expect(Role.prototype.SetServer).toHaveBeenCalledTimes(1); + + expect(Role.prototype.Save).toHaveBeenCalledTimes(1); + expect(newRole).toBeDefined(); + expect(newRole!.RoleId).toBe("roleId"); + + expect(interaction.options.get).toHaveBeenCalledTimes(1); + expect(interaction.options.get).toHaveBeenCalledWith("role"); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Added role to configuration."); + }); + + test("GIVEN interaction.guildId is null, EXPECT error", async () => { + const interaction = { + guildId: null, + options: { + get: jest.fn(), + } + } as unknown as CommandInteraction; + + const config = new Config(); + await config.execute(interaction); + + expect(interaction.options.get).not.toHaveBeenCalled(); + }); + + test("GIVEN interaction.guild is null, EXPECT error", async () => { + const interaction = { + guildId: "guildId", + guild: null, + options: { + get: jest.fn(), + } + } as unknown as CommandInteraction; + + const config = new Config(); + await config.execute(interaction); + + expect(interaction.options.get).not.toHaveBeenCalled(); + }); + + test("GIVEN interaction.member is null, EXPECT error", async () => { + const interaction = { + guildId: "guildId", + guild: {}, + member: null, + options: { + get: jest.fn(), + } + } as unknown as CommandInteraction; + + const config = new Config(); + await config.execute(interaction); + + expect(interaction.options.get).not.toHaveBeenCalled(); + }); + + test("GIVEN role is null, EXPECT error", async () => { + const interaction = { + guildId: "guildId", + guild: {}, + member: {}, + options: { + get: jest.fn().mockReturnValue(null), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + const config = new Config(); + await config.execute(interaction); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Fields are required."); + }); + + test("GIVEN role.role is undefined, EXPECT error", async () => { + const role = { + role: null, + } + + const interaction = { + guildId: "guildId", + guild: {}, + member: {}, + options: { + get: jest.fn().mockReturnValue(role), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + const config = new Config(); + await config.execute(interaction); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Fields are required."); + }); + + test("GIVEN server is not configured in the database, EXPECT error", async () => { + let newRole: Role | undefined; + + const role = { + role: { + id: "roleId", + }, + }; + + const interaction = { + guildId: "guildId", + guild: {}, + member: {}, + options: { + get: jest.fn().mockReturnValue(role), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + Role.FetchOneByRoleId = jest.fn().mockResolvedValue(null); + Role.prototype.SetServer = jest.fn(); + Role.prototype.Save = jest.fn().mockImplementation((_, role) => { + newRole = role; + }); + + Server.FetchOneById = jest.fn().mockResolvedValue(null); + + const config = new Config(); + await config.execute(interaction); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("This server has not been setup."); + }); }); \ No newline at end of file From e7fde3a2ea05a63008883bd2eebe101df32c8126 Mon Sep 17 00:00:00 2001 From: Ethan Lane Date: Wed, 27 Mar 2024 13:57:36 +0000 Subject: [PATCH 7/8] Add role command tests --- src/commands/Role/role.ts | 14 +- tests/commands/Role/role.test.ts | 470 +++++++++++++++++++++++++++++-- 2 files changed, 460 insertions(+), 24 deletions(-) diff --git a/src/commands/Role/role.ts b/src/commands/Role/role.ts index 09e5342..1596a69 100644 --- a/src/commands/Role/role.ts +++ b/src/commands/Role/role.ts @@ -72,20 +72,18 @@ export default class Role extends Command { const userRole = roleManager.cache.find(x => x.name == requestedRole.role!.name); const assignRole = interaction.guild.roles.cache.find(x => x.id == requestedRole.role!.id); - - if (!assignRole) return; - - if (!assignRole.editable) { + + if (!assignRole!.editable) { await interaction.reply('Insufficient permissions. Please contact a moderator.'); return; } if (!userRole) { - await roleManager.add(assignRole); - await interaction.reply(`Gave role: \`${assignRole.name}\``); + await roleManager.add(assignRole!); + await interaction.reply(`Gave role: \`${assignRole!.name}\``); } else { - await roleManager.remove(assignRole); - await interaction.reply(`Removed role: \`${assignRole.name}\``); + await roleManager.remove(assignRole!); + await interaction.reply(`Removed role: \`${assignRole!.name}\``); } } diff --git a/tests/commands/Role/role.test.ts b/tests/commands/Role/role.test.ts index af90fe4..bb133b1 100644 --- a/tests/commands/Role/role.test.ts +++ b/tests/commands/Role/role.test.ts @@ -1,37 +1,475 @@ -beforeEach(() => { - process.env = {}; -}); +import { CommandInteraction, GuildMemberRoleManager, SlashCommandBuilder, SlashCommandRoleOption, SlashCommandSubcommandBuilder } from "discord.js"; +import Command from "../../../src/commands/Role/role"; +import Role from "../../../src/database/entities/Role"; +import { EmbedBuilder } from "@discordjs/builders"; +import EmbedColours from "../../../src/constants/EmbedColours"; describe('Constructor', () => { - test.todo('EXPECT properties are set'); + test('EXPECT properties are set', () => { + const command = new Command(); + + expect(command.CommandBuilder).toBeDefined(); + + const commandBuilder = command.CommandBuilder as SlashCommandBuilder; + + expect(commandBuilder.name).toBe("role"); + expect(commandBuilder.description).toBe("Toggle your roles"); + expect(commandBuilder.options.length).toBe(2); + + const toggleSubcommand = commandBuilder.options[0] as SlashCommandSubcommandBuilder; + + expect(toggleSubcommand.name).toBe("toggle"); + expect(toggleSubcommand.description).toBe("Toggle your role"); + expect(toggleSubcommand.options.length).toBe(1); + + const toggleRoleOption = toggleSubcommand.options[0] as SlashCommandRoleOption; + + expect(toggleRoleOption.name).toBe("role"); + expect(toggleRoleOption.description).toBe("The role name"); + expect(toggleRoleOption.required).toBe(true); + + const listSubcommand = commandBuilder.options[1] as SlashCommandSubcommandBuilder; + + expect(listSubcommand.name).toBe("list"); + expect(listSubcommand.description).toBe("List togglable roles"); + }); }); describe('Execute', () => { - test.todo("GIVEN interaction is not a chat input command, EXPECT nothing to happen"); + test("GIVEN interaction is not a chat input command, EXPECT nothing to happen", async () => { + const interaction = { + isChatInputCommand: jest.fn().mockReturnValue(false), + reply: jest.fn(), + } as unknown as CommandInteraction; - test.todo("GIVEN an invalid subcommand is given, EXPECT not found error"); + const command = new Command(); + await command.execute(interaction); + + expect(interaction.reply).not.toHaveBeenCalled(); + }); + + test("GIVEN an invalid subcommand is given, EXPECT not found error", async () => { + const interaction = { + isChatInputCommand: jest.fn().mockReturnValue(true), + options: { + getSubcommand: jest.fn().mockReturnValue("other"), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + const command = new Command(); + await command.execute(interaction); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Subcommand not found."); + }); }); describe("toggle", () => { - test.todo("GIVEN user has the role, EXPECT role to be removed"); + test("GIVEN user has the role, EXPECT role to be removed", async () => { + const role = { + id: "roleId", + name: "roleName", + editable: true, + }; - test.todo("GIVEN user does not have the role, EXPECT role to be added") + const requestedRole = { + role: { + name: "roleName", + }, + }; - test.todo("GIVEN interaction.guild is null, EXPECT nothing to happen"); + const userRole = {}; - test.todo("GIVEN interaction.member is null, EXPECT nothing to happen"); + const interaction = { + isChatInputCommand: jest.fn().mockReturnValue(true), + guildId: "guildId", + guild: { + roles: { + cache: { + find: jest.fn().mockReturnValue(role), + } + } + }, + member: { + roles: { + cache: { + find: jest.fn().mockReturnValue(userRole), + }, + remove: jest.fn(), + }, + }, + options: { + get: jest.fn().mockReturnValue(requestedRole), + getSubcommand: jest.fn().mockReturnValue("toggle"), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; - test.todo("GIVEN requestedRole is null, EXPECT invalid error"); + Role.FetchAllByServerId = jest.fn().mockResolvedValue([{}]); - test.todo("GIVEN requestedRole.role is undefined, EXPECT invalid error"); + const command = new Command(); + await command.execute(interaction); - test.todo("GIVEN role is not assignable, EXPECT unassignable error"); + expect(Role.FetchAllByServerId).toHaveBeenCalledTimes(1); + expect(Role.FetchAllByServerId).toHaveBeenCalledWith("guildId"); - test.todo("GIVEN assignRole is not foundm, EXPECT nothing to happen"); + expect(interaction.guild?.roles.cache.find).toHaveBeenCalledTimes(2); + + expect(interaction.options.get).toHaveBeenCalledTimes(1); + expect(interaction.options.get).toHaveBeenCalledWith("role"); - test.todo("GIVEN assignRole is not editable, EXPECT insufficient permissions error"); + const roleManager = interaction.member!.roles as GuildMemberRoleManager; + + expect(roleManager.cache.find).toHaveBeenCalledTimes(1); + expect(roleManager.remove).toHaveBeenCalledTimes(1); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Removed role: `roleName`"); + }); + + test("GIVEN user does not have the role, EXPECT role to be added", async () => { + const role = { + id: "roleId", + name: "roleName", + editable: true, + }; + + const requestedRole = { + role: { + name: "roleName", + }, + }; + + const interaction = { + isChatInputCommand: jest.fn().mockReturnValue(true), + guildId: "guildId", + guild: { + roles: { + cache: { + find: jest.fn().mockReturnValue(role), + } + } + }, + member: { + roles: { + cache: { + find: jest.fn().mockReturnValue(undefined), + }, + add: jest.fn(), + }, + }, + options: { + get: jest.fn().mockReturnValue(requestedRole), + getSubcommand: jest.fn().mockReturnValue("toggle"), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + Role.FetchAllByServerId = jest.fn().mockResolvedValue([{}]); + + const command = new Command(); + await command.execute(interaction); + + expect(Role.FetchAllByServerId).toHaveBeenCalledTimes(1); + expect(Role.FetchAllByServerId).toHaveBeenCalledWith("guildId"); + + expect(interaction.guild?.roles.cache.find).toHaveBeenCalledTimes(2); + + expect(interaction.options.get).toHaveBeenCalledTimes(1); + expect(interaction.options.get).toHaveBeenCalledWith("role"); + + const roleManager = interaction.member!.roles as GuildMemberRoleManager; + + expect(roleManager.cache.find).toHaveBeenCalledTimes(1); + expect(roleManager.add).toHaveBeenCalledTimes(1); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Gave role: `roleName`"); + }) + + test("GIVEN interaction.guild is null, EXPECT nothing to happen", async () => { + const role = { + id: "roleId", + name: "roleName", + editable: true, + }; + + const requestedRole = { + role: { + name: "roleName", + }, + }; + + const userRole = {}; + + const interaction = { + isChatInputCommand: jest.fn().mockReturnValue(true), + guildId: "guildId", + guild: null, + member: { + roles: { + cache: { + find: jest.fn().mockReturnValue(userRole), + }, + add: jest.fn(), + remove: jest.fn(), + }, + }, + options: { + get: jest.fn().mockReturnValue(requestedRole), + getSubcommand: jest.fn().mockReturnValue("toggle"), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + Role.FetchAllByServerId = jest.fn().mockResolvedValue([{}]); + + const command = new Command(); + await command.execute(interaction); + + expect(interaction.reply).not.toHaveBeenCalled(); + + const roleManager = interaction.member!.roles as GuildMemberRoleManager; + + expect(roleManager.add).not.toHaveBeenCalled(); + expect(roleManager.remove).not.toHaveBeenCalled(); + }); + + test("GIVEN interaction.member is null, EXPECT nothing to happen", async () => { + const role = { + id: "roleId", + name: "roleName", + editable: true, + }; + + const requestedRole = { + role: { + name: "roleName", + }, + }; + + const userRole = {}; + + const interaction = { + isChatInputCommand: jest.fn().mockReturnValue(true), + guildId: "guildId", + guild: null, + member: { + roles: { + cache: { + find: jest.fn().mockReturnValue(userRole), + }, + add: jest.fn(), + remove: jest.fn(), + }, + }, + options: { + get: jest.fn().mockReturnValue(requestedRole), + getSubcommand: jest.fn().mockReturnValue("toggle"), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + Role.FetchAllByServerId = jest.fn().mockResolvedValue([{}]); + + const command = new Command(); + await command.execute(interaction); + + expect(interaction.reply).not.toHaveBeenCalled(); + + const roleManager = interaction.member!.roles as GuildMemberRoleManager; + + expect(roleManager.add).not.toHaveBeenCalled(); + expect(roleManager.remove).not.toHaveBeenCalled(); + }); + + test("GIVEN requestedRole is null, EXPECT invalid error", async () => { + const role = { + id: "roleId", + name: "roleName", + editable: true, + }; + + const userRole = {}; + + const interaction = { + isChatInputCommand: jest.fn().mockReturnValue(true), + guildId: "guildId", + guild: { + roles: { + cache: { + find: jest.fn().mockReturnValue(role), + } + } + }, + member: { + roles: { + cache: { + find: jest.fn().mockReturnValue(userRole), + }, + remove: jest.fn(), + }, + }, + options: { + get: jest.fn().mockReturnValue(null), + getSubcommand: jest.fn().mockReturnValue("toggle"), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + Role.FetchAllByServerId = jest.fn().mockResolvedValue([{}]); + + const command = new Command(); + await command.execute(interaction); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Fields are required."); + }); + + test("GIVEN requestedRole.role is undefined, EXPECT invalid error", async () => { + const role = { + id: "roleId", + name: "roleName", + editable: true, + }; + + const userRole = {}; + + const requestedRole = { + role: undefined, + }; + + const interaction = { + isChatInputCommand: jest.fn().mockReturnValue(true), + guildId: "guildId", + guild: { + roles: { + cache: { + find: jest.fn().mockReturnValue(role), + } + } + }, + member: { + roles: { + cache: { + find: jest.fn().mockReturnValue(userRole), + }, + remove: jest.fn(), + }, + }, + options: { + get: jest.fn().mockReturnValue(requestedRole), + getSubcommand: jest.fn().mockReturnValue("toggle"), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + Role.FetchAllByServerId = jest.fn().mockResolvedValue([{}]); + + const command = new Command(); + await command.execute(interaction); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Fields are required."); + }); + + test("GIVEN assignRole is not editable, EXPECT insufficient permissions error", async () => { + const role = { + id: "roleId", + name: "roleName", + editable: false, + }; + + const userRole = {}; + + const requestedRole = { + role: { + name: "roleName", + }, + }; + + const interaction = { + isChatInputCommand: jest.fn().mockReturnValue(true), + guildId: "guildId", + guild: { + roles: { + cache: { + find: jest.fn().mockReturnValue(role), + } + } + }, + member: { + roles: { + cache: { + find: jest.fn().mockReturnValue(userRole), + }, + remove: jest.fn(), + }, + }, + options: { + get: jest.fn().mockReturnValue(requestedRole), + getSubcommand: jest.fn().mockReturnValue("toggle"), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + Role.FetchAllByServerId = jest.fn().mockResolvedValue([{}]); + + const command = new Command(); + await command.execute(interaction); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Insufficient permissions. Please contact a moderator."); + }); }); describe("list", () => { - test.todo("EXPECT role list to be sent"); + test("EXPECT role list to be sent", async () => { + let repliedWith; + + const role = { + name: "roleName", + }; + + const interaction = { + guildId: "guildId", + guild: { + roles: { + cache: { + find: jest.fn().mockReturnValue(role), + } + } + }, + isChatInputCommand: jest.fn().mockReturnValue(true), + options: { + getSubcommand: jest.fn().mockReturnValue("list"), + }, + reply: jest.fn().mockImplementation((options) => { + repliedWith = options; + }), + } as unknown as CommandInteraction; + + Role.FetchAllByServerId = jest.fn().mockResolvedValue([role]); + + const command = new Command(); + await command.execute(interaction); + + expect(Role.FetchAllByServerId).toHaveBeenCalledTimes(1); + expect(Role.FetchAllByServerId).toHaveBeenCalledWith("guildId"); + + expect(interaction.guild?.roles.cache.find).toHaveBeenCalledTimes(1); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + + expect(repliedWith).toBeDefined(); + expect(repliedWith!.embeds).toBeDefined(); + expect(repliedWith!.embeds.length).toBe(1); + + const embed = repliedWith!.embeds[0] as EmbedBuilder; + + expect(embed.data.color).toBe(EmbedColours.Ok); + expect(embed.data.title).toBe("Roles"); + expect(embed.data.description).toBe("Roles: 1\n\nroleName"); + }); }); \ No newline at end of file From e860a19bfeb8d2b3d1d6dec3b73b175e9964b8bb Mon Sep 17 00:00:00 2001 From: Ethan Lane Date: Wed, 27 Mar 2024 16:49:39 +0000 Subject: [PATCH 8/8] Create audits command tests --- src/commands/audits.ts | 3 +- tests/commands/audits.test.ts | 767 ++++++++++++++++++++++++++++++++-- 2 files changed, 742 insertions(+), 28 deletions(-) diff --git a/src/commands/audits.ts b/src/commands/audits.ts index 55c7fa9..fe324ef 100644 --- a/src/commands/audits.ts +++ b/src/commands/audits.ts @@ -60,8 +60,7 @@ export default class Audits extends Command { { name: 'Mute', value: AuditType.Mute.toString() }, { name: 'Kick', value: AuditType.Kick.toString() }, { name: 'Ban', value: AuditType.Ban.toString() }, - ) - .setRequired(true)) + )) .addStringOption(option => option .setName('reason') diff --git a/tests/commands/audits.test.ts b/tests/commands/audits.test.ts index a876ce0..1085e19 100644 --- a/tests/commands/audits.test.ts +++ b/tests/commands/audits.test.ts @@ -1,63 +1,778 @@ +import { CommandInteraction, EmbedBuilder, PermissionsBitField, SlashCommandBuilder, SlashCommandStringOption, SlashCommandSubcommandBuilder, SlashCommandUserOption } from "discord.js"; +import Audits from "../../src/commands/audits"; +import Audit from "../../src/database/entities/Audit"; +import { AuditType } from "../../src/constants/AuditType"; +import AuditTools from "../../src/helpers/AuditTools"; +import EmbedColours from "../../src/constants/EmbedColours"; +import StringTools from "../../src/helpers/StringTools"; + describe("constructor", () => { - test.todo("EXPECT properties to be set"); + test("EXPECT properties to be set", () => { + const audits = new Audits(); + + expect(audits.CommandBuilder).toBeDefined(); + + const commandBuilder = audits.CommandBuilder as SlashCommandBuilder; + + expect(commandBuilder.name).toBe("audits"); + expect(commandBuilder.description).toBe("View audits of a particular user in the server"); + expect(commandBuilder.default_member_permissions).toBe(PermissionsBitField.Flags.ModerateMembers.toString()); + expect(commandBuilder.options.length).toBe(4); + + const userSubcommand = commandBuilder.options[0] as SlashCommandSubcommandBuilder; + + expect(userSubcommand.name).toBe("user"); + expect(userSubcommand.description).toBe("View all audits done against a user"); + expect(userSubcommand.options.length).toBe(1); + + const userSubcommandUserOption = userSubcommand.options[0] as SlashCommandUserOption; + + expect(userSubcommandUserOption.name).toBe("target"); + expect(userSubcommandUserOption.description).toBe("The user"); + expect(userSubcommandUserOption.required).toBe(true); + + const viewSubcommand = commandBuilder.options[1] as SlashCommandSubcommandBuilder; + + expect(viewSubcommand.name).toBe("view"); + expect(viewSubcommand.description).toBe("View a particular audit"); + expect(viewSubcommand.options.length).toBe(1); + + const viewSubcommandAuditIdOption = viewSubcommand.options[0] as SlashCommandStringOption; + + expect(viewSubcommandAuditIdOption.name).toBe("auditid"); + expect(viewSubcommandAuditIdOption.description).toBe("The audit id in caps"); + expect(viewSubcommandAuditIdOption.required).toBe(true); + + const clearSubcommand = commandBuilder.options[2] as SlashCommandSubcommandBuilder; + + expect(clearSubcommand.name).toBe("clear"); + expect(clearSubcommand.description).toBe("Clears an audit from a user"); + expect(clearSubcommand.options.length).toBe(1); + + const clearSubcommandAuditIdOption = clearSubcommand.options[0] as SlashCommandStringOption; + + expect(clearSubcommandAuditIdOption.name).toBe("auditid"); + expect(clearSubcommandAuditIdOption.description).toBe("The audit id in caps"); + expect(clearSubcommandAuditIdOption.required).toBe(true); + + const addSubcommand = commandBuilder.options[3] as SlashCommandSubcommandBuilder; + + expect(addSubcommand.name).toBe("add"); + expect(addSubcommand.description).toBe("Manually add an audit"); + expect(addSubcommand.options.length).toBe(3); + + const addSubcommandUserOption = addSubcommand.options[0] as SlashCommandUserOption; + + expect(addSubcommandUserOption.name).toBe("target"); + expect(addSubcommandUserOption.description).toBe("The user"); + expect(addSubcommandUserOption.required).toBe(true); + + const addSubcommandTypeOption = addSubcommand.options[1] as SlashCommandStringOption; + + expect(addSubcommandTypeOption.name).toBe("type"); + expect(addSubcommandTypeOption.description).toBe("The type of audit"); + expect(addSubcommandTypeOption.required).toBe(true); + expect(addSubcommandTypeOption.choices).toBeDefined(); + expect(addSubcommandTypeOption.choices!.length).toBe(5); + + const addSubcommandReasonOption = addSubcommand.options[2] as SlashCommandStringOption; + + expect(addSubcommandReasonOption.name).toBe("reason"); + expect(addSubcommandReasonOption.description).toBe("The reason"); + }); }); describe('execute', () => { - test.todo("GIVEN interaction is not a chat input command, EXPECT nothing to happen"); + test("GIVEN interaction is not a chat input command, EXPECT nothing to happen", async () => { + const interaction = { + isChatInputCommand: jest.fn().mockReturnValue(false), + reply: jest.fn(), + } as unknown as CommandInteraction; - test.todo("GIVEN subcommand is invalid, EXPECT error"); + const audits = new Audits(); + await audits.execute(interaction); + + expect(interaction.isChatInputCommand).toHaveBeenCalledTimes(1); + expect(interaction.reply).not.toHaveBeenCalled(); + }); + + test("GIVEN subcommand is invalid, EXPECT error", async () => { + const interaction = { + isChatInputCommand: jest.fn().mockReturnValue(true), + options: { + getSubcommand: jest.fn().mockReturnValue("invalid"), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + const audits = new Audits(); + await audits.execute(interaction); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Subcommand doesn't exist."); + }); }); describe("user", () => { - test.todo("EXPECT audits for user to be sent"); + test("EXPECT audits for user to be sent", async () => { + let repliedWith; - test.todo("GIVEN interaction.guildId is null, EXPECT nothing to happen"); + const user = { + id: "userId", + }; + const audit = { + AuditId: "auditId", + AuditType: AuditType.Warn, + WhenCreated: new Date(5 * 60 * 1000), + }; - test.todo("GIVEN user is null, EXPECT error"); + const interaction = { + isChatInputCommand: jest.fn().mockReturnValue(true), + options: { + getSubcommand: jest.fn().mockReturnValue("user"), + getUser: jest.fn().mockReturnValue(user), + }, + guildId: "guildId", + reply: jest.fn().mockImplementation((options) => { + repliedWith = options; + }) + } as unknown as CommandInteraction; - test.todo("GIVEN audits null, EXPECT no audits to be displayed"); + Audit.FetchAuditsByUserId = jest.fn().mockReturnValue([ audit ]); + AuditTools.TypeToFriendlyText = jest.fn().mockReturnValue("Warn"); - test.todo("GIVEN audits length is 0, EXPECT no audits to be displayed"); + const audits = new Audits(); + await audits.execute(interaction); + + expect(Audit.FetchAuditsByUserId).toHaveBeenCalledTimes(1); + expect(Audit.FetchAuditsByUserId).toHaveBeenCalledWith("userId", "guildId"); + + expect(AuditTools.TypeToFriendlyText).toHaveBeenCalledTimes(1); + expect(AuditTools.TypeToFriendlyText).toHaveBeenCalledWith(AuditType.Warn); + + expect(interaction.options.getUser).toHaveBeenCalledTimes(1); + expect(interaction.options.getUser).toHaveBeenCalledWith("target"); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(repliedWith).toBeDefined(); + expect(repliedWith!.embeds).toBeDefined(); + expect(repliedWith!.embeds.length).toBe(1); + + const embed = repliedWith!.embeds[0] as EmbedBuilder; + + expect(embed.data.color).toBe(EmbedColours.Ok); + expect(embed.data.title).toBe("Audits"); + expect(embed.data.description).toBe("Audits: 1"); + expect(embed.data.fields).toBeDefined(); + expect(embed.data.fields?.length).toBe(1); + + const embedField = embed.data.fields![0]; + + expect(embedField.name).toBe("auditId // Warn"); + expect(embedField.value).toBe(new Date(5 * 60 * 1000).toString()); + }); + + test("GIVEN interaction.guildId is null, EXPECT nothing to happen", async () => { + const interaction = { + isChatInputCommand: jest.fn().mockReturnValue(true), + options: { + getSubcommand: jest.fn().mockReturnValue("user"), + }, + guildId: null, + reply: jest.fn(), + } as unknown as CommandInteraction; + + const audits = new Audits(); + await audits.execute(interaction); + + expect(interaction.reply).not.toHaveBeenCalled(); + }); + + test("GIVEN user is null, EXPECT error", async () => { + const interaction = { + isChatInputCommand: jest.fn().mockReturnValue(true), + options: { + getSubcommand: jest.fn().mockReturnValue("user"), + getUser: jest.fn().mockReturnValue(null), + }, + guildId: "guildId", + reply: jest.fn(), + } as unknown as CommandInteraction; + + const audits = new Audits(); + await audits.execute(interaction); + + expect(interaction.options.getUser).toHaveBeenCalledTimes(1); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("User not found."); + }); + + test("GIVEN audits null, EXPECT no audits to be displayed", async () => { + const interaction = { + isChatInputCommand: jest.fn().mockReturnValue(true), + options: { + getSubcommand: jest.fn().mockReturnValue("user"), + getUser: jest.fn().mockReturnValue({}), + }, + guildId: "guildId", + reply: jest.fn(), + } as unknown as CommandInteraction; + + Audit.FetchAuditsByUserId = jest.fn().mockResolvedValue(null); + + const audits = new Audits(); + await audits.execute(interaction); + + expect(Audit.FetchAuditsByUserId).toHaveBeenCalledTimes(1); + + expect(interaction.options.getUser).toHaveBeenCalledTimes(1); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("There are no audits for this user."); + }); + + test("GIVEN audits length is 0, EXPECT no audits to be displayed", async () => { + const interaction = { + isChatInputCommand: jest.fn().mockReturnValue(true), + options: { + getSubcommand: jest.fn().mockReturnValue("user"), + getUser: jest.fn().mockReturnValue({}), + }, + guildId: "guildId", + reply: jest.fn(), + } as unknown as CommandInteraction; + + Audit.FetchAuditsByUserId = jest.fn().mockResolvedValue([]); + + const audits = new Audits(); + await audits.execute(interaction); + + expect(Audit.FetchAuditsByUserId).toHaveBeenCalledTimes(1); + + expect(interaction.options.getUser).toHaveBeenCalledTimes(1); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("There are no audits for this user."); + }); }); describe("view", () => { - test.todo("EXPECT specific audit defaults to be sent"); + test("EXPECT specific audit defaults to be sent", async () => { + let repliedWith; - test.todo("GIVEN interaction.guildId is null, expect nothing to happen"); + const auditOption = { + value: "auditId", + }; - test.todo("GIVEN auditId is null, EXPECT error"); + const audit = { + Reason: "Test reason", + AuditType: AuditType.Warn, + ModeratorId: "moderatorId", + AuditId: "auditId", + }; - test.todo("GIVEN auditId.value is undefined, EXPECT error"); + const interaction = { + guildId: "guildId", + isChatInputCommand: jest.fn().mockReturnValue(true), + options: { + getSubcommand: jest.fn().mockReturnValue("view"), + get: jest.fn().mockReturnValue(auditOption), + }, + reply: jest.fn().mockImplementation((options) => { + repliedWith = options; + }), + } as unknown as CommandInteraction; - test.todo("GIVEN audit is not in database, EXPECT error"); + Audit.FetchAuditByAuditId = jest.fn().mockResolvedValue(audit); + AuditTools.TypeToFriendlyText = jest.fn().mockReturnValue("Warn"); - test.todo("GIVEN audit.Reason was not supplied, EXPECT reason to be defaulted"); + const audits = new Audits(); + await audits.execute(interaction); + + expect(Audit.FetchAuditByAuditId).toHaveBeenCalledTimes(1); + expect(Audit.FetchAuditByAuditId).toHaveBeenCalledWith("AUDITID", "guildId"); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(repliedWith).toBeDefined(); + expect(repliedWith!.embeds).toBeDefined(); + expect(repliedWith!.embeds.length).toBe(1); + + const embed = repliedWith!.embeds[0] as EmbedBuilder; + + expect(embed.data.color).toBe(EmbedColours.Ok); + expect(embed.data.title).toBe("Audit"); + expect(embed.data.description).toBe("AUDITID"); + expect(embed.data.fields).toBeDefined(); + expect(embed.data.fields!.length).toBe(3); + + const embedReasonField = embed.data.fields![0]; + + expect(embedReasonField.name).toBe("Reason"); + expect(embedReasonField.value).toBe("Test reason"); + expect(embedReasonField.inline).toBe(true); + + const embedTypeField = embed.data.fields![1]; + + expect(embedTypeField.name).toBe("Type"); + expect(embedTypeField.value).toBe("Warn"); + expect(embedTypeField.inline).toBe(true); + + const embedModeratorField = embed.data.fields![2]; + + expect(embedModeratorField.name).toBe("Moderator"); + expect(embedModeratorField.value).toBe("<@moderatorId>"); + expect(embedModeratorField.inline).toBe(true); + }); + + test("GIVEN interaction.guildId is null, expect nothing to happen", async () => { + const interaction = { + isChatInputCommand: jest.fn().mockReturnValue(true), + options: { + getSubcommand: jest.fn().mockReturnValue("view"), + }, + guildId: null, + reply: jest.fn(), + } as unknown as CommandInteraction; + + const audits = new Audits(); + await audits.execute(interaction); + + expect(interaction.reply).not.toHaveBeenCalled(); + }); + + test("GIVEN auditId is null, EXPECT error", async () => { + const interaction = { + guildId: "guildId", + isChatInputCommand: jest.fn().mockReturnValue(true), + options: { + getSubcommand: jest.fn().mockReturnValue("view"), + get: jest.fn().mockReturnValue(null), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + const audits = new Audits(); + await audits.execute(interaction); + + expect(interaction.options.get).toHaveBeenCalledTimes(1); + expect(interaction.options.get).toHaveBeenCalledWith("auditid"); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("AuditId not found."); + }); + + test("GIVEN auditId.value is undefined, EXPECT error", async () => { + const audit = { + value: undefined, + } + + const interaction = { + guildId: "guildId", + isChatInputCommand: jest.fn().mockReturnValue(true), + options: { + getSubcommand: jest.fn().mockReturnValue("view"), + get: jest.fn().mockReturnValue(audit), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + const audits = new Audits(); + await audits.execute(interaction); + + expect(interaction.options.get).toHaveBeenCalledTimes(1); + expect(interaction.options.get).toHaveBeenCalledWith("auditid"); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("AuditId not found."); + }); + + test("GIVEN audit is not in database, EXPECT error", async () => { + const audit = { + value: "auditId", + } + + const interaction = { + guildId: "guildId", + isChatInputCommand: jest.fn().mockReturnValue(true), + options: { + getSubcommand: jest.fn().mockReturnValue("view"), + get: jest.fn().mockReturnValue(audit), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + Audit.FetchAuditByAuditId = jest.fn().mockResolvedValue(null); + + const audits = new Audits(); + await audits.execute(interaction); + + expect(Audit.FetchAuditByAuditId).toHaveBeenCalledTimes(1); + + expect(interaction.options.get).toHaveBeenCalledTimes(1); + expect(interaction.options.get).toHaveBeenCalledWith("auditid"); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Audit not found."); + }); + + test("GIVEN audit.Reason was not supplied, EXPECT reason to be defaulted", async () => { + let repliedWith; + + const auditOption = { + value: "auditId", + }; + + const audit = { + Reason: undefined, + AuditType: AuditType.Warn, + ModeratorId: "moderatorId", + AuditId: "auditId", + }; + + const interaction = { + guildId: "guildId", + isChatInputCommand: jest.fn().mockReturnValue(true), + options: { + getSubcommand: jest.fn().mockReturnValue("view"), + get: jest.fn().mockReturnValue(auditOption), + }, + reply: jest.fn().mockImplementation((options) => { + repliedWith = options; + }), + } as unknown as CommandInteraction; + + Audit.FetchAuditByAuditId = jest.fn().mockResolvedValue(audit); + AuditTools.TypeToFriendlyText = jest.fn().mockReturnValue("Warn"); + + const audits = new Audits(); + await audits.execute(interaction); + + const embed = repliedWith!.embeds[0] as EmbedBuilder; + + const embedReasonField = embed.data.fields![0]; + + expect(embedReasonField.name).toBe("Reason"); + expect(embedReasonField.value).toBe("*none*"); + expect(embedReasonField.inline).toBe(true); + }); }); describe("clear", () => { - test.todo("EXPECT audit to be cleared"); + test("EXPECT audit to be cleared", async () => { + const auditOption = { + value: "auditId", + } - test.todo("GIVEN interaction.guildId is null, EXPECT nothing to happen"); + const audit = {}; - test.todo("GIVEN auditId is null, EXPECT error"); + const interaction = { + isChatInputCommand: jest.fn().mockReturnValue(true), + options: { + getSubcommand: jest.fn().mockReturnValue("clear"), + get: jest.fn().mockReturnValue(auditOption), + }, + guildId: "guildId", + reply: jest.fn(), + } as unknown as CommandInteraction; - test.todo("GIVEN auditId.value is undefined, EXPECT error"); + Audit.FetchAuditByAuditId = jest.fn().mockReturnValue(audit); + Audit.Remove = jest.fn(); - test.todo("GIVEN audit is not found, EXPECT error"); + const audits = new Audits(); + await audits.execute(interaction); + + expect(Audit.FetchAuditByAuditId).toHaveBeenCalledTimes(1); + expect(Audit.FetchAuditByAuditId).toHaveBeenCalledWith("AUDITID", "guildId"); + + expect(Audit.Remove).toHaveBeenCalledTimes(1); + + expect(interaction.options.get).toHaveBeenCalledTimes(1); + expect(interaction.options.get).toHaveBeenCalledWith("auditid"); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Audit cleared."); + }); + + test("GIVEN interaction.guildId is null, EXPECT nothing to happen", async () => { + const interaction = { + isChatInputCommand: jest.fn().mockReturnValue(true), + options: { + getSubcommand: jest.fn().mockReturnValue("clear"), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + const audits = new Audits(); + await audits.execute(interaction); + + expect(interaction.reply).not.toHaveBeenCalled(); + }); + + test("GIVEN auditId is null, EXPECT error", async () => { + const interaction = { + guildId: "guildId", + isChatInputCommand: jest.fn().mockReturnValue(true), + options: { + getSubcommand: jest.fn().mockReturnValue("clear"), + get: jest.fn().mockReturnValue(null), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + const audits = new Audits(); + await audits.execute(interaction); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("AuditId not found."); + }); + + test("GIVEN auditId.value is undefined, EXPECT error", async () => { + const auditOption = { + value: undefined, + } + + const interaction = { + guildId: "guildId", + isChatInputCommand: jest.fn().mockReturnValue(true), + options: { + getSubcommand: jest.fn().mockReturnValue("clear"), + get: jest.fn().mockReturnValue(auditOption), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + const audits = new Audits(); + await audits.execute(interaction); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("AuditId not found."); + }); + + test("GIVEN audit is not found, EXPECT error", async () => { + const auditOption = { + value: "auditId", + } + + const interaction = { + guildId: "guildId", + isChatInputCommand: jest.fn().mockReturnValue(true), + options: { + getSubcommand: jest.fn().mockReturnValue("clear"), + get: jest.fn().mockReturnValue(auditOption), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + Audit.FetchAuditByAuditId = jest.fn().mockReturnValue(null); + + const audits = new Audits(); + await audits.execute(interaction); + + expect(Audit.FetchAuditByAuditId).toHaveBeenCalledTimes(1); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Audit not found."); + }); }); describe("add", () => { - test.todo("EXPECT audit to be added"); + test("EXPECT audit to be added", async () => { + const user = { + id: "userId", + }; - test.todo("GIVEN interaction.guildId is null, EXPECT nothing to happen"); + const type = { + value: AuditType.Warn, + }; - test.todo("GIVEN user is null, EXPECT error"); + const reason = {}; - test.todo("GIVEN auditType is null, EXPECT error"); + const interaction = { + guildId: "guildId", + isChatInputCommand: jest.fn().mockReturnValue(true), + options: { + getSubcommand: jest.fn().mockReturnValue("add"), + getUser: jest.fn().mockReturnValue(user), + get: jest.fn().mockReturnValueOnce(type) + .mockReturnValue(reason), + }, + user: { + id: "userId", + }, + reply: jest.fn(), + } as unknown as CommandInteraction; - test.todo("GIVEN auditType.value is undefined, EXPECT error"); + Audit.prototype.Save = jest.fn(); + StringTools.RandomString = jest.fn().mockReturnValue("AUDITID"); - test.todo("GIVEN reasonInput is null, EXPECT reason to be empty"); + const audits = new Audits(); + await audits.execute(interaction); - test.todo("GIVEN reasonType.value is undefined, EXPECT reason to be empty"); + expect(Audit.prototype.Save).toHaveBeenCalledTimes(1); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Created new audit with ID `AUDITID`"); + }); + + test("GIVEN interaction.guildId is null, EXPECT nothing to happen", async () => { + const interaction = { + guildId: null, + isChatInputCommand: jest.fn().mockReturnValue(true), + options: { + getSubcommand: jest.fn().mockReturnValue("add"), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + const audits = new Audits(); + await audits.execute(interaction); + + expect(interaction.reply).not.toHaveBeenCalled(); + }); + + test("GIVEN user is null, EXPECT error", async () => { + const interaction = { + guildId: "guildId", + isChatInputCommand: jest.fn().mockReturnValue(true), + options: { + getSubcommand: jest.fn().mockReturnValue("add"), + getUser: jest.fn().mockReturnValue(null), + get: jest.fn().mockReturnValue({}), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + const audits = new Audits(); + await audits.execute(interaction); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Invalid input."); + }); + + test("GIVEN auditType is null, EXPECT error", async () => { + const interaction = { + guildId: "guildId", + isChatInputCommand: jest.fn().mockReturnValue(true), + options: { + getSubcommand: jest.fn().mockReturnValue("add"), + getUser: jest.fn().mockReturnValue(null), + get: jest.fn().mockReturnValueOnce(null) + .mockReturnValue({}), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + const audits = new Audits(); + await audits.execute(interaction); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Invalid input."); + }); + + test("GIVEN auditType.value is undefined, EXPECT error", async () => { + const interaction = { + guildId: "guildId", + isChatInputCommand: jest.fn().mockReturnValue(true), + options: { + getSubcommand: jest.fn().mockReturnValue("add"), + getUser: jest.fn().mockReturnValue(null), + get: jest.fn().mockReturnValueOnce({ + value: undefined + }) + .mockReturnValue({}), + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + const audits = new Audits(); + await audits.execute(interaction); + + expect(interaction.reply).toHaveBeenCalledTimes(1); + expect(interaction.reply).toHaveBeenCalledWith("Invalid input."); + }); + + test("GIVEN reasonInput is null, EXPECT reason to be empty", async ()=> { + let savedAudit: Audit | undefined; + + const user = { + id: "userId", + }; + + const type = { + value: AuditType.Warn, + }; + + const interaction = { + guildId: "guildId", + isChatInputCommand: jest.fn().mockReturnValue(true), + options: { + getSubcommand: jest.fn().mockReturnValue("add"), + getUser: jest.fn().mockReturnValue(user), + get: jest.fn().mockReturnValueOnce(type) + .mockReturnValue(null), + }, + user: { + id: "userId", + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + Audit.prototype.Save = jest.fn().mockImplementation((_, audit: Audit) => { + savedAudit = audit; + }); + StringTools.RandomString = jest.fn().mockReturnValue("AUDITID"); + + const audits = new Audits(); + await audits.execute(interaction); + + expect(Audit.prototype.Save).toHaveBeenCalledTimes(1); + + expect(savedAudit).toBeDefined(); + expect(savedAudit!.Reason).toBe(""); + }); + + test("GIVEN reasonType.value is undefined, EXPECT reason to be empty", async () => { + let savedAudit: Audit | undefined; + + const user = { + id: "userId", + }; + + const type = { + value: AuditType.Warn, + }; + + const reason = { + value: undefined, + }; + + const interaction = { + guildId: "guildId", + isChatInputCommand: jest.fn().mockReturnValue(true), + options: { + getSubcommand: jest.fn().mockReturnValue("add"), + getUser: jest.fn().mockReturnValue(user), + get: jest.fn().mockReturnValueOnce(type) + .mockReturnValue(reason), + }, + user: { + id: "userId", + }, + reply: jest.fn(), + } as unknown as CommandInteraction; + + Audit.prototype.Save = jest.fn().mockImplementation((_, audit: Audit) => { + savedAudit = audit; + }); + StringTools.RandomString = jest.fn().mockReturnValue("AUDITID"); + + const audits = new Audits(); + await audits.execute(interaction); + + expect(Audit.prototype.Save).toHaveBeenCalledTimes(1); + + expect(savedAudit).toBeDefined(); + expect(savedAudit!.Reason).toBe(""); + }); }); \ No newline at end of file