@tellescope/sdk 1.244.4 → 1.245.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 (28) hide show
  1. package/lib/cjs/tests/api_tests/medication_added_trigger.test.d.ts +6 -0
  2. package/lib/cjs/tests/api_tests/medication_added_trigger.test.d.ts.map +1 -0
  3. package/lib/cjs/tests/api_tests/medication_added_trigger.test.js +452 -0
  4. package/lib/cjs/tests/api_tests/medication_added_trigger.test.js.map +1 -0
  5. package/lib/cjs/tests/api_tests/openloop_webhooks.test.d.ts +6 -0
  6. package/lib/cjs/tests/api_tests/openloop_webhooks.test.d.ts.map +1 -0
  7. package/lib/cjs/tests/api_tests/openloop_webhooks.test.js +833 -0
  8. package/lib/cjs/tests/api_tests/openloop_webhooks.test.js.map +1 -0
  9. package/lib/cjs/tests/tests.d.ts.map +1 -1
  10. package/lib/cjs/tests/tests.js +142 -134
  11. package/lib/cjs/tests/tests.js.map +1 -1
  12. package/lib/esm/tests/api_tests/medication_added_trigger.test.d.ts +6 -0
  13. package/lib/esm/tests/api_tests/medication_added_trigger.test.d.ts.map +1 -0
  14. package/lib/esm/tests/api_tests/medication_added_trigger.test.js +448 -0
  15. package/lib/esm/tests/api_tests/medication_added_trigger.test.js.map +1 -0
  16. package/lib/esm/tests/api_tests/openloop_webhooks.test.d.ts +6 -0
  17. package/lib/esm/tests/api_tests/openloop_webhooks.test.d.ts.map +1 -0
  18. package/lib/esm/tests/api_tests/openloop_webhooks.test.js +829 -0
  19. package/lib/esm/tests/api_tests/openloop_webhooks.test.js.map +1 -0
  20. package/lib/esm/tests/tests.d.ts.map +1 -1
  21. package/lib/esm/tests/tests.js +142 -134
  22. package/lib/esm/tests/tests.js.map +1 -1
  23. package/lib/tsconfig.tsbuildinfo +1 -1
  24. package/package.json +10 -10
  25. package/src/tests/api_tests/medication_added_trigger.test.ts +306 -0
  26. package/src/tests/api_tests/openloop_webhooks.test.ts +662 -0
  27. package/src/tests/tests.ts +5 -1
  28. package/test_generated.pdf +0 -0
