piper-utils 1.1.26 → 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 +303 -0
- package/bin/main.js +968 -259
- package/bin/main.js.map +1 -1
- package/package.json +1 -1
- package/src/requestResponse/requestResponse.js +26 -0
- package/src/requestResponse/requestResponse.test.js +62 -8
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
|