Unit testing Discord bot command functions with Jest mocks

I have a Discord bot command module that exports an object with an execute function. This function takes two parameters and uses discord.js to send messages through interaction.reply('Hello World'). I need to write Jest tests for this.

My main questions are:

  1. How can I verify that interaction.reply was called with the correct string argument?
  2. What’s the best way to mock this method so it doesn’t actually execute during tests?

I can import and run the command function, but I’m struggling with mocking the interaction object properly. Since I can’t create a real Discord interaction object in my test environment, I need to mock it completely.

Also, some of my other commands have functions that return values instead of just sending messages. What would be the approach for testing those as well?

I’m working with discord.js but the testing principles should be similar regardless of the specific library.

Partial mock objects are great when you need more control over your tests. Instead of mocking all of discord.js, just build what your command actually needs. Something like const interaction = { reply: jest.fn().mockResolvedValue(undefined), user: { id: '123' } } - you can add properties as you go. One thing I learned the hard way: always mock reply as a resolved promise since discord.js methods are async. For commands that return values, I split them into two parts - a logic function that returns the value, and a thin wrapper that handles the Discord stuff. Then you can test the logic with normal assertions and test the interaction handling by checking mock calls. Way easier to debug when stuff breaks.

I’ve been testing Discord bots for a while and mock factories beat inline mocks every time. Throw jest.mock('discord.js') at the top of your test file, then build mock objects with all the methods your commands actually use. For interactions, you’ll usually need reply, editReply, followUp, and maybe user or guild properties depending on what your command does. Test commands that return values separately from interaction handling. Structure your commands so the business logic lives in pure functions you can test independently, then use thin wrapper functions for Discord API calls. Way cleaner testing and your code stays maintainable. The trick is keeping your logic separate from the Discord API interface.

mock it like this: const mockInteraction = { reply: jest.fn() }. then pass that to your command, run the function, and check expect(mockInteraction.reply).toHaveBeenCalledWith('Hello World'). no real discord calls are needed!