Skip to content

Testing

Honest summary: two services have tests, one has empty scaffolding, and four have none.

PackageFrameworkState
ogunJest + ts-jest6 suites
anansiJest + ts-jest2 suites
apiJest + ts-jest + supertestConfigured, no tests
esuNone
webNone
mobileNone
igdb-heartbeatNone

Running

bash
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 --forceExit

What 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.ts

The 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.ts

Also 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:

js
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.

ts
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:

ts
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:

  1. lib/roomAccess.tscanAccessRoom is the channel paywall. A bug here gives away paid content. Four visibility branches, all pure logic with mockable Prisma calls.
  2. middleware/authenticated.ts — token missing, expired, invalid, user deleted, tokenVersion mismatch. Five branches guarding everything.
  3. modules/revenuecat/ — idempotency, product mapping, each event type. Money.
  4. services/feed.ts — cache key construction, cursor handling, invalidation.
  5. 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

bash
cd apps/<service>
pnpm add -D jest ts-jest @types/jest

Copy 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.

Internal documentation — PlayPalz platform