@@ -0,0 +1,833 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
+ return new (P || (P = Promise))(function (resolve, reject) {
16
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
20
+ });
21
+ };
22
+ var __generator = (this && this.__generator) || function (thisArg, body) {
23
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
24
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
+ function verb(n) { return function (v) { return step([n, v]); }; }
26
+ function step(op) {
27
+ if (f) throw new TypeError("Generator is already executing.");
28
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
29
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
30
+ if (y = 0, t) op = [op[0] & 2, t.value];
31
+ switch (op[0]) {
32
+ case 0: case 1: t = op; break;
33
+ case 4: _.label++; return { value: op[1], done: false };
34
+ case 5: _.label++; y = op[1]; op = [0]; continue;
35
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
36
+ default:
37
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41
+ if (t[2]) _.ops.pop();
42
+ _.trys.pop(); continue;
43
+ }
44
+ op = body.call(thisArg, _);
45
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
+ }
48
+ };
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ exports.openloop_webhooks_tests = void 0;
51
+ require('source-map-support').install();
52
+ var sdk_1 = require("../../sdk");
53
+ var testing_1 = require("@tellescope/testing");
54
+ var setup_1 = require("../setup");
55
+ var host = process.env.API_URL || 'http://localhost:8080';
56
+ var businessId = '60398b1131a295e64f084ff6';
57
+ var v1Url = "".concat(host, "/v1/webhooks/openloop/").concat(businessId);
58
+ var v2Url = "".concat(host, "/v1/webhooks/openloop-v2/").concat(businessId);
59
+ var postJSON = function (url, body) { return __awaiter(void 0, void 0, void 0, function () {
60
+ var res, data, _a;
61
+ return __generator(this, function (_b) {
62
+ switch (_b.label) {
63
+ case 0: return [4 /*yield*/, fetch(url, {
64
+ method: 'POST',
65
+ headers: { 'Content-Type': 'application/json' },
66
+ body: JSON.stringify(body),
67
+ })];
68
+ case 1:
69
+ res = _b.sent();
70
+ _b.label = 2;
71
+ case 2:
72
+ _b.trys.push([2, 4, , 5]);
73
+ return [4 /*yield*/, res.json()];
74
+ case 3:
75
+ data = _b.sent();
76
+ return [3 /*break*/, 5];
77
+ case 4:
78
+ _a = _b.sent();
79
+ data = null;
80
+ return [3 /*break*/, 5];
81
+ case 5: return [2 /*return*/, { status: res.status, data: data }];
82
+ }
83
+ });
84
+ }); };
85
+ var postV1 = function (body) { return postJSON(v1Url, body); };
86
+ var postV2 = function (body) { return postJSON(v2Url, body); };
87
+ var counter = 0;
88
+ var uid = function () { return "".concat(Date.now(), "-").concat(++counter); };
89
+ var makeV1Confirmation = function (overrides) {
90
+ if (overrides === void 0) { overrides = {}; }
91
+ return (__assign({ type: 'order_confirmation', patientID: 'test-healthie-ol-1', pharmacy: 'Test Pharmacy', medication_instructions: 'Take once daily', shipping_address: '123 Test St', orderNumber: "ol-conf-".concat(uid()), weeksOrdered: 'w4', fill: '1', medicationSKU: 'SKU-100', sku_med: 'Test Medication 10mg' }, overrides));
92
+ };
93
+ var makeV1Shipped = function (overrides) {
94
+ if (overrides === void 0) { overrides = {}; }
95
+ return (__assign({ type: 'order_shipped', patientID: 'test-healthie-ol-1', pharmacy: 'Test Pharmacy', shipped_date: '2024-07-09', track_number: 'TRACK123', status: 'shipped', order_date: '2024-07-09', orderNumber: "ol-ship-".concat(uid()), fill: '1', medicationSKU: 'SKU-200', sku_med: 'Shipped Med 20mg' }, overrides));
96
+ };
97
+ var makeV2Payload = function (eventType, overrides) {
98
+ if (overrides === void 0) { overrides = {}; }
99
+ return (__assign({ id: "v2-".concat(uid()), client: 'test-client', eventId: "evt-".concat(uid()), eventType: eventType, chartId: 'chart-1', patientId: 'test-healthie-ol-1', providerId: 'provider-1', medication: 'V2 Test Med', medicationSku: 'v2-sku-001', fill: '1', prescriptionCreatedDate: '2024-01-15' }, overrides));
100
+ };
101
+ var openloop_webhooks_tests = function (_a) {
102
+ var sdk = _a.sdk, sdkNonAdmin = _a.sdkNonAdmin;
103
+ return __awaiter(void 0, void 0, void 0, function () {
104
+ var healthieId1, healthieId2, enduser1, enduser2, confOrderNumber_1, shipOrderNumber_1, v2OrderId_1, v2CancelId_1, v2RefundId_1;
105
+ return __generator(this, function (_b) {
106
+ switch (_b.label) {
107
+ case 0:
108
+ (0, testing_1.log_header)("OpenLoop Webhooks Tests");
109
+ healthieId1 = 'test-healthie-ol-1';
110
+ healthieId2 = 'test-healthie-ol-2';
111
+ return [4 /*yield*/, sdk.api.endusers.createOne({ source: 'Healthie', externalId: healthieId1 })];
112
+ case 1:
113
+ enduser1 = _b.sent();
114
+ return [4 /*yield*/, sdk.api.endusers.createOne({ source: 'Healthie', externalId: healthieId2 })];
115
+ case 2:
116
+ enduser2 = _b.sent();
117
+ _b.label = 3;
118
+ case 3:
119
+ _b.trys.push([3, , 25, 28]);
120
+ // ===== SECTION A: V1 Validation =====
121
+ (0, testing_1.log_header)("V1 Validation");
122
+ return [4 /*yield*/, (0, testing_1.async_test)('V1: missing patientID returns 400', function () { return __awaiter(void 0, void 0, void 0, function () {
123
+ var res;
124
+ return __generator(this, function (_a) {
125
+ switch (_a.label) {
126
+ case 0: return [4 /*yield*/, postV1({ type: 'order_confirmation', pharmacy: 'x', orderNumber: 'x' })];
127
+ case 1:
128
+ res = _a.sent();
129
+ return [2 /*return*/, res.status];
130
+ }
131
+ });
132
+ }); }, { onResult: function (s) { return s === 400; } })];
133
+ case 4:
134
+ _b.sent();
135
+ return [4 /*yield*/, (0, testing_1.async_test)('V1: unknown patient returns 404', function () { return __awaiter(void 0, void 0, void 0, function () {
136
+ var res;
137
+ return __generator(this, function (_a) {
138
+ switch (_a.label) {
139
+ case 0: return [4 /*yield*/, postV1(makeV1Confirmation({ patientID: 'nonexistent-patient-id' }))];
140
+ case 1:
141
+ res = _a.sent();
142
+ return [2 /*return*/, res.status];
143
+ }
144
+ });
145
+ }); }, { onResult: function (s) { return s === 404; } })
146
+ // ===== SECTION B: V1 order_confirmation =====
147
+ ];
148
+ case 5:
149
+ _b.sent();
150
+ // ===== SECTION B: V1 order_confirmation =====
151
+ (0, testing_1.log_header)("V1 order_confirmation");
152
+ confOrderNumber_1 = "ol-conf-fields-".concat(uid());
153
+ return [4 /*yield*/, (0, testing_1.async_test)('V1: order_confirmation creates EnduserOrder with correct fields', function () { return __awaiter(void 0, void 0, void 0, function () {
154
+ var res, orders, order;
155
+ return __generator(this, function (_a) {
156
+ switch (_a.label) {
157
+ case 0: return [4 /*yield*/, postV1(makeV1Confirmation({
158
+ patientID: healthieId1,
159
+ orderNumber: confOrderNumber_1,
160
+ sku_med: 'Test Med 10mg',
161
+ pharmacy: 'PharmaCo',
162
+ medication_instructions: 'Take daily with food',
163
+ shipping_address: '456 Oak Ave',
164
+ weeksOrdered: 'w12',
165
+ fill: '2',
166
+ medicationSKU: 'SKU-ABC',
167
+ }))];
168
+ case 1:
169
+ res = _a.sent();
170
+ (0, testing_1.assert)(res.status === 200, "Expected 200, got ".concat(res.status));
171
+ return [4 /*yield*/, sdk.api.enduser_orders.getSome({
172
+ filter: { source: 'OpenLoop', externalId: confOrderNumber_1 }
173
+ })];
174
+ case 2:
175
+ orders = _a.sent();
176
+ (0, testing_1.assert)(orders.length === 1, "Expected 1 order, got ".concat(orders.length));
177
+ order = orders[0];
178
+ (0, testing_1.assert)(order.enduserId === enduser1.id, 'enduserId mismatch');
179
+ (0, testing_1.assert)(order.title === 'Test Med 10mg', "title mismatch: ".concat(order.title));
180
+ (0, testing_1.assert)(order.status === 'confirmed', "status mismatch: ".concat(order.status));
181
+ (0, testing_1.assert)(order.description === '456 Oak Ave', "description mismatch: ".concat(order.description));
182
+ (0, testing_1.assert)(order.instructions === 'Take daily with food', "instructions mismatch: ".concat(order.instructions));
183
+ (0, testing_1.assert)(order.frequency === 'w12', "frequency mismatch: ".concat(order.frequency));
184
+ (0, testing_1.assert)(order.fill === '2', "fill mismatch: ".concat(order.fill));
185
+ (0, testing_1.assert)(order.sku === 'sku-abc', "sku mismatch (should be lowercased): ".concat(order.sku));
186
+ return [2 /*return*/, true];
187
+ }
188
+ });
189
+ }); }, { onResult: function (r) { return r === true; } })];
190
+ case 6:
191
+ _b.sent();
192
+ return [4 /*yield*/, (0, testing_1.async_test)('V1: order_confirmation idempotency - same order not duplicated', function () { return __awaiter(void 0, void 0, void 0, function () {
193
+ var res, orders;
194
+ return __generator(this, function (_a) {
195
+ switch (_a.label) {
196
+ case 0: return [4 /*yield*/, postV1(makeV1Confirmation({
197
+ patientID: healthieId1,
198
+ orderNumber: confOrderNumber_1,
199
+ sku_med: 'Different Title',
200
+ fill: '99',
201
+ }))];
202
+ case 1:
203
+ res = _a.sent();
204
+ (0, testing_1.assert)(res.status === 200, "Expected 200, got ".concat(res.status));
205
+ return [4 /*yield*/, sdk.api.enduser_orders.getSome({
206
+ filter: { source: 'OpenLoop', externalId: confOrderNumber_1 }
207
+ })];
208
+ case 2:
209
+ orders = _a.sent();
210
+ (0, testing_1.assert)(orders.length === 1, "Expected 1 order after duplicate, got ".concat(orders.length));
211
+ // $setOnInsert means fields should NOT have changed
212
+ (0, testing_1.assert)(orders[0].title === 'Test Med 10mg', "title should not change on duplicate: ".concat(orders[0].title));
213
+ (0, testing_1.assert)(orders[0].fill === '2', "fill should not change on duplicate: ".concat(orders[0].fill));
214
+ return [2 /*return*/, true];
215
+ }
216
+ });
217
+ }); }, { onResult: function (r) { return r === true; } })];
218
+ case 7:
219
+ _b.sent();
220
+ return [4 /*yield*/, (0, testing_1.async_test)('V1: order_confirmation without sku_med falls back to pharmacy name', function () { return __awaiter(void 0, void 0, void 0, function () {
221
+ var orderNum, res, orders;
222
+ return __generator(this, function (_a) {
223
+ switch (_a.label) {
224
+ case 0:
225
+ orderNum = "ol-conf-fallback-".concat(uid());
226
+ return [4 /*yield*/, postV1(makeV1Confirmation({
227
+ patientID: healthieId1,
228
+ orderNumber: orderNum,
229
+ sku_med: undefined,
230
+ pharmacy: 'FallbackPharmacy',
231
+ }))];
232
+ case 1:
233
+ res = _a.sent();
234
+ (0, testing_1.assert)(res.status === 200, "Expected 200, got ".concat(res.status));
235
+ return [4 /*yield*/, sdk.api.enduser_orders.getSome({
236
+ filter: { source: 'OpenLoop', externalId: orderNum }
237
+ })];
238
+ case 2:
239
+ orders = _a.sent();
240
+ (0, testing_1.assert)(orders.length === 1, "Expected 1 order, got ".concat(orders.length));
241
+ (0, testing_1.assert)(orders[0].title === 'OpenLoop: FallbackPharmacy', "title mismatch: ".concat(orders[0].title));
242
+ return [2 /*return*/, true];
243
+ }
244
+ });
245
+ }); }, { onResult: function (r) { return r === true; } })
246
+ // ===== SECTION C: V1 order_shipped =====
247
+ ];
248
+ case 8:
249
+ _b.sent();
250
+ // ===== SECTION C: V1 order_shipped =====
251
+ (0, testing_1.log_header)("V1 order_shipped");
252
+ shipOrderNumber_1 = "ol-ship-update-".concat(uid());
253
+ return [4 /*yield*/, (0, testing_1.async_test)('V1: order_shipped updates existing confirmed order', function () { return __awaiter(void 0, void 0, void 0, function () {
254
+ var res, orders, order;
255
+ return __generator(this, function (_a) {
256
+ switch (_a.label) {
257
+ case 0:
258
+ // First create a confirmed order
259
+ return [4 /*yield*/, postV1(makeV1Confirmation({
260
+ patientID: healthieId1,
261
+ orderNumber: shipOrderNumber_1,
262
+ }))
263
+ // Now ship it
264
+ ];
265
+ case 1:
266
+ // First create a confirmed order
267
+ _a.sent();
268
+ return [4 /*yield*/, postV1(makeV1Shipped({
269
+ patientID: healthieId1,
270
+ orderNumber: shipOrderNumber_1,
271
+ track_number: 'TRACK-ABC',
272
+ shipped_date: '2024-07-09',
273
+ }))];
274
+ case 2:
275
+ res = _a.sent();
276
+ (0, testing_1.assert)(res.status === 200, "Expected 200, got ".concat(res.status));
277
+ return [4 /*yield*/, sdk.api.enduser_orders.getSome({
278
+ filter: { source: 'OpenLoop', externalId: shipOrderNumber_1 }
279
+ })];
280
+ case 3:
281
+ orders = _a.sent();
282
+ (0, testing_1.assert)(orders.length === 1, "Expected 1 order, got ".concat(orders.length));
283
+ order = orders[0];
284
+ (0, testing_1.assert)(order.status === 'shipped', "status mismatch: ".concat(order.status));
285
+ (0, testing_1.assert)(order.tracking === 'TRACK-ABC', "tracking mismatch: ".concat(order.tracking));
286
+ (0, testing_1.assert)(order.shippedDate === '07-09-2024', "shippedDate mismatch (expected MM-DD-YYYY): ".concat(order.shippedDate));
287
+ return [2 /*return*/, true];
288
+ }
289
+ });
290
+ }); }, { onResult: function (r) { return r === true; } })];
291
+ case 9:
292
+ _b.sent();
293
+ return [4 /*yield*/, (0, testing_1.async_test)('V1: order_shipped updates title and sku when provided', function () { return __awaiter(void 0, void 0, void 0, function () {
294
+ var res, orders, order;
295
+ return __generator(this, function (_a) {
296
+ switch (_a.label) {
297
+ case 0: return [4 /*yield*/, postV1(makeV1Shipped({
298
+ patientID: healthieId1,
299
+ orderNumber: shipOrderNumber_1,
300
+ sku_med: 'Updated Title From Ship',
301
+ medicationSKU: 'NEW-SKU-123',
302
+ track_number: 'TRACK-DEF',
303
+ shipped_date: '2024-08-15',
304
+ }))];
305
+ case 1:
306
+ res = _a.sent();
307
+ (0, testing_1.assert)(res.status === 200, "Expected 200, got ".concat(res.status));
308
+ return [4 /*yield*/, sdk.api.enduser_orders.getSome({
309
+ filter: { source: 'OpenLoop', externalId: shipOrderNumber_1 }
310
+ })];
311
+ case 2:
312
+ orders = _a.sent();
313
+ (0, testing_1.assert)(orders.length === 1, "Expected 1 order, got ".concat(orders.length));
314
+ order = orders[0];
315
+ (0, testing_1.assert)(order.title === 'Updated Title From Ship', "title mismatch: ".concat(order.title));
316
+ (0, testing_1.assert)(order.sku === 'new-sku-123', "sku mismatch (should be lowercased): ".concat(order.sku));
317
+ return [2 /*return*/, true];
318
+ }
319
+ });
320
+ }); }, { onResult: function (r) { return r === true; } })];
321
+ case 10:
322
+ _b.sent();
323
+ return [4 /*yield*/, (0, testing_1.async_test)('V1: order_shipped creates new order if none exists', function () { return __awaiter(void 0, void 0, void 0, function () {
324
+ var newOrderNum, res, orders, order;
325
+ return __generator(this, function (_a) {
326
+ switch (_a.label) {
327
+ case 0:
328
+ newOrderNum = "ol-ship-new-".concat(uid());
329
+ return [4 /*yield*/, postV1(makeV1Shipped({
330
+ patientID: healthieId1,
331
+ orderNumber: newOrderNum,
332
+ sku_med: 'Direct Ship Med',
333
+ track_number: 'TRACK-NEW',
334
+ shipped_date: '2024-09-01',
335
+ fill: '3',
336
+ medicationSKU: 'DIRECT-SKU',
337
+ }))];
338
+ case 1:
339
+ res = _a.sent();
340
+ (0, testing_1.assert)(res.status === 200, "Expected 200, got ".concat(res.status));
341
+ return [4 /*yield*/, sdk.api.enduser_orders.getSome({
342
+ filter: { source: 'OpenLoop', externalId: newOrderNum }
343
+ })];
344
+ case 2:
345
+ orders = _a.sent();
346
+ (0, testing_1.assert)(orders.length === 1, "Expected 1 order, got ".concat(orders.length));
347
+ order = orders[0];
348
+ (0, testing_1.assert)(order.status === 'shipped', "status mismatch: ".concat(order.status));
349
+ (0, testing_1.assert)(order.title === 'Direct Ship Med', "title mismatch: ".concat(order.title));
350
+ (0, testing_1.assert)(order.tracking === 'TRACK-NEW', "tracking mismatch: ".concat(order.tracking));
351
+ (0, testing_1.assert)(order.fill === '3', "fill mismatch: ".concat(order.fill));
352
+ (0, testing_1.assert)(order.sku === 'direct-sku', "sku mismatch: ".concat(order.sku));
353
+ return [2 /*return*/, true];
354
+ }
355
+ });
356
+ }); }, { onResult: function (r) { return r === true; } })];
357
+ case 11:
358
+ _b.sent();
359
+ return [4 /*yield*/, (0, testing_1.async_test)('V1: order_shipped can re-ship with updated tracking', function () { return __awaiter(void 0, void 0, void 0, function () {
360
+ var reshipOrderNum, res, orders;
361
+ return __generator(this, function (_a) {
362
+ switch (_a.label) {
363
+ case 0:
364
+ reshipOrderNum = "ol-reship-".concat(uid());
365
+ // Create and ship
366
+ return [4 /*yield*/, postV1(makeV1Confirmation({ patientID: healthieId1, orderNumber: reshipOrderNum }))];
367
+ case 1:
368
+ // Create and ship
369
+ _a.sent();
370
+ return [4 /*yield*/, postV1(makeV1Shipped({
371
+ patientID: healthieId1,
372
+ orderNumber: reshipOrderNum,
373
+ track_number: 'TRACK-FIRST',
374
+ shipped_date: '2024-07-01',
375
+ }))
376
+ // Re-ship with new tracking
377
+ ];
378
+ case 2:
379
+ _a.sent();
380
+ return [4 /*yield*/, postV1(makeV1Shipped({
381
+ patientID: healthieId1,
382
+ orderNumber: reshipOrderNum,
383
+ track_number: 'TRACK-SECOND',
384
+ shipped_date: '2024-07-15',
385
+ }))];
386
+ case 3:
387
+ res = _a.sent();
388
+ (0, testing_1.assert)(res.status === 200, "Expected 200, got ".concat(res.status));
389
+ return [4 /*yield*/, sdk.api.enduser_orders.getSome({
390
+ filter: { source: 'OpenLoop', externalId: reshipOrderNum }
391
+ })];
392
+ case 4:
393
+ orders = _a.sent();
394
+ (0, testing_1.assert)(orders.length === 1, "Expected 1 order, got ".concat(orders.length));
395
+ (0, testing_1.assert)(orders[0].tracking === 'TRACK-SECOND', "tracking should be updated: ".concat(orders[0].tracking));
396
+ (0, testing_1.assert)(orders[0].shippedDate === '07-15-2024', "shippedDate should be updated: ".concat(orders[0].shippedDate));
397
+ return [2 /*return*/, true];
398
+ }
399
+ });
400
+ }); }, { onResult: function (r) { return r === true; } })
401
+ // ===== SECTION D: V1 enduserId Isolation =====
402
+ ];
403
+ case 12:
404
+ _b.sent();
405
+ // ===== SECTION D: V1 enduserId Isolation =====
406
+ (0, testing_1.log_header)("V1 enduserId Isolation");
407
+ return [4 /*yield*/, (0, testing_1.async_test)('V1: same orderNumber for different endusers creates separate orders', function () { return __awaiter(void 0, void 0, void 0, function () {
408
+ var sharedOrderNum, res1, res2, orders, enduserIds, expected;
409
+ return __generator(this, function (_a) {
410
+ switch (_a.label) {
411
+ case 0:
412
+ sharedOrderNum = "ol-shared-".concat(uid());
413
+ return [4 /*yield*/, postV1(makeV1Confirmation({
414
+ patientID: healthieId1,
415
+ orderNumber: sharedOrderNum,
416
+ }))];
417
+ case 1:
418
+ res1 = _a.sent();
419
+ (0, testing_1.assert)(res1.status === 200, "enduser1 confirm failed: ".concat(res1.status));
420
+ return [4 /*yield*/, postV1(makeV1Confirmation({
421
+ patientID: healthieId2,
422
+ orderNumber: sharedOrderNum,
423
+ }))];
424
+ case 2:
425
+ res2 = _a.sent();
426
+ (0, testing_1.assert)(res2.status === 200, "enduser2 confirm failed: ".concat(res2.status));
427
+ return [4 /*yield*/, sdk.api.enduser_orders.getSome({
428
+ filter: { source: 'OpenLoop', externalId: sharedOrderNum }
429
+ })];
430
+ case 3:
431
+ orders = _a.sent();
432
+ (0, testing_1.assert)(orders.length === 2, "Expected 2 separate orders, got ".concat(orders.length));
433
+ enduserIds = orders.map(function (o) { return o.enduserId; }).sort();
434
+ expected = [enduser1.id, enduser2.id].sort();
435
+ (0, testing_1.assert)(enduserIds[0] === expected[0] && enduserIds[1] === expected[1], "Orders should belong to different endusers: ".concat(JSON.stringify(enduserIds), " vs ").concat(JSON.stringify(expected)));
436
+ return [2 /*return*/, true];
437
+ }
438
+ });
439
+ }); }, { onResult: function (r) { return r === true; } })
440
+ // ===== SECTION E: V2 Validation =====
441
+ ];
442
+ case 13:
443
+ _b.sent();
444
+ // ===== SECTION E: V2 Validation =====
445
+ (0, testing_1.log_header)("V2 Validation");
446
+ return [4 /*yield*/, (0, testing_1.async_test)('V2: missing patientId returns 400', function () { return __awaiter(void 0, void 0, void 0, function () {
447
+ var res;
448
+ return __generator(this, function (_a) {
449
+ switch (_a.label) {
450
+ case 0: return [4 /*yield*/, postV2({
451
+ id: 'test', eventType: 'prescription-created', medication: 'x',
452
+ medicationSku: 'x', fill: '1', prescriptionCreatedDate: '2024-01-01',
453
+ })];
454
+ case 1:
455
+ res = _a.sent();
456
+ return [2 /*return*/, res.status];
457
+ }
458
+ });
459
+ }); }, { onResult: function (s) { return s === 400; } })];
460
+ case 14:
461
+ _b.sent();
462
+ return [4 /*yield*/, (0, testing_1.async_test)('V2: invalid eventType returns 400', function () { return __awaiter(void 0, void 0, void 0, function () {
463
+ var res;
464
+ return __generator(this, function (_a) {
465
+ switch (_a.label) {
466
+ case 0: return [4 /*yield*/, postV2(makeV2Payload('invalid-event-type'))];
467
+ case 1:
468
+ res = _a.sent();
469
+ return [2 /*return*/, res.status];
470
+ }
471
+ });
472
+ }); }, { onResult: function (s) { return s === 400; } })];
473
+ case 15:
474
+ _b.sent();
475
+ return [4 /*yield*/, (0, testing_1.async_test)('V2: unknown patient returns 404', function () { return __awaiter(void 0, void 0, void 0, function () {
476
+ var res;
477
+ return __generator(this, function (_a) {
478
+ switch (_a.label) {
479
+ case 0: return [4 /*yield*/, postV2(makeV2Payload('prescription-created', { patientId: 'nonexistent-v2' }))];
480
+ case 1:
481
+ res = _a.sent();
482
+ return [2 /*return*/, res.status];
483
+ }
484
+ });
485
+ }); }, { onResult: function (s) { return s === 404; } })
486
+ // ===== SECTION F: V2 Order Lifecycle =====
487
+ ];
488
+ case 16:
489
+ _b.sent();
490
+ // ===== SECTION F: V2 Order Lifecycle =====
491
+ (0, testing_1.log_header)("V2 Order Lifecycle");
492
+ v2OrderId_1 = "v2-lifecycle-".concat(uid());
493
+ return [4 /*yield*/, (0, testing_1.async_test)('V2: prescription-created creates order with correct fields', function () { return __awaiter(void 0, void 0, void 0, function () {
494
+ var res, orders, order;
495
+ return __generator(this, function (_a) {
496
+ switch (_a.label) {
497
+ case 0: return [4 /*yield*/, postV2(makeV2Payload('prescription-created', {
498
+ id: v2OrderId_1,
499
+ patientId: healthieId1,
500
+ medication: 'Lisinopril 10mg',
501
+ medicationSku: 'LIS-010',
502
+ fill: '2',
503
+ }))];
504
+ case 1:
505
+ res = _a.sent();
506
+ (0, testing_1.assert)(res.status === 200, "Expected 200, got ".concat(res.status));
507
+ return [4 /*yield*/, sdk.api.enduser_orders.getSome({
508
+ filter: { source: 'OpenLoop', externalId: v2OrderId_1 }
509
+ })];
510
+ case 2:
511
+ orders = _a.sent();
512
+ (0, testing_1.assert)(orders.length === 1, "Expected 1 order, got ".concat(orders.length));
513
+ order = orders[0];
514
+ (0, testing_1.assert)(order.enduserId === enduser1.id, 'enduserId mismatch');
515
+ (0, testing_1.assert)(order.status === 'created', "status mismatch: ".concat(order.status));
516
+ (0, testing_1.assert)(order.title === 'Lisinopril 10mg', "title mismatch: ".concat(order.title));
517
+ (0, testing_1.assert)(order.fill === '2', "fill mismatch: ".concat(order.fill));
518
+ (0, testing_1.assert)(order.sku === 'lis-010', "sku mismatch (should be lowercased): ".concat(order.sku));
519
+ return [2 /*return*/, true];
520
+ }
521
+ });
522
+ }); }, { onResult: function (r) { return r === true; } })];
523
+ case 17:
524
+ _b.sent();
525
+ return [4 /*yield*/, (0, testing_1.async_test)('V2: prescription-shipped updates with carrier and tracking', function () { return __awaiter(void 0, void 0, void 0, function () {
526
+ var res, orders, order;
527
+ return __generator(this, function (_a) {
528
+ switch (_a.label) {
529
+ case 0: return [4 /*yield*/, postV2(makeV2Payload('prescription-shipped', {
530
+ id: v2OrderId_1,
531
+ patientId: healthieId1,
532
+ carrier: 'USPS',
533
+ carrierTrackingId: 'V2-TRACK-001',
534
+ prescriptionCarrierDate: '2024-02-20',
535
+ pharmacy: 'CVS',
536
+ }))];
537
+ case 1:
538
+ res = _a.sent();
539
+ (0, testing_1.assert)(res.status === 200, "Expected 200, got ".concat(res.status));
540
+ return [4 /*yield*/, sdk.api.enduser_orders.getSome({
541
+ filter: { source: 'OpenLoop', externalId: v2OrderId_1 }
542
+ })];
543
+ case 2:
544
+ orders = _a.sent();
545
+ (0, testing_1.assert)(orders.length === 1, "Expected 1 order, got ".concat(orders.length));
546
+ order = orders[0];
547
+ (0, testing_1.assert)(order.status === 'shipped', "status mismatch: ".concat(order.status));
548
+ (0, testing_1.assert)(order.carrier === 'USPS', "carrier mismatch: ".concat(order.carrier));
549
+ (0, testing_1.assert)(order.tracking === 'V2-TRACK-001', "tracking mismatch: ".concat(order.tracking));
550
+ (0, testing_1.assert)(order.shippedDate === '2024-02-20', "shippedDate mismatch: ".concat(order.shippedDate));
551
+ (0, testing_1.assert)(order.pharmacy === 'CVS', "pharmacy mismatch: ".concat(order.pharmacy));
552
+ return [2 /*return*/, true];
553
+ }
554
+ });
555
+ }); }, { onResult: function (r) { return r === true; } })];
556
+ case 18:
557
+ _b.sent();
558
+ v2CancelId_1 = "v2-cancel-".concat(uid());
559
+ return [4 /*yield*/, (0, testing_1.async_test)('V2: prescription-cancelled sets cancelledDate and reason', function () { return __awaiter(void 0, void 0, void 0, function () {
560
+ var res, orders, order;
561
+ return __generator(this, function (_a) {
562
+ switch (_a.label) {
563
+ case 0:
564
+ // Create first
565
+ return [4 /*yield*/, postV2(makeV2Payload('prescription-created', {
566
+ id: v2CancelId_1,
567
+ patientId: healthieId1,
568
+ }))
569
+ // Cancel
570
+ ];
571
+ case 1:
572
+ // Create first
573
+ _a.sent();
574
+ return [4 /*yield*/, postV2(makeV2Payload('prescription-cancelled', {
575
+ id: v2CancelId_1,
576
+ patientId: healthieId1,
577
+ prescriptionCancelledDate: '2024-03-01',
578
+ prescriptionCancellationReason: 'Patient request',
579
+ }))];
580
+ case 2:
581
+ res = _a.sent();
582
+ (0, testing_1.assert)(res.status === 200, "Expected 200, got ".concat(res.status));
583
+ return [4 /*yield*/, sdk.api.enduser_orders.getSome({
584
+ filter: { source: 'OpenLoop', externalId: v2CancelId_1 }
585
+ })];
586
+ case 3:
587
+ orders = _a.sent();
588
+ (0, testing_1.assert)(orders.length === 1, "Expected 1 order, got ".concat(orders.length));
589
+ order = orders[0];
590
+ (0, testing_1.assert)(order.status === 'cancelled', "status mismatch: ".concat(order.status));
591
+ (0, testing_1.assert)(order.cancelledDate === '2024-03-01', "cancelledDate mismatch: ".concat(order.cancelledDate));
592
+ (0, testing_1.assert)(order.cancellationReason === 'Patient request', "cancellationReason mismatch: ".concat(order.cancellationReason));
593
+ return [2 /*return*/, true];
594
+ }
595
+ });
596
+ }); }, { onResult: function (r) { return r === true; } })];
597
+ case 19:
598
+ _b.sent();
599
+ v2RefundId_1 = "v2-refund-".concat(uid());
600
+ return [4 /*yield*/, (0, testing_1.async_test)('V2: prescription-refunded sets status', function () { return __awaiter(void 0, void 0, void 0, function () {
601
+ var res, orders;
602
+ return __generator(this, function (_a) {
603
+ switch (_a.label) {
604
+ case 0: return [4 /*yield*/, postV2(makeV2Payload('prescription-created', {
605
+ id: v2RefundId_1,
606
+ patientId: healthieId1,
607
+ }))];
608
+ case 1:
609
+ _a.sent();
610
+ return [4 /*yield*/, postV2(makeV2Payload('prescription-refunded', {
611
+ id: v2RefundId_1,
612
+ patientId: healthieId1,
613
+ prescriptionRefundedDate: '2024-04-01',
614
+ }))];
615
+ case 2:
616
+ res = _a.sent();
617
+ (0, testing_1.assert)(res.status === 200, "Expected 200, got ".concat(res.status));
618
+ return [4 /*yield*/, sdk.api.enduser_orders.getSome({
619
+ filter: { source: 'OpenLoop', externalId: v2RefundId_1 }
620
+ })];
621
+ case 3:
622
+ orders = _a.sent();
623
+ (0, testing_1.assert)(orders.length === 1, "Expected 1 order, got ".concat(orders.length));
624
+ (0, testing_1.assert)(orders[0].status === 'refunded', "status mismatch: ".concat(orders[0].status));
625
+ return [2 /*return*/, true];
626
+ }
627
+ });
628
+ }); }, { onResult: function (r) { return r === true; } })
629
+ // ===== SECTION G: V2 Idempotency & Isolation =====
630
+ ];
631
+ case 20:
632
+ _b.sent();
633
+ // ===== SECTION G: V2 Idempotency & Isolation =====
634
+ (0, testing_1.log_header)("V2 Idempotency & Isolation");
635
+ return [4 /*yield*/, (0, testing_1.async_test)('V2: idempotency - same id and patientId does not create duplicate', function () { return __awaiter(void 0, void 0, void 0, function () {
636
+ var idempotentId, orders;
637
+ return __generator(this, function (_a) {
638
+ switch (_a.label) {
639
+ case 0:
640
+ idempotentId = "v2-idemp-".concat(uid());
641
+ return [4 /*yield*/, postV2(makeV2Payload('prescription-created', {
642
+ id: idempotentId,
643
+ patientId: healthieId1,
644
+ }))];
645
+ case 1:
646
+ _a.sent();
647
+ return [4 /*yield*/, postV2(makeV2Payload('prescription-created', {
648
+ id: idempotentId,
649
+ patientId: healthieId1,
650
+ }))];
651
+ case 2:
652
+ _a.sent();
653
+ return [4 /*yield*/, sdk.api.enduser_orders.getSome({
654
+ filter: { source: 'OpenLoop', externalId: idempotentId }
655
+ })];
656
+ case 3:
657
+ orders = _a.sent();
658
+ (0, testing_1.assert)(orders.length === 1, "Expected 1 order after duplicate, got ".concat(orders.length));
659
+ return [2 /*return*/, true];
660
+ }
661
+ });
662
+ }); }, { onResult: function (r) { return r === true; } })];
663
+ case 21:
664
+ _b.sent();
665
+ return [4 /*yield*/, (0, testing_1.async_test)('V2: same id for different patients creates separate orders', function () { return __awaiter(void 0, void 0, void 0, function () {
666
+ var sharedV2Id, res1, res2, orders, enduserIds, expected;
667
+ return __generator(this, function (_a) {
668
+ switch (_a.label) {
669
+ case 0:
670
+ sharedV2Id = "v2-shared-".concat(uid());
671
+ return [4 /*yield*/, postV2(makeV2Payload('prescription-created', {
672
+ id: sharedV2Id,
673
+ patientId: healthieId1,
674
+ }))];
675
+ case 1:
676
+ res1 = _a.sent();
677
+ (0, testing_1.assert)(res1.status === 200, "enduser1 create failed: ".concat(res1.status));
678
+ return [4 /*yield*/, postV2(makeV2Payload('prescription-created', {
679
+ id: sharedV2Id,
680
+ patientId: healthieId2,
681
+ }))];
682
+ case 2:
683
+ res2 = _a.sent();
684
+ (0, testing_1.assert)(res2.status === 200, "enduser2 create failed: ".concat(res2.status));
685
+ return [4 /*yield*/, sdk.api.enduser_orders.getSome({
686
+ filter: { source: 'OpenLoop', externalId: sharedV2Id }
687
+ })];
688
+ case 3:
689
+ orders = _a.sent();
690
+ (0, testing_1.assert)(orders.length === 2, "Expected 2 separate orders, got ".concat(orders.length));
691
+ enduserIds = orders.map(function (o) { return o.enduserId; }).sort();
692
+ expected = [enduser1.id, enduser2.id].sort();
693
+ (0, testing_1.assert)(enduserIds[0] === expected[0] && enduserIds[1] === expected[1], "Orders should belong to different endusers");
694
+ return [2 /*return*/, true];
695
+ }
696
+ });
697
+ }); }, { onResult: function (r) { return r === true; } })
698
+ // ===== SECTION H: V2 Full Lifecycle =====
699
+ ];
700
+ case 22:
701
+ _b.sent();
702
+ // ===== SECTION H: V2 Full Lifecycle =====
703
+ (0, testing_1.log_header)("V2 Full Lifecycle");
704
+ return [4 /*yield*/, (0, testing_1.async_test)('V2: sequential status progression through full lifecycle', function () { return __awaiter(void 0, void 0, void 0, function () {
705
+ var lifecycleId, base, steps, _i, steps_1, step, res, orders;
706
+ return __generator(this, function (_a) {
707
+ switch (_a.label) {
708
+ case 0:
709
+ lifecycleId = "v2-full-".concat(uid());
710
+ base = { id: lifecycleId, patientId: healthieId1 };
711
+ steps = [
712
+ { eventType: 'prescription-created', expectedStatus: 'created' },
713
+ { eventType: 'prescription-invoiced', expectedStatus: 'invoiced' },
714
+ { eventType: 'prescription-paid', expectedStatus: 'paid' },
715
+ { eventType: 'prescription-ordered', expectedStatus: 'ordered' },
716
+ { eventType: 'prescription-shipped', expectedStatus: 'shipped', extras: { carrier: 'FedEx', carrierTrackingId: 'FX-999' } },
717
+ ];
718
+ _i = 0, steps_1 = steps;
719
+ _a.label = 1;
720
+ case 1:
721
+ if (!(_i < steps_1.length)) return [3 /*break*/, 5];
722
+ step = steps_1[_i];
723
+ return [4 /*yield*/, postV2(makeV2Payload(step.eventType, __assign(__assign({}, base), (step.extras || {}))))];
724
+ case 2:
725
+ res = _a.sent();
726
+ (0, testing_1.assert)(res.status === 200, "".concat(step.eventType, " failed: ").concat(res.status));
727
+ return [4 /*yield*/, sdk.api.enduser_orders.getSome({
728
+ filter: { source: 'OpenLoop', externalId: lifecycleId }
729
+ })];
730
+ case 3:
731
+ orders = _a.sent();
732
+ (0, testing_1.assert)(orders.length === 1, "Expected 1 order at ".concat(step.eventType, ", got ").concat(orders.length));
733
+ (0, testing_1.assert)(orders[0].status === step.expectedStatus, "After ".concat(step.eventType, ": expected status '").concat(step.expectedStatus, "', got '").concat(orders[0].status, "'"));
734
+ _a.label = 4;
735
+ case 4:
736
+ _i++;
737
+ return [3 /*break*/, 1];
738
+ case 5: return [2 /*return*/, true];
739
+ }
740
+ });
741
+ }); }, { onResult: function (r) { return r === true; } })
742
+ // ===== SECTION I: V2 Undefined Field Handling =====
743
+ ];
744
+ case 23:
745
+ _b.sent();
746
+ // ===== SECTION I: V2 Undefined Field Handling =====
747
+ (0, testing_1.log_header)("V2 Undefined Field Handling");
748
+ return [4 /*yield*/, (0, testing_1.async_test)('V2: optional fields not written when absent', function () { return __awaiter(void 0, void 0, void 0, function () {
749
+ var minimalId, res, orders, order;
750
+ return __generator(this, function (_a) {
751
+ switch (_a.label) {
752
+ case 0:
753
+ minimalId = "v2-minimal-".concat(uid());
754
+ return [4 /*yield*/, postV2({
755
+ id: minimalId,
756
+ client: 'test',
757
+ eventId: "evt-".concat(uid()),
758
+ eventType: 'prescription-created',
759
+ chartId: 'chart-1',
760
+ patientId: healthieId1,
761
+ providerId: 'prov-1',
762
+ medication: 'Minimal Med',
763
+ medicationSku: 'min-sku',
764
+ fill: '1',
765
+ prescriptionCreatedDate: '2024-01-01',
766
+ // Intentionally omitting: pharmacy, carrier, carrierTrackingId,
767
+ // prescriptionCancelledDate, prescriptionCancellationReason, etc.
768
+ })];
769
+ case 1:
770
+ res = _a.sent();
771
+ (0, testing_1.assert)(res.status === 200, "Expected 200, got ".concat(res.status));
772
+ return [4 /*yield*/, sdk.api.enduser_orders.getSome({
773
+ filter: { source: 'OpenLoop', externalId: minimalId }
774
+ })];
775
+ case 2:
776
+ orders = _a.sent();
777
+ (0, testing_1.assert)(orders.length === 1, "Expected 1 order, got ".concat(orders.length));
778
+ order = orders[0];
779
+ (0, testing_1.assert)(order.carrier === undefined, "carrier should be undefined, got: ".concat(order.carrier));
780
+ (0, testing_1.assert)(order.tracking === undefined, "tracking should be undefined, got: ".concat(order.tracking));
781
+ (0, testing_1.assert)(order.pharmacy === undefined, "pharmacy should be undefined, got: ".concat(order.pharmacy));
782
+ (0, testing_1.assert)(order.cancelledDate === undefined, "cancelledDate should be undefined, got: ".concat(order.cancelledDate));
783
+ (0, testing_1.assert)(order.cancellationReason === undefined, "cancellationReason should be undefined, got: ".concat(order.cancellationReason));
784
+ return [2 /*return*/, true];
785
+ }
786
+ });
787
+ }); }, { onResult: function (r) { return r === true; } })];
788
+ case 24:
789
+ _b.sent();
790
+ console.log("All OpenLoop webhook tests passed!");
791
+ return [3 /*break*/, 28];
792
+ case 25: return [4 /*yield*/, sdk.api.endusers.deleteOne(enduser1.id).catch(console.error)];
793
+ case 26:
794
+ _b.sent();
795
+ return [4 /*yield*/, sdk.api.endusers.deleteOne(enduser2.id).catch(console.error)];
796
+ case 27:
797
+ _b.sent();
798
+ return [7 /*endfinally*/];
799
+ case 28: return [2 /*return*/];
800
+ }
801
+ });
802
+ });
803
+ };
804
+ exports.openloop_webhooks_tests = openloop_webhooks_tests;
805
+ // Allow running this test file independently
806
+ if (require.main === module) {
807
+ console.log("Using API URL: ".concat(host));
808
+ var sdk_2 = new sdk_1.Session({ host: host });
809
+ var sdkNonAdmin_1 = new sdk_1.Session({ host: host });
810
+ var runTests = function () { return __awaiter(void 0, void 0, void 0, function () {
811
+ return __generator(this, function (_a) {
812
+ switch (_a.label) {
813
+ case 0: return [4 /*yield*/, (0, setup_1.setup_tests)(sdk_2, sdkNonAdmin_1)];
814
+ case 1:
815
+ _a.sent();
816
+ return [4 /*yield*/, (0, exports.openloop_webhooks_tests)({ sdk: sdk_2, sdkNonAdmin: sdkNonAdmin_1 })];
817
+ case 2:
818
+ _a.sent();
819
+ return [2 /*return*/];
820
+ }
821
+ });
822
+ }); };
823
+ runTests()
824
+ .then(function () {
825
+ console.log("OpenLoop webhooks test suite completed successfully");
826
+ process.exit(0);
827
+ })
828
+ .catch(function (error) {
829
+ console.error("OpenLoop webhooks test suite failed:", error);
830
+ process.exit(1);
831
+ });
832
+ }
833
+ //# sourceMappingURL=openloop_webhooks.test.js.map