Testing
Honest summary: two services have tests, one has empty scaffolding, and four have none.
| Package | Framework | State |
|---|---|---|
ogun | Jest + ts-jest | 6 suites |
anansi | Jest + ts-jest | 2 suites |
api | Jest + ts-jest + supertest | Configured, no tests |
esu | — | None |
web | — | None |
mobile | — | None |
igdb-heartbeat | — | None |
Running
cd apps/ogun && pnpm test
cd apps/anansi && pnpm test
cd apps/api && pnpm test # currently fails — no test files match
pnpm test:watch
pnpm test:coverage
pnpm test:ci # --ci --coverage --forceExitWhat is covered
ogun
src/__tests__/
├── jobs/processMedia.test.ts
├── jobs/processImage.test.ts
├── jobs/processVideo.test.ts
├── utils/helper.test.ts
├── utils/redis.test.ts
└── utils/storage.test.tsThe media pipeline is the best-tested part of the platform — sensible, since it is the most complex pure-logic code in the repo and the hardest to verify by hand.
anansi
__tests__/unit/services/
├── payoutRun.test.ts
└── earnings.test.tsAlso the right priority: the earnings calculation and payout orchestration are where a bug costs money.
The API's empty scaffolding
apps/api has full Jest configuration and a complete directory structure with no test files:
apps/api/__tests__/
├── setup.ts
├── __mocks__/@playpals/db.ts ← Prisma mock
├── helpers/ (empty)
├── unit/
│ ├── controllers/ services/ middleware/ lib/ (all empty)
└── integration/routes/ (empty)Because testMatch finds nothing, pnpm test exits non-zero. That is worth knowing before you put it in a script.
The configuration itself is well thought out and ready to use:
moduleNameMapper: {
"^@playpals/db$": "<rootDir>/__tests__/__mocks__/@playpals/db.ts",
},
setupFiles: ["<rootDir>/__tests__/setup.ts"],
clearMocks: true,
restoreMocks: true,
coverageThreshold: {
global: { branches: 50, functions: 50, lines: 60, statements: 60 },
},The @playpals/db module mapper is the important piece — it swaps Prisma for a mock, so unit tests need no database. Infrastructure modules (logger, upload, mux, livekit, redis, server, configs) are excluded from coverage, so the thresholds measure business logic rather than glue.
dev-notes/api-jest-testing-plan.md and dev-notes/api-jest-implementation-guide.md contain the intended plan.
Writing tests
Unit — a service
Services are the highest-value target: pure logic, database mocked.
import { prisma } from "@playpals/db"; // resolves to the mock
import * as sessionService from "../../../src/services/session";
jest.mock("@playpals/db");
describe("createSession", () => {
it("rejects a booking outside the creator's availability", async () => {
(prisma.availability.findMany as jest.Mock).mockResolvedValue([]);
await expect(
sessionService.createSession({ playpalId: "c1", purchaserId: "u1", /* … */ }),
).rejects.toThrow();
});
});Integration — a route
supertest exercises the full middleware stack:
import request from "supertest";
import app from "../../../src/app";
describe("GET /api/v1/feed", () => {
it("401s without a token", async () => {
await request(app).get("/api/v1/feed").expect(401);
});
});Where to start
If you are adding tests, take them in this order — highest risk first:
lib/roomAccess.ts—canAccessRoomis the channel paywall. A bug here gives away paid content. Four visibility branches, all pure logic with mockable Prisma calls.middleware/authenticated.ts— token missing, expired, invalid, user deleted,tokenVersionmismatch. Five branches guarding everything.modules/revenuecat/— idempotency, product mapping, each event type. Money.services/feed.ts— cache key construction, cursor handling, invalidation.services/notify.ts— preference gating, target building.
Each is a contained, high-consequence unit that the existing mock setup already supports.
What is not tested anywhere
esu— socket handlers, authorization callbacks, presence. All logic, all untested.- Mobile — no test setup at all. React Native Testing Library plus a mocked query client would cover hooks and screens.
- End-to-end — nothing exercises a full flow (register → post → process → appear in feed).
Adding tests to a package without them
cd apps/<service>
pnpm add -D jest ts-jest @types/jestCopy apps/ogun/jest.config.js as a starting point, and mirror the @playpals/db mock from apps/api/__tests__/__mocks__/ if the service touches the database.
CI
There is none. Tests run only when someone remembers. The single highest-value change to this situation is a GitHub Actions workflow running pnpm check-types, pnpm lint, and the existing test suites on every pull request — that alone turns the tests that already exist into a real safety net. See Deploying.
