@nest-util/nest-crud 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 +2 -4
- package/dist/lib/testing/crud-controller.test-suites.d.ts +4 -0
- package/dist/lib/testing/crud-controller.test-suites.d.ts.map +1 -0
- package/dist/lib/testing/crud-controller.test-suites.js +165 -0
- package/dist/lib/testing/crud-service.test-suites.d.ts +4 -0
- package/dist/lib/testing/crud-service.test-suites.d.ts.map +1 -0
- package/dist/lib/testing/crud-service.test-suites.js +279 -0
- package/dist/lib/testing/index.d.ts +5 -0
- package/dist/lib/testing/index.d.ts.map +1 -0
- package/dist/lib/testing/index.js +7 -0
- package/dist/lib/testing/mock-repository.d.ts +7 -0
- package/dist/lib/testing/mock-repository.d.ts.map +1 -0
- package/dist/lib/testing/mock-repository.js +97 -0
- package/dist/lib/testing/testing.interface.d.ts +52 -0
- package/dist/lib/testing/testing.interface.d.ts.map +1 -0
- package/dist/lib/testing/testing.interface.js +2 -0
- package/package.json +8 -1
package/README.md
CHANGED
|
@@ -4,14 +4,12 @@ This library was generated with [Nx](https://nx.dev).
|
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
We recommend using **pnpm** as your package manager.
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
pnpm add
|
|
10
|
+
pnpm add @nest-util/nest-crud@^1.0.1 @nest-util/nest-auth@^1.0.1 typeorm@^1.1.0 @nestjs/typeorm @nestjs/swagger @nestjs/jwt @nestjs/passport class-validator class-transformer bcrypt
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
> **Tip:** This tarball contains only the compiled code and its specific dependencies, making it as clean as a standard npm package.
|
|
14
|
-
|
|
15
13
|
## Features
|
|
16
14
|
|
|
17
15
|
- Generic CRUD service with filtering, pagination, and sorting
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { ObjectLiteral } from 'typeorm';
|
|
2
|
+
import { CrudControllerTestConfig, CrudTestContext } from './testing.interface';
|
|
3
|
+
export declare function crudControllerTests<TEntity extends ObjectLiteral, TCreateDto, TUpdateDto, TResponseDto>(config: CrudControllerTestConfig<TEntity, TCreateDto, TUpdateDto, TResponseDto>): CrudTestContext;
|
|
4
|
+
//# sourceMappingURL=crud-controller.test-suites.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crud-controller.test-suites.d.ts","sourceRoot":"","sources":["../../../src/lib/testing/crud-controller.test-suites.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAMxC,OAAO,EAAE,wBAAwB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAGhF,wBAAgB,mBAAmB,CACjC,OAAO,SAAS,aAAa,EAC7B,UAAU,EACV,UAAU,EACV,YAAY,EAEZ,MAAM,EAAE,wBAAwB,CAAC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,CAAC,GAC9E,eAAe,CAoNjB"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.crudControllerTests = crudControllerTests;
|
|
4
|
+
const testing_1 = require("@nestjs/testing");
|
|
5
|
+
const common_1 = require("@nestjs/common");
|
|
6
|
+
const nest_crud_controller_1 = require("../controllers/nest-crud.controller");
|
|
7
|
+
const mock_repository_1 = require("./mock-repository");
|
|
8
|
+
function crudControllerTests(config) {
|
|
9
|
+
let controller;
|
|
10
|
+
let service;
|
|
11
|
+
let ControllerBase;
|
|
12
|
+
let moduleRef;
|
|
13
|
+
beforeEach(async () => {
|
|
14
|
+
service = {
|
|
15
|
+
disabledEndpoints: [],
|
|
16
|
+
findAll: jest.fn(),
|
|
17
|
+
findOne: jest.fn(),
|
|
18
|
+
create: jest.fn(),
|
|
19
|
+
update: jest.fn(),
|
|
20
|
+
remove: jest.fn(),
|
|
21
|
+
findAuditLogs: jest.fn(),
|
|
22
|
+
findMine: jest.fn(),
|
|
23
|
+
};
|
|
24
|
+
ControllerBase = config.controllerFactory();
|
|
25
|
+
class TestController extends ControllerBase {
|
|
26
|
+
constructor() {
|
|
27
|
+
super(service);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
moduleRef = await testing_1.Test.createTestingModule({
|
|
31
|
+
controllers: [TestController],
|
|
32
|
+
}).compile();
|
|
33
|
+
controller = moduleRef.get(TestController);
|
|
34
|
+
});
|
|
35
|
+
describe('findAll', () => {
|
|
36
|
+
it('should call service.findAll with query params', async () => {
|
|
37
|
+
const query = { page: 1, limit: 10 };
|
|
38
|
+
const expected = { data: [], meta: { total: 0 } };
|
|
39
|
+
service.findAll.mockResolvedValue(expected);
|
|
40
|
+
const result = await controller.findAll(query);
|
|
41
|
+
expect(service.findAll).toHaveBeenCalledWith(query);
|
|
42
|
+
expect(result).toEqual(expected);
|
|
43
|
+
});
|
|
44
|
+
it('should handle pagination parameters', async () => {
|
|
45
|
+
const query = { page: 5, limit: 100 };
|
|
46
|
+
service.findAll.mockResolvedValue({ data: [] });
|
|
47
|
+
await controller.findAll(query);
|
|
48
|
+
expect(service.findAll).toHaveBeenCalledWith(expect.objectContaining({ page: 5, limit: 100 }));
|
|
49
|
+
});
|
|
50
|
+
it('should handle complex filter objects', async () => {
|
|
51
|
+
const query = {
|
|
52
|
+
filter: { name_cont: 'Alice', isActive_eq: 'true' },
|
|
53
|
+
};
|
|
54
|
+
service.findAll.mockResolvedValue({ data: [] });
|
|
55
|
+
await controller.findAll(query);
|
|
56
|
+
expect(service.findAll).toHaveBeenCalledWith(expect.objectContaining({
|
|
57
|
+
filter: { name_cont: 'Alice', isActive_eq: 'true' },
|
|
58
|
+
}));
|
|
59
|
+
});
|
|
60
|
+
it('should work with no query parameters', async () => {
|
|
61
|
+
service.findAll.mockResolvedValue({ data: [] });
|
|
62
|
+
await controller.findAll({});
|
|
63
|
+
expect(service.findAll).toHaveBeenCalledWith({});
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
describe('findOne', () => {
|
|
67
|
+
it('should call service.findOne with correct id', async () => {
|
|
68
|
+
const expectedResult = { id: 1, name: 'Test' };
|
|
69
|
+
service.findOne.mockResolvedValue(expectedResult);
|
|
70
|
+
const result = await controller.findOne(1);
|
|
71
|
+
expect(service.findOne).toHaveBeenCalledWith(1);
|
|
72
|
+
expect(result).toEqual(expectedResult);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
describe('create', () => {
|
|
76
|
+
it('should call service.create with dto', async () => {
|
|
77
|
+
const dto = config.test.createPayload;
|
|
78
|
+
const expectedResult = { id: 1 };
|
|
79
|
+
service.create.mockResolvedValue(expectedResult);
|
|
80
|
+
const result = await controller.create(dto);
|
|
81
|
+
expect(service.create).toHaveBeenCalledWith(dto);
|
|
82
|
+
expect(result).toEqual(expectedResult);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
describe('update', () => {
|
|
86
|
+
it('should call service.update with id and dto', async () => {
|
|
87
|
+
const dto = config.test.updatePayload;
|
|
88
|
+
const expectedResult = { id: 1 };
|
|
89
|
+
service.update.mockResolvedValue(expectedResult);
|
|
90
|
+
const result = await controller.update(1, dto);
|
|
91
|
+
expect(service.update).toHaveBeenCalledWith(1, dto);
|
|
92
|
+
expect(result).toEqual(expectedResult);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
describe('remove', () => {
|
|
96
|
+
it('should call service.remove', async () => {
|
|
97
|
+
service.remove.mockResolvedValue(true);
|
|
98
|
+
const result = await controller.remove(1);
|
|
99
|
+
expect(service.remove).toHaveBeenCalledWith(1);
|
|
100
|
+
expect(result).toBe(true);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
describe('findMine', () => {
|
|
104
|
+
it('should call service.findMine with user id', async () => {
|
|
105
|
+
const query = { page: 1, limit: 10 };
|
|
106
|
+
const expected = { data: [] };
|
|
107
|
+
service.findMine.mockResolvedValue(expected);
|
|
108
|
+
const mockUser = { id: 42 };
|
|
109
|
+
const result = await controller.findMine(mockUser, query);
|
|
110
|
+
expect(service.findMine).toHaveBeenCalledWith(42, query);
|
|
111
|
+
expect(result).toEqual(expected);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
describe('disabledEndpoints', () => {
|
|
115
|
+
it('should block disabled endpoints', async () => {
|
|
116
|
+
service.disabledEndpoints = ['create'];
|
|
117
|
+
expect(() => controller.create({})).toThrow(common_1.NotFoundException);
|
|
118
|
+
expect(service.create).not.toHaveBeenCalled();
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
describe('findAuditLogs', () => {
|
|
122
|
+
it('should call service.findAuditLogs with query params', async () => {
|
|
123
|
+
const query = { page: 1, limit: 5, user_id: '1' };
|
|
124
|
+
const expected = { data: [], meta: { total: 0, page: 1, limit: 5 } };
|
|
125
|
+
service.findAuditLogs.mockResolvedValue(expected);
|
|
126
|
+
const result = await controller.findAuditLogs?.(query);
|
|
127
|
+
expect(service.findAuditLogs).toHaveBeenCalledWith(query);
|
|
128
|
+
expect(result).toEqual(expected);
|
|
129
|
+
});
|
|
130
|
+
it('should throw when audit logs endpoint is not available', () => {
|
|
131
|
+
service.findAuditLogs = undefined;
|
|
132
|
+
expect(() => controller.findAuditLogs?.({})).toThrow(common_1.NotFoundException);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
describe('permissions', () => {
|
|
136
|
+
it('should attach auth permission metadata to configured handlers', () => {
|
|
137
|
+
if (!config.permissions)
|
|
138
|
+
return;
|
|
139
|
+
const PermissionedBase = config.controllerFactory();
|
|
140
|
+
class PermissionedCtrl extends PermissionedBase {
|
|
141
|
+
constructor() {
|
|
142
|
+
super(service);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
for (const [endpoint, permission] of Object.entries(config.permissions)) {
|
|
146
|
+
const method = PermissionedCtrl.prototype[endpoint];
|
|
147
|
+
if (!method)
|
|
148
|
+
continue;
|
|
149
|
+
const metadata = Reflect.getMetadata(nest_crud_controller_1.AUTH_PERMISSIONS_METADATA_KEY, method);
|
|
150
|
+
const expected = Array.isArray(permission)
|
|
151
|
+
? permission
|
|
152
|
+
: [permission];
|
|
153
|
+
expect(metadata).toEqual(expected);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
const ctx = {
|
|
158
|
+
get module() {
|
|
159
|
+
return moduleRef;
|
|
160
|
+
},
|
|
161
|
+
repository: null,
|
|
162
|
+
createMockQb: mock_repository_1.createMockQb,
|
|
163
|
+
};
|
|
164
|
+
return ctx;
|
|
165
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { ObjectLiteral } from 'typeorm';
|
|
2
|
+
import { CrudTestConfig, CrudTestContext } from './testing.interface';
|
|
3
|
+
export declare function crudServiceTests<TEntity extends ObjectLiteral, TCreateDto, TUpdateDto, TResponseDto>(config: CrudTestConfig<TEntity, TCreateDto, TUpdateDto, TResponseDto>): CrudTestContext;
|
|
4
|
+
//# sourceMappingURL=crud-service.test-suites.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crud-service.test-suites.d.ts","sourceRoot":"","sources":["../../../src/lib/testing/crud-service.test-suites.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAExC,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAGtE,wBAAgB,gBAAgB,CAC9B,OAAO,SAAS,aAAa,EAC7B,UAAU,EACV,UAAU,EACV,YAAY,EACZ,MAAM,EAAE,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,CAAC,GAAG,eAAe,CAqVxF"}
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.crudServiceTests = crudServiceTests;
|
|
4
|
+
const testing_1 = require("@nestjs/testing");
|
|
5
|
+
const common_1 = require("@nestjs/common");
|
|
6
|
+
const typeorm_1 = require("@nestjs/typeorm");
|
|
7
|
+
const nest_crud_service_1 = require("../services/nest-crud.service");
|
|
8
|
+
const mock_repository_1 = require("./mock-repository");
|
|
9
|
+
function crudServiceTests(config) {
|
|
10
|
+
let service;
|
|
11
|
+
let repository;
|
|
12
|
+
let moduleRef;
|
|
13
|
+
let lastQb;
|
|
14
|
+
beforeEach(async () => {
|
|
15
|
+
repository = (0, mock_repository_1.createMockRepository)(config.entity, config.test.mockRepoOverrides);
|
|
16
|
+
const serviceOptions = {
|
|
17
|
+
repository,
|
|
18
|
+
allowedFilters: config.allowedFilters ?? [],
|
|
19
|
+
allowedSortFields: config.allowedSortFields ?? [],
|
|
20
|
+
include: config.include ?? [],
|
|
21
|
+
relations: config.relations ?? [],
|
|
22
|
+
toResponseDto: config.toResponseDto,
|
|
23
|
+
disabledEndpoints: config.disabledEndpoints ?? [],
|
|
24
|
+
hooks: config.hooks,
|
|
25
|
+
userOwnershipField: config.userOwnershipField,
|
|
26
|
+
findMineQuery: config.findMineQuery,
|
|
27
|
+
};
|
|
28
|
+
service = new nest_crud_service_1.NestCrudService(serviceOptions);
|
|
29
|
+
moduleRef = await testing_1.Test.createTestingModule({
|
|
30
|
+
providers: [
|
|
31
|
+
{ provide: config.serviceClass, useValue: service },
|
|
32
|
+
{ provide: (0, typeorm_1.getRepositoryToken)(config.entity), useValue: repository },
|
|
33
|
+
],
|
|
34
|
+
}).compile();
|
|
35
|
+
});
|
|
36
|
+
describe('findAll', () => {
|
|
37
|
+
it('should return paginated data and meta', async () => {
|
|
38
|
+
lastQb = (0, mock_repository_1.createMockQb)();
|
|
39
|
+
const mockEntity = createMockEntity(config);
|
|
40
|
+
lastQb.getManyAndCount.mockResolvedValue([[mockEntity], 1]);
|
|
41
|
+
repository.createQueryBuilder.mockReturnValue(lastQb);
|
|
42
|
+
const result = await service.findAll({ page: 1, limit: 10 });
|
|
43
|
+
expect(repository.createQueryBuilder).toHaveBeenCalledWith('e');
|
|
44
|
+
expect(lastQb.getManyAndCount).toHaveBeenCalled();
|
|
45
|
+
expect(result).toHaveProperty('data');
|
|
46
|
+
expect(result).toHaveProperty('meta');
|
|
47
|
+
});
|
|
48
|
+
it('should apply filters via andWhen allowedFilters is configured', async () => {
|
|
49
|
+
if (!config.allowedFilters || config.allowedFilters.length === 0)
|
|
50
|
+
return;
|
|
51
|
+
lastQb = (0, mock_repository_1.createMockQb)();
|
|
52
|
+
lastQb.getManyAndCount.mockResolvedValue([[], 0]);
|
|
53
|
+
repository.createQueryBuilder.mockReturnValue(lastQb);
|
|
54
|
+
const filterKey = config.allowedFilters[0];
|
|
55
|
+
await service.findAll({
|
|
56
|
+
page: 1,
|
|
57
|
+
limit: 10,
|
|
58
|
+
filter: { [`${String(filterKey)}_cont`]: 'test' },
|
|
59
|
+
});
|
|
60
|
+
expect(lastQb.andWhere).toHaveBeenCalled();
|
|
61
|
+
});
|
|
62
|
+
it('should join include relations via leftJoinAndSelect', async () => {
|
|
63
|
+
if (!config.include || config.include.length === 0)
|
|
64
|
+
return;
|
|
65
|
+
lastQb = (0, mock_repository_1.createMockQb)();
|
|
66
|
+
lastQb.getManyAndCount.mockResolvedValue([[], 0]);
|
|
67
|
+
repository.createQueryBuilder.mockReturnValue(lastQb);
|
|
68
|
+
await service.findAll({ page: 1, limit: 10 });
|
|
69
|
+
expect(lastQb.leftJoinAndSelect).toHaveBeenCalled();
|
|
70
|
+
});
|
|
71
|
+
it('should apply orderBy when specified', async () => {
|
|
72
|
+
lastQb = (0, mock_repository_1.createMockQb)();
|
|
73
|
+
lastQb.getManyAndCount.mockResolvedValue([[], 0]);
|
|
74
|
+
repository.createQueryBuilder.mockReturnValue(lastQb);
|
|
75
|
+
await service.findAll({
|
|
76
|
+
page: 1,
|
|
77
|
+
limit: 10,
|
|
78
|
+
orderBy: 'id',
|
|
79
|
+
orderDirection: 'ASC',
|
|
80
|
+
});
|
|
81
|
+
expect(lastQb.orderBy).toHaveBeenCalledWith('e.id', 'ASC');
|
|
82
|
+
});
|
|
83
|
+
it('should default orderBy to DESC', async () => {
|
|
84
|
+
lastQb = (0, mock_repository_1.createMockQb)();
|
|
85
|
+
lastQb.getManyAndCount.mockResolvedValue([[], 0]);
|
|
86
|
+
repository.createQueryBuilder.mockReturnValue(lastQb);
|
|
87
|
+
await service.findAll({
|
|
88
|
+
page: 1,
|
|
89
|
+
limit: 10,
|
|
90
|
+
orderBy: 'id',
|
|
91
|
+
});
|
|
92
|
+
expect(lastQb.orderBy).toHaveBeenCalledWith('e.id', 'DESC');
|
|
93
|
+
});
|
|
94
|
+
it('should return empty data when no results', async () => {
|
|
95
|
+
lastQb = (0, mock_repository_1.createMockQb)();
|
|
96
|
+
lastQb.getManyAndCount.mockResolvedValue([[], 0]);
|
|
97
|
+
repository.createQueryBuilder.mockReturnValue(lastQb);
|
|
98
|
+
const result = await service.findAll({ page: 1, limit: 10 });
|
|
99
|
+
expect(result).toHaveProperty('data');
|
|
100
|
+
expect(result.data).toEqual([]);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
describe('findOne', () => {
|
|
104
|
+
it('should return the entity', async () => {
|
|
105
|
+
const mockEntity = createMockEntity(config);
|
|
106
|
+
repository.findOne.mockResolvedValue(mockEntity);
|
|
107
|
+
const result = await service.findOne(1);
|
|
108
|
+
expect(repository.findOne).toHaveBeenCalledWith({
|
|
109
|
+
where: { id: 1 },
|
|
110
|
+
relations: config.include ?? [],
|
|
111
|
+
});
|
|
112
|
+
expect(result).toBeDefined();
|
|
113
|
+
});
|
|
114
|
+
it('should throw NotFoundException when not found', async () => {
|
|
115
|
+
repository.findOne.mockResolvedValue(null);
|
|
116
|
+
await expect(service.findOne(999)).rejects.toThrow(common_1.NotFoundException);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
describe('create', () => {
|
|
120
|
+
it('should save and return the entity', async () => {
|
|
121
|
+
const mockEntity = createMockEntity(config);
|
|
122
|
+
repository.save.mockResolvedValue(mockEntity);
|
|
123
|
+
const result = await service.create(config.test.createPayload);
|
|
124
|
+
expect(repository.save).toHaveBeenCalled();
|
|
125
|
+
expect(result).toBeDefined();
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
describe('update', () => {
|
|
129
|
+
it('should merge, save, and return the updated entity', async () => {
|
|
130
|
+
const mockEntity = createMockEntity(config);
|
|
131
|
+
repository.findOneBy.mockResolvedValue(mockEntity);
|
|
132
|
+
repository.save.mockResolvedValue(mockEntity);
|
|
133
|
+
repository.findOne.mockResolvedValue(mockEntity);
|
|
134
|
+
const result = await service.update(1, config.test.updatePayload);
|
|
135
|
+
expect(repository.findOneBy).toHaveBeenCalled();
|
|
136
|
+
expect(repository.merge).toHaveBeenCalled();
|
|
137
|
+
expect(repository.save).toHaveBeenCalled();
|
|
138
|
+
expect(result).toBeDefined();
|
|
139
|
+
});
|
|
140
|
+
it('should throw NotFoundException when entity not found', async () => {
|
|
141
|
+
repository.findOneBy.mockResolvedValue(null);
|
|
142
|
+
await expect(service.update(999, config.test.updatePayload)).rejects.toThrow(common_1.NotFoundException);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
describe('remove', () => {
|
|
146
|
+
it('should delete and return true', async () => {
|
|
147
|
+
const mockEntity = createMockEntity(config);
|
|
148
|
+
repository.findOneBy.mockResolvedValue(mockEntity);
|
|
149
|
+
repository.delete.mockResolvedValue({ affected: 1 });
|
|
150
|
+
const result = await service.remove(1);
|
|
151
|
+
expect(repository.findOneBy).toHaveBeenCalled();
|
|
152
|
+
expect(repository.delete).toHaveBeenCalledWith(1);
|
|
153
|
+
expect(result).toBe(true);
|
|
154
|
+
});
|
|
155
|
+
it('should throw NotFoundException when not found', async () => {
|
|
156
|
+
repository.findOneBy.mockResolvedValue(null);
|
|
157
|
+
await expect(service.remove(999)).rejects.toThrow(common_1.NotFoundException);
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
describe('findMine', () => {
|
|
161
|
+
it('should filter by ownership field', async () => {
|
|
162
|
+
if (!config.userOwnershipField && !config.findMineQuery)
|
|
163
|
+
return;
|
|
164
|
+
lastQb = (0, mock_repository_1.createMockQb)();
|
|
165
|
+
const mockEntity = createMockEntity(config);
|
|
166
|
+
lastQb.getManyAndCount.mockResolvedValue([[mockEntity], 1]);
|
|
167
|
+
repository.createQueryBuilder.mockReturnValue(lastQb);
|
|
168
|
+
const result = await service.findMine(123, { page: 1, limit: 10 });
|
|
169
|
+
expect(repository.createQueryBuilder).toHaveBeenCalled();
|
|
170
|
+
expect(result).toHaveProperty('data');
|
|
171
|
+
});
|
|
172
|
+
it('should throw BadRequestException when not configured', async () => {
|
|
173
|
+
if (config.userOwnershipField || config.findMineQuery)
|
|
174
|
+
return;
|
|
175
|
+
await expect(service.findMine(123, {})).rejects.toThrow(common_1.BadRequestException);
|
|
176
|
+
});
|
|
177
|
+
it('should apply filters via andWhere', async () => {
|
|
178
|
+
if (!config.userOwnershipField && !config.findMineQuery)
|
|
179
|
+
return;
|
|
180
|
+
if (!config.allowedFilters || config.allowedFilters.length === 0)
|
|
181
|
+
return;
|
|
182
|
+
lastQb = (0, mock_repository_1.createMockQb)();
|
|
183
|
+
lastQb.getManyAndCount.mockResolvedValue([[], 0]);
|
|
184
|
+
repository.createQueryBuilder.mockReturnValue(lastQb);
|
|
185
|
+
const filterKey = config.allowedFilters[0];
|
|
186
|
+
await service.findMine(123, {
|
|
187
|
+
filter: { [`${String(filterKey)}_cont`]: 'test' },
|
|
188
|
+
});
|
|
189
|
+
expect(lastQb.andWhere).toHaveBeenCalled();
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
describe('findAllWithCursor', () => {
|
|
193
|
+
it('should return cursor-based results', async () => {
|
|
194
|
+
if (config.disabledEndpoints?.includes('findMine'))
|
|
195
|
+
return;
|
|
196
|
+
lastQb = (0, mock_repository_1.createMockQb)();
|
|
197
|
+
const mockEntity = createMockEntity(config);
|
|
198
|
+
lastQb.getMany.mockResolvedValue([mockEntity]);
|
|
199
|
+
repository.createQueryBuilder.mockReturnValue(lastQb);
|
|
200
|
+
const result = await service.findAllWithCursor({ limit: 10 });
|
|
201
|
+
expect(result).toHaveProperty('data');
|
|
202
|
+
expect(result).toHaveProperty('meta');
|
|
203
|
+
expect(result.meta).toHaveProperty('limit', 10);
|
|
204
|
+
expect(result.meta).toHaveProperty('hasMore');
|
|
205
|
+
expect(result.meta).toHaveProperty('nextCursor');
|
|
206
|
+
});
|
|
207
|
+
it('should detect hasMore when entities exceed limit', async () => {
|
|
208
|
+
lastQb = (0, mock_repository_1.createMockQb)();
|
|
209
|
+
const entities = Array.from({ length: 11 }, () => createMockEntity(config));
|
|
210
|
+
lastQb.getMany.mockResolvedValue(entities);
|
|
211
|
+
repository.createQueryBuilder.mockReturnValue(lastQb);
|
|
212
|
+
const result = await service.findAllWithCursor({ limit: 10 });
|
|
213
|
+
expect(result.meta.hasMore).toBe(true);
|
|
214
|
+
expect(result.meta.nextCursor).toBeDefined();
|
|
215
|
+
});
|
|
216
|
+
it('should set hasMore false when entities <= limit', async () => {
|
|
217
|
+
lastQb = (0, mock_repository_1.createMockQb)();
|
|
218
|
+
const mockEntity = createMockEntity(config);
|
|
219
|
+
lastQb.getMany.mockResolvedValue([mockEntity]);
|
|
220
|
+
repository.createQueryBuilder.mockReturnValue(lastQb);
|
|
221
|
+
const result = await service.findAllWithCursor({ limit: 10 });
|
|
222
|
+
expect(result.meta.hasMore).toBe(false);
|
|
223
|
+
expect(result.meta.nextCursor).toBeNull();
|
|
224
|
+
});
|
|
225
|
+
it('should include total when includeTotal is true', async () => {
|
|
226
|
+
lastQb = (0, mock_repository_1.createMockQb)();
|
|
227
|
+
const mockEntity = createMockEntity(config);
|
|
228
|
+
lastQb.getMany.mockResolvedValue([mockEntity]);
|
|
229
|
+
lastQb.getCount.mockResolvedValue(1);
|
|
230
|
+
repository.createQueryBuilder.mockReturnValue(lastQb);
|
|
231
|
+
const countQb = (0, mock_repository_1.createMockQb)();
|
|
232
|
+
countQb.getCount.mockResolvedValue(1);
|
|
233
|
+
repository.createQueryBuilder.mockReturnValueOnce(lastQb);
|
|
234
|
+
repository.createQueryBuilder.mockReturnValueOnce(countQb);
|
|
235
|
+
const result = await service.findAllWithCursor({
|
|
236
|
+
limit: 10,
|
|
237
|
+
includeTotal: true,
|
|
238
|
+
});
|
|
239
|
+
expect(result.meta).toHaveProperty('total');
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
describe('findAuditLogs', () => {
|
|
243
|
+
it('should query audit logs with pagination', async () => {
|
|
244
|
+
const auditQb = (0, mock_repository_1.createMockQb)();
|
|
245
|
+
auditQb.getManyAndCount.mockResolvedValue([[], 0]);
|
|
246
|
+
repository.manager.getRepository.mockReturnValue({
|
|
247
|
+
createQueryBuilder: jest.fn().mockReturnValue(auditQb),
|
|
248
|
+
});
|
|
249
|
+
const result = await service.findAuditLogs({ page: 1, limit: 10 });
|
|
250
|
+
expect(repository.manager.getRepository).toHaveBeenCalled();
|
|
251
|
+
expect(result).toHaveProperty('data');
|
|
252
|
+
expect(result).toHaveProperty('meta');
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
describe('disabledEndpoints', () => {
|
|
256
|
+
it('should block disabled endpoints', async () => {
|
|
257
|
+
if (!config.disabledEndpoints || config.disabledEndpoints.length === 0)
|
|
258
|
+
return;
|
|
259
|
+
const disabled = config.disabledEndpoints[0];
|
|
260
|
+
service.disabledEndpoints = config.disabledEndpoints;
|
|
261
|
+
expect(service.disabledEndpoints).toContain(disabled);
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
const ctx = {
|
|
265
|
+
get module() {
|
|
266
|
+
return moduleRef;
|
|
267
|
+
},
|
|
268
|
+
get repository() {
|
|
269
|
+
return repository;
|
|
270
|
+
},
|
|
271
|
+
createMockQb: mock_repository_1.createMockQb,
|
|
272
|
+
};
|
|
273
|
+
return ctx;
|
|
274
|
+
}
|
|
275
|
+
function createMockEntity(config) {
|
|
276
|
+
const { createDefaultMockEntity } = require('./mock-repository');
|
|
277
|
+
const defaults = createDefaultMockEntity(config.entity);
|
|
278
|
+
return { ...defaults, ...(config.test.mockEntity ?? {}) };
|
|
279
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/testing/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,+BAA+B,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
tslib_1.__exportStar(require("./testing.interface"), exports);
|
|
5
|
+
tslib_1.__exportStar(require("./mock-repository"), exports);
|
|
6
|
+
tslib_1.__exportStar(require("./crud-service.test-suites"), exports);
|
|
7
|
+
tslib_1.__exportStar(require("./crud-controller.test-suites"), exports);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Type } from '@nestjs/common';
|
|
2
|
+
import { ObjectLiteral, Repository } from 'typeorm';
|
|
3
|
+
import { MockQueryBuilder } from './testing.interface';
|
|
4
|
+
export declare function createMockQb(): MockQueryBuilder;
|
|
5
|
+
export declare function createMockRepository<TEntity extends ObjectLiteral>(entity: Type<TEntity>, overrides?: Partial<jest.Mocked<Repository<TEntity>>>): jest.Mocked<Repository<TEntity>>;
|
|
6
|
+
export declare function createDefaultMockEntity<TEntity extends ObjectLiteral>(entity: Type<TEntity>): TEntity;
|
|
7
|
+
//# sourceMappingURL=mock-repository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock-repository.d.ts","sourceRoot":"","sources":["../../../src/lib/testing/mock-repository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEvD,wBAAgB,YAAY,IAAI,gBAAgB,CAgB/C;AAED,wBAAgB,oBAAoB,CAAC,OAAO,SAAS,aAAa,EAChE,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,EACrB,SAAS,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,GACpD,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAiClC;AAED,wBAAgB,uBAAuB,CAAC,OAAO,SAAS,aAAa,EACnE,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,GACpB,OAAO,CAuCT"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createMockQb = createMockQb;
|
|
4
|
+
exports.createMockRepository = createMockRepository;
|
|
5
|
+
exports.createDefaultMockEntity = createDefaultMockEntity;
|
|
6
|
+
function createMockQb() {
|
|
7
|
+
const qb = {
|
|
8
|
+
where: jest.fn().mockReturnThis(),
|
|
9
|
+
andWhere: jest.fn().mockReturnThis(),
|
|
10
|
+
leftJoinAndSelect: jest.fn().mockReturnThis(),
|
|
11
|
+
leftJoin: jest.fn().mockReturnThis(),
|
|
12
|
+
orderBy: jest.fn().mockReturnThis(),
|
|
13
|
+
skip: jest.fn().mockReturnThis(),
|
|
14
|
+
take: jest.fn().mockReturnThis(),
|
|
15
|
+
getManyAndCount: jest.fn().mockResolvedValue([[], 0]),
|
|
16
|
+
getMany: jest.fn().mockResolvedValue([]),
|
|
17
|
+
getOne: jest.fn().mockResolvedValue(null),
|
|
18
|
+
getCount: jest.fn().mockResolvedValue(0),
|
|
19
|
+
getRawOne: jest.fn().mockResolvedValue({}),
|
|
20
|
+
};
|
|
21
|
+
return qb;
|
|
22
|
+
}
|
|
23
|
+
function createMockRepository(entity, overrides) {
|
|
24
|
+
const mockEntity = createDefaultMockEntity(entity);
|
|
25
|
+
const auditQb = createMockQb();
|
|
26
|
+
const repo = {
|
|
27
|
+
createQueryBuilder: jest.fn().mockReturnValue(createMockQb()),
|
|
28
|
+
findOne: jest.fn().mockResolvedValue(mockEntity),
|
|
29
|
+
findOneBy: jest.fn().mockResolvedValue(mockEntity),
|
|
30
|
+
merge: jest.fn((e, p) => Object.assign(e, p)),
|
|
31
|
+
save: jest.fn().mockImplementation((e) => Promise.resolve(e)),
|
|
32
|
+
delete: jest.fn().mockResolvedValue({ affected: 1 }),
|
|
33
|
+
find: jest.fn().mockResolvedValue([mockEntity]),
|
|
34
|
+
metadata: {
|
|
35
|
+
name: entity.name,
|
|
36
|
+
primaryColumns: [{ propertyPath: 'id', type: () => Number }],
|
|
37
|
+
},
|
|
38
|
+
manager: {
|
|
39
|
+
getRepository: jest.fn().mockReturnValue({
|
|
40
|
+
createQueryBuilder: jest.fn().mockReturnValue(auditQb),
|
|
41
|
+
}),
|
|
42
|
+
connection: {
|
|
43
|
+
createQueryRunner: jest.fn().mockReturnValue({
|
|
44
|
+
startTransaction: jest.fn(),
|
|
45
|
+
commitTransaction: jest.fn(),
|
|
46
|
+
rollbackTransaction: jest.fn(),
|
|
47
|
+
release: jest.fn(),
|
|
48
|
+
}),
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
...overrides,
|
|
52
|
+
};
|
|
53
|
+
return repo;
|
|
54
|
+
}
|
|
55
|
+
function createDefaultMockEntity(entity) {
|
|
56
|
+
try {
|
|
57
|
+
const { getMetadata } = require('typeorm');
|
|
58
|
+
const metadata = getMetadata(entity);
|
|
59
|
+
const instance = {};
|
|
60
|
+
for (const col of metadata.columns) {
|
|
61
|
+
const type = col.type;
|
|
62
|
+
const name = col.propertyPath;
|
|
63
|
+
if (col.isPrimary) {
|
|
64
|
+
if (type === 'uuid') {
|
|
65
|
+
instance[name] = '00000000-0000-0000-0000-000000000001';
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
instance[name] = 1;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else if (type === String || type === 'varchar' || type === 'text') {
|
|
72
|
+
instance[name] = `mock_${name}`;
|
|
73
|
+
}
|
|
74
|
+
else if (type === Number || type === 'int' || type === 'integer') {
|
|
75
|
+
instance[name] = 0;
|
|
76
|
+
}
|
|
77
|
+
else if (type === Boolean || type === 'boolean') {
|
|
78
|
+
instance[name] = true;
|
|
79
|
+
}
|
|
80
|
+
else if (type === Date ||
|
|
81
|
+
type === 'timestamp' ||
|
|
82
|
+
type === 'datetime') {
|
|
83
|
+
instance[name] = new Date('2024-01-01T00:00:00.000Z');
|
|
84
|
+
}
|
|
85
|
+
else if (type === 'json' || type === 'jsonb') {
|
|
86
|
+
instance[name] = {};
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
instance[name] = null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return instance;
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
return { id: 1 };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Type } from '@nestjs/common';
|
|
2
|
+
import { ObjectLiteral, Repository } from 'typeorm';
|
|
3
|
+
import { CrudServiceOptions } from '../services/nest-crud.service';
|
|
4
|
+
import { CrudEndpoint } from '../interfaces/crud.interface';
|
|
5
|
+
export interface CrudTestConfig<TEntity extends ObjectLiteral, TCreateDto, TUpdateDto, TResponseDto> {
|
|
6
|
+
entity: Type<TEntity>;
|
|
7
|
+
serviceClass: Type<any>;
|
|
8
|
+
createDto?: Type<TCreateDto>;
|
|
9
|
+
updateDto?: Type<TUpdateDto>;
|
|
10
|
+
responseDto?: Type<TResponseDto>;
|
|
11
|
+
allowedFilters?: readonly (keyof TEntity)[];
|
|
12
|
+
allowedSortFields?: readonly (keyof TEntity)[];
|
|
13
|
+
include?: readonly string[];
|
|
14
|
+
userOwnershipField?: keyof TEntity;
|
|
15
|
+
findMineQuery?: (qb: any, userId: string | number) => void;
|
|
16
|
+
disabledEndpoints?: readonly CrudEndpoint[];
|
|
17
|
+
hooks?: CrudServiceOptions<TEntity, TResponseDto>['hooks'];
|
|
18
|
+
toResponseDto?: (entity: TEntity | TEntity[]) => TResponseDto | TResponseDto[];
|
|
19
|
+
relations?: CrudServiceOptions<TEntity, TResponseDto>['relations'];
|
|
20
|
+
test: {
|
|
21
|
+
createPayload: Partial<TCreateDto>;
|
|
22
|
+
updatePayload: Partial<TUpdateDto>;
|
|
23
|
+
mockEntity?: Partial<TEntity>;
|
|
24
|
+
mockEntities?: TEntity[];
|
|
25
|
+
mockRepoOverrides?: Partial<jest.Mocked<Repository<TEntity>>>;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export interface CrudControllerTestConfig<TEntity extends ObjectLiteral, TCreateDto, TUpdateDto, TResponseDto> extends Omit<CrudTestConfig<TEntity, TCreateDto, TUpdateDto, TResponseDto>, 'serviceClass'> {
|
|
29
|
+
controllerFactory: () => Type<any>;
|
|
30
|
+
serviceClass: Type<any>;
|
|
31
|
+
permissions?: Record<CrudEndpoint, string | string[]>;
|
|
32
|
+
}
|
|
33
|
+
export interface CrudTestContext {
|
|
34
|
+
module: any;
|
|
35
|
+
repository: jest.Mocked<any>;
|
|
36
|
+
createMockQb: () => MockQueryBuilder;
|
|
37
|
+
}
|
|
38
|
+
export interface MockQueryBuilder {
|
|
39
|
+
where: jest.Mock;
|
|
40
|
+
andWhere: jest.Mock;
|
|
41
|
+
leftJoinAndSelect: jest.Mock;
|
|
42
|
+
leftJoin: jest.Mock;
|
|
43
|
+
orderBy: jest.Mock;
|
|
44
|
+
skip: jest.Mock;
|
|
45
|
+
take: jest.Mock;
|
|
46
|
+
getManyAndCount: jest.Mock;
|
|
47
|
+
getMany: jest.Mock;
|
|
48
|
+
getOne: jest.Mock;
|
|
49
|
+
getCount: jest.Mock;
|
|
50
|
+
getRawOne: jest.Mock;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=testing.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.interface.d.ts","sourceRoot":"","sources":["../../../src/lib/testing/testing.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAE5D,MAAM,WAAW,cAAc,CAC7B,OAAO,SAAS,aAAa,EAC7B,UAAU,EACV,UAAU,EACV,YAAY;IAEZ,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IACtB,YAAY,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;IACxB,SAAS,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IAC7B,SAAS,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IAC7B,WAAW,CAAC,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;IACjC,cAAc,CAAC,EAAE,SAAS,CAAC,MAAM,OAAO,CAAC,EAAE,CAAC;IAC5C,iBAAiB,CAAC,EAAE,SAAS,CAAC,MAAM,OAAO,CAAC,EAAE,CAAC;IAC/C,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,kBAAkB,CAAC,EAAE,MAAM,OAAO,CAAC;IACnC,aAAa,CAAC,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC;IAC3D,iBAAiB,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IAC5C,KAAK,CAAC,EAAE,kBAAkB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC;IAC3D,aAAa,CAAC,EAAE,CACd,MAAM,EAAE,OAAO,GAAG,OAAO,EAAE,KACxB,YAAY,GAAG,YAAY,EAAE,CAAC;IACnC,SAAS,CAAC,EAAE,kBAAkB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,WAAW,CAAC,CAAC;IACnE,IAAI,EAAE;QACJ,aAAa,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QACnC,aAAa,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QACnC,UAAU,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;QAC9B,YAAY,CAAC,EAAE,OAAO,EAAE,CAAC;QACzB,iBAAiB,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;KAC/D,CAAC;CACH;AAED,MAAM,WAAW,wBAAwB,CACvC,OAAO,SAAS,aAAa,EAC7B,UAAU,EACV,UAAU,EACV,YAAY,CACZ,SAAQ,IAAI,CACV,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,CAAC,EAC7D,cAAc,CACf;IACD,iBAAiB,EAAE,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC;IACnC,YAAY,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;CACvD;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,GAAG,CAAC;IACZ,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC7B,YAAY,EAAE,MAAM,gBAAgB,CAAC;CACtC;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC;IACjB,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC;IACpB,iBAAiB,EAAE,IAAI,CAAC,IAAI,CAAC;IAC7B,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC;IACpB,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC;IACnB,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC;IAChB,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC;IAChB,eAAe,EAAE,IAAI,CAAC,IAAI,CAAC;IAC3B,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC;IACnB,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC;IAClB,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC;IACpB,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC;CACtB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nest-util/nest-crud",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"module": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -11,6 +11,12 @@
|
|
|
11
11
|
"types": "./dist/index.d.ts",
|
|
12
12
|
"import": "./dist/index.js",
|
|
13
13
|
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./testing": {
|
|
16
|
+
"@nest-util/source": "./src/lib/testing/index.ts",
|
|
17
|
+
"types": "./dist/lib/testing/index.d.ts",
|
|
18
|
+
"import": "./dist/lib/testing/index.js",
|
|
19
|
+
"default": "./dist/lib/testing/index.js"
|
|
14
20
|
}
|
|
15
21
|
},
|
|
16
22
|
"files": [
|
|
@@ -18,6 +24,7 @@
|
|
|
18
24
|
"!**/*.tsbuildinfo"
|
|
19
25
|
],
|
|
20
26
|
"dependencies": {
|
|
27
|
+
"@nestjs/testing": "^11.0.0",
|
|
21
28
|
"tslib": "^2.8.1"
|
|
22
29
|
},
|
|
23
30
|
"devDependencies": {
|