@smartsoft001/pro-claude-plugins 0.2.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 (198) hide show
  1. package/.claude-plugin/marketplace.json +26 -0
  2. package/README.md +56 -0
  3. package/package.json +14 -0
  4. package/plugins/flow/.claude-plugin/README.md +91 -0
  5. package/plugins/flow/.claude-plugin/merge-permissions.js +115 -0
  6. package/plugins/flow/.claude-plugin/plugin.json +5 -0
  7. package/plugins/flow/.claude-plugin/settings.template.json +86 -0
  8. package/plugins/flow/agents/angular-component-scaffolder.md +176 -0
  9. package/plugins/flow/agents/angular-directive-builder.md +154 -0
  10. package/plugins/flow/agents/angular-guard-builder.md +244 -0
  11. package/plugins/flow/agents/angular-jest-test-writer.md +475 -0
  12. package/plugins/flow/agents/angular-pipe-builder.md +170 -0
  13. package/plugins/flow/agents/angular-resolver-builder.md +287 -0
  14. package/plugins/flow/agents/angular-service-builder.md +162 -0
  15. package/plugins/flow/agents/angular-signal-state-builder.md +340 -0
  16. package/plugins/flow/agents/angular-test-diagnostician.md +279 -0
  17. package/plugins/flow/agents/angular-testbed-configurator.md +315 -0
  18. package/plugins/flow/agents/arch-scaffolder.md +278 -0
  19. package/plugins/flow/agents/e2e-data-testid-injector.md +195 -0
  20. package/plugins/flow/agents/e2e-project-scaffolder.md +194 -0
  21. package/plugins/flow/agents/e2e-test-writer.md +357 -0
  22. package/plugins/flow/agents/shared-agent-evolver.md +294 -0
  23. package/plugins/flow/agents/shared-build-verifier.md +160 -0
  24. package/plugins/flow/agents/shared-config-updater.md +310 -0
  25. package/plugins/flow/agents/shared-coverage-enforcer.md +184 -0
  26. package/plugins/flow/agents/shared-error-handler.md +217 -0
  27. package/plugins/flow/agents/shared-file-creator.md +344 -0
  28. package/plugins/flow/agents/shared-impl-orchestrator.md +312 -0
  29. package/plugins/flow/agents/shared-impl-reporter.md +368 -0
  30. package/plugins/flow/agents/shared-impl-teammate.md +201 -0
  31. package/plugins/flow/agents/shared-linear-subtask-iterator.md +337 -0
  32. package/plugins/flow/agents/shared-logic-implementer.md +244 -0
  33. package/plugins/flow/agents/shared-maia-api.md +26 -0
  34. package/plugins/flow/agents/shared-parallelization-analyzer.md +343 -0
  35. package/plugins/flow/agents/shared-performance-validator.md +168 -0
  36. package/plugins/flow/agents/shared-plan-perspective.md +271 -0
  37. package/plugins/flow/agents/shared-project-standardizer.md +205 -0
  38. package/plugins/flow/agents/shared-report-synthesizer.md +188 -0
  39. package/plugins/flow/agents/shared-review-teammate.md +189 -0
  40. package/plugins/flow/agents/shared-security-scanner.md +186 -0
  41. package/plugins/flow/agents/shared-style-enforcer.md +230 -0
  42. package/plugins/flow/agents/shared-subtask-dependency-analyzer.md +189 -0
  43. package/plugins/flow/agents/shared-tdd-developer.md +350 -0
  44. package/plugins/flow/agents/shared-team-coordinator.md +192 -0
  45. package/plugins/flow/agents/shared-test-fixer.md +186 -0
  46. package/plugins/flow/agents/shared-test-runner.md +191 -0
  47. package/plugins/flow/agents/shared-ui-classifier.md +263 -0
  48. package/plugins/flow/agents/shared-verification-orchestrator.md +194 -0
  49. package/plugins/flow/agents/shared-verification-runner.md +140 -0
  50. package/plugins/flow/agents/ui-a11y-validator.md +305 -0
  51. package/plugins/flow/agents/ui-screenshot-reporter.md +329 -0
  52. package/plugins/flow/agents/ui-web-designer.md +214 -0
  53. package/plugins/flow/scripts/compute-session-tokens.sh +39 -0
  54. package/plugins/flow/skills/a11y-audit/SKILL.md +214 -0
  55. package/plugins/flow/skills/angular-patterns/SKILL.md +191 -0
  56. package/plugins/flow/skills/browser-capture/SKILL.md +238 -0
  57. package/plugins/flow/skills/commit/SKILL.md +259 -0
  58. package/plugins/flow/skills/debug-helper/SKILL.md +375 -0
  59. package/plugins/flow/skills/impl/SKILL.md +992 -0
  60. package/plugins/flow/skills/karpathy-guidelines/SKILL.md +72 -0
  61. package/plugins/flow/skills/linear-suggestion/SKILL.md +132 -0
  62. package/plugins/flow/skills/maia-files-delete/SKILL.md +59 -0
  63. package/plugins/flow/skills/maia-files-upload/SKILL.md +57 -0
  64. package/plugins/flow/skills/nx-conventions/SKILL.md +326 -0
  65. package/plugins/flow/skills/plan/SKILL.md +1033 -0
  66. package/plugins/flow/skills/push/SKILL.md +759 -0
  67. package/plugins/flow/skills/review/SKILL.md +443 -0
  68. package/plugins/flow/skills/test-e2e/SKILL.md +164 -0
  69. package/plugins/flow/skills/test-unit/SKILL.md +456 -0
  70. package/plugins/flow-external/.claude-plugin/README.md +146 -0
  71. package/plugins/flow-external/.claude-plugin/merge-permissions.js +94 -0
  72. package/plugins/flow-external/.claude-plugin/plugin.json +5 -0
  73. package/plugins/flow-external/.claude-plugin/settings.template.json +78 -0
  74. package/plugins/flow-external/agents/angular-component-scaffolder.md +271 -0
  75. package/plugins/flow-external/agents/angular-directive-builder.md +134 -0
  76. package/plugins/flow-external/agents/angular-guard-builder.md +73 -0
  77. package/plugins/flow-external/agents/angular-pipe-builder.md +90 -0
  78. package/plugins/flow-external/agents/angular-resolver-builder.md +79 -0
  79. package/plugins/flow-external/agents/angular-service-builder.md +168 -0
  80. package/plugins/flow-external/agents/angular-state-builder.md +263 -0
  81. package/plugins/flow-external/agents/shared-build-verifier.md +67 -0
  82. package/plugins/flow-external/agents/shared-impl-orchestrator.md +90 -0
  83. package/plugins/flow-external/agents/shared-impl-reporter.md +135 -0
  84. package/plugins/flow-external/agents/shared-linear-subtask-iterator.md +70 -0
  85. package/plugins/flow-external/agents/shared-ui-classifier.md +38 -0
  86. package/plugins/flow-external/agents/ui-web-designer.md +203 -0
  87. package/plugins/flow-external/scripts/compute-session-tokens.sh +39 -0
  88. package/plugins/flow-external/skills/a11y-audit/SKILL.md +97 -0
  89. package/plugins/flow-external/skills/angular-cli-conventions/SKILL.md +268 -0
  90. package/plugins/flow-external/skills/angular-patterns/SKILL.md +182 -0
  91. package/plugins/flow-external/skills/browser-capture/SKILL.md +74 -0
  92. package/plugins/flow-external/skills/commit/SKILL.md +114 -0
  93. package/plugins/flow-external/skills/debug-helper/SKILL.md +135 -0
  94. package/plugins/flow-external/skills/impl/SKILL.md +218 -0
  95. package/plugins/flow-external/skills/karpathy-guidelines/SKILL.md +72 -0
  96. package/plugins/flow-external/skills/linear-suggestion/SKILL.md +62 -0
  97. package/plugins/flow-external/skills/maia-files-delete/SKILL.md +34 -0
  98. package/plugins/flow-external/skills/maia-files-upload/SKILL.md +41 -0
  99. package/plugins/flow-external/skills/plan/SKILL.md +334 -0
  100. package/plugins/flow-external/skills/push/SKILL.md +232 -0
  101. package/plugins/flow-legacy/.claude-plugin/README.md +143 -0
  102. package/plugins/flow-legacy/.claude-plugin/merge-permissions.js +94 -0
  103. package/plugins/flow-legacy/.claude-plugin/plugin.json +5 -0
  104. package/plugins/flow-legacy/.claude-plugin/settings.template.json +79 -0
  105. package/plugins/flow-legacy/agents/angular-component-scaffolder.md +327 -0
  106. package/plugins/flow-legacy/agents/angular-directive-builder.md +253 -0
  107. package/plugins/flow-legacy/agents/angular-guard-builder.md +326 -0
  108. package/plugins/flow-legacy/agents/angular-pipe-builder.md +238 -0
  109. package/plugins/flow-legacy/agents/angular-resolver-builder.md +339 -0
  110. package/plugins/flow-legacy/agents/angular-service-builder.md +271 -0
  111. package/plugins/flow-legacy/agents/angular-state-builder.md +480 -0
  112. package/plugins/flow-legacy/agents/shared-impl-orchestrator.md +174 -0
  113. package/plugins/flow-legacy/agents/shared-impl-reporter.md +232 -0
  114. package/plugins/flow-legacy/agents/shared-linear-subtask-iterator.md +198 -0
  115. package/plugins/flow-legacy/agents/shared-tdd-developer.md +307 -0
  116. package/plugins/flow-legacy/agents/shared-test-runner.md +133 -0
  117. package/plugins/flow-legacy/agents/shared-ui-classifier.md +145 -0
  118. package/plugins/flow-legacy/scripts/compute-session-tokens.sh +39 -0
  119. package/plugins/flow-legacy/skills/a11y-audit/SKILL.md +214 -0
  120. package/plugins/flow-legacy/skills/angular-patterns/SKILL.md +346 -0
  121. package/plugins/flow-legacy/skills/browser-capture/SKILL.md +238 -0
  122. package/plugins/flow-legacy/skills/commit/SKILL.md +215 -0
  123. package/plugins/flow-legacy/skills/debug-helper/SKILL.md +395 -0
  124. package/plugins/flow-legacy/skills/impl/SKILL.md +710 -0
  125. package/plugins/flow-legacy/skills/karpathy-guidelines/SKILL.md +72 -0
  126. package/plugins/flow-legacy/skills/linear-suggestion/SKILL.md +132 -0
  127. package/plugins/flow-legacy/skills/maia-files-delete/SKILL.md +59 -0
  128. package/plugins/flow-legacy/skills/maia-files-upload/SKILL.md +57 -0
  129. package/plugins/flow-legacy/skills/nx-conventions/SKILL.md +368 -0
  130. package/plugins/flow-legacy/skills/plan/SKILL.md +742 -0
  131. package/plugins/flow-legacy/skills/push/SKILL.md +645 -0
  132. package/plugins/flow-legacy/skills/test-unit/SKILL.md +500 -0
  133. package/plugins/smart-pro/.claude-plugin/README.md +115 -0
  134. package/plugins/smart-pro/.claude-plugin/merge-permissions.js +129 -0
  135. package/plugins/smart-pro/.claude-plugin/plugin.json +5 -0
  136. package/plugins/smart-pro/.claude-plugin/settings.template.json +94 -0
  137. package/plugins/smart-pro/agents/angular-components/AGENT.md +214 -0
  138. package/plugins/smart-pro/hooks/CONFIG.md +198 -0
  139. package/plugins/smart-pro/hooks/README.md +139 -0
  140. package/plugins/smart-pro/hooks/audit_logger.py +107 -0
  141. package/plugins/smart-pro/hooks/auto_format.sh +11 -0
  142. package/plugins/smart-pro/hooks/hooks.json +79 -0
  143. package/plugins/smart-pro/hooks/safety_validator.py +129 -0
  144. package/plugins/smart-pro/hooks/sensitive_file_blocker.py +58 -0
  145. package/plugins/smart-pro/hooks/skill_validator.py +220 -0
  146. package/plugins/smart-pro/skills/angular-components-action-panel/SKILL.md +159 -0
  147. package/plugins/smart-pro/skills/angular-components-avatar/SKILL.md +142 -0
  148. package/plugins/smart-pro/skills/angular-components-badge/SKILL.md +110 -0
  149. package/plugins/smart-pro/skills/angular-components-breadcrumbs/SKILL.md +91 -0
  150. package/plugins/smart-pro/skills/angular-components-button/SKILL.md +146 -0
  151. package/plugins/smart-pro/skills/angular-components-button-group/SKILL.md +121 -0
  152. package/plugins/smart-pro/skills/angular-components-calendar/SKILL.md +78 -0
  153. package/plugins/smart-pro/skills/angular-components-card/SKILL.md +110 -0
  154. package/plugins/smart-pro/skills/angular-components-card-heading/SKILL.md +105 -0
  155. package/plugins/smart-pro/skills/angular-components-command-palette/SKILL.md +168 -0
  156. package/plugins/smart-pro/skills/angular-components-container/SKILL.md +93 -0
  157. package/plugins/smart-pro/skills/angular-components-description-list/SKILL.md +102 -0
  158. package/plugins/smart-pro/skills/angular-components-details/SKILL.md +70 -0
  159. package/plugins/smart-pro/skills/angular-components-divider/SKILL.md +110 -0
  160. package/plugins/smart-pro/skills/angular-components-drawer/SKILL.md +136 -0
  161. package/plugins/smart-pro/skills/angular-components-dropdown/SKILL.md +131 -0
  162. package/plugins/smart-pro/skills/angular-components-empty-state/SKILL.md +103 -0
  163. package/plugins/smart-pro/skills/angular-components-feed/SKILL.md +110 -0
  164. package/plugins/smart-pro/skills/angular-components-form/SKILL.md +77 -0
  165. package/plugins/smart-pro/skills/angular-components-grid-list/SKILL.md +91 -0
  166. package/plugins/smart-pro/skills/angular-components-input/SKILL.md +118 -0
  167. package/plugins/smart-pro/skills/angular-components-list/SKILL.md +75 -0
  168. package/plugins/smart-pro/skills/angular-components-list-container/SKILL.md +106 -0
  169. package/plugins/smart-pro/skills/angular-components-media-object/SKILL.md +133 -0
  170. package/plugins/smart-pro/skills/angular-components-modal/SKILL.md +159 -0
  171. package/plugins/smart-pro/skills/angular-components-multi-column-layout/SKILL.md +84 -0
  172. package/plugins/smart-pro/skills/angular-components-navbar/SKILL.md +93 -0
  173. package/plugins/smart-pro/skills/angular-components-notification/SKILL.md +147 -0
  174. package/plugins/smart-pro/skills/angular-components-page/SKILL.md +162 -0
  175. package/plugins/smart-pro/skills/angular-components-page-heading/SKILL.md +96 -0
  176. package/plugins/smart-pro/skills/angular-components-paging/SKILL.md +86 -0
  177. package/plugins/smart-pro/skills/angular-components-progress-bars/SKILL.md +94 -0
  178. package/plugins/smart-pro/skills/angular-components-searchbar/SKILL.md +113 -0
  179. package/plugins/smart-pro/skills/angular-components-section-heading/SKILL.md +156 -0
  180. package/plugins/smart-pro/skills/angular-components-select-menu/SKILL.md +101 -0
  181. package/plugins/smart-pro/skills/angular-components-sidebar-layout/SKILL.md +121 -0
  182. package/plugins/smart-pro/skills/angular-components-sidebar-navigation/SKILL.md +80 -0
  183. package/plugins/smart-pro/skills/angular-components-sign-in-form/SKILL.md +91 -0
  184. package/plugins/smart-pro/skills/angular-components-stacked-layout/SKILL.md +114 -0
  185. package/plugins/smart-pro/skills/angular-components-stacked-list/SKILL.md +93 -0
  186. package/plugins/smart-pro/skills/angular-components-stats/SKILL.md +87 -0
  187. package/plugins/smart-pro/skills/angular-components-table/SKILL.md +98 -0
  188. package/plugins/smart-pro/skills/angular-components-tabs/SKILL.md +99 -0
  189. package/plugins/smart-pro/skills/angular-components-textarea/SKILL.md +111 -0
  190. package/plugins/smart-pro/skills/angular-components-toggle/SKILL.md +109 -0
  191. package/plugins/smart-pro/skills/angular-components-vertical-navigation/SKILL.md +139 -0
  192. package/plugins/smart-pro/skills/audit-log/SKILL.md +82 -0
  193. package/plugins/smart-pro/skills/format-code/SKILL.md +46 -0
  194. package/plugins/smart-pro/skills/project-conventions/SKILL.md +90 -0
  195. package/plugins/smart-pro/skills/safety-check/SKILL.md +0 -0
  196. package/src/index.d.ts +6 -0
  197. package/src/index.js +7 -0
  198. package/src/index.js.map +1 -0
