Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions docs/recipes/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
sidebar_position: 3
title: Recipes
description: Practical testing recipes for NestJS with Suites, covering ORMs, databases, and real-world patterns.
keywords: [suites, nestjs testing, unit testing recipes, mock database, typescript testing]
---

# Recipes

> **What this covers:** Practical examples for testing NestJS services with Suites \
> **Best for:** Developers looking for patterns beyond the core guides

This section contains real-world examples showing how to use Suites with popular libraries and frameworks. Each recipe walks through the pattern, implementation, and test code.

:::tip Examples Repository
For complete, runnable code examples, browse the [Suites Examples repository](https://github.com/suites-dev/examples).
:::

## Available Recipes

- **[Mocking ORMs](/docs/recipes/mocking-orm)** - Mock TypeORM, Prisma, Drizzle, and MikroORM in NestJS unit tests
159 changes: 159 additions & 0 deletions docs/recipes/mocking-orm/drizzle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
---
sidebar_position: 11
title: "Mocking Drizzle ORM in NestJS Unit Tests"
description: Mock Drizzle database instances in NestJS unit tests using Suites. Wrap the Drizzle client in an injectable service for clean, isolated testing with TypeScript.
keywords: [mock drizzle, drizzle orm unit test, nestjs drizzle testing, mock database, typescript testing, suites]
---

# Mocking Drizzle in NestJS Unit Tests

:::info Overview
For an overview of the pattern and approach to mocking ORMs, see the [Mocking ORMs overview](/docs/recipes/mocking-orm).
:::

Drizzle uses a database instance that you typically import directly. Wrap it in an injectable class so Suites can auto-mock it.

## Step 1: Create a Database Injectable

```typescript title="database.service.ts"
import { Injectable } from "@nestjs/common";
import { drizzle } from "drizzle-orm/node-postgres";
import { Pool } from "pg";
import * as schema from "./schema";

@Injectable()
export class DatabaseService {
private db: ReturnType<typeof drizzle>;

constructor() {
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
});
this.db = drizzle(pool, { schema });
}

getDb() {
return this.db;
}
}
```

## Step 2: Create a Repository Wrapper

```typescript title="user.repository.ts"
import { Injectable } from "@nestjs/common";
import { DatabaseService } from "./database.service";
import { users } from "./schema";
import { eq } from "drizzle-orm";

@Injectable()
export class UserRepository {
constructor(private readonly database: DatabaseService) {}

async findById(id: number) {
const db = this.database.getDb();
const result = await db
.select()
.from(users)
.where(eq(users.id, id))
.limit(1);
return result[0] || null;
}

async findByEmail(email: string) {
const db = this.database.getDb();
const result = await db
.select()
.from(users)
.where(eq(users.email, email))
.limit(1);
return result[0] || null;
}

async create(email: string, name: string) {
const db = this.database.getDb();
const result = await db.insert(users).values({ email, name }).returning();
return result[0];
}
}
```

## Step 3: Use the Repository in Your Service

```typescript title="user.service.ts"
import { Injectable } from "@nestjs/common";
import { UserRepository } from "./user.repository";

@Injectable()
export class UserService {
constructor(private readonly userRepository: UserRepository) {}

async getUserById(id: number) {
return this.userRepository.findById(id);
}

async createUser(email: string, name: string) {
const existingUser = await this.userRepository.findByEmail(email);
if (existingUser) {
throw new Error("User already exists");
}

return this.userRepository.create(email, name);
}
}
```

## Step 4: Test with Suites

```typescript title="user.service.spec.ts"
import { TestBed, type Mocked } from "@suites/unit";
import { UserService } from "./user.service";
import { UserRepository } from "./user.repository";

describe("UserService", () => {
let userService: UserService;
let userRepository: Mocked<UserRepository>;

beforeAll(async () => {
const { unit, unitRef } = await TestBed.solitary(UserService).compile();
userService = unit;
userRepository = unitRef.get(UserRepository);
});

it("should get user by id", async () => {
const mockUser = { id: 1, email: "test@example.com", name: "Test User" };
userRepository.findById.mockResolvedValue(mockUser);

const result = await userService.getUserById(1);

expect(result).toEqual(mockUser);
expect(userRepository.findById).toHaveBeenCalledWith(1);
});

it("should create a new user", async () => {
userRepository.findByEmail.mockResolvedValue(null);
const newUser = { id: 1, email: "new@example.com", name: "New User" };
userRepository.create.mockResolvedValue(newUser);

const result = await userService.createUser("new@example.com", "New User");

expect(result).toEqual(newUser);
expect(userRepository.findByEmail).toHaveBeenCalledWith("new@example.com");
expect(userRepository.create).toHaveBeenCalledWith(
"new@example.com",
"New User"
);
});
});
```

## Summary

- **Wrap Drizzle database instance** in an injectable `DatabaseService` class to make it mockable
- **Create repository wrappers** for clean separation between data access and business logic
- **Use Suites** to automatically mock repository dependencies in your service tests

## Next Steps

- **[Solitary Unit Tests](/docs/guides/solitary)**: Deep dive into testing in isolation
- **[Test Doubles](/docs/guides/test-doubles)**: Understand mocks and stubs in depth
60 changes: 60 additions & 0 deletions docs/recipes/mocking-orm/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
---
sidebar_position: 8
title: "Mocking ORMs in NestJS Unit Tests: TypeORM, Prisma, Drizzle, MikroORM"
description: Mock TypeORM repositories, Prisma client, Drizzle, and MikroORM EntityManager in NestJS unit tests using Suites. Step-by-step patterns with TypeScript examples.
keywords: [mock typeorm, mock prisma, mock drizzle, mock mikroorm, nestjs unit test, mock database, typescript testing, suites]
---

# Mocking ORMs in NestJS Unit Tests

> **What this covers:** Mocking ORM libraries (TypeORM, Prisma, Drizzle, MikroORM) in NestJS services \
> **Time to read:** ~12 minutes \
> **Prerequisites:** [Unit Testing Fundamentals](/docs/guides/fundamentals), [Solitary Unit Tests](/docs/guides/solitary) \
> **Best for:** Testing NestJS services that interact with databases without hitting real connections

When testing NestJS services that interact with databases, you need to mock ORM clients to keep tests isolated. This guide shows you how to structure your code and write tests for popular ORMs: TypeORM, Prisma, Drizzle, and MikroORM.

## Overview

This guide covers:

1. The pattern: Wrapping ORM clients in injectables
2. [TypeORM](/docs/recipes/mocking-orm/typeorm): Mocking repositories and entity managers
3. [Prisma](/docs/recipes/mocking-orm/prisma): Mocking Prisma client instances
4. [Drizzle](/docs/recipes/mocking-orm/drizzle): Mocking Drizzle database instances
5. [MikroORM](/docs/recipes/mocking-orm/mikroorm): Mocking entity managers and repositories

## The Pattern: Wrap ORM Clients with Injectables

ORMs typically provide clients or managers that you import directly. To make them mockable with Suites, wrap them in injectable classes that your business logic depends on.

**Why wrap ORM clients?**

- **Explicit dependencies**: Suites can only mock dependencies passed through constructors
- **Type safety**: Full TypeScript support for mocked methods
- **Testability**: Easy to replace with mocks in tests
- **Abstraction**: Business logic doesn't depend on specific ORM implementation details

## ORM-Specific Guides

Each ORM has its own guide with detailed examples:

- **[TypeORM](/docs/recipes/mocking-orm/typeorm)** - Mocking TypeORM repositories and EntityManager
- **[Prisma](/docs/recipes/mocking-orm/prisma)** - Mocking Prisma client instances
- **[Drizzle](/docs/recipes/mocking-orm/drizzle)** - Mocking Drizzle database instances
- **[MikroORM](/docs/recipes/mocking-orm/mikroorm)** - Mocking MikroORM EntityManager and repositories

## Summary

- **Wrap ORM clients** in injectables to make them mockable
- **Create repository classes** that encapsulate ORM-specific logic
- **Use Suites** to automatically mock repository dependencies
- **Keep repositories focused** on data access, not business logic
- **Type everything** for full TypeScript support
- **Test error scenarios** in addition to happy paths

## Next Steps

- **[Solitary Unit Tests](/docs/guides/solitary)**: Learn more about testing in isolation
- **[Sociable Unit Tests](/docs/guides/sociable)**: Test multiple components together
- **[Test Doubles](/docs/guides/test-doubles)**: Understand mocks and stubs in depth
Loading