piper-utils 1.1.25 → 1.1.27

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/Test-Prompt.md ADDED
@@ -0,0 +1,303 @@
1
+ # Test Spy Creation System Prompt
2
+
3
+ ## run test
4
+
5
+ ```PowerShell
6
+ npm run test
7
+ ```
8
+ #### do not use && in Power Shell
9
+
10
+ ## Overview
11
+ When writing unit tests for functions that interact with external dependencies, follow these strict guidelines for creating spies. Each test should be self-contained with its own spies defined inline, not in beforeEach blocks.
12
+
13
+ ## What TO Spy On (External Boundaries Only)
14
+
15
+ ### 1. Database Operations
16
+ ```javascript
17
+ spyOn(Payment, 'findOne').and.returnValue(Promise.resolve(mockData));
18
+ spyOn(Order, 'create').and.returnValue(Promise.resolve(mockData));
19
+ spyOn(Company, 'findOne').and.returnValue(Promise.resolve(mockData));
20
+ spyOn(Model, 'destroy').and.returnValue(Promise.resolve());
21
+ ```
22
+
23
+ ### 2. External Service Calls
24
+ ```javascript
25
+ // HTTP requests
26
+ spyOn(axios, 'post').and.returnValue({ data: mockResponse });
27
+ spyOn(axios, 'get').and.returnValue({ data: mockResponse });
28
+ spyOn(axios, 'put').and.returnValue({ data: mockResponse });
29
+
30
+ // Third-party services
31
+ spyOn(flopay, 'processPayment').and.returnValue(Promise.resolve(mockResponse));
32
+ spyOn(S3, 's3').and.returnValue(Promise.resolve());
33
+ ```
34
+
35
+ ### 3. Email/SMS Services
36
+ ```javascript
37
+ spyOn(inboxUtils, 'sendEmailToInbox').and.returnValue(Promise.resolve());
38
+ spyOn(inboxUtils, 'sendTextToInbox').and.returnValue(Promise.resolve());
39
+ spyOn(htmlTemplateUtils, 'sendGridInvoiceOrReceiptTemplate').and.returnValue(Promise.resolve());
40
+ ```
41
+
42
+ ### 4. Audit/Logging Mechanisms
43
+ ```javascript
44
+ spyOn(audit, 'attach').and.returnValue(Promise.resolve());
45
+ ```
46
+
47
+ ### 5. Database Transactions
48
+ ```javascript
49
+ spyOn(db, 'getConnection').and.returnValue({
50
+ transaction: () => ({
51
+ commit: () => {},
52
+ rollback: () => {}
53
+ })
54
+ });
55
+ ```
56
+
57
+ ### 6. Webhook Utilities
58
+ ```javascript
59
+ spyOn(webhookUtils, 'sendToWebhook').and.returnValue(Promise.resolve());
60
+ ```
61
+
62
+ ### 7. Route-level Functions (when testing other routes)
63
+ ```javascript
64
+ spyOn(orderRoutes, 'updateOrderStatus').and.returnValue(Promise.resolve());
65
+ ```
66
+
67
+ ## What NOT to Spy On
68
+
69
+ ### 1. Authorization/Access Control Functions
70
+ These are pure functions that should be tested with proper mock events:
71
+ - `checkModule`
72
+ - `checkWriteAccess`
73
+ - `accessRightsUtils`
74
+ - `getCurrentUser`
75
+
76
+ ### 2. Data Transformation Functions
77
+ - `createFilters`
78
+ - `createSort`
79
+ - `parseBody`
80
+ - `userDefaultBid`
81
+
82
+ ### 3. Internal Utility Functions
83
+ - Pure functions that don't have side effects
84
+ - Data formatting functions
85
+ - Validation functions
86
+
87
+ ## Event Mock Pattern
88
+
89
+ Create comprehensive event mocks instead of spying on auth functions:
90
+
91
+ ```javascript
92
+ const mockEvent = {
93
+ body: {
94
+ businessId: 'ABC',
95
+ amount: 100,
96
+ customerId: 1,
97
+ // ... other required fields
98
+ },
99
+ pathParameters: {
100
+ id: 1
101
+ },
102
+ queryStringParameters: {
103
+ businessId: 'ABC',
104
+ limit: '10',
105
+ offset: '0'
106
+ },
107
+ requestContext: {
108
+ authorizer: {
109
+ claims: {
110
+ 'custom:AR': JSON.stringify({
111
+ businessIds: { 'ABC': 'A' },
112
+ module: {
113
+ payment: { read: true, write: true }
114
+ }
115
+ })
116
+ }
117
+ }
118
+ },
119
+ headers: {
120
+ Authorization: 'Bearer mock-jwt-token'
121
+ }
122
+ };
123
+ ```
124
+
125
+ ## Spy Pattern Guidelines
126
+
127
+ ### 1. Create Spies Inline
128
+ ```javascript
129
+ it('should handle database failure', async () => {
130
+ // Create spies specific to this test
131
+ const paymentFindSpy = spyOn(Payment, 'findOne').and.returnValue(Promise.reject(new Error('DB Error')));
132
+ const auditSpy = spyOn(audit, 'attach').and.returnValue(Promise.resolve());
133
+
134
+ const result = await getPayment(mockEvent);
135
+
136
+ expect(result.statusCode).toBe(500);
137
+ expect(paymentFindSpy).toHaveBeenCalled();
138
+ expect(auditSpy).toHaveBeenCalled();
139
+ });
140
+ ```
141
+
142
+ ### 2. Use Descriptive Spy Names
143
+ ```javascript
144
+ const paymentCreateSpy = spyOn(Payment, 'create');
145
+ const sendEmailSpy = spyOn(inboxUtils, 'sendEmailToInbox');
146
+ const webhookSpy = spyOn(webhookUtils, 'sendToWebhook');
147
+ ```
148
+
149
+ ### 3. Control Test Flow with Return Values
150
+ ```javascript
151
+ // Success case
152
+ spyOn(Payment, 'findOne').and.returnValue(Promise.resolve(mockPayment));
153
+
154
+ // Failure case
155
+ spyOn(Payment, 'findOne').and.returnValue(Promise.reject(new Error('Not found')));
156
+
157
+ // Null/empty case
158
+ spyOn(Payment, 'findOne').and.returnValue(Promise.resolve(null));
159
+ ```
160
+
161
+ ### 4. Mock Complex Objects Properly
162
+ ```javascript
163
+ const mockPayment = {
164
+ id: 1,
165
+ status: 'Open',
166
+ amount: 100,
167
+ toJSON: () => ({
168
+ id: 1,
169
+ status: 'Open',
170
+ amount: 100,
171
+ customer: { contacts: [] }
172
+ }),
173
+ set: () => {},
174
+ save: () => Promise.resolve(),
175
+ get: () => {}
176
+ };
177
+ ```
178
+
179
+ ### 5. Verify Spy Calls When Necessary
180
+ ```javascript
181
+ // Verify the spy was called
182
+ expect(webhookSpy).toHaveBeenCalled();
183
+
184
+ // Verify specific arguments
185
+ expect(webhookSpy).toHaveBeenCalledWith(1, 'hookRef', webhookTypes.paymentCreated, jasmine.any(Object));
186
+
187
+ // Verify call count
188
+ expect(emailSpy).toHaveBeenCalledTimes(1);
189
+
190
+ // Get call details
191
+ const lastCall = webhookSpy.calls.mostRecent();
192
+ expect(lastCall.args[2].type).toBe('paymentCreated');
193
+ ```
194
+
195
+ ## Key Principles
196
+
197
+ 1. **Self-Contained Tests**: Each test should have its own spies, not shared in beforeEach
198
+ 2. **Minimal Spying**: Only spy on what's necessary for the specific test scenario
199
+ 3. **External Boundaries**: Only mock external dependencies (DB, network, file system)
200
+ 4. **No Lodash Get**: Use optional chaining or destructuring instead
201
+ 5. **No Nested Ternaries**: Use if/else statements for clarity
202
+ 6. **No beforeEach**: Define all test setup inline within each test
203
+
204
+ ## Example Test Structure
205
+
206
+ ```javascript
207
+ describe('paymentRoutes', () => {
208
+ describe('createPayment', () => {
209
+ it('should successfully create a payment', async () => {
210
+ // Arrange - Create spies for external dependencies
211
+ const auditSpy = spyOn(audit, 'attach').and.returnValue(Promise.resolve());
212
+ const paymentCreateSpy = spyOn(Payment, 'create').and.returnValue(Promise.resolve({ id: 1 }));
213
+ const paymentFindSpy = spyOn(Payment, 'findOne').and.returnValue(Promise.resolve(mockPayment));
214
+ const webhookSpy = spyOn(webhookUtils, 'sendToWebhook').and.returnValue(Promise.resolve());
215
+
216
+ // Arrange - Create mock event
217
+ const mockEvent = {
218
+ body: { amount: 100, customerId: 1 },
219
+ requestContext: {
220
+ authorizer: {
221
+ claims: {
222
+ 'custom:AR': JSON.stringify({
223
+ businessIds: { 'ABC': 'A' },
224
+ module: { payment: { write: true } }
225
+ })
226
+ }
227
+ }
228
+ }
229
+ };
230
+
231
+ // Act
232
+ const result = await createPaymentFromRoute(mockEvent);
233
+
234
+ // Assert
235
+ expect(result.statusCode).toBe(200);
236
+ expect(paymentCreateSpy).toHaveBeenCalled();
237
+ expect(webhookSpy).toHaveBeenCalledWith(
238
+ 1,
239
+ jasmine.any(String),
240
+ webhookTypes.paymentCreated,
241
+ jasmine.any(Object)
242
+ );
243
+ });
244
+
245
+ it('should handle database transaction failure', async () => {
246
+ // Arrange - Mock transaction failure
247
+ const transactionMock = {
248
+ commit: jasmine.createSpy('commit'),
249
+ rollback: jasmine.createSpy('rollback')
250
+ };
251
+ spyOn(db, 'getConnection').and.returnValue({
252
+ transaction: () => transactionMock
253
+ });
254
+ spyOn(Payment, 'create').and.returnValue(Promise.reject(new Error('DB Error')));
255
+
256
+ // Arrange - Create mock event
257
+ const mockEvent = {
258
+ body: { amount: 100 },
259
+ requestContext: {
260
+ authorizer: {
261
+ claims: {
262
+ 'custom:AR': JSON.stringify({
263
+ businessIds: { 'ABC': 'A' },
264
+ module: { payment: { write: true } }
265
+ })
266
+ }
267
+ }
268
+ }
269
+ };
270
+
271
+ // Act
272
+ const result = await createPaymentFromRoute(mockEvent);
273
+
274
+ // Assert
275
+ expect(result.statusCode).toBe(500);
276
+ expect(transactionMock.rollback).toHaveBeenCalled();
277
+ expect(transactionMock.commit).not.toHaveBeenCalled();
278
+ });
279
+ });
280
+ });
281
+ ```
282
+
283
+ ## Common Patterns to Follow
284
+
285
+ 1. **Database Mock Pattern**:
286
+ - Always include required methods like `toJSON()`, `set()`, `save()`, `get()`
287
+ - Return promises for async operations
288
+
289
+ 2. **Error Testing Pattern**:
290
+ - Test both rejection and null returns
291
+ - Verify proper error codes and messages
292
+
293
+ 3. **Transaction Pattern**:
294
+ - Mock both commit and rollback
295
+ - Verify rollback on failure, commit on success
296
+
297
+ 4. **External Service Pattern**:
298
+ - Mock the exact response structure expected
299
+ - Test both success and failure scenarios
300
+
301
+ 5. **Webhook Pattern**:
302
+ - Verify webhook type and payload structure
303
+ - Check that webhooks are sent at appropriate times