@hed-hog/category 0.0.366 → 0.0.370

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hed-hog/category",
3
- "version": "0.0.366",
3
+ "version": "0.0.370",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "dependencies": {
@@ -9,11 +9,11 @@
9
9
  "@nestjs/core": "^11",
10
10
  "@nestjs/jwt": "^11",
11
11
  "@nestjs/mapped-types": "*",
12
+ "@hed-hog/core": "0.0.370",
12
13
  "@hed-hog/api-locale": "0.0.14",
13
- "@hed-hog/api-prisma": "0.0.6",
14
+ "@hed-hog/api-pagination": "0.0.7",
14
15
  "@hed-hog/api": "0.0.8",
15
- "@hed-hog/core": "0.0.366",
16
- "@hed-hog/api-pagination": "0.0.7"
16
+ "@hed-hog/api-prisma": "0.0.6"
17
17
  },
18
18
  "exports": {
19
19
  ".": {
@@ -29,6 +29,7 @@
29
29
  ],
30
30
  "scripts": {
31
31
  "lint": "eslint \"{src,apps,libs,test}/**/*.ts\"",
32
+ "test": "jest --config jest.config.ts --runInBand",
32
33
  "prebuild": "pnpm --dir ../.. exec ts-node ./scripts/build-dependencies.ts libraries/category",
33
34
  "build": "tsc --project tsconfig.production.json",
34
35
  "patch": "npx ts-node ../../scripts/patch.ts libraries/category",
@@ -0,0 +1,259 @@
1
+ jest.mock('@hed-hog/api', () => ({
2
+ itemTranslations: jest.fn((_key: string, item: any) => item),
3
+ }));
4
+ jest.mock('@hed-hog/api-locale', () => ({
5
+ getLocaleText: jest.fn((_key: string, _locale: string, fallback: string) => fallback ?? 'Error'),
6
+ LocaleService: class {},
7
+ }));
8
+
9
+ import { BadRequestException, NotFoundException } from '@nestjs/common';
10
+ import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';
11
+ import { CategoryService } from './category.service';
12
+
13
+ const makeLocaleService = (overrides: Partial<Record<string, jest.Mock>> = {}) => ({
14
+ getByCode: jest.fn().mockResolvedValue({ id: 1, code: 'en' }),
15
+ ...overrides,
16
+ });
17
+
18
+ describe('CategoryService', () => {
19
+ let prisma: any;
20
+ let pagination: any;
21
+ let localeService: any;
22
+ let service: CategoryService;
23
+
24
+ beforeEach(() => {
25
+ prisma = {
26
+ category: {
27
+ count: jest.fn().mockResolvedValue(0),
28
+ findUnique: jest.fn(),
29
+ findMany: jest.fn().mockResolvedValue([]),
30
+ create: jest.fn(),
31
+ update: jest.fn(),
32
+ delete: jest.fn(),
33
+ },
34
+ category_locale: {
35
+ findFirst: jest.fn(),
36
+ create: jest.fn().mockResolvedValue({}),
37
+ update: jest.fn().mockResolvedValue({}),
38
+ },
39
+ createInsensitiveSearch: jest.fn().mockReturnValue([]),
40
+ };
41
+
42
+ pagination = {
43
+ paginate: jest.fn().mockResolvedValue({ data: [], total: 0 }),
44
+ };
45
+
46
+ localeService = makeLocaleService();
47
+ service = new CategoryService(prisma as any, pagination as any, localeService as any);
48
+ });
49
+
50
+ afterEach(() => {
51
+ jest.clearAllMocks();
52
+ });
53
+
54
+ describe('getStats', () => {
55
+ it('retorna total, totalActive, totalInactive, totalRoot', async () => {
56
+ prisma.category.count
57
+ .mockResolvedValueOnce(20)
58
+ .mockResolvedValueOnce(15)
59
+ .mockResolvedValueOnce(5)
60
+ .mockResolvedValueOnce(8);
61
+
62
+ const result = await service.getStats();
63
+
64
+ expect(result).toEqual({ total: 20, totalActive: 15, totalInactive: 5, totalRoot: 8 });
65
+ });
66
+ });
67
+
68
+ describe('getById', () => {
69
+ it('retorna categoria quando encontrada', async () => {
70
+ prisma.category.findUnique.mockResolvedValue({
71
+ id: 1,
72
+ slug: 'tech',
73
+ category_locale: [],
74
+ });
75
+
76
+ const result = await service.getById('en', 1);
77
+
78
+ expect(result).toMatchObject({ id: 1, slug: 'tech' });
79
+ });
80
+
81
+ it('lança NotFoundException quando categoria não existe', async () => {
82
+ prisma.category.findUnique.mockResolvedValue(null);
83
+
84
+ await expect(service.getById('en', 999)).rejects.toThrow(NotFoundException);
85
+ });
86
+ });
87
+
88
+ describe('getRootCategories', () => {
89
+ it('lança BadRequestException quando locale não existe', async () => {
90
+ localeService.getByCode.mockResolvedValue(null);
91
+
92
+ await expect(service.getRootCategories('xx')).rejects.toThrow(BadRequestException);
93
+ });
94
+
95
+ it('retorna categorias raiz mapeadas', async () => {
96
+ prisma.category.findMany.mockResolvedValue([
97
+ { id: 1, slug: 'tech', category_locale: [] },
98
+ { id: 2, slug: 'news', category_locale: [] },
99
+ ]);
100
+
101
+ const result = await service.getRootCategories('en');
102
+
103
+ expect(result).toHaveLength(2);
104
+ });
105
+ });
106
+
107
+ describe('getByParent', () => {
108
+ it('lança BadRequestException quando locale não existe', async () => {
109
+ localeService.getByCode.mockResolvedValue(null);
110
+
111
+ await expect(service.getByParent('1', 'xx')).rejects.toThrow(BadRequestException);
112
+ });
113
+
114
+ it('lança NotFoundException quando não há filhos', async () => {
115
+ prisma.category.findMany.mockResolvedValue([]);
116
+
117
+ await expect(service.getByParent('1', 'en')).rejects.toThrow(NotFoundException);
118
+ });
119
+
120
+ it('retorna categorias filhas mapeadas', async () => {
121
+ prisma.category.findMany.mockResolvedValue([
122
+ { id: 3, slug: 'phones', category_locale: [] },
123
+ ]);
124
+
125
+ const result = await service.getByParent('1', 'en');
126
+
127
+ expect(result).toHaveLength(1);
128
+ });
129
+ });
130
+
131
+ describe('delete', () => {
132
+ it('lança NotFoundException quando categoria não existe', async () => {
133
+ prisma.category.findUnique.mockResolvedValue(null);
134
+
135
+ await expect(service.delete(999, 'en')).rejects.toThrow(NotFoundException);
136
+ });
137
+
138
+ it('deleta categoria quando encontrada', async () => {
139
+ prisma.category.findUnique.mockResolvedValue({ id: 1, slug: 'tech' });
140
+ prisma.category.delete.mockResolvedValue({ id: 1 });
141
+
142
+ const result = await service.delete(1, 'en');
143
+
144
+ expect(prisma.category.delete).toHaveBeenCalledWith({ where: { id: 1 } });
145
+ expect(result).toMatchObject({ id: 1 });
146
+ });
147
+ });
148
+
149
+ describe('create', () => {
150
+ it('lança BadRequestException quando locale está vazio', async () => {
151
+ await expect(
152
+ service.create('en', { slug: 'test', locale: {} } as any),
153
+ ).rejects.toThrow(BadRequestException);
154
+ });
155
+
156
+ it('lança BadRequestException quando categoria pai não existe', async () => {
157
+ prisma.category.findUnique.mockResolvedValue(null);
158
+
159
+ await expect(
160
+ service.create('en', {
161
+ slug: 'test',
162
+ category_id: 999,
163
+ locale: { en: { name: 'Test' } },
164
+ } as any),
165
+ ).rejects.toThrow(BadRequestException);
166
+ });
167
+
168
+ it('lança BadRequestException quando locale código não existe', async () => {
169
+ prisma.category.findUnique.mockResolvedValue(null);
170
+ prisma.category.create.mockResolvedValue({ id: 1, slug: 'test' });
171
+ localeService.getByCode.mockResolvedValue(null);
172
+
173
+ await expect(
174
+ service.create('en', { slug: 'test', locale: { xx: { name: 'Test' } } } as any),
175
+ ).rejects.toThrow(BadRequestException);
176
+ });
177
+
178
+ it('cria categoria e entradas de locale', async () => {
179
+ prisma.category.create.mockResolvedValue({ id: 1, slug: 'test' });
180
+
181
+ const result = await service.create('en', {
182
+ slug: 'test',
183
+ locale: { en: { name: 'Test' } },
184
+ } as any);
185
+
186
+ expect(prisma.category.create).toHaveBeenCalledWith(
187
+ expect.objectContaining({ data: expect.objectContaining({ slug: 'test' }) }),
188
+ );
189
+ expect(prisma.category_locale.create).toHaveBeenCalled();
190
+ expect(result).toMatchObject({ id: 1 });
191
+ });
192
+ });
193
+
194
+ describe('update', () => {
195
+ it('lança NotFoundException quando categoria não existe', async () => {
196
+ prisma.category.findUnique.mockResolvedValue(null);
197
+
198
+ await expect(service.update('en', 999, { slug: 'x' } as any)).rejects.toThrow(
199
+ NotFoundException,
200
+ );
201
+ });
202
+
203
+ it('lança BadRequestException quando categoria pai não existe', async () => {
204
+ prisma.category.findUnique
205
+ .mockResolvedValueOnce({ id: 1, slug: 'test' })
206
+ .mockResolvedValueOnce(null);
207
+
208
+ await expect(
209
+ service.update('en', 1, { category_id: 999 } as any),
210
+ ).rejects.toThrow(BadRequestException);
211
+ });
212
+
213
+ it('atualiza categoria e retorna resultado via getById', async () => {
214
+ prisma.category.findUnique
215
+ .mockResolvedValueOnce({ id: 1, slug: 'old' })
216
+ .mockResolvedValueOnce({ id: 1, slug: 'new', category_locale: [] });
217
+ prisma.category.update.mockResolvedValue({ id: 1 });
218
+
219
+ const result = await service.update('en', 1, { slug: 'new' } as any);
220
+
221
+ expect(prisma.category.update).toHaveBeenCalledWith(
222
+ expect.objectContaining({ where: { id: 1 } }),
223
+ );
224
+ expect(result).toMatchObject({ id: 1 });
225
+ });
226
+
227
+ it('atualiza entrada de locale existente', async () => {
228
+ prisma.category.findUnique
229
+ .mockResolvedValueOnce({ id: 1, slug: 'test' })
230
+ .mockResolvedValueOnce({ id: 1, slug: 'test', category_locale: [] });
231
+ prisma.category.update.mockResolvedValue({ id: 1 });
232
+ prisma.category_locale.findFirst.mockResolvedValue({ id: 5 });
233
+
234
+ await service.update('en', 1, {
235
+ slug: 'test',
236
+ locale: { en: { name: 'Updated' } },
237
+ } as any);
238
+
239
+ expect(prisma.category_locale.update).toHaveBeenCalledWith(
240
+ expect.objectContaining({ where: { id: 5 }, data: { name: 'Updated' } }),
241
+ );
242
+ });
243
+
244
+ it('cria nova entrada de locale quando não existe', async () => {
245
+ prisma.category.findUnique
246
+ .mockResolvedValueOnce({ id: 1, slug: 'test' })
247
+ .mockResolvedValueOnce({ id: 1, slug: 'test', category_locale: [] });
248
+ prisma.category.update.mockResolvedValue({ id: 1 });
249
+ prisma.category_locale.findFirst.mockResolvedValue(null);
250
+
251
+ await service.update('en', 1, {
252
+ slug: 'test',
253
+ locale: { en: { name: 'New Locale' } },
254
+ } as any);
255
+
256
+ expect(prisma.category_locale.create).toHaveBeenCalled();
257
+ });
258
+ });
259
+ });