Popii - v0.5.1
    Preparing search index...

    Testing

    Popii ships a testing sub-package that lets you unit-test commands without a Discord connection or live bot. Tests run in Bun's built-in test runner.

    // No extra install needed — it's included with popii
    import { createTestClient, runCommand } from "popii/testing";
    // test/commands/ping.test.ts
    import { describe, it, expect } from "bun:test";
    import { createTestClient, runCommand } from "popii/testing";
    import pingCommand from "../../src/commands/ping";

    describe("/ping", () => {
    it("replies with Pong!", async () => {
    const client = createTestClient();
    const result = await runCommand(pingCommand, { client });

    expect(result.replies[0].content).toContain("Pong!");
    });
    });
    import { runCommand, mockOptions } from "popii/testing";
    import greetCommand from "../../src/commands/greet";

    it("greets the specified user", async () => {
    const client = createTestClient();
    const result = await runCommand(greetCommand, {
    client,
    options: mockOptions({ user: { id: "123", username: "Alice" } })
    });

    expect(result.replies[0].content).toContain("Alice");
    });
    it("rejects when not premium", async () => {
    const client = createTestClient();
    const result = await runCommand(premiumCommand, {
    client,
    locals: { dbUser: { premium: false, balance: 0 } }
    });

    expect(result.replies[0].ephemeral).toBe(true);
    expect(result.replies[0].content).toContain("Premium users only");
    });

    Pass an array of middlewares to run the full pipeline:

    import { middleware } from "popii";
    import myMiddleware from "../../src/middlewares/02-load-user";

    it("loads the user before running the command", async () => {
    const client = createTestClient();
    const result = await runCommand(someCommand, {
    client,
    middlewares: [myMiddleware],
    locals: {}
    });

    expect(result.replies[0].content).toBeDefined();
    });
    it("defers and then replies", async () => {
    const client = createTestClient();
    const result = await runCommand(slowCommand, { client });

    expect(result.deferred).toBe(true);
    expect(result.replies[0]).toBeDefined();
    });
    bun test                         # run all tests
    bun test test/commands/ping.test.ts # run a specific file
    bun test --watch # re-run on file changes

    Or use the CLI generator to scaffold a test file:

    popii g test ping
    # creates test/commands/ping.test.ts with boilerplate