nestjs-testing-utils 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +173 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,2 +1,174 @@
|
|
|
1
1
|
# nestjs-testing-utils
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
A lightweight utility package for NestJS providing a generic **mock in-memory repository** and **validation pipes** to simplify both unit testing and production use.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install nestjs-testing-utils
|
|
11
|
+
# or
|
|
12
|
+
yarn add nestjs-testing-utils
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## What's Included
|
|
18
|
+
|
|
19
|
+
| Export | Description |
|
|
20
|
+
|---|---|
|
|
21
|
+
| `BaseMockRepository<T>` | Generic in-memory repository implementing `IRepository<T>` |
|
|
22
|
+
| `Validator<T>` | NestJS pipe that validates a full request body against a reference object |
|
|
23
|
+
| `UpdateValidator<T>` | NestJS pipe that validates partial update request bodies |
|
|
24
|
+
| `IRepository<T>` | TypeScript interface for repository abstraction |
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
### `IRepository<T>` — Repository Interface
|
|
31
|
+
|
|
32
|
+
Use this interface to type your repositories in services, keeping them decoupled from the underlying data source (TypeORM, mock, etc).
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
import { type IRepository } from 'nestjs-testing-utils';
|
|
36
|
+
import { Order } from './entities/order.entity';
|
|
37
|
+
|
|
38
|
+
@Injectable()
|
|
39
|
+
export class OrdersService {
|
|
40
|
+
constructor(
|
|
41
|
+
@Inject('OrderRepository')
|
|
42
|
+
private readonly orderRepo: IRepository<Order>,
|
|
43
|
+
) {}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
### `BaseMockRepository<T>` — In-Memory Mock Repository
|
|
50
|
+
|
|
51
|
+
Extend `BaseMockRepository` to create a mock repository backed by an in-memory array. Useful for unit tests or in-memory/mock database modules.
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import { BaseMockRepository } from 'nestjs-testing-utils';
|
|
55
|
+
import { Order } from './entities/order.entity';
|
|
56
|
+
import { mockOrders } from '../mockDatas/orders.stub';
|
|
57
|
+
|
|
58
|
+
export class OrderMockRepository extends BaseMockRepository<Order> {
|
|
59
|
+
constructor() {
|
|
60
|
+
super(Promise.resolve(mockOrders));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Optionally override methods for custom behaviour
|
|
64
|
+
async create(entity: Order): Promise<Order | null> {
|
|
65
|
+
return super.create({ ...entity, time: new Date() });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
You can also implement `IRepository<T>` on your production TypeORM repository to keep the same interface:
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import { IRepository } from 'nestjs-testing-utils';
|
|
74
|
+
import { Repository } from 'typeorm';
|
|
75
|
+
|
|
76
|
+
export class BaseTypeormRepository<T extends { id: string }>
|
|
77
|
+
implements IRepository<T>
|
|
78
|
+
{
|
|
79
|
+
constructor(protected readonly repo: Repository<T>) {}
|
|
80
|
+
// ... implement methods
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
### Using in NestJS Unit Tests
|
|
87
|
+
|
|
88
|
+
`IRepository<T>` makes it easy to mock repositories in `@nestjs/testing`:
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
import { IRepository } from 'nestjs-testing-utils';
|
|
92
|
+
import { Order } from './entities/order.entity';
|
|
93
|
+
|
|
94
|
+
describe('OrdersService', () => {
|
|
95
|
+
let orderRepo: IRepository<Order>;
|
|
96
|
+
|
|
97
|
+
beforeEach(async () => {
|
|
98
|
+
const module = await Test.createTestingModule({
|
|
99
|
+
providers: [
|
|
100
|
+
OrdersService,
|
|
101
|
+
{
|
|
102
|
+
provide: 'OrderRepository',
|
|
103
|
+
useValue: {
|
|
104
|
+
create: jest.fn(),
|
|
105
|
+
update: jest.fn(),
|
|
106
|
+
findBy: jest.fn(),
|
|
107
|
+
findOneBy: jest.fn(),
|
|
108
|
+
deleteBy: jest.fn(),
|
|
109
|
+
isExists: jest.fn(),
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
}).compile();
|
|
114
|
+
|
|
115
|
+
orderRepo = module.get<IRepository<Order>>('OrderRepository');
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
### `Validator<T>` — Full Body Validation Pipe
|
|
123
|
+
|
|
124
|
+
Validates that an incoming request body matches the full structure and types of a reference object. Throws `BadRequestException` if any field is missing or has the wrong type.
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
import { Validator } from 'nestjs-testing-utils';
|
|
128
|
+
|
|
129
|
+
const referenceOrder = { username: '', productId: '', quantity: 0 };
|
|
130
|
+
|
|
131
|
+
@Post()
|
|
132
|
+
create(@Body(new Validator(referenceOrder)) body: CreateOrderDto) {
|
|
133
|
+
return this.ordersService.create(body);
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
### `UpdateValidator<T>` — Partial Update Validation Pipe
|
|
140
|
+
|
|
141
|
+
Validates partial update bodies — only validates fields that are present in the request.
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
import { UpdateValidator } from 'nestjs-testing-utils';
|
|
145
|
+
|
|
146
|
+
const referenceOrder = { username: '', productId: '', quantity: 0 };
|
|
147
|
+
|
|
148
|
+
@Patch(':id')
|
|
149
|
+
update(@Body(new UpdateValidator(referenceOrder)) body: Partial<CreateOrderDto>) {
|
|
150
|
+
return this.ordersService.update(body);
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## `IRepository<T>` Interface
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
export interface IRepository<T> {
|
|
160
|
+
create(entity: Partial<T>): Promise<T | null>;
|
|
161
|
+
findBy(where?: Partial<T>, isOr?: boolean): Promise<T[]>;
|
|
162
|
+
isExists(where: Partial<T>, isOr?: boolean): Promise<boolean>;
|
|
163
|
+
findOneBy(where: Partial<T>, isOr?: boolean): Promise<T | null>;
|
|
164
|
+
update(entity: Partial<T> & { id: string }): Promise<T | null>;
|
|
165
|
+
deleteBy(where: Partial<T>, isOr?: boolean): Promise<void>;
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## License
|
|
172
|
+
|
|
173
|
+
ISC
|
|
174
|
+
|