Skip to content

Reduce test mocking: real fs, stub executables, mock only at the fetch boundary #12

Description

@miridius

Problem

The unit tests mock our own runtime's primitives (Bun.file, Bun.write, Bun.spawn, fs.unlink/symlink/stat). A mock encodes the author's belief about how the real thing behaves — so it can never catch the cases where that belief is wrong, which is exactly where bugs live. Proven in practice: the corrupt-cache recovery bug (BunFile caches its stat after a read, so exists() returned stale true after unlink) passed the fully-mocked unit test and was only caught by manual QA (#11, commit 7db0bd8).

Policy

Mock only at boundaries we don't own and can't run hermetically:

  • Telegram API → MockBotApi at the fetch boundary (already the pattern; keep).
  • yt-dlp / ffprobe → instead of mocking Bun.spawn, put stub executables on PATH in the test container that emit canned stdout/stderr/exit codes. Real process spawn, real stream consumption, real signal/exit handling.
  • Filesystem → always real. The test container has a writable container-local /storage; test/download-video.integration.test.ts (added in Durable job queue with parallel downloads; contain handler errors; workflow gates #11) shows the pattern.
  • Module mocks (spyMock on our own modules) → only to isolate wiring (e.g. bot.ts routing tests); behavior tests should drive the real stack.

Work

  • Migrate download-video.test.ts off Bun.file/Bun.write/fs mocks onto real fs (fold the integration test file back in once the main file is real-fs)
  • Replace Bun.spawn mocks with stub yt-dlp/ffprobe executables
  • Audit handlers.test.ts/log-message.test.ts for module mocks that could be real code over real fs
  • Update CLAUDE.md or the test docs only if a non-discoverable rule remains after the migration

Related: #9 (test gaps).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions