sinon#createSandbox TypeScript Examples

The following examples show how to use sinon#createSandbox. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: WebsiteUserServiceTest.ts    From discord-bot with MIT License 6 votes vote down vote up
describe("WebsiteUserService", () => {
	describe("::getInstance()", () => {
		it("returns an instance of WebsiteUserService", () => {
			const service = WebsiteUserService.getInstance();

			expect(service).to.be.instanceOf(WebsiteUserService);
		});
	});

	describe("buildProfileURL()", () => {
		let sandbox: SinonSandbox;
		let websiteUserService: WebsiteUserService;

		beforeEach(() => {
			sandbox = createSandbox();
			websiteUserService = WebsiteUserService.getInstance();
		});

		it("Generates url containing profile name", async () => {
			const mockArticle = {
				createdBy: {
					alias: "userAwesome"
				}
			};

			const result = await websiteUserService.buildProfileURL(mockArticle.createdBy.alias);

			expect(result).to.equal("https://codesupport.dev/profile/userawesome");
		});

		afterEach(() => {
			sandbox.restore();
		});
	});
});
Example #2
Source File: AutomaticMemberRoleHandlerTest.ts    From discord-bot with MIT License 6 votes vote down vote up
describe("AutomaticMemberRoleHandler", () => {
	describe("constructor()", () => {
		it("creates a handler for GUILD_MEMBER_ADD", () => {
			const handler = new AutomaticMemberRoleHandler();

			expect(handler.getEvent()).to.equal(Constants.Events.GUILD_MEMBER_ADD);
		});
	});

	describe("handle()", () => {
		let sandbox: SinonSandbox;
		let handler: EventHandler;
		let member: GuildMember;

		beforeEach(() => {
			sandbox = createSandbox();
			handler = new AutomaticMemberRoleHandler();
			member = BaseMocks.getGuildMember();
		});

		it("doesn't give the member the role if they don't have an avatar", async () => {
			member.user.avatar = null;

			const addMock = sandbox.stub(member.roles, "add");

			await handler.handle(member);

			expect(addMock.calledOnce).to.be.false;
		});

		afterEach(() => {
			sandbox.restore();
		});
	});
});
Example #3
Source File: ScheduleTest.ts    From discord-bot with MIT License 6 votes vote down vote up
describe("@Schedule()", () => {
	let sandbox: SinonSandbox;
	let scheduleJobStub: SinonStub;

	beforeEach(() => {
		sandbox = createSandbox();
		scheduleJobStub = sandbox.stub(schedule, "scheduleJob").returns({});
	});

	afterEach(() => sandbox.restore());

	it("schedules a job with the given crontab", () => {
		class Test {
			@Schedule("0 0 * * *")
			doSomething() {
				console.log("test");
			}
		}

		expect(scheduleJobStub.calledOnce).to.be.true;
		expect(scheduleJobStub.args[0][0]).to.equal("0 0 * * *");
	});

	it("schedules a job to run the decorated method", () => {
		class Test {
			@Schedule("0 0 * * *")
			doSomething() {
				console.log("test");
			}
		}

		expect(scheduleJobStub.args[0][1]).to.equal(Test.prototype.doSomething);
	});
});
Example #4
Source File: SearchCommandTest.ts    From discord-bot with MIT License 5 votes vote down vote up
describe("SearchCommand", () => {
	describe("onInteract()", () => {
		let sandbox: SinonSandbox;
		let command: searchCommand;
		let interaction: CommandInteraction;
		let replyStub: sinon.SinonStub<any[], any>;
		let instantAnswer: InstantAnswerService;

		beforeEach(() => {
			sandbox = createSandbox();
			command = new SearchCommand();
			replyStub = sandbox.stub().resolves();
			interaction = {
				reply: replyStub,
				user: BaseMocks.getGuildMember()
			};
			instantAnswer = InstantAnswerService.getInstance();
		});

		it("sends a message to the channel", async () => {
			sandbox.stub(instantAnswer, "query");

			await command.onInteract("1", interaction);

			expect(replyStub.calledOnce).to.be.true;
		});

		it("states it can not query duckduckgo if the result isn't found", async () => {
			sandbox.stub(instantAnswer, "query").resolves(null);

			await command.onInteract("thisruledoesnotexist", interaction);

			const embed = replyStub.getCall(0).firstArg.embeds[0];

			expect(replyStub.calledOnce).to.be.true;
			expect(embed.title).to.equal("Error");
			expect(embed.description).to.equal("No results found.");
			expect(embed.hexColor).to.equal(EMBED_COLOURS.ERROR.toLowerCase());
		});

		it("states the result from the instant answer service", async () => {
			sandbox.stub(instantAnswer, "query").resolves({
				heading: "Example Heading",
				description: "Example Description",
				url: "https://example.com"
			});

			await command.onInteract("thisruledoesnotexist", interaction);

			const embed = replyStub.getCall(0).firstArg.embeds[0];

			expect(replyStub.calledOnce).to.be.true;
			expect(embed.title).to.equal("Example Heading");
			expect(embed.description).to.equal("Example Description\n\n[View on example.com](https://example.com)");
			expect(embed.footer.text).to.equal("Result powered by the DuckDuckGo API.");
			expect(embed.hexColor).to.equal(EMBED_COLOURS.SUCCESS.toLowerCase());
		});

		it("correctly renders URLs from websites with subdomains", async () => {
			sandbox.stub(instantAnswer, "query").resolves({
				heading: "Capybara",
				description: "The capybara is an adorable rodent.",
				url: "https://en.wikipedia.org/wiki/Capybara"
			});

			await command.onInteract("thisruledoesnotexist", interaction);

			const embed = replyStub.getCall(0).firstArg.embeds[0];

			expect(embed.description).to.equal("The capybara is an adorable rodent.\n\n[View on en.wikipedia.org](https://en.wikipedia.org/wiki/Capybara)");
		});

		afterEach(() => {
			sandbox.restore();
		});
	});
});
Example #5
Source File: LogMessageUpdateHandlerTest.ts    From discord-bot with MIT License 5 votes vote down vote up
describe("LogMessageUpdateHandler", () => {
	describe("constructor()", () => {
		it("creates a handler for MESSAGE_UPDATE", () => {
			const handler = new LogMessageUpdateHandler();

			expect(handler.getEvent()).to.equal(Constants.Events.MESSAGE_UPDATE);
		});
	});

	describe("handle()", () => {
		let sandbox: SinonSandbox;
		let handler: EventHandler;

		beforeEach(() => {
			sandbox = createSandbox();
			handler = new LogMessageUpdateHandler();
		});

		it("doesn't send a message if the old message content is the same as the new message content", async () => {
			const oldMessage = CustomMocks.getMessage();
			const newMessage = CustomMocks.getMessage();
			const messageMock = sandbox.stub(oldMessage.guild.channels.cache, "find");

			oldMessage.content = "example message";
			newMessage.content = "example message";

			await handler.handle(oldMessage, newMessage);

			expect(messageMock.calledOnce).to.be.false;
		});

		it("doesn't send a message if the new message content is empty", async () => {
			const oldMessage = CustomMocks.getMessage();
			const newMessage = CustomMocks.getMessage();
			const messageMock = sandbox.stub(oldMessage.guild.channels.cache, "find");

			oldMessage.content = "asdf";
			newMessage.content = "";

			await handler.handle(oldMessage, newMessage);

			expect(messageMock.calledOnce).to.be.false;
		});

		it("sends a message if the message contents are different", async () => {
			const oldMessage = CustomMocks.getMessage();
			const newMessage = CustomMocks.getMessage();
			const messageMock = sandbox.stub(oldMessage.guild.channels.cache, "find");

			oldMessage.content = "oldMessage content";
			newMessage.content = "newMessage content";

			await handler.handle(oldMessage, newMessage);

			expect(messageMock.calledOnce).to.be.true;
		});

		afterEach(() => {
			sandbox.restore();
		});
	});
});
Example #6
Source File: LogMessageSingleDeleteHandlerTest.ts    From discord-bot with MIT License 5 votes vote down vote up
describe("LogMessageDeleteHandler", () => {
	describe("constructor()", () => {
		it("creates a handler for MESSAGE_Delete", () => {
			const handler = new LogMessageSingleDeleteHandler();

			expect(handler.getEvent()).to.equal(Constants.Events.MESSAGE_DELETE);
		});
	});

	describe("handle()", () => {
		let sandbox: SinonSandbox;
		let handler: EventHandler;

		beforeEach(() => {
			sandbox = createSandbox();
			handler = new LogMessageSingleDeleteHandler();
		});

		it("sends a message in logs channel when a message is deleted", async () => {
			const message = CustomMocks.getMessage({
				content: "message content"
			});
			const messageMock = sandbox.stub(message.guild.channels.cache, "find");

			await handler.handle(message);

			expect(messageMock.calledOnce).to.be.true;
		});

		it("does not send a message in logs channel when message is deleted but content is empty - only image", async () => {
			const message = CustomMocks.getMessage({
				content: ""
			});
			const messageMock = sandbox.stub(message.guild.channels.cache, "find");

			await handler.handle(message);

			expect(messageMock.calledOnce).to.be.false;
		});

		afterEach(() => {
			sandbox.restore();
		});
	});
});
Example #7
Source File: LogMessageBulkDeleteHandlerTest.ts    From discord-bot with MIT License 5 votes vote down vote up
describe("LogMessageDeleteHandler", () => {
	describe("constructor()", () => {
		it("creates a handler for MESSAGE_Delete", () => {
			const handler = new LogMessageBulkDeleteHandler();

			expect(handler.getEvent()).to.equal(Constants.Events.MESSAGE_BULK_DELETE);
		});
	});

	describe("handle()", () => {
		let sandbox: SinonSandbox;
		let handler: EventHandler;

		beforeEach(() => {
			sandbox = createSandbox();
			handler = new LogMessageBulkDeleteHandler();
		});

		it("sends a message in logs channel when a message is deleted", async () => {
			const sendLogMock = sandbox.stub(Collection.prototype, "find");

			await handler.handle(messageFactory(1));

			expect(sendLogMock.calledOnce).to.be.true;
		});

		it("sends messages in logs channel when multiple messages are deleted", async () => {
			const sendLogMock = sandbox.stub(Collection.prototype, "find");

			await handler.handle(messageFactory(5));

			expect(sendLogMock.callCount).to.be.eq(5);
		});

		it("does not send a message in logs channel when message is deleted but content is empty - only image", async () => {
			const sendLogMock = sandbox.stub(Collection.prototype, "find");

			await handler.handle(messageFactory(1, {
				content: ""
			}));

			expect(sendLogMock.calledOnce).to.be.false;
		});

		it("does not send a message in logs channel when multiple messages are deleted but content is empty - only image", async () => {
			const sendLogMock = sandbox.stub(Collection.prototype, "find");

			await handler.handle(messageFactory(5, {
				content: ""
			}));

			expect(sendLogMock.calledOnce).to.be.false;
		});

		afterEach(() => {
			sandbox.restore();
		});
	});
});
Example #8
Source File: LogMemberLeaveHandlerTest.ts    From discord-bot with MIT License 5 votes vote down vote up
describe("LogMemberLeaveHandler", () => {
	describe("constructor()", () => {
		it("creates a handler for GUILD_MEMBER_REMOVE)", () => {
			const handler = new LogMemberLeaveHandler();

			expect(handler.getEvent()).to.equal(Constants.Events.GUILD_MEMBER_REMOVE);
		});
	});

	describe("handle()", () => {
		let sandbox: SinonSandbox;
		let handler: EventHandler;

		beforeEach(() => {
			sandbox = createSandbox();
			handler = new LogMemberLeaveHandler();
		});

		it("sends a message in logs channel when a member leaves", async () => {
			const message = CustomMocks.getMessage();
			const messageMock = sandbox.stub(message.guild!.channels.cache, "find");

			const guildMember = CustomMocks.getGuildMember({joined_at: new Date(1610478967732).toISOString()});

			const roleCollection = new Collection([["12345", new Role(BaseMocks.getClient(), {
				id: MEMBER_ROLE.toString(),
				name: "member",
				permissions: "1"
			}, BaseMocks.getGuild())], [BaseMocks.getGuild().id, new Role(BaseMocks.getClient(), {
				id: BaseMocks.getGuild().id,
				name: "@everyone",
				permissions: "1"
			}, BaseMocks.getGuild())]]);

			sandbox.stub(DateUtils, "getFormattedTimeSinceDate").returns("10 seconds");
			sandbox.stub(GuildMemberRoleManager.prototype, "cache").get(() => roleCollection);

			await handler.handle(guildMember);

			expect(messageMock.calledOnce).to.be.true;
		});

		afterEach(() => {
			sandbox.restore();
		});
	});
});
Example #9
Source File: RaidDetectionHandlerTest.ts    From discord-bot with MIT License 5 votes vote down vote up
describe("RaidDetectionHandler", () => {
	describe("constructor()", () => {
		it("creates a handler for GUILD_MEMBER_ADD", () => {
			const handler = new RaidDetectionHandler();

			expect(handler.getEvent()).to.equal(Constants.Events.GUILD_MEMBER_ADD);
		});
	});

	describe("handle()", () => {
		let sandbox: SinonSandbox;
		let handler: RaidDetectionHandler;

		beforeEach(() => {
			sandbox = createSandbox();
			handler = new RaidDetectionHandler();
		});

		it("adds a member to the joinQueue", async () => {
			const mockGuildMember = BaseMocks.getGuildMember();

			await handler.handle(mockGuildMember);

			expect(handler.joinQueue.includes(mockGuildMember)).to.be.true;
		});

		it("removes member from joinQueue", done => {
			const mockGuildMember = BaseMocks.getGuildMember();

			sandbox.stub(getConfigValue, "default").returns(0.002);

			handler.handle(mockGuildMember).then(() => {
				expect(handler.joinQueue.includes(mockGuildMember)).to.be.true;

				setTimeout(() => {
					expect(handler.joinQueue.includes(mockGuildMember)).to.be.false;

					done();
				}, 10);
			});
		}).timeout(200);

		it("sends message to mods channel when raid is detected and kicks user", async () => {
			const mockMember = BaseMocks.getGuildMember();
			const mockModChannel = BaseMocks.getTextChannel();

			mockModChannel.id = MOD_CHANNEL_ID;
			sandbox.stub(mockMember.guild.channels.cache, "find").returns(mockModChannel);

			const messageMock = sandbox.stub(mockModChannel, "send");
			const kickMocks = [];

			for (let i = 0; i < RAID_SETTINGS.MAX_QUEUE_SIZE; i++) {
				const member = CustomMocks.getGuildMember();

				kickMocks.push(sandbox.stub(member, "kick"));

				await handler.handle(member);
			}

			await handler.handle(mockMember);

			expect(kickMocks.map(mock => mock.called)).not.to.contain(false);
			expect(messageMock.called).to.be.true;
		});

		afterEach(() => {
			sandbox.restore();
		});
	});
});
Example #10
Source File: WebsiteCommandTest.ts    From discord-bot with MIT License 5 votes vote down vote up
describe("WebsiteCommand", () => {
	describe("oninteract()", () => {
		let sandbox: SinonSandbox;
		let command: WebsiteCommand;
		let interaction: Interaction;
		let replyStub: sinon.SinonStub;

		beforeEach(() => {
			sandbox = createSandbox();
			command = new WebsiteCommand();
			replyStub = sandbox.stub().resolves();
			interaction = {
				reply: replyStub,
				user: BaseMocks.getGuildMember()
			};
		});

		it("sends a message to the channel", async () => {
			await command.onInteract(null, interaction);

			expect(replyStub.calledOnce).to.be.true;
		});

		it("sends default link to website if no argument is given", async () => {
			await command.onInteract(null, interaction);

			expect(replyStub.firstCall.firstArg).to.equal("https://codesupport.dev/");
			expect(replyStub.calledOnce).to.be.true;
		});

		it("sends the link to website + addon if argument is given", async () => {
			await command.onInteract("test", interaction);

			expect(replyStub.firstCall.firstArg).to.equal("https://codesupport.dev/test");
			expect(replyStub.calledOnce).to.be.true;
		});

		afterEach(() => {
			sandbox.restore();
		});
	});
});
Example #11
Source File: InstantAnswerServiceTest.ts    From discord-bot with MIT License 5 votes vote down vote up
describe("InstantAnswerService", () => {
	describe("::getInstance()", () => {
		it("returns an instance of InstantAnswerService", () => {
			const service = InstantAnswerService.getInstance();

			expect(service).to.be.instanceOf(InstantAnswerService);
		});
	});

	describe("query", () => {
		let sandbox: SinonSandbox;
		let instantAnswer: InstantAnswerService;

		beforeEach(() => {
			sandbox = createSandbox();
			instantAnswer = InstantAnswerService.getInstance();
		});

		it("makes a GET request to the DuckDuckGo API", async () => {
			const axiosGet = sandbox.stub(axios, "get").resolves({
				status: 200,
				data: {
					Heading: "This is a heading",
					AbstractText: "This is a description."
				}
			});

			await instantAnswer.query("test");

			expect(axiosGet.called).to.be.true;
		});

		it("throws an error if the API does not return a success", async () => {
			const axiosGet = sandbox.stub(axios, "get").resolves({
				status: 500,
				data: {}
			});

			// Chai can't detect throws inside async functions. This is a hack to get it working.
			try {
				await instantAnswer.query("test");
			} catch ({ message }) {
				expect(message).to.equal("There was a problem with the DuckDuckGo API.");
			}

			expect(axiosGet.called).to.be.true;
		});

		afterEach(() => {
			sandbox.restore();
		});
	});
});
Example #12
Source File: ResourcesCommandTest.ts    From discord-bot with MIT License 5 votes vote down vote up
describe("ResourcesCommand", () => {
	describe("onInteract()", () => {
		let sandbox: SinonSandbox;
		let command: Command;

		beforeEach(() => {
			sandbox = createSandbox();
			command = new ResourcesCommand();
		});

		it("sends a message to the channel", async () => {
			const replyStub = sandbox.stub().resolves();

			await command.onInteract(undefined, {
				reply: replyStub
			});

			expect(replyStub.calledOnce).to.be.true;
		});

		it("sends the link to resources page if no argument is given", async () => {
			const replyStub = sandbox.stub().resolves();

			await command.onInteract(undefined, {
				reply: replyStub
			});

			const { content: url } = replyStub.firstCall.lastArg;

			expect(replyStub.calledOnce).to.be.true;
			expect(url).to.equal("https://codesupport.dev/resources");
		});

		it("sends link to the category page if an argument is given", async () => {
			const replyStub = sandbox.stub().resolves();

			await command.onInteract("javascript", {
				reply: replyStub
			});

			const { content: url } = replyStub.firstCall.lastArg;

			expect(replyStub.calledOnce).to.be.true;
			expect(url).to.equal("https://codesupport.dev/resources?category=javascript");
		});

		afterEach(() => {
			sandbox.restore();
		});
	});
});
Example #13
Source File: NPMCommandTest.ts    From discord-bot with MIT License 5 votes vote down vote up
describe("NPMCommand", () => {
	describe("run()", () => {
		let sandbox: SinonSandbox;
		let command: NPMCommand;
		let interaction: any;
		let replyStub: sinon.SinonStub<any[], any>;

		beforeEach(() => {
			sandbox = createSandbox();
			command = new NPMCommand();
			replyStub = sandbox.stub().resolves();
			interaction = {
				reply: replyStub,
				user: BaseMocks.getGuildMember()
			};
		});

		it("sends a message to the channel", async () => {
			sandbox.stub(axios, "get");

			await command.onInteract("discord.js", interaction);

			expect(replyStub.calledOnce).to.be.true;
		});

		it("states the package name is not valid if it doesn't find a package", async () => {
			sandbox.stub(axios, "get").rejects({ status: 404 });

			await command.onInteract("mongoboy", interaction);

			const embed = replyStub.getCall(0).lastArg.embeds[0];

			expect(replyStub.calledOnce).to.be.true;
			expect(embed.title).to.equal("Error");
			expect(embed.description).to.equal("That is not a valid NPM package.");
			expect(embed.hexColor).to.equal(EMBED_COLOURS.ERROR.toLowerCase());
		});

		it("sends a message with the package URL if you provide a valid package", async () => {
			sandbox.stub(axios, "get").resolves({ status: 200 });

			await command.onInteract("factory-girl", interaction);

			const url = replyStub.getCall(0).lastArg;

			expect(replyStub.calledOnce).to.be.true;
			expect(url).to.equal("https://www.npmjs.com/package/factory-girl");
		});

		afterEach(() => {
			sandbox.restore();
		});
	});
});
Example #14
Source File: MineSweeperServiceTest.ts    From discord-bot with MIT License 5 votes vote down vote up
describe("MineSweeperService", () => {
	describe("::getInstance()", () => {
		it("returns an instance of MineSweeperService", () => {
			const service = MineSweeperService.getInstance();

			expect(service).to.be.instanceOf(MineSweeperService);
		});
	});

	describe("generateGame()", () => {
		let sandbox: SinonSandbox;
		let mineSweeperService: MineSweeperService;

		beforeEach(() => {
			sandbox = createSandbox();
			mineSweeperService = MineSweeperService.getInstance();
		});

		it("has the correct amount of cells", async () => {
			const result = mineSweeperService.generateGame(1);
			const count = (result.split("||")!.length - 1) / 2;

			expect(count).to.equal(121);
		});

		it("has the correct amount of bombs", async () => {
			const result = mineSweeperService.generateGame(1);
			const count = result.split(":boom:")!.length - 1;

			expect(count).to.equal(121);
		});

		it("returned string has no numbers", async () => {
			const result = mineSweeperService.generateGame(1);
			const hasNumber = (/\d/).test(result);

			expect(hasNumber).to.equal(false);
		});

		afterEach(() => {
			sandbox.restore();
		});
	});
});
Example #15
Source File: HiringLookingCommandTest.ts    From discord-bot with MIT License 5 votes vote down vote up
describe("HiringLookingCommand", () => {
	describe("onInteract()", () => {
		let sandbox: SinonSandbox;
		let command: HiringLookingCommand;

		beforeEach(() => {
			sandbox = createSandbox();
			command = new HiringLookingCommand();
		});

		it("sends a message to the channel", async () => {
			const replyStub = sandbox.stub().resolves();

			await command.onInteract({
				reply: replyStub
			});

			expect(replyStub.calledOnce).to.be.true;
		});

		it("states how to format a post", async () => {
			const replyStub = sandbox.stub().resolves();

			await command.onInteract({
				reply: replyStub
			});

			// @ts-ignore - firstArg does not live on getCall()
			const embed = replyStub.getCall(0).firstArg.embeds[0];

			expect(replyStub.calledOnce).to.be.true;
			expect(embed.title).to.equal("Hiring or Looking Posts");
			expect(embed.hexColor).to.equal(EMBED_COLOURS.DEFAULT.toLowerCase());

			// The indentation on these is a mess due to the test comparing white space.
			expect(embed.description).to.equal(`
			CodeSupport offers a free to use hiring or looking section.\n
			Here you can find people to work for you and offer your services,
			as long as it fits in with the rules. If you get scammed in hiring or looking there is
			nothing we can do, however, we do ask that you let a moderator know.
		`);
			expect(embed.fields[0].name).to.equal("Payment");
			expect(embed.fields[0].value).to.equal("If you are trying to hire people for a project, and that project is not open source, your post must state how much you will pay them (or a percentage of profits they will receive).");
			expect(embed.fields[1].name).to.equal("Post Frequency");
			expect(embed.fields[1].value).to.equal(`Please only post in <#${getConfigValue<GenericObject<string>>("BOTLESS_CHANNELS").HIRING_OR_LOOKING}> once per week to keep the channel clean and fair. Posting multiple times per week will lead to your access to the channel being revoked.`);
			expect(embed.fields[2].name).to.equal("Example Post");
			expect(embed.fields[2].value).to.equal(`
			Please use the example below as a template to base your post on.\n
			\`\`\`
[HIRING]
Full Stack Website Developer
We are looking for a developer who is willing to bring our video streaming service to life.
Pay: $20/hour
Requirements:
- Solid knowledge of HTML, CSS and JavaScript
- Knowledge of Node.js, Express and EJS.
- Able to turn Adobe XD design documents into working web pages.
- Able to stick to deadlines and work as a team.
			\`\`\`
		`);
		});

		afterEach(() => {
			sandbox.restore();
		});
	});
});
Example #16
Source File: DirectoryUtilsTest.ts    From discord-bot with MIT License 5 votes vote down vote up
describe("DirectoryUtils", () => {
	describe("::getFilesInDirectory()", () => {
		let sandbox: SinonSandbox;

		beforeEach(() => {
			sandbox = createSandbox();
		});

		it("should call readDirectory()", () => {
			const readDirectoryStub = sandbox.stub(DirectoryUtils, "readDirectory").returns(["FakeFile.js"]);

			sandbox.stub(Array.prototype, "map");

			DirectoryUtils.getFilesInDirectory(".", ".js");

			expect(readDirectoryStub.called).to.be.true;
		});

		it("should filter files", async () => {
			sandbox.stub(DirectoryUtils, "readDirectory").returns(["FakeFile.js", "FakeCommand.js"]);
			sandbox.stub(DirectoryUtils, "require").callsFake(arg => arg);

			const files = await DirectoryUtils.getFilesInDirectory(".", "Command.js");

			expect(files.includes("./FakeFile.js")).to.be.false;
			expect(files.includes("./FakeCommand.js")).to.be.true;
		});

		it("should require the files", async () => {
			const requireStub = sandbox.stub(DirectoryUtils, "require");

			sandbox.stub(DirectoryUtils, "readDirectory").returns(["FakeFile.js", "FakeCommand.js"]);

			await DirectoryUtils.getFilesInDirectory(".", "Command.js");

			expect(requireStub.calledWith("./FakeCommand.js")).to.be.true;
		});

		afterEach(() => {
			sandbox.restore();
		});
	});

	it("Should return typescript file in development", async () => {
		const testEnv = process.env.NODE_ENV;

		process.env.NODE_ENV = DEVELOPMENT_ENV;

		const file = DirectoryUtils.appendFileExtension("test");

		expect(file).to.include(".ts");
		expect(file).to.not.include(".js");

		process.env.NODE_ENV = testEnv;
	});

	it("Should return javascript in non-development", async () => {
		const testEnv = process.env.NODE_ENV;

		process.env.NODE_ENV = PRODUCTION_ENV;

		const file = DirectoryUtils.appendFileExtension("test");

		expect(file).to.include(".js");
		expect(file).to.not.include(".ts");

		process.env.NODE_ENV = testEnv;
	});
});
Example #17
Source File: CodeblockCommandTest.ts    From discord-bot with MIT License 5 votes vote down vote up
describe("CodeblockCommand", () => {
	describe("onInteract()", () => {
		let sandbox: SinonSandbox;
		let command: CodeblockCommand;

		beforeEach(() => {
			sandbox = createSandbox();
			command = new CodeblockCommand();
		});

		it("sends a message to the channel", async () => {
			const replyStub = sandbox.stub().resolves();

			await command.onInteract({
				reply: replyStub
			});

			expect(replyStub.calledOnce).to.be.true;
		});

		it("states how to create a codeblock", async () => {
			const replyStub = sandbox.stub().resolves();

			await command.onInteract({
				reply: replyStub
			});

			// @ts-ignore - firstArg does not live on getCall()
			const embed = replyStub.getCall(0).firstArg.embeds[0];

			expect(replyStub.calledOnce).to.be.true;
			expect(embed.title).to.equal("Codeblock Tutorial");
			expect(embed.description).to.equal("Please use codeblocks when sending code.");
			expect(embed.hexColor).to.equal(EMBED_COLOURS.DEFAULT.toLowerCase());

			expect(embed.fields[0].name).to.equal("Sending lots of code?");
			expect(embed.fields[0].value).to.equal("Consider using a [GitHub Gist](http://gist.github.com).");

			expect(embed.image.url).to.equal("attachment://codeblock-tutorial.png");
		});

		afterEach(() => {
			sandbox.restore();
		});
	});
});
Example #18
Source File: DiscordUtilsTest.ts    From discord-bot with MIT License 5 votes vote down vote up
describe("DiscordUtils", () => {
	describe("::getGuildMember()", () => {
		let sandbox: SinonSandbox;

		beforeEach(() => {
			sandbox = createSandbox();
		});

		it("returns GuildMember if value is a username + discriminator", async () => {
			sandbox.stub(GuildMemberManager.prototype, "fetch").resolves(new Collection([["12345", member]]));

			expect(await DiscordUtils.getGuildMember("fakeUser#1234", BaseMocks.getGuild())).to.equal(member);
		});

		it("returns GuildMember if value is a username", async () => {
			sandbox.stub(GuildMemberManager.prototype, "fetch").resolves(new Collection([["12345", member]]));

			expect(await DiscordUtils.getGuildMember("fakeUser", BaseMocks.getGuild())).to.equal(member);
		});

		it("returns GuildMember if value is a userID", async () => {
			// @ts-ignore (the types aren't recognising the overloaded fetch function)
			sandbox.stub(GuildMemberManager.prototype, "fetch").resolves(member);

			expect(await DiscordUtils.getGuildMember("123456789", BaseMocks.getGuild())).to.equal(member);
		});

		it("returns GuildMember if value is a nickname", async () => {
			const nicknameMember = CustomMocks.getGuildMember({nick: "Lambo", user: user});

			sandbox.stub(GuildMemberManager.prototype, "fetch").resolves(new Collection([["12345", nicknameMember]]));

			expect(await DiscordUtils.getGuildMember("Lambo", BaseMocks.getGuild())).to.equal(nicknameMember);
		});

		afterEach(() => {
			sandbox.restore();
		});
	});
});
Example #19
Source File: DiscordMessageLinkHandlerTest.ts    From discord-bot with MIT License 4 votes vote down vote up
describe("DiscordMessageLinkHandler", () => {
	describe("Constructor()", () => {
		it("creates a handler for MESSAGE_CREATE", () => {
			const handler = new DiscordMessageLinkHandler();

			expect(handler.getEvent()).to.equal(Constants.Events.MESSAGE_CREATE);
		});
	});

	describe("handle()", () => {
		let sandbox: SinonSandbox;
		let handler: EventHandler;
		let message: Message;

		beforeEach(() => {
			sandbox = createSandbox();
			handler = new DiscordMessageLinkHandler();
			message = CustomMocks.getMessage({}, {
				channel: CustomMocks.getTextChannel()
			});
		});

		it("sends a message in message channel when contains discord message link mid sentence", async () => {
			const generatePreviewMock = sandbox.stub(MessagePreviewService.prototype, "generatePreview");

			message.content = "aaaaaaaaa\nhttps://ptb.discordapp.com/channels/240880736851329024/518817917438001152/732711501345062982 aaaa";

			await handler.handle(message);

			expect(generatePreviewMock.called).to.be.true;
		});

		it("sends a message in message channel when contains discord message link", async () => {
			const generatePreviewMock = sandbox.stub(MessagePreviewService.prototype, "generatePreview");

			message.content = "https://ptb.discordapp.com/channels/240880736851329024/518817917438001152/732711501345062982";

			await handler.handle(message);

			expect(generatePreviewMock.called).to.be.true;
		});

		it("sends a single message in message channel when contains multiple discord message links however one is escaped", async () => {
			const generatePreviewMock = sandbox.stub(MessagePreviewService.prototype, "generatePreview");

			message.content = "https://ptb.discordapp.com/channels/240880736851329024/518817917438001152/732711501345062982 <https://ptb.discordapp.com/channels/240880736851329024/518817917438001152/732711501345062982>";

			await handler.handle(message);

			expect(generatePreviewMock.calledOnce).to.be.true;
		});

		it("sends multiple messages in message channel when contains multiple discord message link", async () => {
			const generatePreviewMock = sandbox.stub(MessagePreviewService.prototype, "generatePreview");

			message.content = "https://ptb.discordapp.com/channels/240880736851329024/518817917438001152/732711501345062982 https://ptb.discordapp.com/channels/240880736851329024/518817917438001152/732711501345062982";

			await handler.handle(message);

			expect(generatePreviewMock.calledTwice).to.be.true;
		});

		it("does not send a message if the message starts with < and ends with >", async () => {
			const generatePreviewMock = sandbox.stub(MessagePreviewService.prototype, "generatePreview");

			message.content = "<https://ptb.discordapp.com/channels/240880736851329024/518817917438001152/732711501345062982>";

			await handler.handle(message);

			expect(generatePreviewMock.called).to.be.false;
		});

		it("does not send a message if the url was escaped mid sentence", async () => {
			const generatePreviewMock = sandbox.stub(MessagePreviewService.prototype, "generatePreview");

			message.content = "placeholderText <https://ptb.discordapp.com/channels/240880736851329024/518817917438001152/732711501345062982> placeholderText";

			await handler.handle(message);

			expect(generatePreviewMock.called).to.be.false;
		});

		afterEach(() => {
			sandbox.restore();
		});
	});
});
Example #20
Source File: MessagePreviewServiceTest.ts    From discord-bot with MIT License 4 votes vote down vote up
describe("MessagePreviewService", () => {
	describe("::getInstance()", () => {
		it("returns an instance of MessagePreviewService", () => {
			const service = MessagePreviewService.getInstance();

			expect(service).to.be.instanceOf(MessagePreviewService);
		});
	});

	describe("generatePreview()", () => {
		let sandbox: SinonSandbox;
		let messagePreview: MessagePreviewService;
		let link: string;
		let callingMessage: Message;
		let channel: TextChannel;
		let getChannelMock: SinonStub;
		let sendMessageMock: SinonStub;
		let fetchMessageMock: SinonStub;

		beforeEach(() => {
			sandbox = createSandbox();

			messagePreview = MessagePreviewService.getInstance();

			const guild = CustomMocks.getGuild({
				id: "guild-id",
				channels: []
			});

			channel = CustomMocks.getTextChannel({
				id: "518817917438001152"
			}, guild);

			callingMessage = CustomMocks.getMessage({}, {
				channel
			});

			link = "https://discord.com/channels/guild-id/518817917438001152/732711501345062982";

			getChannelMock = sandbox.stub(callingMessage.guild.channels.cache, "get").returns(channel);
			sendMessageMock = sandbox.stub(callingMessage.channel, "send");

			fetchMessageMock = sandbox.stub(channel.messages, "fetch").resolves(callingMessage);
			sandbox.stub(callingMessage.member, "displayColor").get(() => "#FFFFFF");
		});

		it("gets the channel from the link", async () => {
			await messagePreview.generatePreview(link, callingMessage);

			expect(getChannelMock.calledOnce).to.be.true;
		});

		it("sends preview message", async () => {
			await messagePreview.generatePreview(link, callingMessage);

			expect(sendMessageMock.calledOnce).to.be.true;
		});

		it("escapes hyperlinks", async () => {
			const escapeHyperlinksMock = sandbox.stub(messagePreview, "escapeHyperlinks").returns("Parsed message");

			await messagePreview.generatePreview(link, callingMessage);

			expect(escapeHyperlinksMock.calledOnce);
		});

		it("doesn't send preview message if it is a bot message", async () => {
			callingMessage.author.bot = true;

			await messagePreview.generatePreview(link, callingMessage);

			expect(sendMessageMock.called).to.be.false;
		});

		it("doesn't send preview message if the channel ID is wrong", async () => {
			getChannelMock.restore();
			getChannelMock = sandbox.stub(callingMessage.guild.channels.cache, "get").returns(undefined);

			await messagePreview.generatePreview(link, callingMessage);

			expect(sendMessageMock.called).to.be.false;
		});

		it("doesn't send preview message if the message ID is wrong", async () => {
			fetchMessageMock.restore();
			fetchMessageMock = sandbox.stub(channel.messages, "fetch").returns(Promise.reject());

			await messagePreview.generatePreview(link, callingMessage);

			expect(sendMessageMock.called).to.be.false;
		});

		afterEach(() => {
			sandbox.restore();
		});
	});

	describe("verifyGuild()", () => {
		let sandbox: SinonSandbox;
		let messagePreview: MessagePreviewService;
		let message: Message;

		beforeEach(() => {
			sandbox = createSandbox();
			messagePreview = MessagePreviewService.getInstance();
			message = CustomMocks.getMessage();
		});

		it("should return true if message's guild and provided guild id match", () => {
			expect(messagePreview.verifyGuild(message, BaseMocks.getGuild().id)).to.be.true;
		});

		it("should return false if message's guild and provided guild id don't match", () => {
			expect(messagePreview.verifyGuild(message, "OTHER_GUILD_ID")).to.be.false;
		});

		afterEach(() => {
			sandbox.restore();
		});
	});

	describe("stripLink()", () => {
		let sandbox: SinonSandbox;
		let messagePreview: MessagePreviewService;
		let link: string;

		beforeEach(() => {
			sandbox = createSandbox();
			messagePreview = MessagePreviewService.getInstance();
			link = "https://ptb.discordapp.com/channels/240880736851329024/518817917438001152/732711501345062982";
		});

		it("strips link of unnecessary details", () => {
			const array = messagePreview.stripLink(link);

			expect(array).to.include("240880736851329024");
			expect(array).to.include("518817917438001152");
			expect(array).to.include("732711501345062982");
		});

		afterEach(() => {
			sandbox.restore();
		});
	});

	describe("escapeHyperlinks()", () => {
		let sandbox: SinonSandbox;
		let messagePreview: MessagePreviewService;

		beforeEach(() => {
			sandbox = createSandbox();
			messagePreview = MessagePreviewService.getInstance();
		});

		it("should return the string as it is if there are no hyperlinks", () => {
			expect(messagePreview.escapeHyperlinks("I am the night")).to.equal("I am the night");
		});

		it("should escape hyperlinks", () => {
			expect(messagePreview.escapeHyperlinks("Do you feel lucky, [punk](punkrock.com)?"))
				.to.equal("Do you feel lucky, \\[punk\\]\\(punkrock.com\\)?");
		});

		it("should scape all hyperlinks if there is more than one", () => {
			expect(messagePreview.escapeHyperlinks("[Link1](l1.com) and [Link2](l2.com)"))
				.to.equal("\\[Link1\\]\\(l1.com\\) and \\[Link2\\]\\(l2.com\\)");
		});

		it("should escape hyperlinks even if they are empty", () => {
			expect(messagePreview.escapeHyperlinks("[]()")).to.equal("\\[\\]\\(\\)");
			expect(messagePreview.escapeHyperlinks("[half]()")).to.equal("\\[half\\]\\(\\)");
			expect(messagePreview.escapeHyperlinks("[](half)")).to.equal("\\[\\]\\(half\\)");
		});

		afterEach(() => {
			sandbox.restore();
		});
	});
});
Example #21
Source File: GitHubServiceTest.ts    From discord-bot with MIT License 4 votes vote down vote up
describe("GitHubService", () => {
	describe("::getInstance()", () => {
		it("returns an instance of GitHubService", () => {
			const service = GitHubService.getInstance();

			expect(service).to.be.instanceOf(GitHubService);
		});
	});

	describe("getRepository()", () => {
		let sandbox: SinonSandbox;
		let gitHub: GitHubService;

		beforeEach(() => {
			sandbox = createSandbox();
			gitHub = GitHubService.getInstance();
		});

		it("performs a GET request to the GitHub API", async () => {
			const axiosGet = sandbox.stub(axios, "get").resolves({
				status: 200,
				data: {
					owner: {
						login: "user"
					},
					name: "repo-github",
					description: "The repo description",
					language: "TypeScript",
					html_url: "https://github.com/codesupport/discord-bot",
					open_issues_count: 1,
					forks: 5,
					subscribers_count: 3,
					watchers: 10
				}
			});

			await gitHub.getRepository("user", "repo");

			expect(axiosGet.called).to.be.true;
		});

		it("throws an error if the API responds with Not Found", async () => {
			const axiosGet = sandbox.stub(axios, "get").resolves({
				status: 404,
				data: {}
			});

			// Chai can't detect throws inside async functions. This is a hack to get it working.
			try {
				await gitHub.getRepository("user", "repo");
			} catch ({ message }) {
				expect(message).to.equal("There was a problem with the request to GitHub.");
			}

			expect(axiosGet.called).to.be.true;
		});

		afterEach(() => {
			sandbox.restore();
		});
	});

	describe("getPullRequest()", () => {
		let sandbox: SinonSandbox;
		let gitHub: GitHubService;

		beforeEach(() => {
			sandbox = createSandbox();
			gitHub = GitHubService.getInstance();
		});

		it("performs a GET request to the GitHub pulls API", async () => {
			const axiosGet = sandbox.stub(axios, "get").resolves({
				status: 200,
				data: [{
					title: "This is a title",
					body: "This is a description",
					user: {
						login: "user"
					}
				}]
			});

			const result = await gitHub.getPullRequest("user", "repo");

			expect(axiosGet.called).to.be.true;
			expect(result).to.have.length(1);
		});

		it("returns an empty array if there is no data present", async () => {
			const axiosGet = sandbox.stub(axios, "get").resolves({
				status: 200,
				data: []
			});

			const result = await gitHub.getPullRequest("user", "repo");

			expect(axiosGet.called).to.be.true;
			expect(result).to.have.length(0);
		});

		afterEach(() => {
			sandbox.restore();
		});
	});

	describe("getIssues()", () => {
		let sandbox: SinonSandbox;
		let gitHub: GitHubService;

		beforeEach(() => {
			sandbox = createSandbox();
			gitHub = GitHubService.getInstance();
		});

		it("performs a GET request to the GitHub issues API", async () => {
			const axiosGet = sandbox.stub(axios, "get").resolves({
				status: 200,
				data: [{
					title: "This is a title",
					number: 69,
					user: {
						login: "user",
						html_url: "https://github.com/user/"
					},
					html_url: "https://github.com/codesupport/discord-bot",
					created_at: "2020-01-01T12:00:00Z"
				}]
			});

			const result = await gitHub.getIssues("user", "repo");

			expect(axiosGet.called).to.be.true;
			expect(result).to.have.length(1);
		});

		it("returns an empty array if there are no issues", async () => {
			const axiosGet = sandbox.stub(axios, "get").resolves({
				status: 200,
				data: []
			});

			const result = await gitHub.getIssues("user", "repo");

			expect(axiosGet.called).to.be.true;
			expect(result).to.have.length(0);
		});

		afterEach(() => {
			sandbox.restore();
		});
	});
});
Example #22
Source File: AdventOfCodeServiceTest.ts    From discord-bot with MIT License 4 votes vote down vote up
describe("AdventOfCodeService", () => {
	describe("::getInstance()", () => {
		it("creates an instance of AdventOfCodeService", () => {
			const service = AdventOfCodeService.getInstance();

			expect(service).to.be.instanceOf(AdventOfCodeService);
		});
	});

	describe("getLeaderBoard()", () => {
		let sandbox: SinonSandbox;
		let aoc: AdventOfCodeService;

		beforeEach(() => {
			sandbox = createSandbox();
			aoc = AdventOfCodeService.getInstance();
		});

		it("performs a GET request to the Advent Of Code Api", async () => {
			const axiosGet = sandbox.stub(aoc.api, "get").resolves({
				status: 200,
				data: mockAPIData
			});

			await aoc.getLeaderBoard("leaderboard", 2021);

			expect(axiosGet.called).to.be.true;
		});

		it("throws an error if the API responds when not authorized", async () => {
			const axiosGet = sandbox.stub(aoc.api, "get").resolves({
				status: 500,
				data: {}
			});

			// Chai can't detect throws inside async functions. This is a hack to get it working.
			try {
				await aoc.getLeaderBoard("leaderboard", 2021);
			} catch ({ message }) {
				expect(message).to.equal("Advent Of code leaderboard not found");
			}

			expect(axiosGet.called).to.be.true;
		});

		afterEach(() => {
			sandbox.restore();
		});
	});

	describe("getSingelPlayer()", () => {
		let sandbox: SinonSandbox;
		let aoc: AdventOfCodeService;

		beforeEach(() => {
			sandbox = createSandbox();
			aoc = AdventOfCodeService.getInstance();
		});

		it("performs a GET request to the Advent Of Code Api", async () => {
			const axiosGet = sandbox.stub(aoc.api, "get").resolves({
				status: 200,
				data: mockAPIData
			});

			await aoc.getLeaderBoard("leaderboard", 2021);

			expect(axiosGet.called).to.be.true;
		});

		it("returns the position and the member when the user exist on the leaderboard", async () => {
			sandbox.stub(aoc.api, "get").resolves({
				status: 200,
				data: mockAPIData
			});

			const [position, member] = await aoc.getSinglePlayer("leaderboard", 2021, "JonaVDM");

			expect(position).to.equal(1);
			expect(member.name).to.equal("JonaVDM");
		});

		it("finds the player if the name is weirdly capitalized", async () => {
			sandbox.stub(aoc.api, "get").resolves({
				status: 200,
				data: mockAPIData
			});

			const [position, member] = await aoc.getSinglePlayer("leaderboard", 2021, "lAmBo");

			expect(position).to.equal(2);
			expect(member.name).to.equal("Lambo");
		});

		it("finds the player when there are spaces in the name", async () => {
			sandbox.stub(aoc.api, "get").resolves({
				status: 200,
				data: mockAPIData
			});

			const [position, member] = await aoc.getSinglePlayer("leaderboard", 2021, "Bob Pieter");

			expect(position).to.equal(3);
			expect(member.name).to.equal("Bob Pieter");
		});

		it("returns 0 and undefined when the user does not exist on the leaderboard", async () => {
			sandbox.stub(aoc.api, "get").resolves({
				status: 200,
				data: mockAPIData
			});

			const [position, member] = await aoc.getSinglePlayer("leaderboard", 2021, "bob");

			expect(position).to.equal(0);
			expect(member).to.be.undefined;
		});

		afterEach(() => {
			sandbox.restore();
		});
	});
});
Example #23
Source File: CommandFactoryTest.ts    From discord-bot with MIT License 4 votes vote down vote up
describe("CommandFactory", () => {
	let factory: CommandFactory;
	let commandName: string;
	let commandWithAliasesName: string;
	let aliases: string[];

	before(() => {
		commandName = new MockCommand().getName();
		commandWithAliasesName = new MockCommandWithAlias().getName();
		aliases = new MockCommandWithAlias().getAliases();

		factory = new CommandFactory();
		factory.commands = {};
		factory.commands[commandName] = () => new MockCommand();
		factory.commands[commandWithAliasesName] = () => new MockCommandWithAlias();

		aliases.forEach(alias => {
			factory.commands[alias] = () => new MockCommandWithAlias();
		});
	});

	describe("loadCommands()", () => {
		let sandbox: SinonSandbox;
		let emptyFactory: CommandFactory;
		let getFilesStub: SinonStub;

		beforeEach(() => {
			sandbox = createSandbox();
			emptyFactory = new CommandFactory();

			getFilesStub = sandbox.stub(DirectoryUtils, "getFilesInDirectory").callsFake(async () => [
				// eslint-disable-next-line global-require
				require("../MockCommand"),

				// eslint-disable-next-line global-require
				require("../MockCommandWithAlias")
			]);
		});

		it("should call DirectoryUtils::getFilesInDirectory()", async () => {
			await emptyFactory.loadCommands();

			expect(getFilesStub.called).to.be.true;
		});

		it("should load commands", async () => {
			expect(emptyFactory.commandExists(new MockCommand().getName())).to.be.false;

			await emptyFactory.loadCommands();

			expect(emptyFactory.commandExists(new MockCommand().getName())).to.be.true;
		});

		it("should load aliases", async () => {
			expect(emptyFactory.commandExists(new MockCommandWithAlias().getName())).to.be.false;

			await emptyFactory.loadCommands();

			expect(emptyFactory.commandExists(new MockCommandWithAlias().getName())).to.be.true;
		});

		afterEach(() => {
			sandbox.restore();
		});
	});

	describe("commandExists()", () => {
		it("checks to see a command exists", () => {
			expect(factory.commandExists(commandName)).to.be.true;
		});

		it("checks to see a command exists - lowercase", () => {
			expect(factory.commandExists(commandName.toLowerCase())).to.be.true;
		});

		it("checks to see a command exists - uppercase", () => {
			expect(factory.commandExists(commandName.toUpperCase())).to.be.true;
		});

		it("checks to see a command doesn't exist", () => {
			expect(factory.commandExists("bad command")).to.be.false;
		});

		it("checks to see a command exists by it's aliases", () => {
			aliases.forEach(alias => {
				expect(factory.commandExists(alias)).to.be.true;
			});
		});
	});

	describe("getCommand()", () => {
		it("gets a mocked command", () => {
			expect(factory.getCommand(commandName)).to.be.a("object");
		});

		it("gets a mocked command - lowercase", () => {
			expect(factory.getCommand(commandName.toLowerCase())).to.be.a("object");
		});

		it("gets a mocked command - uppercase", () => {
			expect(factory.getCommand(commandName.toUpperCase())).to.be.a("object");
		});

		it("gets a mocked command by it's aliases", () => {
			aliases.forEach(alias => {
				expect(factory.getCommand(alias)).to.be.a("object");
			});
		});
	});
});
Example #24
Source File: NewUserAuthenticationHandlerTest.ts    From discord-bot with MIT License 4 votes vote down vote up
describe("NewUserAuthenticationHandler", () => {
	describe("constructor()", () => {
		it("creates a handler for MESSAGE_REACTION_ADD", () => {
			const handler = new NewUserAuthenticationHandler();

			expect(handler.getEvent()).to.equal(Constants.Events.MESSAGE_REACTION_ADD);
		});
	});

	describe("handle()", () => {
		let sandbox: SinonSandbox;
		let handler: EventHandler;
		let user: User;

		beforeEach(() => {
			sandbox = createSandbox();
			handler = new NewUserAuthenticationHandler();
			user = BaseMocks.getUser();
		});

		it("gives the user the member role if they meet the requirements", async () => {
			const message = CustomMocks.getMessage({
				id: "592316062796873738"
			});

			const reaction = CustomMocks.getMessageReaction({
				emoji: {
					name: "?"
				}
			}, { message });

			// @ts-ignore
			const fetchMock = sandbox.stub(reaction.message.guild?.members, "fetch").resolves({
				roles: {
					add: async (role: string, reason: string) => [role, reason]
				}
			});

			await handler.handle(reaction, user);

			expect(fetchMock.calledOnce).to.be.true;
		});

		it("does not give the user the member role if they react with the wrong emoji", async () => {
			const message = CustomMocks.getMessage({
				id: "592316062796873738"
			});

			const reaction = CustomMocks.getMessageReaction({
				emoji: {
					name: "?"
				}
			}, { message });

			// @ts-ignore
			const fetchMock = sandbox.stub(reaction.message.guild?.members, "fetch").resolves({
				roles: {
					add: async (role: string, reason: string) => [role, reason]
				}
			});

			await handler.handle(reaction, user);

			expect(fetchMock.calledOnce).to.be.false;
		});

		it("does not give the user the member role if they react to the wrong message", async () => {
			const message = CustomMocks.getMessage({
				id: "1234"
			});

			const reaction = CustomMocks.getMessageReaction({
				emoji: {
					name: "?"
				}
			}, { message });

			// @ts-ignore
			const fetchMock = sandbox.stub(reaction.message.guild?.members, "fetch").resolves({
				roles: {
					add: async (role: string, reason: string) => [role, reason]
				}
			});

			await handler.handle(reaction, user);

			expect(fetchMock.calledOnce).to.be.false;
		});

		it("does not give the user the member role if they react to the wrong message with the wrong emoji", async () => {
			const message = CustomMocks.getMessage({
				id: "1234"
			});

			const reaction = CustomMocks.getMessageReaction({
				emoji: {
					name: "?"
				}
			}, { message });

			// @ts-ignore
			const fetchMock = sandbox.stub(reaction.message.guild?.members, "fetch").resolves({
				roles: {
					add: async (role: string, reason: string) => [role, reason]
				}
			});

			await handler.handle(reaction, user);

			expect(fetchMock.calledOnce).to.be.false;
		});

		afterEach(() => {
			sandbox.restore();
		});
	});
});
Example #25
Source File: GhostPingHandlerTest.ts    From discord-bot with MIT License 4 votes vote down vote up
describe("GhostPingHandler", () => {
	describe("constructor()", () => {
		it("creates a handler for MESSAGE_DELETE", () => {
			const handler = new GhostPingHandler();

			expect(handler.getEvent()).to.equal(Constants.Events.MESSAGE_DELETE);
		});
	});

	describe("handle()", () => {
		let sandbox: SinonSandbox;
		let handler: EventHandler;

		beforeEach(() => {
			sandbox = createSandbox();
			handler = new GhostPingHandler();
		});

		it("sends a message when a message is deleted that pinged a user", async () => {
			const message = CustomMocks.getMessage();
			const messageMock = sandbox.stub(message.channel, "send");

			message.mentions = new MessageMentions(message, [CustomMocks.getUser({ id: "328194044587147278" })], [], false);
			message.content = "Hey <@328194044587147278>!";

			await handler.handle(message);

			expect(messageMock.calledOnce).to.be.true;
		});

		it("does not send a message when a message is deleted that didn't ping a user", async () => {
			const message = CustomMocks.getMessage();
			const messageMock = sandbox.stub(message.channel, "send");

			message.mentions = new MessageMentions(message, [], [], false);
			message.content = "Hey everybody!";

			await handler.handle(message);

			expect(messageMock.calledOnce).to.be.false;
		});

		it("does not send a message when it's author is a bot", async () => {
			const message = CustomMocks.getMessage();
			const messageMock = sandbox.stub(message.channel, "send");

			const author = BaseMocks.getUser();

			author.bot = true;

			message.author = author;
			message.mentions = new MessageMentions(message, [BaseMocks.getUser()], [], false);
			message.content = "Hey <@328194044587147278>, stop spamming or we'll arrest you!";

			await handler.handle(message);

			expect(messageMock.called).to.be.false;
		});

		it("does not send a message when author only mentions himself", async () => {
			const message = CustomMocks.getMessage();
			const messageMock = sandbox.stub(message.channel, "send");

			message.author = BaseMocks.getUser();
			message.mentions = new MessageMentions(message, [CustomMocks.getUser()], [], false);
			message.content = `<@${message.author.id}>`;

			await handler.handle(message);

			expect(messageMock.called).to.be.false;
		});

		it("sends a message when message author and someone else is being mentioned", async () => {
			const message = CustomMocks.getMessage();
			const messageMock = sandbox.stub(message.channel, "send");

			const author = CustomMocks.getUser();

			message.author = author;
			message.mentions = new MessageMentions(message, [author, CustomMocks.getUser({ id: "328194044587147278" })], [], false);
			message.content = `<@${message.author.id}> <@328194044587147278>`;

			await handler.handle(message);
			expect(messageMock.called).to.be.true;
		});

		it("provides additional info if message is a reply to another message", async () => {
			const message = CustomMocks.getMessage({guild: CustomMocks.getGuild()});
			const messageMock = sandbox.stub(message.channel, "send");
			const channelMock = CustomMocks.getTextChannel();
			const repliedToMessage = CustomMocks.getMessage({ id: "328194044587147280", guild: CustomMocks.getGuild()}, {
				channel: CustomMocks.getTextChannel({ id: "328194044587147278"})
			});
			const resolveChannelStub = sandbox.stub(message.guild.channels, "resolve").returns(channelMock);
			const fetchMessageStub = sandbox.stub(channelMock.messages, "fetch").returns(Promise.resolve(repliedToMessage));
			const author = CustomMocks.getUser();

			message.author = author;
			message.mentions = new MessageMentions(message, [CustomMocks.getUser({ id: "328194044587147278" })], [], false);
			message.guild.id = "328194044587147279";
			message.content = "this is a reply";
			message.reference = {
				channelId: "328194044587147278",
				guildId: "328194044587147279",
				messageId: "328194044587147280"
			};

			await handler.handle(message);
			expect(messageMock.called).to.be.true;
			expect(resolveChannelStub.called).to.be.true;
			expect(fetchMessageStub.called).to.be.true;
			const sentEmbed = messageMock.getCall(0).args[0].embeds[0];

			expect(sentEmbed).to.be.an.instanceOf(MessageEmbed);
			if (sentEmbed instanceof MessageEmbed) {
				const replyToField = sentEmbed.fields.find(field => field.name === "Reply to");

				expect(replyToField).to.not.be.null;

				const messageLinkField = sentEmbed.fields.find(field => field.name === "Message replied to");

				expect(messageLinkField).to.not.be.null;
				expect(messageLinkField.value).to.equal("https://discord.com/channels/328194044587147279/328194044587147278/328194044587147280");
			}
		});

		it("does not send a message when author only mentions himself and bots", async () => {
			const message = CustomMocks.getMessage();
			const messageMock = sandbox.stub(message.channel, "send");

			const botUser = CustomMocks.getUser({id: "328194044587147278"});

			botUser.bot = true;

			message.author = BaseMocks.getUser();
			message.mentions = new MessageMentions(message, [message.author, botUser], [], false);
			message.content = `<@${message.author.id}> <@${botUser.id}>`;

			await handler.handle(message);

			expect(messageMock.called).to.be.false;
		});

		it("does not send a message when author only mentions bots", async () => {
			const message = CustomMocks.getMessage();
			const messageMock = sandbox.stub(message.channel, "send");

			const botUser = CustomMocks.getUser({id: "328194044587147278"});
			const botUser2 = CustomMocks.getUser({id: "328194044587147279"});

			botUser.bot = true;
			botUser2.bot = true;

			message.author = BaseMocks.getUser();
			message.mentions = new MessageMentions(message, [botUser, botUser2], [], false);
			message.content = `<@${botUser.id}> <@${botUser2.id}>`;

			await handler.handle(message);

			expect(messageMock.called).to.be.false;
		});

		it("does not send a message when author replies to a bot", async () => {
			const message = CustomMocks.getMessage({guild: CustomMocks.getGuild()});
			const messageMock = sandbox.stub(message.channel, "send");
			const channelMock = CustomMocks.getTextChannel();
			const repliedToMessage = CustomMocks.getMessage({ id: "328194044587147280", guild: CustomMocks.getGuild() }, {
				channel: CustomMocks.getTextChannel({ id: "328194044587147278"})
			});
			const resolveChannelStub = sandbox.stub(message.guild.channels, "resolve").returns(channelMock);
			const fetchMessageStub = sandbox.stub(channelMock.messages, "fetch").returns(Promise.resolve(repliedToMessage));
			const author = BaseMocks.getUser();
			const botUser = CustomMocks.getUser({id: "328194044587147276"});

			botUser.bot = true;

			message.author = author;
			message.mentions = new MessageMentions(message, [botUser], [], false);
			message.guild.id = "328194044587147279";
			message.content = "this is a reply";
			message.reference = {
				channelId: "328194044587147278",
				guildId: "328194044587147279",
				messageId: "328194044587147280"
			};

			await handler.handle(message);
			expect(messageMock.called).to.be.false;
			expect(resolveChannelStub.called).to.be.false;
			expect(fetchMessageStub.called).to.be.false;
		});

		afterEach(() => {
			sandbox.restore();
		});
	});
});
Example #26
Source File: appTest.ts    From discord-bot with MIT License 4 votes vote down vote up
describe("App", () => {
	let sandbox: SinonSandbox;
	let loginStub: SinonStub;
	let getStub: SinonStub;

	beforeEach(() => {
		sandbox = createSandbox();

		loginStub = sandbox.stub(Client.prototype, "login");
		getStub = sandbox.stub(axios, "get").resolves();

		process.env.DISCORD_TOKEN = "FAKE_TOKEN";
		process.env.HEALTH_CHECK_URL = "https://health-check.com";
	});

	describe("constructor()", () => {
		it("should throw error if DISCORD_TOKEN is not set", async () => {
			process.env.DISCORD_TOKEN = undefined;

			try {
				await new App();
			} catch ({ message }) {
				expect(message).to.equal("You must supply the DISCORD_TOKEN environment variable.");
			}
		});
	});

	describe("reportHealth()", () => {
		it("sends a GET request to a health check endpoint", () => {
			new App().reportHealth();

			expect(getStub.calledOnce).to.be.true;
			expect(getStub.calledWith("https://health-check.com")).to.be.true;
		});
	});

	describe("init()", () => {
		it("should login with the provided DISCORD_TOKEN", async () => {
			sandbox.stub(DirectoryUtils, "getFilesInDirectory").resolves([]);

			await new App().init();

			expect(loginStub.calledWith("FAKE_TOKEN")).to.be.true;
		});

		it("should look for slash commands", async () => {
			const getFilesStub = sandbox.stub(DirectoryUtils, "getFilesInDirectory").resolves([]);

			await new App().init();

			expect(getFilesStub.args[0][1]).to.equal("Command.js");
		});

		it("should look for handler files", async () => {
			const getFilesStub = sandbox.stub(DirectoryUtils, "getFilesInDirectory").resolves([]);

			await new App().init();

			expect(getFilesStub.args[1][1]).to.equal("Handler.js");
		});

		it("should bind handlers to events", async () => {
			// eslint-disable-next-line global-require
			sandbox.stub(DirectoryUtils, "getFilesInDirectory").callsFake(async () => [require("./MockHandler")]);
			const onStub = sandbox.stub(Client.prototype, "on");

			await new App().init();

			const mockHandler = new MockHandler();

			expect(onStub.calledWith(mockHandler.getEvent())).to.be.true;
		});

		it("should fetch auth channel and messages in production environment", async () => {
			const testEnv = process.env.NODE_ENV;

			process.env.NODE_ENV = PRODUCTION_ENV;

			sandbox.stub(DirectoryUtils, "getFilesInDirectory").callsFake(() => []);

			const textChannel = BaseMocks.getTextChannel();

			const fetchChannelsStub = sandbox.stub(ChannelManager.prototype, "fetch").callsFake(async () => textChannel);
			const fetchMessagesStub = sandbox.stub(textChannel.messages, "fetch");

			await new App().init();

			expect(fetchChannelsStub.calledWith(AUTHENTICATION_MESSAGE_CHANNEL)).to.be.true;
			expect(fetchMessagesStub.calledWith(AUTHENTICATION_MESSAGE_ID)).to.be.true;

			process.env.NODE_ENV = testEnv;
		});
	});

	afterEach(() => {
		sandbox.restore();
	});
});
Example #27
Source File: CommandParserHandlerTest.ts    From discord-bot with MIT License 4 votes vote down vote up
describe("CommandParserHandler", () => {
	describe("constructor()", () => {
		let sandbox: SinonSandbox;

		beforeEach(() => {
			sandbox = createSandbox();
		});

		it("creates a handler for MESSAGE_CREATE", () => {
			const handler = new CommandParserHandler();

			expect(handler.getEvent()).to.equal(Constants.Events.MESSAGE_CREATE);
		});

		it("should call loadCommands()", () => {
			const factoryMock = sandbox.stub(CommandFactory.prototype, "loadCommands");

			const handler = new CommandParserHandler();

			expect(factoryMock.calledOnce).to.be.true;
		});

		afterEach(() => {
			sandbox.restore();
		});
	});

	describe("handle", () => {
		let sandbox: SinonSandbox;
		let handler: CommandParserHandler;
		let command: MockCommand;

		beforeEach(() => {
			sandbox = createSandbox();
			handler = new CommandParserHandler();
			command = new MockCommand();
		});

		it("should not run command if it doesn't start with command prefix", async () => {
			sandbox.stub(CommandFactory.prototype, "commandExists").returns(true);

			const runCommandMock = sandbox.stub(command, "run");
			const message = BaseMocks.getMessage();

			message.content = command.getName();

			await handler.handle(message);

			expect(runCommandMock.called).to.be.false;
		});

		it("should not run command if message was sent on a botless channel", async () => {
			sandbox.stub(CommandFactory.prototype, "commandExists").returns(true);
			sandbox.stub(getConfigValue, "default").returns({ MOCK_CHANNEL: "mock-channel-lol"});

			const runCommandMock = sandbox.stub(command, "run");
			const message = BaseMocks.getMessage();

			message.content = COMMAND_PREFIX + command.getName();
			message.channel.id = "mock-channel-lol";

			await handler.handle(message);

			expect(runCommandMock.called).to.be.false;
		});

		it("should not run a nonexistent command", async () => {
			sandbox.stub(CommandFactory.prototype, "commandExists").returns(false);

			const runCommandMock = sandbox.stub(command, "run");
			const message = BaseMocks.getMessage();

			message.content = COMMAND_PREFIX + command.getName();
			message.channel.id = "fake-bot-enabled-channel-id-123";

			await handler.handle(message);

			expect(runCommandMock.called).to.be.false;
		});

		it("should not throw error if message consists in command prefix", async () => {
			const message = BaseMocks.getMessage();

			message.content = COMMAND_PREFIX;
			message.channel.id = "fake-bot-enabled-channel-id";

			let errorWasThrown = false;

			try {
				await handler.handle(message);
			} catch (error) {
				errorWasThrown = true;
			}

			expect(errorWasThrown).to.be.false;
		});

		it("should run command", async () => {
			sandbox.stub(CommandFactory.prototype, "commandExists").returns(true);
			sandbox.stub(CommandFactory.prototype, "getCommand").returns(command);

			const runCommandMock = sandbox.stub(command, "run");
			const message = BaseMocks.getMessage();

			message.content = COMMAND_PREFIX + command.getName();
			message.channel.id = "fake-bot-enabled-channel-id-123";

			await handler.handle(message);

			expect(runCommandMock.called).to.be.true;
		});

		it("should delete messages that trigger a self destructing command", async () => {
			sandbox.stub(CommandFactory.prototype, "commandExists").returns(true);
			sandbox.stub(CommandFactory.prototype, "getCommand").returns(command);
			sandbox.stub(MockCommand.prototype, "isSelfDestructing").returns(true);

			const message = BaseMocks.getMessage();

			const deleteMessageMock = sandbox.stub(message, "delete");

			message.content = COMMAND_PREFIX + command.getName();
			message.channel.id = "fake-bot-enabled-channel-id-123";

			await handler.handle(message);

			expect(deleteMessageMock.called).to.be.true;
		});

		afterEach(() => {
			sandbox.restore();
		});
	});
});
Example #28
Source File: CodeblocksOverFileUploadsHandlerTest.ts    From discord-bot with MIT License 4 votes vote down vote up
describe("CodeblocksOverFileUploadsHandler", () => {
	describe("constructor()", () => {
		it("creates a handler for MESSAGE_CREATE", () => {
			const handler = new CodeblocksOverFileUploadsHandler();

			expect(handler.getEvent()).to.equal(Constants.Events.MESSAGE_CREATE);
		});
	});

	describe("handle()", () => {
		let sandbox: SinonSandbox;
		let handler: EventHandler;
		let message: Message;

		beforeEach(() => {
			sandbox = createSandbox();
			handler = new CodeblocksOverFileUploadsHandler();
			message = CustomMocks.getMessage({
				id: "1234",
				author: BaseMocks.getUser()
			});
			message.client.user = BaseMocks.getUser();
			message.attachments = new Collection<string, MessageAttachment>();
		});

		it("does nothing when there are no attachments.", async () => {
			const addMock = sandbox.stub(message.channel, "send");

			await handler.handle(message);

			expect(addMock.calledOnce).to.be.false;
		});

		it("does nothing when there is a valid attachment.", async () => {
			message.attachments.set("720390958847361064", new MessageAttachment("720390958847361064", "test.png"));
			const addMockSend = sandbox.stub(message.channel, "send");

			await handler.handle(message);
			expect(addMockSend.notCalled).to.be.true;
		});

		it("isn't case sensitive", async () => {
			message.attachments.set("720390958847361064", new MessageAttachment("720390958847361064", "test.PNG"));
			const addMockSend = sandbox.stub(message.channel, "send");

			await handler.handle(message);
			expect(addMockSend.notCalled).to.be.true;
		});

		it("sends a message and deletes the user's upload when there is an invalid attachment.", async () => {
			message.attachments.set("720390958847361064", new MessageAttachment("720390958847361064", "test.cpp"));
			const addMockSend = sandbox.stub(message.channel, "send");
			const addMockDelete = sandbox.stub(message, "delete");

			await handler.handle(message);
			const embed = addMockSend.getCall(0).firstArg.embeds[0];

			expect(addMockSend.calledOnce).to.be.true;
			expect(addMockDelete.calledOnce).to.be.true;
			expect(embed.title).to.equal("Uploading Files");
			expect(embed.description).to.equal("<@010101010101010101>, you tried to upload a \`.cpp\` file, which is not allowed. Please use codeblocks over attachments when sending code.");
			expect(embed.hexColor).to.equal(EMBED_COLOURS.DEFAULT.toLowerCase());
		});

		it("deletes the message when any attachment on the message is invalid.", async () => {
			message.attachments.set("720390958847361064", new MessageAttachment("720390958847361064", "test.png"));
			message.attachments.set("72039095884736104", new MessageAttachment("72039095884736105", "test.cpp"));
			const addMockSend = sandbox.stub(message.channel, "send");
			const addMockDelete = sandbox.stub(message, "delete");

			await handler.handle(message);

			const embed = addMockSend.getCall(0).firstArg.embeds[0];

			expect(addMockSend.calledOnce).to.be.true;
			expect(addMockDelete.calledOnce).to.be.true;
			expect(embed.title).to.equal("Uploading Files");
			expect(embed.description).to.equal("<@010101010101010101>, you tried to upload a \`.cpp\` file, which is not allowed. Please use codeblocks over attachments when sending code.");
			expect(embed.hexColor).to.equal(EMBED_COLOURS.DEFAULT.toLowerCase());
		});

		afterEach(() => {
			sandbox.restore();
		});
	});
});
Example #29
Source File: RuleCommandTest.ts    From discord-bot with MIT License 4 votes vote down vote up
describe("RuleCommand", () => {
	describe("run()", () => {
		let sandbox: SinonSandbox;
		let command: RuleCommand;

		beforeEach(() => {
			sandbox = createSandbox();
			command = new RuleCommand();
		});

		it("sends a message to the channel", async () => {
			const replyStub = sandbox.stub().resolves();

			await command.onInteract("0", {
				reply: replyStub
			});

			expect(replyStub.calledOnce).to.be.true;
		});

		it("states rule 0 if you ask for rule 0", async () => {
			const replyStub = sandbox.stub().resolves();

			await command.onInteract("0", {
				reply: replyStub
			});

			const embed = replyStub.getCall(0).firstArg.embeds[0];

			expect(replyStub.calledOnce).to.be.true;
			expect(embed.title).to.equal("Rule: Asking For Help");
			expect(embed.description).to.equal("Help us to help you, instead of just saying \"my code doesn't work\" or \"can someone help me.\"");
			expect(embed.fields[0].name).to.equal("To familiarise yourself with all of the server's rules please see");
			expect(embed.fields[0].value).to.equal("<#240884566519185408>");
			expect(embed.hexColor).to.equal(EMBED_COLOURS.SUCCESS.toLowerCase());
		});

		it("states rule 1 if you ask for rule 1", async () => {
			const replyStub = sandbox.stub().resolves();

			await command.onInteract("1", {
				reply: replyStub
			});

			const embed = replyStub.getCall(0).firstArg.embeds[0];

			expect(replyStub.calledOnce).to.be.true;
			expect(embed.title).to.equal("Rule: Be Patient");
			expect(embed.description).to.equal("Responses to your questions are not guaranteed. The people here offer their expertise on their own time and for free.");
			expect(embed.hexColor).to.equal(EMBED_COLOURS.SUCCESS.toLowerCase());
			expect(embed.fields[0].name).to.equal("To familiarise yourself with all of the server's rules please see");
			expect(embed.fields[0].value).to.equal("<#240884566519185408>");
		});

		it("states rule 2 if you ask for rule 2", async () => {
			const replyStub = sandbox.stub().resolves();

			await command.onInteract("2", {
				reply: replyStub
			});

			const embed = replyStub.getCall(0).firstArg.embeds[0];

			expect(replyStub.calledOnce).to.be.true;
			expect(embed.title).to.equal("Rule: Unsolicited Contact/Bumps");
			expect(embed.hexColor).to.equal(EMBED_COLOURS.SUCCESS.toLowerCase());
			expect(embed.description).to.equal("Do not send unsolicited DMs, bump questions, or ping for questions outside of an established conversation.");
			expect(embed.fields[0].name).to.equal("To familiarise yourself with all of the server's rules please see");
			expect(embed.fields[0].value).to.equal("<#240884566519185408>");
		});

		it("states rule 3 if you ask for rule 3", async () => {
			const replyStub = sandbox.stub().resolves();

			await command.onInteract("3", {
				reply: replyStub
			});

			const embed = replyStub.getCall(0).firstArg.embeds[0];

			expect(replyStub.calledOnce).to.be.true;
			expect(embed.title).to.equal("Rule: Be Nice");
			expect(embed.description).to.equal("Be respectful; no personal attacks, sexism, homophobia, transphobia, racism, hate speech or other disruptive behaviour.");
			expect(embed.hexColor).to.equal(EMBED_COLOURS.SUCCESS.toLowerCase());
			expect(embed.fields[0].name).to.equal("To familiarise yourself with all of the server's rules please see");
			expect(embed.fields[0].value).to.equal("<#240884566519185408>");
		});

		it("states rule 4 if you ask for rule 4", async () => {
			const replyStub = sandbox.stub().resolves();

			await command.onInteract("4", {
				reply: replyStub
			});

			const embed = replyStub.getCall(0).firstArg.embeds[0];

			expect(replyStub.calledOnce).to.be.true;
			expect(embed.title).to.equal("Rule: No Advertising");
			expect(embed.description).to.equal("Don't advertise. If you're not sure whether it would be considered advertising or not, ask a moderator.");
			expect(embed.hexColor).to.equal(EMBED_COLOURS.SUCCESS.toLowerCase());
			expect(embed.fields[0].name).to.equal("To familiarise yourself with all of the server's rules please see");
			expect(embed.fields[0].value).to.equal("<#240884566519185408>");
		});

		it("states rule 5 if you ask for rule 5", async () => {
			const replyStub = sandbox.stub().resolves();

			await command.onInteract("5", {
				reply: replyStub
			});

			const embed = replyStub.getCall(0).firstArg.embeds[0];

			expect(replyStub.calledOnce).to.be.true;
			expect(embed.title).to.equal("Rule: Use The Right Channel");
			expect(embed.description).to.equal("Stick to the correct channels. If you're unsure which channel to put your question in, you can ask in [#general](https://codesupport.dev/discord) which channel is best for your question.");
			expect(embed.hexColor).to.equal(EMBED_COLOURS.SUCCESS.toLowerCase());
			expect(embed.fields[0].name).to.equal("To familiarise yourself with all of the server's rules please see");
			expect(embed.fields[0].value).to.equal("<#240884566519185408>");
		});

		it("states rule 6 if you ask for rule 6", async () => {
			const replyStub = sandbox.stub().resolves();

			await command.onInteract("6", {
				reply: replyStub
			});

			const embed = replyStub.getCall(0).firstArg.embeds[0];

			expect(replyStub.calledOnce).to.be.true;
			expect(embed.title).to.equal("Rule: Illegal/Immoral Tasks");
			expect(embed.description).to.equal("Don't ask for help with illegal or immoral tasks. Doing so not only risks your continued participation in this community but is in violation of Discord's TOS and can get your account banned.");
			expect(embed.hexColor).to.equal(EMBED_COLOURS.SUCCESS.toLowerCase());
			expect(embed.fields[0].name).to.equal("To familiarise yourself with all of the server's rules please see");
			expect(embed.fields[0].value).to.equal("<#240884566519185408>");
		});

		it("states rule 7 if you ask for rule 7", async () => {
			const replyStub = sandbox.stub().resolves();

			await command.onInteract("7", {
				reply: replyStub
			});

			const embed = replyStub.getCall(0).firstArg.embeds[0];

			expect(replyStub.calledOnce).to.be.true;
			expect(embed.title).to.equal("Rule: No Spoon-feeding");
			expect(embed.description).to.equal("No spoon-feeding, it's not useful and won't help anyone learn.");
			expect(embed.hexColor).to.equal(EMBED_COLOURS.SUCCESS.toLowerCase());
			expect(embed.fields[0].name).to.equal("To familiarise yourself with all of the server's rules please see");
			expect(embed.fields[0].value).to.equal("<#240884566519185408>");
		});

		it("states rule 8 if you ask for rule 8", async () => {
			const replyStub = sandbox.stub().resolves();

			await command.onInteract("8", {
				reply: replyStub
			});

			const embed = replyStub.getCall(0).firstArg.embeds[0];

			expect(replyStub.calledOnce).to.be.true;
			expect(embed.title).to.equal("Rule: Use Codeblocks");
			expect(embed.description).to.equal("When posting code, please use code blocks (see `?codeblock` for help).");
			expect(embed.hexColor).to.equal(EMBED_COLOURS.SUCCESS.toLowerCase());
			expect(embed.fields[0].name).to.equal("To familiarise yourself with all of the server's rules please see");
			expect(embed.fields[0].value).to.equal("<#240884566519185408>");
		});

		it("states rule 9 if you ask for rule 9", async () => {
			const replyStub = sandbox.stub().resolves();

			await command.onInteract("9", {
				reply: replyStub
			});

			const embed = replyStub.getCall(0).firstArg.embeds[0];

			expect(replyStub.calledOnce).to.be.true;
			expect(embed.title).to.equal("Rule: Keep it Clean");
			expect(embed.description).to.equal("Keep it appropriate, some people use this at school or at work.");
			expect(embed.hexColor).to.equal(EMBED_COLOURS.SUCCESS.toLowerCase());
			expect(embed.fields[0].name).to.equal("To familiarise yourself with all of the server's rules please see");
			expect(embed.fields[0].value).to.equal("<#240884566519185408>");
		});

		afterEach(() => {
			sandbox.restore();
		});
	});
});