@oalacea/daemon 0.6.4 → 0.7.0

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.
Files changed (285) hide show
  1. package/README.md +268 -58
  2. package/bin/Dockerfile +158 -16
  3. package/dist/cli/cli.d.ts.map +1 -1
  4. package/dist/cli/cli.js +22 -2
  5. package/dist/cli/cli.js.map +1 -1
  6. package/dist/cli/commands/command.types.d.ts +216 -0
  7. package/dist/cli/commands/command.types.d.ts.map +1 -0
  8. package/dist/cli/commands/command.types.js +64 -0
  9. package/dist/cli/commands/command.types.js.map +1 -0
  10. package/dist/cli/commands/history.command.d.ts +91 -0
  11. package/dist/cli/commands/history.command.d.ts.map +1 -0
  12. package/dist/cli/commands/history.command.js +336 -0
  13. package/dist/cli/commands/history.command.js.map +1 -0
  14. package/dist/cli/commands/index.d.ts +14 -3
  15. package/dist/cli/commands/index.d.ts.map +1 -1
  16. package/dist/cli/commands/index.js +7 -0
  17. package/dist/cli/commands/index.js.map +1 -1
  18. package/dist/cli/commands/optimize.command.d.ts +110 -0
  19. package/dist/cli/commands/optimize.command.d.ts.map +1 -0
  20. package/dist/cli/commands/optimize.command.js +497 -0
  21. package/dist/cli/commands/optimize.command.js.map +1 -0
  22. package/dist/cli/commands/report.command.d.ts +110 -0
  23. package/dist/cli/commands/report.command.d.ts.map +1 -0
  24. package/dist/cli/commands/report.command.js +532 -0
  25. package/dist/cli/commands/report.command.js.map +1 -0
  26. package/dist/cli/commands/review.command.d.ts +110 -0
  27. package/dist/cli/commands/review.command.d.ts.map +1 -0
  28. package/dist/cli/commands/review.command.js +520 -0
  29. package/dist/cli/commands/review.command.js.map +1 -0
  30. package/dist/cli/commands/score.command.d.ts +47 -0
  31. package/dist/cli/commands/score.command.d.ts.map +1 -0
  32. package/dist/cli/commands/score.command.js +261 -0
  33. package/dist/cli/commands/score.command.js.map +1 -0
  34. package/dist/cli/utils/index.d.ts +10 -0
  35. package/dist/cli/utils/index.d.ts.map +1 -0
  36. package/dist/cli/utils/index.js +10 -0
  37. package/dist/cli/utils/index.js.map +1 -0
  38. package/dist/cli/utils/output.d.ts +192 -0
  39. package/dist/cli/utils/output.d.ts.map +1 -0
  40. package/dist/cli/utils/output.js +411 -0
  41. package/dist/cli/utils/output.js.map +1 -0
  42. package/dist/cli/utils/progress.d.ts +204 -0
  43. package/dist/cli/utils/progress.d.ts.map +1 -0
  44. package/dist/cli/utils/progress.js +396 -0
  45. package/dist/cli/utils/progress.js.map +1 -0
  46. package/dist/core/types/index.d.ts +1 -0
  47. package/dist/core/types/index.d.ts.map +1 -1
  48. package/dist/core/types/project.types.d.ts +3 -3
  49. package/dist/core/types/project.types.d.ts.map +1 -1
  50. package/dist/core/types/scoring.types.d.ts +301 -0
  51. package/dist/core/types/scoring.types.d.ts.map +1 -0
  52. package/dist/core/types/scoring.types.js +8 -0
  53. package/dist/core/types/scoring.types.js.map +1 -0
  54. package/dist/services/detection/framework-detector.d.ts.map +1 -1
  55. package/dist/services/detection/framework-detector.js +74 -5
  56. package/dist/services/detection/framework-detector.js.map +1 -1
  57. package/dist/services/index.d.ts +12 -0
  58. package/dist/services/index.d.ts.map +1 -1
  59. package/dist/services/index.js +14 -0
  60. package/dist/services/index.js.map +1 -1
  61. package/dist/services/optimization/detectors/bug-detector.d.ts +82 -0
  62. package/dist/services/optimization/detectors/bug-detector.d.ts.map +1 -0
  63. package/dist/services/optimization/detectors/bug-detector.js +443 -0
  64. package/dist/services/optimization/detectors/bug-detector.js.map +1 -0
  65. package/dist/services/optimization/detectors/code-smell-detector.d.ts +108 -0
  66. package/dist/services/optimization/detectors/code-smell-detector.d.ts.map +1 -0
  67. package/dist/services/optimization/detectors/code-smell-detector.js +569 -0
  68. package/dist/services/optimization/detectors/code-smell-detector.js.map +1 -0
  69. package/dist/services/optimization/detectors/index.d.ts +7 -0
  70. package/dist/services/optimization/detectors/index.d.ts.map +1 -0
  71. package/dist/services/optimization/detectors/index.js +7 -0
  72. package/dist/services/optimization/detectors/index.js.map +1 -0
  73. package/dist/services/optimization/detectors/perf-detector.d.ts +80 -0
  74. package/dist/services/optimization/detectors/perf-detector.d.ts.map +1 -0
  75. package/dist/services/optimization/detectors/perf-detector.js +451 -0
  76. package/dist/services/optimization/detectors/perf-detector.js.map +1 -0
  77. package/dist/services/optimization/index.d.ts +61 -0
  78. package/dist/services/optimization/index.d.ts.map +1 -0
  79. package/dist/services/optimization/index.js +69 -0
  80. package/dist/services/optimization/index.js.map +1 -0
  81. package/dist/services/optimization/optimization.service.d.ts +65 -0
  82. package/dist/services/optimization/optimization.service.d.ts.map +1 -0
  83. package/dist/services/optimization/optimization.service.js +511 -0
  84. package/dist/services/optimization/optimization.service.js.map +1 -0
  85. package/dist/services/optimization/optimization.types.d.ts +343 -0
  86. package/dist/services/optimization/optimization.types.d.ts.map +1 -0
  87. package/dist/services/optimization/optimization.types.js +8 -0
  88. package/dist/services/optimization/optimization.types.js.map +1 -0
  89. package/dist/services/optimization/optimizers/code-optimizer.d.ts +87 -0
  90. package/dist/services/optimization/optimizers/code-optimizer.d.ts.map +1 -0
  91. package/dist/services/optimization/optimizers/code-optimizer.js +436 -0
  92. package/dist/services/optimization/optimizers/code-optimizer.js.map +1 -0
  93. package/dist/services/optimization/optimizers/index.d.ts +7 -0
  94. package/dist/services/optimization/optimizers/index.d.ts.map +1 -0
  95. package/dist/services/optimization/optimizers/index.js +7 -0
  96. package/dist/services/optimization/optimizers/index.js.map +1 -0
  97. package/dist/services/optimization/optimizers/perf-optimizer.d.ts +64 -0
  98. package/dist/services/optimization/optimizers/perf-optimizer.d.ts.map +1 -0
  99. package/dist/services/optimization/optimizers/perf-optimizer.js +330 -0
  100. package/dist/services/optimization/optimizers/perf-optimizer.js.map +1 -0
  101. package/dist/services/optimization/optimizers/refact-optimizer.d.ts +82 -0
  102. package/dist/services/optimization/optimizers/refact-optimizer.d.ts.map +1 -0
  103. package/dist/services/optimization/optimizers/refact-optimizer.js +354 -0
  104. package/dist/services/optimization/optimizers/refact-optimizer.js.map +1 -0
  105. package/dist/services/optimization/patterns/anti-patterns.d.ts +31 -0
  106. package/dist/services/optimization/patterns/anti-patterns.d.ts.map +1 -0
  107. package/dist/services/optimization/patterns/anti-patterns.js +501 -0
  108. package/dist/services/optimization/patterns/anti-patterns.js.map +1 -0
  109. package/dist/services/optimization/patterns/index.d.ts +5 -0
  110. package/dist/services/optimization/patterns/index.d.ts.map +1 -0
  111. package/dist/services/optimization/patterns/index.js +5 -0
  112. package/dist/services/optimization/patterns/index.js.map +1 -0
  113. package/dist/services/reporting/export/chart.exporter.d.ts +59 -0
  114. package/dist/services/reporting/export/chart.exporter.d.ts.map +1 -0
  115. package/dist/services/reporting/export/chart.exporter.js +350 -0
  116. package/dist/services/reporting/export/chart.exporter.js.map +1 -0
  117. package/dist/services/reporting/export/index.d.ts +9 -0
  118. package/dist/services/reporting/export/index.d.ts.map +1 -0
  119. package/dist/services/reporting/export/index.js +10 -0
  120. package/dist/services/reporting/export/index.js.map +1 -0
  121. package/dist/services/reporting/export/pdf.exporter.d.ts +133 -0
  122. package/dist/services/reporting/export/pdf.exporter.d.ts.map +1 -0
  123. package/dist/services/reporting/export/pdf.exporter.js +270 -0
  124. package/dist/services/reporting/export/pdf.exporter.js.map +1 -0
  125. package/dist/services/reporting/history.service.d.ts +93 -0
  126. package/dist/services/reporting/history.service.d.ts.map +1 -0
  127. package/dist/services/reporting/history.service.js +285 -0
  128. package/dist/services/reporting/history.service.js.map +1 -0
  129. package/dist/services/reporting/index.d.ts +15 -0
  130. package/dist/services/reporting/index.d.ts.map +1 -0
  131. package/dist/services/reporting/index.js +16 -0
  132. package/dist/services/reporting/index.js.map +1 -0
  133. package/dist/services/reporting/report.service.d.ts +102 -0
  134. package/dist/services/reporting/report.service.d.ts.map +1 -0
  135. package/dist/services/reporting/report.service.js +240 -0
  136. package/dist/services/reporting/report.service.js.map +1 -0
  137. package/dist/services/reporting/reporting.types.d.ts +329 -0
  138. package/dist/services/reporting/reporting.types.d.ts.map +1 -0
  139. package/dist/services/reporting/reporting.types.js +8 -0
  140. package/dist/services/reporting/reporting.types.js.map +1 -0
  141. package/dist/services/reporting/templates/html.template.d.ts +81 -0
  142. package/dist/services/reporting/templates/html.template.d.ts.map +1 -0
  143. package/dist/services/reporting/templates/html.template.js +741 -0
  144. package/dist/services/reporting/templates/html.template.js.map +1 -0
  145. package/dist/services/reporting/templates/json.template.d.ts +85 -0
  146. package/dist/services/reporting/templates/json.template.d.ts.map +1 -0
  147. package/dist/services/reporting/templates/json.template.js +308 -0
  148. package/dist/services/reporting/templates/json.template.js.map +1 -0
  149. package/dist/services/reporting/templates/markdown.template.d.ts +69 -0
  150. package/dist/services/reporting/templates/markdown.template.d.ts.map +1 -0
  151. package/dist/services/reporting/templates/markdown.template.js +311 -0
  152. package/dist/services/reporting/templates/markdown.template.js.map +1 -0
  153. package/dist/services/reporting/trend-analyzer.d.ts +73 -0
  154. package/dist/services/reporting/trend-analyzer.d.ts.map +1 -0
  155. package/dist/services/reporting/trend-analyzer.js +291 -0
  156. package/dist/services/reporting/trend-analyzer.js.map +1 -0
  157. package/dist/services/review/analyzers/dependency-analyzer.d.ts +87 -0
  158. package/dist/services/review/analyzers/dependency-analyzer.d.ts.map +1 -0
  159. package/dist/services/review/analyzers/dependency-analyzer.js +458 -0
  160. package/dist/services/review/analyzers/dependency-analyzer.js.map +1 -0
  161. package/dist/services/review/analyzers/index.d.ts +13 -0
  162. package/dist/services/review/analyzers/index.d.ts.map +1 -0
  163. package/dist/services/review/analyzers/index.js +13 -0
  164. package/dist/services/review/analyzers/index.js.map +1 -0
  165. package/dist/services/review/analyzers/nestjs-analyzer.d.ts +210 -0
  166. package/dist/services/review/analyzers/nestjs-analyzer.d.ts.map +1 -0
  167. package/dist/services/review/analyzers/nestjs-analyzer.js +571 -0
  168. package/dist/services/review/analyzers/nestjs-analyzer.js.map +1 -0
  169. package/dist/services/review/analyzers/performance-analyzer.d.ts +91 -0
  170. package/dist/services/review/analyzers/performance-analyzer.d.ts.map +1 -0
  171. package/dist/services/review/analyzers/performance-analyzer.js +589 -0
  172. package/dist/services/review/analyzers/performance-analyzer.js.map +1 -0
  173. package/dist/services/review/analyzers/security-analyzer.d.ts +96 -0
  174. package/dist/services/review/analyzers/security-analyzer.d.ts.map +1 -0
  175. package/dist/services/review/analyzers/security-analyzer.js +512 -0
  176. package/dist/services/review/analyzers/security-analyzer.js.map +1 -0
  177. package/dist/services/review/analyzers/static-analyzer.d.ts +90 -0
  178. package/dist/services/review/analyzers/static-analyzer.d.ts.map +1 -0
  179. package/dist/services/review/analyzers/static-analyzer.js +423 -0
  180. package/dist/services/review/analyzers/static-analyzer.js.map +1 -0
  181. package/dist/services/review/fixers/auto-fixer.d.ts +94 -0
  182. package/dist/services/review/fixers/auto-fixer.d.ts.map +1 -0
  183. package/dist/services/review/fixers/auto-fixer.js +404 -0
  184. package/dist/services/review/fixers/auto-fixer.js.map +1 -0
  185. package/dist/services/review/fixers/index.d.ts +11 -0
  186. package/dist/services/review/fixers/index.d.ts.map +1 -0
  187. package/dist/services/review/fixers/index.js +11 -0
  188. package/dist/services/review/fixers/index.js.map +1 -0
  189. package/dist/services/review/fixers/refactor-suggester.d.ts +100 -0
  190. package/dist/services/review/fixers/refactor-suggester.d.ts.map +1 -0
  191. package/dist/services/review/fixers/refactor-suggester.js +555 -0
  192. package/dist/services/review/fixers/refactor-suggester.js.map +1 -0
  193. package/dist/services/review/fixers/test-generator.d.ts +99 -0
  194. package/dist/services/review/fixers/test-generator.d.ts.map +1 -0
  195. package/dist/services/review/fixers/test-generator.js +458 -0
  196. package/dist/services/review/fixers/test-generator.js.map +1 -0
  197. package/dist/services/review/index.d.ts +14 -0
  198. package/dist/services/review/index.d.ts.map +1 -0
  199. package/dist/services/review/index.js +14 -0
  200. package/dist/services/review/index.js.map +1 -0
  201. package/dist/services/review/reporters/fix-reporter.d.ts +67 -0
  202. package/dist/services/review/reporters/fix-reporter.d.ts.map +1 -0
  203. package/dist/services/review/reporters/fix-reporter.js +437 -0
  204. package/dist/services/review/reporters/fix-reporter.js.map +1 -0
  205. package/dist/services/review/reporters/index.d.ts +10 -0
  206. package/dist/services/review/reporters/index.d.ts.map +1 -0
  207. package/dist/services/review/reporters/index.js +10 -0
  208. package/dist/services/review/reporters/index.js.map +1 -0
  209. package/dist/services/review/reporters/score-reporter.d.ts +84 -0
  210. package/dist/services/review/reporters/score-reporter.d.ts.map +1 -0
  211. package/dist/services/review/reporters/score-reporter.js +560 -0
  212. package/dist/services/review/reporters/score-reporter.js.map +1 -0
  213. package/dist/services/review/review.service.d.ts +129 -0
  214. package/dist/services/review/review.service.d.ts.map +1 -0
  215. package/dist/services/review/review.service.js +396 -0
  216. package/dist/services/review/review.service.js.map +1 -0
  217. package/dist/services/review/review.types.d.ts +443 -0
  218. package/dist/services/review/review.types.d.ts.map +1 -0
  219. package/dist/services/review/review.types.js +11 -0
  220. package/dist/services/review/review.types.js.map +1 -0
  221. package/dist/services/scoring/dimensions/accessibility.analyzer.d.ts +53 -0
  222. package/dist/services/scoring/dimensions/accessibility.analyzer.d.ts.map +1 -0
  223. package/dist/services/scoring/dimensions/accessibility.analyzer.js +260 -0
  224. package/dist/services/scoring/dimensions/accessibility.analyzer.js.map +1 -0
  225. package/dist/services/scoring/dimensions/backend-logic.analyzer.d.ts +138 -0
  226. package/dist/services/scoring/dimensions/backend-logic.analyzer.d.ts.map +1 -0
  227. package/dist/services/scoring/dimensions/backend-logic.analyzer.js +713 -0
  228. package/dist/services/scoring/dimensions/backend-logic.analyzer.js.map +1 -0
  229. package/dist/services/scoring/dimensions/business-logic.analyzer.d.ts +142 -0
  230. package/dist/services/scoring/dimensions/business-logic.analyzer.d.ts.map +1 -0
  231. package/dist/services/scoring/dimensions/business-logic.analyzer.js +747 -0
  232. package/dist/services/scoring/dimensions/business-logic.analyzer.js.map +1 -0
  233. package/dist/services/scoring/dimensions/code-quality.analyzer.d.ts +142 -0
  234. package/dist/services/scoring/dimensions/code-quality.analyzer.d.ts.map +1 -0
  235. package/dist/services/scoring/dimensions/code-quality.analyzer.js +685 -0
  236. package/dist/services/scoring/dimensions/code-quality.analyzer.js.map +1 -0
  237. package/dist/services/scoring/dimensions/index.d.ts +18 -0
  238. package/dist/services/scoring/dimensions/index.d.ts.map +1 -0
  239. package/dist/services/scoring/dimensions/index.js +27 -0
  240. package/dist/services/scoring/dimensions/index.js.map +1 -0
  241. package/dist/services/scoring/dimensions/performance.analyzer.d.ts +125 -0
  242. package/dist/services/scoring/dimensions/performance.analyzer.d.ts.map +1 -0
  243. package/dist/services/scoring/dimensions/performance.analyzer.js +615 -0
  244. package/dist/services/scoring/dimensions/performance.analyzer.js.map +1 -0
  245. package/dist/services/scoring/dimensions/security.analyzer.d.ts +53 -0
  246. package/dist/services/scoring/dimensions/security.analyzer.d.ts.map +1 -0
  247. package/dist/services/scoring/dimensions/security.analyzer.js +327 -0
  248. package/dist/services/scoring/dimensions/security.analyzer.js.map +1 -0
  249. package/dist/services/scoring/dimensions/seo.analyzer.d.ts +77 -0
  250. package/dist/services/scoring/dimensions/seo.analyzer.d.ts.map +1 -0
  251. package/dist/services/scoring/dimensions/seo.analyzer.js +502 -0
  252. package/dist/services/scoring/dimensions/seo.analyzer.js.map +1 -0
  253. package/dist/services/scoring/dimensions/test-coverage.analyzer.d.ts +106 -0
  254. package/dist/services/scoring/dimensions/test-coverage.analyzer.d.ts.map +1 -0
  255. package/dist/services/scoring/dimensions/test-coverage.analyzer.js +496 -0
  256. package/dist/services/scoring/dimensions/test-coverage.analyzer.js.map +1 -0
  257. package/dist/services/scoring/dimensions/ui-ux.analyzer.d.ts +126 -0
  258. package/dist/services/scoring/dimensions/ui-ux.analyzer.d.ts.map +1 -0
  259. package/dist/services/scoring/dimensions/ui-ux.analyzer.js +665 -0
  260. package/dist/services/scoring/dimensions/ui-ux.analyzer.js.map +1 -0
  261. package/dist/services/scoring/index.d.ts +10 -0
  262. package/dist/services/scoring/index.d.ts.map +1 -0
  263. package/dist/services/scoring/index.js +10 -0
  264. package/dist/services/scoring/index.js.map +1 -0
  265. package/dist/services/scoring/scoring-service.d.ts +222 -0
  266. package/dist/services/scoring/scoring-service.d.ts.map +1 -0
  267. package/dist/services/scoring/scoring-service.js +636 -0
  268. package/dist/services/scoring/scoring-service.js.map +1 -0
  269. package/package.json +11 -3
  270. package/templates/README.md +183 -0
  271. package/templates/nestjs/controller.spec.ts +203 -0
  272. package/templates/nestjs/e2e/api.e2e-spec.ts +451 -0
  273. package/templates/nestjs/e2e/auth.e2e-spec.ts +533 -0
  274. package/templates/nestjs/fixtures/test-module.ts +311 -0
  275. package/templates/nestjs/guard.spec.ts +314 -0
  276. package/templates/nestjs/interceptor.spec.ts +458 -0
  277. package/templates/nestjs/module.spec.ts +173 -0
  278. package/templates/nestjs/pipe.spec.ts +474 -0
  279. package/templates/nestjs/service.spec.ts +296 -0
  280. package/templates/rust/Cargo.toml +72 -0
  281. package/templates/rust/actix-controller.test.rs +114 -0
  282. package/templates/rust/axum-handler.test.rs +117 -0
  283. package/templates/rust/integration.test.rs +63 -0
  284. package/templates/rust/rocket-route.test.rs +106 -0
  285. package/templates/rust/unit.test.rs +38 -0