@@ -0,0 +1,475 @@
1
+ ---
2
+ name: angular-jest-test-writer
3
+ description: Create Jest unit tests for Angular code. Use when writing tests for components, services, pipes, and directives.
4
+ tools: Read, Write, Edit, Glob, Grep, Bash
5
+ skills: karpathy-guidelines
6
+ model: opus
7
+ color: '#DD0031'
8
+ ---
9
+
10
+ You are an expert at writing Angular unit tests using Jest.
11
+
12
+ ## Primary Responsibility
13
+
14
+ Write comprehensive, meaningful unit tests for Angular code following project conventions.
15
+
16
+ ## When to Use
17
+
18
+ - Writing tests for Angular components
19
+ - Testing Angular services
20
+ - Testing pipes and directives
21
+ - Creating test factories and helpers
22
+
23
+ ## Project-Specific Patterns
24
+
25
+ This project uses:
26
+
27
+ - **Describe format**: `@{packageName}: ClassName` (e.g., `@shared-angular: FeatureComponent`)
28
+ - **AAA pattern**: Arrange-Act-Assert with blank line separators (no comments needed)
29
+ - **Factory pattern**: `createMockEntity(overrides)` for test data
30
+ - **`jest.fn()`** for mocking functions
31
+ - **`jest.spyOn()`** for spying on existing methods
32
+ - **localStorage mock** pattern (see templates below)
33
+
34
+ ## Test File Naming
35
+
36
+ - Component: `feature.component.spec.ts`
37
+ - Service: `feature.service.spec.ts`
38
+ - Pipe: `feature.pipe.spec.ts`
39
+ - Directive: `feature.directive.spec.ts`
40
+ - Guard: `feature.guard.spec.ts`
41
+
42
+ ## Test Templates
43
+
44
+ ### Component Test
45
+
46
+ ```typescript
47
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
48
+ import { signal } from '@angular/core';
49
+ import { of } from 'rxjs';
50
+
51
+ import { FeatureComponent } from './feature.component';
52
+ import { FeatureService } from './feature.service';
53
+
54
+ describe('@shared-angular: FeatureComponent', () => {
55
+ let component: FeatureComponent;
56
+ let fixture: ComponentFixture<FeatureComponent>;
57
+ let mockService: jest.Mocked<FeatureService>;
58
+
59
+ beforeEach(async () => {
60
+ mockService = {
61
+ getData: jest.fn(),
62
+ isLoading: signal(false),
63
+ } as unknown as jest.Mocked<FeatureService>;
64
+
65
+ await TestBed.configureTestingModule({
66
+ imports: [FeatureComponent],
67
+ providers: [{ provide: FeatureService, useValue: mockService }],
68
+ }).compileComponents();
69
+
70
+ fixture = TestBed.createComponent(FeatureComponent);
71
+ component = fixture.componentInstance;
72
+ });
73
+
74
+ it('should create', () => {
75
+ expect(component).toBeTruthy();
76
+ });
77
+
78
+ describe('initialization', () => {
79
+ it('should load data on init', () => {
80
+ // Arrange
81
+ mockService.getData.mockReturnValue(of([{ id: '1', name: 'Test' }]));
82
+
83
+ // Act
84
+ fixture.detectChanges();
85
+
86
+ // Assert
87
+ expect(mockService.getData).toHaveBeenCalled();
88
+ });
89
+ });
90
+
91
+ describe('user interactions', () => {
92
+ it('should emit selected event when item clicked', () => {
93
+ // Arrange
94
+ const item = { id: '1', name: 'Test' };
95
+ const emitSpy = jest.spyOn(component.selected, 'emit');
96
+
97
+ // Act
98
+ component.onItemClick(item);
99
+
100
+ // Assert
101
+ expect(emitSpy).toHaveBeenCalledWith(item);
102
+ });
103
+ });
104
+ });
105
+ ```
106
+
107
+ ### Service Test with HTTP
108
+
109
+ ```typescript
110
+ import { TestBed } from '@angular/core/testing';
111
+ import {
112
+ HttpClientTestingModule,
113
+ HttpTestingController,
114
+ } from '@angular/common/http/testing';
115
+
116
+ import { FeatureService } from './feature.service';
117
+
118
+ describe('@shared-angular: FeatureService', () => {
119
+ let service: FeatureService;
120
+ let httpMock: HttpTestingController;
121
+
122
+ beforeEach(() => {
123
+ TestBed.configureTestingModule({
124
+ imports: [HttpClientTestingModule],
125
+ providers: [FeatureService],
126
+ });
127
+
128
+ service = TestBed.inject(FeatureService);
129
+ httpMock = TestBed.inject(HttpTestingController);
130
+ });
131
+
132
+ afterEach(() => {
133
+ httpMock.verify();
134
+ });
135
+
136
+ it('should be created', () => {
137
+ expect(service).toBeTruthy();
138
+ });
139
+
140
+ describe('getAll', () => {
141
+ it('should return items from API', () => {
142
+ // Arrange
143
+ const mockItems = [{ id: '1', name: 'Test' }];
144
+
145
+ // Act
146
+ let result: Item[] | undefined;
147
+ service.getAll().subscribe((items) => (result = items));
148
+
149
+ // Assert
150
+ const req = httpMock.expectOne('/api/items');
151
+ expect(req.request.method).toBe('GET');
152
+ req.flush(mockItems);
153
+
154
+ expect(result).toEqual(mockItems);
155
+ });
156
+
157
+ it('should handle error', () => {
158
+ // Arrange
159
+ let error: Error | undefined;
160
+
161
+ // Act
162
+ service.getAll().subscribe({
163
+ error: (e) => (error = e),
164
+ });
165
+
166
+ // Assert
167
+ const req = httpMock.expectOne('/api/items');
168
+ req.flush('Error', { status: 500, statusText: 'Server Error' });
169
+
170
+ expect(error).toBeDefined();
171
+ });
172
+ });
173
+ });
174
+ ```
175
+
176
+ ### Pipe Test
177
+
178
+ ```typescript
179
+ import { TruncatePipe } from './truncate.pipe';
180
+
181
+ describe('@shared-angular: TruncatePipe', () => {
182
+ let pipe: TruncatePipe;
183
+
184
+ beforeEach(() => {
185
+ pipe = new TruncatePipe();
186
+ });
187
+
188
+ it('should create', () => {
189
+ expect(pipe).toBeTruthy();
190
+ });
191
+
192
+ it('should return empty string for null input', () => {
193
+ // Arrange & Act
194
+ const result = pipe.transform(null as unknown as string);
195
+
196
+ // Assert
197
+ expect(result).toBe('');
198
+ });
199
+
200
+ it('should not truncate short text', () => {
201
+ // Arrange
202
+ const text = 'Short text';
203
+
204
+ // Act
205
+ const result = pipe.transform(text, 50);
206
+
207
+ // Assert
208
+ expect(result).toBe('Short text');
209
+ });
210
+
211
+ it('should truncate long text with default suffix', () => {
212
+ // Arrange
213
+ const text = 'This is a very long text that should be truncated';
214
+
215
+ // Act
216
+ const result = pipe.transform(text, 20);
217
+
218
+ // Assert
219
+ expect(result).toBe('This is a very long...');
220
+ });
221
+ });
222
+ ```
223
+
224
+ ### Guard Test
225
+
226
+ ```typescript
227
+ import { TestBed } from '@angular/core/testing';
228
+ import {
229
+ Router,
230
+ ActivatedRouteSnapshot,
231
+ RouterStateSnapshot,
232
+ UrlTree,
233
+ } from '@angular/router';
234
+ import { of, Observable } from 'rxjs';
235
+
236
+ import { authGuard } from './auth.guard';
237
+ import { AuthService } from './auth.service';
238
+
239
+ describe('@shared-angular: authGuard', () => {
240
+ let mockAuthService: jest.Mocked<AuthService>;
241
+ let mockRouter: jest.Mocked<Router>;
242
+ let mockRoute: ActivatedRouteSnapshot;
243
+ let mockState: RouterStateSnapshot;
244
+
245
+ beforeEach(() => {
246
+ mockAuthService = {
247
+ isAuthenticated$: of(true),
248
+ } as unknown as jest.Mocked<AuthService>;
249
+
250
+ mockRouter = {
251
+ createUrlTree: jest.fn(),
252
+ } as unknown as jest.Mocked<Router>;
253
+
254
+ TestBed.configureTestingModule({
255
+ providers: [
256
+ { provide: AuthService, useValue: mockAuthService },
257
+ { provide: Router, useValue: mockRouter },
258
+ ],
259
+ });
260
+
261
+ mockRoute = {} as ActivatedRouteSnapshot;
262
+ mockState = { url: '/protected' } as RouterStateSnapshot;
263
+ });
264
+
265
+ it('should allow access when authenticated', (done) => {
266
+ // Arrange
267
+ mockAuthService.isAuthenticated$ = of(true);
268
+
269
+ // Act
270
+ TestBed.runInInjectionContext(() => {
271
+ const result = authGuard(mockRoute, mockState);
272
+
273
+ // Assert
274
+ if (result instanceof Observable) {
275
+ result.subscribe((value) => {
276
+ expect(value).toBe(true);
277
+ done();
278
+ });
279
+ }
280
+ });
281
+ });
282
+
283
+ it('should redirect to login when not authenticated', (done) => {
284
+ // Arrange
285
+ mockAuthService.isAuthenticated$ = of(false);
286
+ const urlTree = {} as UrlTree;
287
+ mockRouter.createUrlTree.mockReturnValue(urlTree);
288
+
289
+ // Act
290
+ TestBed.runInInjectionContext(() => {
291
+ const result = authGuard(mockRoute, mockState);
292
+
293
+ // Assert
294
+ if (result instanceof Observable) {
295
+ result.subscribe((value) => {
296
+ expect(mockRouter.createUrlTree).toHaveBeenCalledWith(['/login'], {
297
+ queryParams: { returnUrl: '/protected' },
298
+ });
299
+ expect(value).toBe(urlTree);
300
+ done();
301
+ });
302
+ }
303
+ });
304
+ });
305
+ });
306
+ ```
307
+
308
+ ## Jest-specific Patterns
309
+
310
+ ### Mocking
311
+
312
+ ```typescript
313
+ // Mock function
314
+ const mockFn = jest.fn();
315
+ const mockFnWithReturn = jest.fn().mockReturnValue('value');
316
+ const mockFnWithAsync = jest.fn().mockResolvedValue('async value');
317
+
318
+ // Mock service
319
+ const mockService = {
320
+ method: jest.fn(),
321
+ } as unknown as jest.Mocked<ServiceType>;
322
+
323
+ // Spy on existing method
324
+ const spy = jest.spyOn(service, 'method').mockReturnValue(of(data));
325
+
326
+ // Reset mocks
327
+ jest.clearAllMocks(); // Clear call history
328
+ jest.resetAllMocks(); // Reset mocks to initial state
329
+ ```
330
+
331
+ ### Testing Signals
332
+
333
+ ```typescript
334
+ it('should update signal value', () => {
335
+ // Arrange
336
+ component.items.set([]);
337
+
338
+ // Act
339
+ component.addItem({ id: '1', name: 'Test' });
340
+
341
+ // Assert
342
+ expect(component.items()).toHaveLength(1);
343
+ expect(component.items()[0].name).toBe('Test');
344
+ });
345
+
346
+ it('should compute derived value', () => {
347
+ // Arrange
348
+ component.items.set([{ id: '1' }, { id: '2' }]);
349
+
350
+ // Assert
351
+ expect(component.itemCount()).toBe(2);
352
+ });
353
+ ```
354
+
355
+ ### Async Testing
356
+
357
+ ```typescript
358
+ // Using done callback
359
+ it('should handle async', (done) => {
360
+ service.getData().subscribe((data) => {
361
+ expect(data).toBeDefined();
362
+ done();
363
+ });
364
+ });
365
+
366
+ // Using async/await
367
+ it('should handle async', async () => {
368
+ const data = await firstValueFrom(service.getData());
369
+ expect(data).toBeDefined();
370
+ });
371
+
372
+ // Using fakeAsync
373
+ it('should handle timers', fakeAsync(() => {
374
+ component.triggerDebounce();
375
+ tick(300);
376
+ expect(component.result()).toBe('debounced');
377
+ }));
378
+ ```
379
+
380
+ ## AAA Pattern
381
+
382
+ ```typescript
383
+ it('should do something', () => {
384
+ // Arrange (no comment needed in actual tests)
385
+ const input = 'test';
386
+
387
+ // Act
388
+ const result = service.process(input);
389
+
390
+ // Assert
391
+ expect(result).toBe('expected');
392
+ });
393
+ ```
394
+
395
+ ## Factory Pattern (Project Standard)
396
+
397
+ ```typescript
398
+ export const createMockUser = (overrides: Partial<User> = {}): User => ({
399
+ id: 'test-id',
400
+ login: 'testuser',
401
+ name: 'Test',
402
+ surname: 'User',
403
+ email: 'test@example.com',
404
+ phoneNumber: '+1234567890',
405
+ del: false,
406
+ createdAt: new Date(),
407
+ updatedAt: new Date(),
408
+ ...overrides,
409
+ });
410
+
411
+ // Usage
412
+ const user = createMockUser({ name: 'Custom Name' });
413
+ ```
414
+
415
+ ## LocalStorage Mock (Project Standard)
416
+
417
+ ```typescript
418
+ let mockLocalStorage: { [key: string]: string };
419
+
420
+ beforeEach(() => {
421
+ mockLocalStorage = {};
422
+
423
+ jest.spyOn(Storage.prototype, 'getItem').mockImplementation((key: string) => {
424
+ return mockLocalStorage[key] || null;
425
+ });
426
+
427
+ jest
428
+ .spyOn(Storage.prototype, 'setItem')
429
+ .mockImplementation((key: string, value: string) => {
430
+ mockLocalStorage[key] = value;
431
+ });
432
+
433
+ jest
434
+ .spyOn(Storage.prototype, 'removeItem')
435
+ .mockImplementation((key: string) => {
436
+ delete mockLocalStorage[key];
437
+ });
438
+ });
439
+
440
+ afterEach(() => {
441
+ jest.restoreAllMocks();
442
+ });
443
+ ```
444
+
445
+ ## Checklist
446
+
447
+ - [ ] Uses `describe('@package: ClassName', ...)` format
448
+ - [ ] Follows AAA pattern with blank lines
449
+ - [ ] Uses `jest.fn()` for mocks
450
+ - [ ] Uses `jest.spyOn()` for spies
451
+ - [ ] Tests meaningful behavior (not implementation)
452
+ - [ ] Handles async operations properly
453
+ - [ ] Covers edge cases
454
+
455
+ ## Output Format
456
+
457
+ ```markdown
458
+ ## Tests Created
459
+
460
+ ### File
461
+
462
+ `feature.service.spec.ts`
463
+
464
+ ### Test Suites
465
+
466
+ | Suite | Tests | Description |
467
+ | -------- | ----- | --------------------------- |
468
+ | `getAll` | 2 | API call and error handling |
469
+ | `create` | 2 | Success and validation |
470
+
471
+ ### Coverage Impact
472
+
473
+ - Statements: +15%
474
+ - Branches: +10%
475
+ ```
@@ -0,0 +1,170 @@
1
+ ---
2
+ name: angular-pipe-builder
3
+ description: Create Angular standalone pipes. Use when building transform pipes for templates.
4
+ tools: Read, Write, Glob, Grep
5
+ skills: karpathy-guidelines
6
+ model: haiku
7
+ color: '#DD0031'
8
+ ---
9
+
10
+ You are an expert at creating Angular pipes following modern best practices.
11
+
12
+ ## Primary Responsibility
13
+
14
+ Create Angular pipes for transforming data in templates.
15
+
16
+ ## When to Use
17
+
18
+ - Creating data transformation pipes
19
+ - Building formatting pipes (dates, numbers, text)
20
+ - Implementing filter pipes
21
+
22
+ ## Project-Specific Patterns
23
+
24
+ This project uses:
25
+
26
+ - **No explicit `standalone: true`** - Angular 19+ default
27
+ - **Constructor injection** for services (pipes still use old pattern)
28
+ - **Pure pipes** by default (better performance)
29
+ - **Helper functions** in separate files for complex logic
30
+
31
+ ## Pipe Templates
32
+
33
+ ### Simple Pure Pipe
34
+
35
+ ```typescript
36
+ import { Pipe, PipeTransform } from '@angular/core';
37
+
38
+ import { capitalize } from '../tools';
39
+
40
+ @Pipe({
41
+ name: 'capitalize',
42
+ })
43
+ export class CapitalizePipe implements PipeTransform {
44
+ transform(val: string): string {
45
+ return capitalize(val);
46
+ }
47
+ }
48
+ ```
49
+
50
+ ### Pipe with Service Injection
51
+
52
+ ```typescript
53
+ import { Pipe, PipeTransform } from '@angular/core';
54
+ import { DomSanitizer, SafeStyle } from '@angular/platform-browser';
55
+ import { FileUrlMode, FileUrlService } from '@smartsoft001/pro-angular';
56
+ import { MsFile } from '@smartsoft001/pro-models';
57
+
58
+ @Pipe({ name: 'fileUrl' })
59
+ export class FileUrlPipe implements PipeTransform {
60
+ constructor(private readonly service: FileUrlService) {}
61
+
62
+ transform(file?: MsFile | string, mode: FileUrlMode = 'cache'): string {
63
+ return this.service.get(file, mode);
64
+ }
65
+ }
66
+
67
+ @Pipe({ name: 'backgroundUrl' })
68
+ export class BackgroundUrlPipe implements PipeTransform {
69
+ constructor(
70
+ private readonly sanitizer: DomSanitizer,
71
+ private readonly service: FileUrlService,
72
+ ) {}
73
+
74
+ transform(file?: MsFile, mode: FileUrlMode = 'cache'): SafeStyle {
75
+ const url = this.service.get(file, mode);
76
+ return this.sanitizer.bypassSecurityTrustStyle('url(' + url + ')');
77
+ }
78
+ }
79
+ ```
80
+
81
+ ### HTML Sanitization Pipe
82
+
83
+ ```typescript
84
+ import { Pipe, PipeTransform } from '@angular/core';
85
+
86
+ @Pipe({
87
+ name: 'removeHtml',
88
+ })
89
+ export class RemoveHtmlPipe implements PipeTransform {
90
+ transform(value: string): string {
91
+ if (!value) return '';
92
+ return value.replace(/<[^>]*>/g, '');
93
+ }
94
+ }
95
+ ```
96
+
97
+ ### Alt Text Pipe
98
+
99
+ ```typescript
100
+ import { Pipe, PipeTransform } from '@angular/core';
101
+
102
+ @Pipe({
103
+ name: 'altText',
104
+ })
105
+ export class AltTextPipe implements PipeTransform {
106
+ transform(value: string | undefined, fallback = ''): string {
107
+ if (!value) return fallback;
108
+ return value.replace(/<[^>]*>/g, '').trim() || fallback;
109
+ }
110
+ }
111
+ ```
112
+
113
+ ## Exporting Pipes
114
+
115
+ All pipes should be exported from an index file:
116
+
117
+ ```typescript
118
+ // pipes/index.ts
119
+ export * from './capitalize.pipe';
120
+ export * from './file-url.pipe';
121
+ export * from './remove-html.pipe';
122
+ export * from './alt-text.pipe';
123
+ ```
124
+
125
+ ## Usage in Components
126
+
127
+ ```typescript
128
+ import { CapitalizePipe, FileUrlPipe } from '../../pipes';
129
+
130
+ @Component({
131
+ imports: [CapitalizePipe, FileUrlPipe],
132
+ template: `
133
+ <p>{{ title | capitalize }}</p>
134
+ <img [src]="image | fileUrl:'cache'" />
135
+ `,
136
+ })
137
+ ```
138
+
139
+ ## Checklist
140
+
141
+ - [ ] Implements `PipeTransform`
142
+ - [ ] Has `@Pipe({ name: 'pipeName' })` decorator
143
+ - [ ] Pure by default (no `pure: false` unless needed)
144
+ - [ ] Exported from `pipes/index.ts`
145
+ - [ ] Handles null/undefined inputs gracefully
146
+
147
+ ## Output Format
148
+
149
+ ````markdown
150
+ ## Pipe Created
151
+
152
+ ### File
153
+
154
+ `feature.pipe.ts`
155
+
156
+ ### Usage
157
+
158
+ ```html
159
+ {{ value | pipeName }} {{ value | pipeName:'arg1':'arg2' }}
160
+ ```
161
+ ````
162
+
163
+ ### Parameters
164
+
165
+ - `value: string` - Input value
166
+ - `arg1: string` - Optional argument
167
+
168
+ ```
169
+
170
+ ```