Testing & Mocking
Mocking Pattern: Combining Everything
Section titled “Mocking Pattern: Combining Everything”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.
Isolating Test Containers
Section titled “Isolating Test Containers”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 envfunction 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);}Verifying the Chat Outputs
Section titled “Verifying the Chat Outputs”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:
- You never touch WhatsApp during your tests.
- The database is purely local RAM (blazing fast) ensuring predictable tests without locking real databases.
ChatMockcatches all text, multimedia, polls, and reactions seamlessly tracking the exact output of your command.- It natively resolves mentions and arguments inside group chat simulators.