Skip to content

Testing & Mocking

One of the largest benefits of having a strictly decoupled architecture with Dependency Injection is how easy it becomes to write robust integration tests.

WhatsBotCord provides a powerful ChatMock class that simulates a WhatsApp chat, capturing every outgoing message, media, and reaction generated by your command.

In your testing framework (like bun:test or jest), we create a local factory function that spins up a fresh DependencyContainer for every test. This completely stops state bleeding between tests.

import { container, Lifecycle } from "tsyringe";
import { ChatMock, SenderType } from "whatsbotcord";
import { describe, expect, it } from "bun:test";
import ProfileCommand from "./profile.js";
// Factory to spin an isolated env
function createProfileCommand(mockPlayers = [], mockStats = []) {
// 1. Isolate DI container
const localContainer = container.createChildContainer();
// 2. Load Testing Dependencies (RAM DBs and Mock FS)
PRELOAD_DI_Testing(localContainer);
// 3. Seed our RAM Database with custom inputs!
localContainer.registerInstance("Repo_Player", { data: mockPlayers });
// 4. Resolve the command ready to be tested
return localContainer.resolve(ProfileCommand);
}

Now we can use ChatMock to simulate a user messaging the bot and assert what our command replied with.

describe("Profile Command Tests", () => {
it("Should send error msg when User is not found", async () => {
// Create command with empty DB
const commandToTest = createProfileCommand([]);
// Initialize mock chat context
const mockChat = new ChatMock(commandToTest, {
senderType: SenderType.Individual,
chatId: "non_existent_id",
});
// Run the command virtually
await mockChat.StartChatSimulation();
// Assertions!
expect(mockChat.SentFromCommand.Images).toHaveLength(0);
expect(mockChat.SentFromCommand.Texts.at(0).text).toBe("Profile not found");
// Check if it reacted with a failure emoji
expect(mockChat.EmitedReactions.some(r => r.reactionText === "")).toBe(true);
});
it("Should successfully send the user profile picture when found", async () => {
// Seed DB with mock player profile
const mockPlayer = { id: "123", username: "Test User", pictureFileName: "test.png" };
const commandToTest = createProfileCommand([mockPlayer]);
const mockChat = new ChatMock(commandToTest, {
senderType: SenderType.Group,
participantId_LID: "123",
args: ["@Test User"], // Testing an argument mention!
});
await mockChat.StartChatSimulation();
// Verify it sent an image with the correct caption!
expect(mockChat.SentFromCommand.Texts).toHaveLength(0);
expect(mockChat.SentFromCommand.Images).toHaveLength(1);
expect(mockChat.SentFromCommand.Images.at(0).imageOptions.caption).toContain("Test User");
});
});

With this architecture:

  1. You never touch WhatsApp during your tests.
  2. The database is purely local RAM (blazing fast) ensuring predictable tests without locking real databases.
  3. ChatMock catches all text, multimedia, polls, and reactions seamlessly tracking the exact output of your command.
  4. It natively resolves mentions and arguments inside group chat simulators.