@@ -0,0 +1,311 @@
1
+ /**
2
+ * NestJS Test Module Fixture
3
+ *
4
+ * Reusable test module configuration for unit testing.
5
+ * Provides common providers, mocks, and utilities.
6
+ *
7
+ * @package test
8
+ */
9
+
10
+ import { Test, TestingModule } from '@nestjs/testing';
11
+ import { INestApplication, ValidationPipe } from '@nestjs/common';
12
+ import { JwtService } from '@nestjs/jwt';
13
+ import { getRepositoryToken } from '@nestjs/typeorm';
14
+ import { Repository } from 'typeorm';
15
+ import { ConfigModule } from '@nestjs/config';
16
+ import { PassportModule } from '@nestjs/passport';
17
+ import { JwtModule } from '@nestjs/jwt';
18
+
19
+ // Mock repositories
20
+ export const mockRepository = () => ({
21
+ find: jest.fn(),
22
+ findOne: jest.fn(),
23
+ findOneBy: jest.fn(),
24
+ create: jest.fn(),
25
+ save: jest.fn(),
26
+ update: jest.fn(),
27
+ delete: jest.fn(),
28
+ count: jest.fn(),
29
+ query: jest.fn(),
30
+ });
31
+
32
+ // Mock JwtService
33
+ export const mockJwtService = () => ({
34
+ sign: jest.fn(),
35
+ verify: jest.fn(),
36
+ verifyAsync: jest.fn(),
37
+ decode: jest.fn(),
38
+ });
39
+
40
+ // Mock ConfigService
41
+ export const mockConfigService = () => ({
42
+ get: jest.fn((key: string) => {
43
+ const config: Record<string, any> = {
44
+ JWT_SECRET: 'test-secret',
45
+ JWT_EXPIRES_IN: '1h',
46
+ DATABASE_URL: 'sqlite::memory:',
47
+ };
48
+ return config[key];
49
+ }),
50
+ });
51
+
52
+ /**
53
+ * Create a test module with common configuration
54
+ */
55
+ export async function createTestModule(options: {
56
+ imports?: any[];
57
+ providers?: any[];
58
+ controllers?: any[];
59
+ }) {
60
+ const moduleFixture: TestingModule = await Test.createTestingModule({
61
+ imports: [
62
+ ConfigModule.forRoot({ isGlobal: true }),
63
+ PassportModule.register({ defaultStrategy: 'jwt' }),
64
+ JwtModule.register({
65
+ secret: 'test-secret',
66
+ signOptions: { expiresIn: '1h' },
67
+ }),
68
+ ...(options.imports ?? []),
69
+ ],
70
+ providers: options.providers ?? [],
71
+ controllers: options.controllers ?? [],
72
+ })
73
+ .overrideProvider(JwtService)
74
+ .useValue(mockJwtService())
75
+ .compile();
76
+
77
+ return moduleFixture;
78
+ }
79
+
80
+ /**
81
+ * Create a test application with global configuration
82
+ */
83
+ export async function createTestApplication(module: TestingModule): Promise<INestApplication> {
84
+ const app = module.createNestApplication();
85
+
86
+ // Apply global validation pipe
87
+ app.useGlobalPipes(
88
+ new ValidationPipe({
89
+ whitelist: true,
90
+ transform: true,
91
+ forbidNonWhitelisted: true,
92
+ transformOptions: {
93
+ enableImplicitConversion: true,
94
+ },
95
+ })
96
+ );
97
+
98
+ // Enable shutdown hooks
99
+ app.enableShutdownHooks();
100
+
101
+ await app.init();
102
+
103
+ return app;
104
+ }
105
+
106
+ /**
107
+ * Mock user for authentication tests
108
+ */
109
+ export const mockUser = {
110
+ id: '1',
111
+ email: 'test@example.com',
112
+ name: 'Test User',
113
+ roles: ['user'],
114
+ createdAt: new Date(),
115
+ updatedAt: new Date(),
116
+ };
117
+
118
+ /**
119
+ * Mock admin user for role tests
120
+ */
121
+ export const mockAdmin = {
122
+ id: '2',
123
+ email: 'admin@example.com',
124
+ name: 'Admin User',
125
+ roles: ['admin'],
126
+ createdAt: new Date(),
127
+ updatedAt: new Date(),
128
+ };
129
+
130
+ /**
131
+ * Create mock ExecutionContext
132
+ */
133
+ export function createMockExecutionContext(request: any = {}) {
134
+ return {
135
+ switchToHttp: () => ({
136
+ getRequest: () => ({
137
+ method: 'GET',
138
+ url: '/',
139
+ headers: {},
140
+ user: null,
141
+ ...request,
142
+ }),
143
+ getResponse: () => ({
144
+ statusCode: 200,
145
+ }),
146
+ }),
147
+ getHandler: () => ({}),
148
+ getClass: () => ({}),
149
+ getArgByIndex: () => ({}),
150
+ getArgs: () => [],
151
+ getType: () => 'http',
152
+ };
153
+ }
154
+
155
+ /**
156
+ * Create mock CallHandler
157
+ */
158
+ export function createMockCallHandler(value: any = { data: 'test' }) {
159
+ return {
160
+ handle: () => of(value),
161
+ };
162
+ }
163
+
164
+ /**
165
+ * Helper to create test entity
166
+ */
167
+ export function createTestEntity(overrides: Partial<any> = {}) {
168
+ return {
169
+ id: '1',
170
+ createdAt: new Date(),
171
+ updatedAt: new Date(),
172
+ ...overrides,
173
+ };
174
+ }
175
+
176
+ /**
177
+ * Wait for async operations
178
+ */
179
+ export function delay(ms: number): Promise<void> {
180
+ return new Promise((resolve) => setTimeout(resolve, ms));
181
+ }
182
+
183
+ /**
184
+ * Create test database connection options
185
+ */
186
+ export function createTestDatabaseOptions() {
187
+ return {
188
+ type: 'sqlite',
189
+ database: ':memory:',
190
+ dropSchema: true,
191
+ synchronize: true,
192
+ logging: false,
193
+ };
194
+ }
195
+
196
+ /**
197
+ * Setup test database
198
+ */
199
+ export async function setupTestDatabase(entities: any[]) {
200
+ const { DataSource } = require('typeorm');
201
+
202
+ const dataSource = new DataSource({
203
+ type: 'sqlite',
204
+ database: ':memory:',
205
+ entities,
206
+ synchronize: true,
207
+ logging: false,
208
+ });
209
+
210
+ await dataSource.initialize();
211
+
212
+ return dataSource;
213
+ }
214
+
215
+ /**
216
+ * Clean test database
217
+ */
218
+ export async function cleanTestDatabase(dataSource: any) {
219
+ const entities = dataSource.entityMetadatas;
220
+ const repositoryNames = entities.map((e: any) => e.name);
221
+
222
+ // Clear all tables
223
+ for (const name of repositoryNames) {
224
+ const repository = dataSource.getRepository(name);
225
+ await repository.clear();
226
+ }
227
+ }
228
+
229
+ /**
230
+ * Mock file upload for testing
231
+ */
232
+ export function createMockFile(overrides: Partial<Express.Multer.File> = {}) {
233
+ return {
234
+ fieldname: 'file',
235
+ originalname: 'test.jpg',
236
+ encoding: '7bit',
237
+ mimetype: 'image/jpeg',
238
+ size: 1024,
239
+ buffer: Buffer.from('test'),
240
+ destination: '/tmp',
241
+ filename: 'test.jpg',
242
+ path: '/tmp/test.jpg',
243
+ stream: null,
244
+ ...overrides,
245
+ };
246
+ }
247
+
248
+ /**
249
+ * Create test DTO with validation
250
+ */
251
+ export function createTestDto<T>(dto: Class<T>, data: Partial<T>): T {
252
+ return Object.assign(Object.create(dto.prototype), data);
253
+ }
254
+
255
+ /**
256
+ * Type for class reference
257
+ */
258
+ type Class<T> = new (...args: any[]) => T;
259
+
260
+ /**
261
+ * Mock pagination options
262
+ */
263
+ export function createMockPaginationOptions(overrides: any = {}) {
264
+ return {
265
+ page: 1,
266
+ limit: 10,
267
+ sortBy: 'createdAt',
268
+ sortOrder: 'DESC' as const,
269
+ ...overrides,
270
+ };
271
+ }
272
+
273
+ /**
274
+ * Mock filtered query options
275
+ */
276
+ export function createMockFilterOptions(overrides: any = {}) {
277
+ return {
278
+ search: '',
279
+ status: null,
280
+ dateFrom: null,
281
+ dateTo: null,
282
+ ...overrides,
283
+ };
284
+ }
285
+
286
+ /**
287
+ * Export all test utilities
288
+ */
289
+ export const testUtils = {
290
+ createTestModule,
291
+ createTestApplication,
292
+ createMockExecutionContext,
293
+ createMockCallHandler,
294
+ createTestEntity,
295
+ delay,
296
+ createTestDatabaseOptions,
297
+ setupTestDatabase,
298
+ cleanTestDatabase,
299
+ createMockFile,
300
+ createTestDto,
301
+ createMockPaginationOptions,
302
+ createMockFilterOptions,
303
+ mockRepository,
304
+ mockJwtService,
305
+ mockConfigService,
306
+ mockUser,
307
+ mockAdmin,
308
+ };
309
+
310
+ // Import RxJS 'of' for observable creation
311
+ import { of } from 'rxjs';
@@ -0,0 +1,314 @@
1
+ /**
2
+ * NestJS Guard Test Template
3
+ *
4
+ * Tests for NestJS guards following best practices:
5
+ * - Authentication logic
6
+ * - Authorization checks
7
+ * - Role/permission validation
8
+ * - Context handling
9
+ *
10
+ * @package test
11
+ */
12
+
13
+ import { ExecutionContext, ForbiddenException } from '@nestjs/common';
14
+ import { Reflector } from '@nestjs/core';
15
+ import { AuthGuard } from './auth.guard';
16
+ import { RolesGuard } from './roles.guard';
17
+ import { JwtAuthGuard } from './jwt-auth.guard';
18
+
19
+ describe('AuthGuard', () => {
20
+ let guard: AuthGuard;
21
+ let reflector: Reflector;
22
+
23
+ beforeEach(() => {
24
+ reflector = new Reflector();
25
+ guard = new AuthGuard(reflector);
26
+ });
27
+
28
+ describe('canActivate', () => {
29
+ it('should allow access with valid token', () => {
30
+ const context = createMockExecutionContext({
31
+ headers: {
32
+ authorization: 'Bearer valid-token',
33
+ },
34
+ });
35
+
36
+ jest.spyOn(guard, 'validateToken').mockResolvedValue(true);
37
+
38
+ const result = guard.canActivate(context);
39
+
40
+ expect(result).resolves.toBe(true);
41
+ });
42
+
43
+ it('should deny access without token', () => {
44
+ const context = createMockExecutionContext({
45
+ headers: {},
46
+ });
47
+
48
+ const result = guard.canActivate(context);
49
+
50
+ expect(result).resolves.toBe(false);
51
+ });
52
+
53
+ it('should deny access with invalid token', () => {
54
+ const context = createMockExecutionContext({
55
+ headers: {
56
+ authorization: 'Bearer invalid-token',
57
+ },
58
+ });
59
+
60
+ jest.spyOn(guard, 'validateToken').mockResolvedValue(false);
61
+
62
+ const result = guard.canActivate(context);
63
+
64
+ expect(result).resolves.toBe(false);
65
+ });
66
+
67
+ it('should handle malformed authorization header', () => {
68
+ const context = createMockExecutionContext({
69
+ headers: {
70
+ authorization: 'InvalidFormat token',
71
+ },
72
+ });
73
+
74
+ const result = guard.canActivate(context);
75
+
76
+ expect(result).resolves.toBe(false);
77
+ });
78
+
79
+ it('should extract user from request and attach to context', async () => {
80
+ const context = createMockExecutionContext({
81
+ headers: {
82
+ authorization: 'Bearer valid-token',
83
+ },
84
+ });
85
+
86
+ const mockUser = { id: '1', username: 'test' };
87
+ jest.spyOn(guard, 'getUserFromToken').mockResolvedValue(mockUser);
88
+
89
+ await guard.canActivate(context);
90
+
91
+ const request = context.switchToHttp().getRequest();
92
+ expect(request.user).toEqual(mockUser);
93
+ });
94
+ });
95
+
96
+ describe('public routes', () => {
97
+ it('should allow access to public routes', () => {
98
+ const context = createMockExecutionContext({
99
+ headers: {},
100
+ });
101
+
102
+ jest.spyOn(reflector, 'get').mockReturnValue(true);
103
+
104
+ const result = guard.canActivate(context);
105
+
106
+ expect(result).resolves.toBe(true);
107
+ expect(reflector.get).toHaveBeenCalledWith('isPublic', expect.any());
108
+ });
109
+
110
+ it('should check for isPublic decorator on handler', () => {
111
+ const context = createMockExecutionContext();
112
+
113
+ jest.spyOn(reflector, 'get').mockReturnValue(true);
114
+
115
+ guard.canActivate(context);
116
+
117
+ expect(reflector.get).toHaveBeenCalledWith(
118
+ 'isPublic',
119
+ context.getHandler()
120
+ );
121
+ });
122
+ });
123
+ });
124
+
125
+ describe('RolesGuard', () => {
126
+ let guard: RolesGuard;
127
+ let reflector: Reflector;
128
+
129
+ beforeEach(() => {
130
+ reflector = new Reflector();
131
+ guard = new RolesGuard(reflector);
132
+ });
133
+
134
+ describe('canActivate', () => {
135
+ it('should allow access when user has required role', () => {
136
+ const context = createMockExecutionContext({
137
+ user: { roles: ['admin'] },
138
+ });
139
+
140
+ jest.spyOn(reflector, 'get').mockReturnValue(['admin']);
141
+
142
+ const result = guard.canActivate(context);
143
+
144
+ expect(result).resolves.toBe(true);
145
+ });
146
+
147
+ it('should deny access when user lacks required role', () => {
148
+ const context = createMockExecutionContext({
149
+ user: { roles: ['user'] },
150
+ });
151
+
152
+ jest.spyOn(reflector, 'get').mockReturnValue(['admin']);
153
+
154
+ const result = guard.canActivate(context);
155
+
156
+ expect(result).resolves.toBe(false);
157
+ });
158
+
159
+ it('should allow access when no roles are required', () => {
160
+ const context = createMockExecutionContext({
161
+ user: { roles: ['user'] },
162
+ });
163
+
164
+ jest.spyOn(reflector, 'get').mockReturnValue(null);
165
+
166
+ const result = guard.canActivate(context);
167
+
168
+ expect(result).resolves.toBe(true);
169
+ });
170
+
171
+ it('should allow access when user has multiple roles including required', () => {
172
+ const context = createMockExecutionContext({
173
+ user: { roles: ['user', 'moderator', 'admin'] },
174
+ });
175
+
176
+ jest.spyOn(reflector, 'get').mockReturnValue(['admin', 'moderator']);
177
+
178
+ const result = guard.canActivate(context);
179
+
180
+ expect(result).resolves.toBe(true);
181
+ });
182
+
183
+ it('should handle user without roles property', () => {
184
+ const context = createMockExecutionContext({
185
+ user: {},
186
+ });
187
+
188
+ jest.spyOn(reflector, 'get').mockReturnValue(['user']);
189
+
190
+ const result = guard.canActivate(context);
191
+
192
+ expect(result).resolves.toBe(false);
193
+ });
194
+
195
+ it('should handle missing user in request', () => {
196
+ const context = createMockExecutionContext({
197
+ user: null,
198
+ });
199
+
200
+ jest.spyOn(reflector, 'get').mockReturnValue(['admin']);
201
+
202
+ const result = guard.canActivate(context);
203
+
204
+ expect(result).resolves.toBe(false);
205
+ });
206
+ });
207
+
208
+ describe('role hierarchy', () => {
209
+ it('should respect role hierarchy', () => {
210
+ const context = createMockExecutionContext({
211
+ user: { roles: ['super-admin'] },
212
+ });
213
+
214
+ jest.spyOn(reflector, 'get').mockReturnValue(['admin']);
215
+ jest.spyOn(guard, 'hasHigherRole').mockReturnValue(true);
216
+
217
+ const result = guard.canActivate(context);
218
+
219
+ expect(result).resolves.toBe(true);
220
+ });
221
+ });
222
+ });
223
+
224
+ describe('JwtAuthGuard', () => {
225
+ let guard: JwtAuthGuard;
226
+ let jwtService: any;
227
+
228
+ beforeEach(() => {
229
+ jwtService = {
230
+ verifyAsync: jest.fn(),
231
+ };
232
+ guard = new JwtAuthGuard(jwtService);
233
+ });
234
+
235
+ describe('canActivate', () => {
236
+ it('should validate JWT token', async () => {
237
+ const context = createMockExecutionContext({
238
+ headers: {
239
+ authorization: 'Bearer valid.jwt.token',
240
+ },
241
+ });
242
+
243
+ const payload = { sub: '1', username: 'test' };
244
+ jest.spyOn(jwtService, 'verifyAsync').mockResolvedValue(payload);
245
+
246
+ const result = await guard.canActivate(context);
247
+
248
+ expect(result).toBe(true);
249
+ expect(jwtService.verifyAsync).toHaveBeenCalledWith('valid.jwt.token');
250
+ });
251
+
252
+ it('should attach user payload to request', async () => {
253
+ const context = createMockExecutionContext({
254
+ headers: {
255
+ authorization: 'Bearer valid.jwt.token',
256
+ },
257
+ });
258
+
259
+ const payload = { sub: '1', username: 'test' };
260
+ jest.spyOn(jwtService, 'verifyAsync').mockResolvedValue(payload);
261
+
262
+ await guard.canActivate(context);
263
+
264
+ const request = context.switchToHttp().getRequest();
265
+ expect(request.user).toEqual(payload);
266
+ });
267
+
268
+ it('should throw UnauthorizedException for invalid token', async () => {
269
+ const context = createMockExecutionContext({
270
+ headers: {
271
+ authorization: 'Bearer invalid.token',
272
+ },
273
+ });
274
+
275
+ jest.spyOn(jwtService, 'verifyAsync').mockRejectedValue(
276
+ new Error('Invalid token')
277
+ );
278
+
279
+ await expect(guard.canActivate(context)).rejects.toThrow();
280
+ });
281
+
282
+ it('should handle expired tokens', async () => {
283
+ const context = createMockExecutionContext({
284
+ headers: {
285
+ authorization: 'Bearer expired.token',
286
+ },
287
+ });
288
+
289
+ jest.spyOn(jwtService, 'verifyAsync').mockRejectedValue(
290
+ new Error('Token expired')
291
+ );
292
+
293
+ await expect(guard.canActivate(context)).rejects.toThrow();
294
+ });
295
+ });
296
+ });
297
+
298
+ // Helper function to create mock ExecutionContext
299
+ function createMockExecutionContext(requestData: any = {}): ExecutionContext {
300
+ return {
301
+ switchToHttp: () => ({
302
+ getRequest: () => ({
303
+ headers: requestData.headers || {},
304
+ user: requestData.user,
305
+ ...requestData,
306
+ }),
307
+ }),
308
+ getHandler: () => ({}),
309
+ getClass: () => ({}),
310
+ getArgByIndex: () => ({}),
311
+ getArgs: () => [],
312
+ getType: () => 'http',
313
+ } as unknown as ExecutionContext;
314
+ }