From aadf4ab4022a700a2e5c815d9677c825686a13b7 Mon Sep 17 00:00:00 2001 From: Ethan Lane Date: Sat, 22 Jan 2022 15:19:03 +0000 Subject: [PATCH] Add warn command tests --- src/commands/warn.ts | 29 ++- tests/commands/warn.test.ts | 485 ++++++++++++++++++++++++++++++++++++ 2 files changed, 508 insertions(+), 6 deletions(-) create mode 100644 tests/commands/warn.test.ts diff --git a/src/commands/warn.ts b/src/commands/warn.ts index 542c12f..b4fc236 100644 --- a/src/commands/warn.ts +++ b/src/commands/warn.ts @@ -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] + }; } } \ No newline at end of file diff --git a/tests/commands/warn.test.ts b/tests/commands/warn.test.ts new file mode 100644 index 0000000..f77ba0a --- /dev/null +++ b/tests/commands/warn.test.ts @@ -0,0 +1,485 @@ +import { GuildMember, Message, TextChannel, User } from "discord.js"; +import Warn from "../../src/commands/warn"; +import { ICommandContext } from "../../src/contracts/ICommandContext"; + +beforeEach(() => { + process.env = {}; +}); + +describe('Constructor', () => { + test('Expect values to be set', () => { + process.env.ROLES_MODERATOR = 'Moderator'; + + const warn = new Warn(); + + expect(warn._category).toBe('Moderation'); + expect(warn._roles.length).toBe(1); + expect(warn._roles[0]).toBe('Moderator'); + }); +}); + +describe('Execute', () => { + test('Given user has permission, expect user to be warnned', async () => { + process.env = { + ROLES_MODERATOR: 'Moderator', + CHANNELS_LOGS_MOD: 'mod-logs' + }; + + const mentionedUser = { + displayAvatarURL: jest.fn(), + tag: 'USERTAG' + } as unknown as User; + const mentionedMember = { + warnnable: true, + warn: jest.fn() + } as unknown as GuildMember; + const logChannel = { + name: 'mod-logs', + send: jest.fn() + } as unknown as TextChannel; + + const messageChannelSend = jest.fn(); + const messageMentionsUsersFirst = jest.fn() + .mockReturnValue(mentionedUser); + const messageGuildMember = jest.fn() + .mockReturnValue(mentionedMember); + const messageGuildChannelsCacheFind = jest.fn() + .mockImplementation((callback): TextChannel | undefined => { + const result = callback(logChannel); + + if (!result) { + return undefined; + } + + return logChannel; + }); + + const message = { + channel: { + send: messageChannelSend + }, + mentions: { + users: { + first: messageMentionsUsersFirst + } + }, + guild: { + member: messageGuildMember , + channels: { + cache: { + find: messageGuildChannelsCacheFind + } + }, + available: true + }, + author: { + tag: 'AUTHORTAG' + } + } as unknown as Message; + + const context: ICommandContext = { + name: 'warn', + args: ['warn', 'Test', 'Reason'], + message: message + }; + + const warn = new Warn(); + + const result = await warn.execute(context); + + expect(messageChannelSend).toBeCalledTimes(1); + expect(logChannel.send).toBeCalledTimes(1); + }); + + test('Given user has permissions, expect embeds to be correct', async () => { + process.env = { + ROLES_MODERATOR: 'Moderator', + CHANNELS_LOGS_MOD: 'mod-logs' + }; + + const mentionedUser = { + displayAvatarURL: jest.fn(), + tag: 'USERTAG' + } as unknown as User; + const mentionedMember = { + warnnable: true, + warn: jest.fn() + } as unknown as GuildMember; + const logChannel = { + name: 'mod-logs', + send: jest.fn() + } as unknown as TextChannel; + + const messageChannelSend = jest.fn(); + const messageMentionsUsersFirst = jest.fn() + .mockReturnValue(mentionedUser); + const messageGuildMember = jest.fn() + .mockReturnValue(mentionedMember); + const messageGuildChannelsCacheFind = jest.fn() + .mockImplementation((callback): TextChannel | undefined => { + const result = callback(logChannel); + + if (!result) { + return undefined; + } + + return logChannel; + }); + + const message = { + channel: { + send: messageChannelSend + }, + mentions: { + users: { + first: messageMentionsUsersFirst + } + }, + guild: { + member: messageGuildMember , + channels: { + cache: { + find: messageGuildChannelsCacheFind + } + }, + available: true + }, + author: { + tag: 'AUTHORTAG' + } + } as unknown as Message; + + const context: ICommandContext = { + name: 'warn', + args: ['warn', 'Test', 'Reason'], + message: message + }; + + const warn = new Warn(); + + const result = await warn.execute(context); + + expect(result.embeds.length).toBe(2); + + const logEmbed = result.embeds[0]; + const publicEmbed = result.embeds[1]; + + expect(logEmbed.title).toBe('Member Warned'); + expect(publicEmbed.title).toBe(""); + expect(publicEmbed.description).toBe('[object Object] has been warned'); + expect(logEmbed.fields.length).toBe(3); + expect(publicEmbed.fields.length).toBe(1); + expect(publicEmbed.fields[0].name).toBe('Reason'); + expect(publicEmbed.fields[0].value).toBe('Test Reason'); + }); + + test('Given user has permission, expect logEmbed fields to be correct', async () => { + process.env = { + ROLES_MODERATOR: 'Moderator', + CHANNELS_LOGS_MOD: 'mod-logs' + }; + + const mentionedUser = { + displayAvatarURL: jest.fn().mockReturnValue('URL'), + tag: 'USERTAG' + } as unknown as User; + const mentionedMember = { + warnnable: true, + warn: jest.fn() + } as unknown as GuildMember; + const logChannel = { + name: 'mod-logs', + send: jest.fn() + } as unknown as TextChannel; + + const messageChannelSend = jest.fn(); + const messageMentionsUsersFirst = jest.fn() + .mockReturnValue(mentionedUser); + const messageGuildMember = jest.fn() + .mockReturnValue(mentionedMember); + const messageGuildChannelsCacheFind = jest.fn() + .mockImplementation((callback): TextChannel | undefined => { + const result = callback(logChannel); + + if (!result) { + return undefined; + } + + return logChannel; + }); + + const message = { + channel: { + send: messageChannelSend + }, + mentions: { + users: { + first: messageMentionsUsersFirst + } + }, + guild: { + member: messageGuildMember , + channels: { + cache: { + find: messageGuildChannelsCacheFind + } + }, + available: true + }, + author: { + tag: 'AUTHORTAG' + } + } as unknown as Message; + + const context: ICommandContext = { + name: 'warn', + args: ['warn', 'Test', 'Reason'], + message: message + }; + + const warn = new Warn(); + + const result = await warn.execute(context); + + const logEmbed = result.embeds[0]; + + const fieldUser = logEmbed.fields[0]; + const fieldModerator = logEmbed.fields[1]; + const fieldReason = logEmbed.fields[2]; + + expect(fieldUser.name).toBe("User"); + expect(fieldUser.value).toBe("[object Object] `USERTAG`"); + expect(logEmbed.thumbnail?.url).toBe("URL"); + + expect(fieldModerator.name).toBe('Moderator'); + expect(fieldModerator.value).toBe('[object Object] `AUTHORTAG`'); + + expect(fieldReason.name).toBe('Reason'); + expect(fieldReason.value).toBe('Test Reason'); + }); + + test('Given user is not mentioned, expect error embed to be sent', async () => { + process.env = { + ROLES_MODERATOR: 'Moderator', + CHANNELS_LOGS_MOD: 'mod-logs' + }; + + const mentionedMember = { + warnnable: true, + warn: jest.fn() + } as unknown as GuildMember; + const logChannel = { + name: 'mod-logs', + send: jest.fn() + } as unknown as TextChannel; + + const messageChannelSend = jest.fn(); + const messageMentionsUsersFirst = jest.fn() + .mockReturnValue(null); + const messageGuildMember = jest.fn() + .mockReturnValue(mentionedMember); + const messageGuildChannelsCacheFind = jest.fn() + .mockImplementation((callback): TextChannel | undefined => { + const result = callback(logChannel); + + if (!result) { + return undefined; + } + + return logChannel; + }); + + const message = { + channel: { + send: messageChannelSend + }, + mentions: { + users: { + first: messageMentionsUsersFirst + } + }, + guild: { + member: messageGuildMember , + channels: { + cache: { + find: messageGuildChannelsCacheFind + } + }, + available: true + }, + author: { + tag: 'AUTHORTAG' + } + } as unknown as Message; + + const context: ICommandContext = { + name: 'warn', + args: ['warn', 'Test', 'Reason'], + message: message + }; + + const warn = new Warn(); + + const result = await warn.execute(context); + + expect(messageChannelSend).toBeCalledTimes(1); + expect(logChannel.send).not.toBeCalled(); + + expect(result.embeds.length).toBe(1); + + const embedError = result.embeds[0]; + + expect(embedError.description).toBe('User does not exist'); + }); + + test('Given member is not in server, expect error embed to be sent', async () => { + process.env = { + ROLES_MODERATOR: 'Moderator', + CHANNELS_LOGS_MOD: 'mod-logs' + }; + + const mentionedUser = { + displayAvatarURL: jest.fn(), + tag: 'USERTAG' + } as unknown as User; + const mentionedMember = { + warnnable: true, + warn: jest.fn() + } as unknown as GuildMember; + const logChannel = { + name: 'mod-logs', + send: jest.fn() + } as unknown as TextChannel; + + const messageChannelSend = jest.fn(); + const messageMentionsUsersFirst = jest.fn() + .mockReturnValue(mentionedUser); + const messageGuildMember = jest.fn() + .mockReturnValue(null); + const messageGuildChannelsCacheFind = jest.fn() + .mockImplementation((callback): TextChannel | undefined => { + const result = callback(logChannel); + + if (!result) { + return undefined; + } + + return logChannel; + }); + + const message = { + channel: { + send: messageChannelSend + }, + mentions: { + users: { + first: messageMentionsUsersFirst + } + }, + guild: { + member: messageGuildMember , + channels: { + cache: { + find: messageGuildChannelsCacheFind + } + }, + available: true + }, + author: { + tag: 'AUTHORTAG' + } + } as unknown as Message; + + const context: ICommandContext = { + name: 'warn', + args: ['warn', 'Test', 'Reason'], + message: message + }; + + const warn = new Warn(); + + const result = await warn.execute(context); + + expect(messageChannelSend).toBeCalledTimes(1); + expect(logChannel.send).not.toBeCalled(); + + expect(result.embeds.length).toBe(1); + + const embedError = result.embeds[0]; + + expect(embedError.description).toBe('User is not in this server'); + }); + + test('Given guild is unavailable, expect return and do nothing', async () => { + process.env = { + ROLES_MODERATOR: 'Moderator', + CHANNELS_LOGS_MOD: 'mod-logs' + }; + + const mentionedUser = { + displayAvatarURL: jest.fn(), + tag: 'USERTAG' + } as unknown as User; + const mentionedMember = { + warnnable: true, + warn: jest.fn() + } as unknown as GuildMember; + const logChannel = { + name: 'mod-logs', + send: jest.fn() + } as unknown as TextChannel; + + const messageChannelSend = jest.fn(); + const messageMentionsUsersFirst = jest.fn() + .mockReturnValue(mentionedUser); + const messageGuildMember = jest.fn() + .mockReturnValue(mentionedMember); + const messageGuildChannelsCacheFind = jest.fn() + .mockImplementation((callback): TextChannel | undefined => { + const result = callback(logChannel); + + if (!result) { + return undefined; + } + + return logChannel; + }); + + const message = { + channel: { + send: messageChannelSend + }, + mentions: { + users: { + first: messageMentionsUsersFirst + } + }, + guild: { + member: messageGuildMember , + channels: { + cache: { + find: messageGuildChannelsCacheFind + } + }, + available: false + }, + author: { + tag: 'AUTHORTAG' + } + } as unknown as Message; + + const context: ICommandContext = { + name: 'warn', + args: ['warn', 'Test', 'Reason'], + message: message + }; + + const warn = new Warn(); + + const result = await warn.execute(context); + + expect(messageChannelSend).not.toBeCalled(); + expect(logChannel.send).not.toBeCalled(); + expect(result.embeds.length).toBe(0); + }); +}); \ No newline at end of file