Skip to main content
This guide explains how to add JSDoc to new/changed code, instrument logging with Pino, and write Jest tests in this pnpm/TypeScript monorepo.

JSDoc: document your public surface

  • When to add JSDoc
    • Add JSDoc for exported functions, classes, public types, and any non-trivial logic.
    • Keep it concise; explain the “why” and parameters/return types.
  • Basic pattern (TypeScript)
/**
 * Returns a human-readable label for a user.
 * @param user - The user object.
 * @param fallback - Optional fallback label when missing names.
 * @returns The display label.
 * @example
 * getUserLabel({ firstName: "Ada", lastName: "Lovelace" }) // "Ada Lovelace"
 */
export function getUserLabel(
  user: { firstName?: string; lastName?: string; email?: string },
  fallback: string = "Unknown"
): string {
  if (user.firstName || user.lastName) return `${user.firstName ?? ""} ${user.lastName ?? ""}`.trim();
  return user.email ?? fallback;
}
  • Inline types vs TSDoc tags
    • Prefer TypeScript types in signatures. Use JSDoc tags like @example, @deprecated, @remarks for extra context.
  • Tips
    • Keep examples small and copy‑pastable.
    • Update JSDoc when behavior or parameters change.

Logging with Pino: structured, fast logs

  • Goals
    • Use structured logs (JSON in production, pretty in dev).
    • Add context: module name, request id, user id when available.
  • Install (per package/app that needs logging)
    • Devs should add locally in the target workspace:
pnpm add pino pino-pretty
  • Create a logger utility
    • Create logger.ts (or reuse an existing shared logger in packages/observability/ when available) with environment‑aware transports.
// logger.ts
import pino from "pino";

export const logger = pino({
  level: process.env.LOG_LEVEL ?? (process.env.NODE_ENV === "production" ? "info" : "debug"),
  transport: process.env.NODE_ENV === "production" ? undefined : {
    target: "pino-pretty",
    options: { colorize: true, translateTime: "SYS:standard", singleLine: false }
  },
  base: { service: "wrappy" }
});
  • Use in modules
import { logger } from "./logger";

export async function createThing(input: unknown) {
  logger.debug({ input }, "creating thing");
  try {
    // ...logic
    logger.info({ id: "abc123" }, "created thing");
  } catch (err) {
    logger.error({ err }, "failed to create thing");
    throw err;
  }
}
  • HTTP request logging (optional)
    • For Node/Express/Fastify services, consider pino-http for request‑scoped logs and request IDs.
pnpm add pino-http
import pinoHttp from "pino-http";
import { logger } from "./logger";

app.use(pinoHttp({ logger, customProps: (req) => ({ route: req.url }) }));

Testing with Jest: unit and integration

  • What to test
    • Public functions, components, and critical branches (errors, edge cases).
    • For React/Next.js, use @testing-library/react for behavior tests.
  • Install (per package/app)
pnpm add -D jest ts-jest @types/jest
# For React code
pnpm add -D @testing-library/react @testing-library/jest-dom
  • Minimal config (TypeScript)
    • Create jest.config.ts next to package.json of the target workspace:
import type { Config } from "jest";

const config: Config = {
  preset: "ts-jest",
  testEnvironment: "node",
  roots: ["<rootDir>/src"],
  moduleFileExtensions: ["ts", "tsx", "js"],
  testMatch: ["**/__tests__/**/*.test.(ts|tsx)", "**/?(*.)+(spec|test).(ts|tsx)"]
};
export default config;
  • Example unit test
// src/__tests__/getUserLabel.test.ts
import { getUserLabel } from "../getUserLabel";

test("falls back to email", () => {
  expect(getUserLabel({ email: "user@x.com" })).toBe("user@x.com");
});
  • Scripts
    • Add to the package/app package.json:
{
  "scripts": {
    "test": "jest",
    "test:watch": "jest --watch",
    "test:ci": "jest --ci --reporters=default --reporters=jest-junit"
  }
}
  • Next.js notes
    • Use testEnvironment: "jsdom" for component tests.
    • Mock Next/router and server modules as needed.

Pull request checklist

  • JSDoc: Public APIs documented; examples updated.
  • Logs: Key paths log debug and success/error with context. No secrets in logs.
  • Tests: Unit tests covering main behavior and error paths; added test scripts.
  • Consistency: Filenames, import paths, and configs follow the existing package conventions.

Where to put things in this repo

  • Per‑package tooling: Install Jest/Pino in the specific apps/* or packages/* workspace that needs it.
  • Shared utilities: If a common logger module exists in packages/observability/, prefer importing that to avoid duplication.
  • Docs: Update this page if conventions evolve.