Testing djs commands/flows

What's the generic consensus for (unit/integration) testing commands? Mock the djs return values? Room for error if I my mock doesn't reproduce the behaviour accurately. I'm currently testing all of the beneath code for accessing my data (services/models).
6 Replies
d.js toolkit
d.js toolkit2w ago
- What's your exact discord.js npm list discord.js and node node -v version? - Not a discord.js issue? Check out #other-js-ts. - Consider reading #how-to-get-help to improve your question! - Explain what exactly your issue is. - Post the full error stack trace, not just the top part! - Show your code! - Issue solved? Press the button!
veksen
veksenOP2w ago
To expand, my current mocking is someting like this:
vi.mock("discord.js", async () => {
const actual = await vi.importActual("discord.js");
return {
...actual,
EmbedBuilder: vi.fn().mockImplementation(() => ({
setTitle: vi.fn().mockReturnThis(),
setDescription: vi.fn().mockReturnThis(),
setColor: vi.fn().mockReturnThis()
}))
};
});

// mocked interaction
type MockChatInputCommandInteraction = Pick<
ChatInputCommandInteraction,
"deferReply" | "editReply" | "user"
>;

let mockInteraction: MockChatInputCommandInteraction;

beforeEach(async () => {
vi.clearAllMocks();

await resetTestDatabase();

mockInteraction = {
deferReply: vi.fn().mockResolvedValue(undefined),
editReply: vi.fn().mockResolvedValue(undefined),
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
user: {
id: "123456789"
}
};
});
vi.mock("discord.js", async () => {
const actual = await vi.importActual("discord.js");
return {
...actual,
EmbedBuilder: vi.fn().mockImplementation(() => ({
setTitle: vi.fn().mockReturnThis(),
setDescription: vi.fn().mockReturnThis(),
setColor: vi.fn().mockReturnThis()
}))
};
});

// mocked interaction
type MockChatInputCommandInteraction = Pick<
ChatInputCommandInteraction,
"deferReply" | "editReply" | "user"
>;

let mockInteraction: MockChatInputCommandInteraction;

beforeEach(async () => {
vi.clearAllMocks();

await resetTestDatabase();

mockInteraction = {
deferReply: vi.fn().mockResolvedValue(undefined),
editReply: vi.fn().mockResolvedValue(undefined),
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
user: {
id: "123456789"
}
};
});
Amgelo
Amgelo2w ago
imo just testing the backend logic and not the bot layer is enough
veksen
veksenOP2w ago
Yeah I’ve taken such approach. Abstracted the reply method, and spy on that
Amgelo
Amgelo2w ago
that's not what I said though say you wanted to test the /pay command, you can make your command execute look like (in a very simplified way)
const paid = interaction.options.getUser("paid");
const payer = interaction.user;
const amount = interaction.options.getNumber("amount");

const result = await this.bankService.pay(paid.id, payer.id, amount);

// reply accordingly whether the result was a success or else
const paid = interaction.options.getUser("paid");
const payer = interaction.user;
const amount = interaction.options.getNumber("amount");

const result = await this.bankService.pay(paid.id, payer.id, amount);

// reply accordingly whether the result was a success or else
then testing the banking service would be enough to test almost all of the logic, and pretty much all the parts you'd want to test
veksen
veksenOP2w ago
right ok, thank you

Did you find this page helpful?