@tellescope/sdk 1.236.0 → 1.236.2

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 (32) hide show
  1. package/lib/cjs/enduser.d.ts +20 -0
  2. package/lib/cjs/enduser.d.ts.map +1 -1
  3. package/lib/cjs/sdk.d.ts +43 -0
  4. package/lib/cjs/sdk.d.ts.map +1 -1
  5. package/lib/cjs/sdk.js +1 -0
  6. package/lib/cjs/sdk.js.map +1 -1
  7. package/lib/cjs/tests/api_tests/auto_merge_form_submission.test.d.ts +9 -0
  8. package/lib/cjs/tests/api_tests/auto_merge_form_submission.test.d.ts.map +1 -0
  9. package/lib/cjs/tests/api_tests/auto_merge_form_submission.test.js +1399 -0
  10. package/lib/cjs/tests/api_tests/auto_merge_form_submission.test.js.map +1 -0
  11. package/lib/cjs/tests/tests.d.ts.map +1 -1
  12. package/lib/cjs/tests/tests.js +214 -122
  13. package/lib/cjs/tests/tests.js.map +1 -1
  14. package/lib/esm/enduser.d.ts +20 -0
  15. package/lib/esm/enduser.d.ts.map +1 -1
  16. package/lib/esm/sdk.d.ts +43 -0
  17. package/lib/esm/sdk.d.ts.map +1 -1
  18. package/lib/esm/sdk.js +1 -0
  19. package/lib/esm/sdk.js.map +1 -1
  20. package/lib/esm/tests/api_tests/auto_merge_form_submission.test.d.ts +9 -0
  21. package/lib/esm/tests/api_tests/auto_merge_form_submission.test.d.ts.map +1 -0
  22. package/lib/esm/tests/api_tests/auto_merge_form_submission.test.js +1372 -0
  23. package/lib/esm/tests/api_tests/auto_merge_form_submission.test.js.map +1 -0
  24. package/lib/esm/tests/tests.d.ts.map +1 -1
  25. package/lib/esm/tests/tests.js +214 -122
  26. package/lib/esm/tests/tests.js.map +1 -1
  27. package/lib/tsconfig.tsbuildinfo +1 -1
  28. package/package.json +10 -10
  29. package/src/sdk.ts +3 -2
  30. package/src/tests/api_tests/auto_merge_form_submission.test.ts +876 -0
  31. package/src/tests/tests.ts +76 -5
  32. package/test_generated.pdf +0 -0
@@ -0,0 +1,1399 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
+ return new (P || (P = Promise))(function (resolve, reject) {
28
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
32
+ });
33
+ };
34
+ var __generator = (this && this.__generator) || function (thisArg, body) {
35
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
36
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
37
+ function verb(n) { return function (v) { return step([n, v]); }; }
38
+ function step(op) {
39
+ if (f) throw new TypeError("Generator is already executing.");
40
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
41
+ 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;
42
+ if (y = 0, t) op = [op[0] & 2, t.value];
43
+ switch (op[0]) {
44
+ case 0: case 1: t = op; break;
45
+ case 4: _.label++; return { value: op[1], done: false };
46
+ case 5: _.label++; y = op[1]; op = [0]; continue;
47
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
48
+ default:
49
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
50
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
51
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
52
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
53
+ if (t[2]) _.ops.pop();
54
+ _.trys.pop(); continue;
55
+ }
56
+ op = body.call(thisArg, _);
57
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
58
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
59
+ }
60
+ };
61
+ Object.defineProperty(exports, "__esModule", { value: true });
62
+ exports.auto_merge_form_submission_tests = void 0;
63
+ require('source-map-support').install();
64
+ var buffer = __importStar(require("buffer"));
65
+ var sdk_1 = require("../../sdk");
66
+ var testing_1 = require("@tellescope/testing");
67
+ var setup_1 = require("../setup");
68
+ var host = process.env.API_URL || 'http://localhost:8080';
69
+ /**
70
+ * Helper: Create a form with auto-merge enabled and intake fields
71
+ */
72
+ var createAutoMergeForm = function (sdk, autoMergeOnSubmission) {
73
+ if (autoMergeOnSubmission === void 0) { autoMergeOnSubmission = true; }
74
+ return __awaiter(void 0, void 0, void 0, function () {
75
+ var form, fnameField, lnameField, emailField, phoneField, dobField, fields;
76
+ return __generator(this, function (_a) {
77
+ switch (_a.label) {
78
+ case 0: return [4 /*yield*/, sdk.api.forms.createOne({
79
+ title: 'Auto Merge Test Form',
80
+ allowPublicURL: true,
81
+ autoMergeOnSubmission: autoMergeOnSubmission,
82
+ })
83
+ // Add intake fields - must create sequentially due to previousFields dependencies
84
+ ];
85
+ case 1:
86
+ form = _a.sent();
87
+ return [4 /*yield*/, sdk.api.form_fields.createOne({
88
+ formId: form.id,
89
+ title: 'First Name',
90
+ type: 'string',
91
+ intakeField: 'fname',
92
+ previousFields: [{ type: 'root', info: {} }]
93
+ })];
94
+ case 2:
95
+ fnameField = _a.sent();
96
+ return [4 /*yield*/, sdk.api.form_fields.createOne({
97
+ formId: form.id,
98
+ title: 'Last Name',
99
+ type: 'string',
100
+ intakeField: 'lname',
101
+ previousFields: [{ type: 'after', info: { fieldId: fnameField.id } }]
102
+ })];
103
+ case 3:
104
+ lnameField = _a.sent();
105
+ return [4 /*yield*/, sdk.api.form_fields.createOne({
106
+ formId: form.id,
107
+ title: 'Email',
108
+ type: 'email',
109
+ intakeField: 'email',
110
+ previousFields: [{ type: 'after', info: { fieldId: lnameField.id } }]
111
+ })];
112
+ case 4:
113
+ emailField = _a.sent();
114
+ return [4 /*yield*/, sdk.api.form_fields.createOne({
115
+ formId: form.id,
116
+ title: 'Phone',
117
+ type: 'phone',
118
+ intakeField: 'phone',
119
+ previousFields: [{ type: 'after', info: { fieldId: emailField.id } }]
120
+ })];
121
+ case 5:
122
+ phoneField = _a.sent();
123
+ return [4 /*yield*/, sdk.api.form_fields.createOne({
124
+ formId: form.id,
125
+ title: 'Date of Birth',
126
+ type: 'dateString',
127
+ intakeField: 'dateOfBirth',
128
+ previousFields: [{ type: 'after', info: { fieldId: phoneField.id } }]
129
+ })];
130
+ case 6:
131
+ dobField = _a.sent();
132
+ fields = [fnameField, lnameField, emailField, phoneField, dobField];
133
+ return [2 /*return*/, { form: form, fields: fields }];
134
+ }
135
+ });
136
+ });
137
+ };
138
+ /**
139
+ * Helper: Submit a public form with skipMatch and get the created enduser ID
140
+ */
141
+ var submitPublicFormWithSkipMatch = function (form, fields, values) { return __awaiter(void 0, void 0, void 0, function () {
142
+ var enduserSDK, _a, authToken, accessCode, enduserId, authedSDK, responses, fnameField, lnameField, emailField, phoneField, dobField;
143
+ return __generator(this, function (_b) {
144
+ switch (_b.label) {
145
+ case 0:
146
+ enduserSDK = new sdk_1.EnduserSession({ host: host, businessId: form.businessId });
147
+ return [4 /*yield*/, enduserSDK.api.form_responses.session_for_public_form({
148
+ formId: form.id,
149
+ businessId: form.businessId,
150
+ skipMatch: true,
151
+ })];
152
+ case 1:
153
+ _a = _b.sent(), authToken = _a.authToken, accessCode = _a.accessCode, enduserId = _a.enduserId;
154
+ authedSDK = new sdk_1.EnduserSession({ host: host, businessId: form.businessId, authToken: authToken });
155
+ responses = [];
156
+ fnameField = fields.find(function (f) { return f.intakeField === 'fname'; });
157
+ lnameField = fields.find(function (f) { return f.intakeField === 'lname'; });
158
+ emailField = fields.find(function (f) { return f.intakeField === 'email'; });
159
+ phoneField = fields.find(function (f) { return f.intakeField === 'phone'; });
160
+ dobField = fields.find(function (f) { return f.intakeField === 'dateOfBirth'; });
161
+ if (values.fname && fnameField) {
162
+ responses.push({ fieldId: fnameField.id, fieldTitle: fnameField.title, answer: { type: 'string', value: values.fname } });
163
+ }
164
+ if (values.lname && lnameField) {
165
+ responses.push({ fieldId: lnameField.id, fieldTitle: lnameField.title, answer: { type: 'string', value: values.lname } });
166
+ }
167
+ if (values.email && emailField) {
168
+ responses.push({ fieldId: emailField.id, fieldTitle: emailField.title, answer: { type: 'email', value: values.email } });
169
+ }
170
+ if (values.phone && phoneField) {
171
+ responses.push({ fieldId: phoneField.id, fieldTitle: phoneField.title, answer: { type: 'phone', value: values.phone } });
172
+ }
173
+ if (values.dateOfBirth && dobField) {
174
+ responses.push({ fieldId: dobField.id, fieldTitle: dobField.title, answer: { type: 'dateString', value: values.dateOfBirth } });
175
+ }
176
+ return [4 /*yield*/, authedSDK.api.form_responses.submit_form_response({
177
+ accessCode: accessCode,
178
+ responses: responses,
179
+ })];
180
+ case 2:
181
+ _b.sent();
182
+ return [2 /*return*/, { enduserId: enduserId, accessCode: accessCode, authedSDK: authedSDK }];
183
+ }
184
+ });
185
+ }); };
186
+ /**
187
+ * Helper: Check if enduser has been deleted (immediate check, no polling)
188
+ * Since auto-merge is now synchronous, we don't need to poll
189
+ */
190
+ var isEnduserDeleted = function (sdk, enduserId) { return __awaiter(void 0, void 0, void 0, function () {
191
+ var _a;
192
+ return __generator(this, function (_b) {
193
+ switch (_b.label) {
194
+ case 0:
195
+ _b.trys.push([0, 2, , 3]);
196
+ return [4 /*yield*/, sdk.api.endusers.getOne(enduserId)];
197
+ case 1:
198
+ _b.sent();
199
+ return [2 /*return*/, false]; // Still exists
200
+ case 2:
201
+ _a = _b.sent();
202
+ return [2 /*return*/, true]; // Deleted
203
+ case 3: return [2 /*return*/];
204
+ }
205
+ });
206
+ }); };
207
+ /**
208
+ * Main test function that can be called independently or as part of the test suite
209
+ */
210
+ var auto_merge_form_submission_tests = function (_a) {
211
+ var sdk = _a.sdk, sdkNonAdmin = _a.sdkNonAdmin;
212
+ return __awaiter(void 0, void 0, void 0, function () {
213
+ return __generator(this, function (_b) {
214
+ switch (_b.label) {
215
+ case 0:
216
+ (0, testing_1.log_header)("Auto-Merge Form Submission Tests");
217
+ // Test 1: Happy Path - Merge by Email Match
218
+ return [4 /*yield*/, (0, testing_1.async_test)("Auto-merge: Merge occurs when matching by email", function () { return __awaiter(void 0, void 0, void 0, function () {
219
+ var testEmail, destination, _a, form, fields, sourceId, sourceDeleted, updatedDestination, formResponses;
220
+ var _b;
221
+ return __generator(this, function (_c) {
222
+ switch (_c.label) {
223
+ case 0:
224
+ testEmail = "automerge.email.".concat(Date.now(), "@test.com");
225
+ return [4 /*yield*/, sdk.api.endusers.createOne({
226
+ fname: 'John',
227
+ lname: 'Doe',
228
+ email: testEmail
229
+ })];
230
+ case 1:
231
+ destination = _c.sent();
232
+ return [4 /*yield*/, createAutoMergeForm(sdk, true)];
233
+ case 2:
234
+ _a = _c.sent(), form = _a.form, fields = _a.fields;
235
+ return [4 /*yield*/, submitPublicFormWithSkipMatch(form, fields, {
236
+ fname: 'John',
237
+ lname: 'Doe',
238
+ email: testEmail,
239
+ })
240
+ // Merge is synchronous - source should be deleted immediately after submission
241
+ ];
242
+ case 3:
243
+ sourceId = (_c.sent()).enduserId;
244
+ return [4 /*yield*/, isEnduserDeleted(sdk, sourceId)];
245
+ case 4:
246
+ sourceDeleted = _c.sent();
247
+ return [4 /*yield*/, sdk.api.endusers.getOne(destination.id)];
248
+ case 5:
249
+ updatedDestination = _c.sent();
250
+ return [4 /*yield*/, sdk.api.form_responses.getSome({ filter: { enduserId: destination.id } })
251
+ // Cleanup
252
+ ];
253
+ case 6:
254
+ formResponses = _c.sent();
255
+ // Cleanup
256
+ return [4 /*yield*/, sdk.api.forms.deleteOne(form.id)];
257
+ case 7:
258
+ // Cleanup
259
+ _c.sent();
260
+ return [4 /*yield*/, sdk.api.endusers.deleteOne(destination.id)];
261
+ case 8:
262
+ _c.sent();
263
+ return [2 /*return*/, sourceDeleted
264
+ && ((_b = updatedDestination.mergedIds) === null || _b === void 0 ? void 0 : _b.includes(sourceId))
265
+ && formResponses.length === 1];
266
+ }
267
+ });
268
+ }); }, { expectedResult: true })
269
+ // Test 2: Happy Path - Merge by Phone Match
270
+ ];
271
+ case 1:
272
+ // Test 1: Happy Path - Merge by Email Match
273
+ _b.sent();
274
+ // Test 2: Happy Path - Merge by Phone Match
275
+ return [4 /*yield*/, (0, testing_1.async_test)("Auto-merge: Merge occurs when matching by phone", function () { return __awaiter(void 0, void 0, void 0, function () {
276
+ var testPhone, destination, _a, form, fields, sourceId, sourceDeleted, updatedDestination;
277
+ var _b;
278
+ return __generator(this, function (_c) {
279
+ switch (_c.label) {
280
+ case 0:
281
+ testPhone = '+15555551234';
282
+ return [4 /*yield*/, sdk.api.endusers.createOne({
283
+ fname: 'Jane',
284
+ lname: 'Smith',
285
+ phone: testPhone
286
+ })];
287
+ case 1:
288
+ destination = _c.sent();
289
+ return [4 /*yield*/, createAutoMergeForm(sdk, true)];
290
+ case 2:
291
+ _a = _c.sent(), form = _a.form, fields = _a.fields;
292
+ return [4 /*yield*/, submitPublicFormWithSkipMatch(form, fields, {
293
+ fname: 'Jane',
294
+ lname: 'Smith',
295
+ phone: testPhone,
296
+ })
297
+ // Merge is synchronous - source should be deleted immediately after submission
298
+ ];
299
+ case 3:
300
+ sourceId = (_c.sent()).enduserId;
301
+ return [4 /*yield*/, isEnduserDeleted(sdk, sourceId)];
302
+ case 4:
303
+ sourceDeleted = _c.sent();
304
+ return [4 /*yield*/, sdk.api.endusers.getOne(destination.id)
305
+ // Cleanup
306
+ ];
307
+ case 5:
308
+ updatedDestination = _c.sent();
309
+ // Cleanup
310
+ return [4 /*yield*/, sdk.api.forms.deleteOne(form.id)];
311
+ case 6:
312
+ // Cleanup
313
+ _c.sent();
314
+ return [4 /*yield*/, sdk.api.endusers.deleteOne(destination.id)];
315
+ case 7:
316
+ _c.sent();
317
+ return [2 /*return*/, sourceDeleted && ((_b = updatedDestination.mergedIds) === null || _b === void 0 ? void 0 : _b.includes(sourceId))];
318
+ }
319
+ });
320
+ }); }, { expectedResult: true })
321
+ // Test 3: Happy Path - Merge by DateOfBirth Match
322
+ ];
323
+ case 2:
324
+ // Test 2: Happy Path - Merge by Phone Match
325
+ _b.sent();
326
+ // Test 3: Happy Path - Merge by DateOfBirth Match
327
+ return [4 /*yield*/, (0, testing_1.async_test)("Auto-merge: Merge occurs when matching by dateOfBirth", function () { return __awaiter(void 0, void 0, void 0, function () {
328
+ var testDOB, destination, _a, form, fields, sourceId, sourceDeleted, updatedDestination;
329
+ var _b;
330
+ return __generator(this, function (_c) {
331
+ switch (_c.label) {
332
+ case 0:
333
+ testDOB = '1990-05-15';
334
+ return [4 /*yield*/, sdk.api.endusers.createOne({
335
+ fname: 'Bob',
336
+ lname: 'Johnson',
337
+ dateOfBirth: testDOB
338
+ })];
339
+ case 1:
340
+ destination = _c.sent();
341
+ return [4 /*yield*/, createAutoMergeForm(sdk, true)];
342
+ case 2:
343
+ _a = _c.sent(), form = _a.form, fields = _a.fields;
344
+ return [4 /*yield*/, submitPublicFormWithSkipMatch(form, fields, {
345
+ fname: 'Bob',
346
+ lname: 'Johnson',
347
+ dateOfBirth: testDOB,
348
+ })
349
+ // Merge is synchronous - source should be deleted immediately after submission
350
+ ];
351
+ case 3:
352
+ sourceId = (_c.sent()).enduserId;
353
+ return [4 /*yield*/, isEnduserDeleted(sdk, sourceId)];
354
+ case 4:
355
+ sourceDeleted = _c.sent();
356
+ return [4 /*yield*/, sdk.api.endusers.getOne(destination.id)
357
+ // Cleanup
358
+ ];
359
+ case 5:
360
+ updatedDestination = _c.sent();
361
+ // Cleanup
362
+ return [4 /*yield*/, sdk.api.forms.deleteOne(form.id)];
363
+ case 6:
364
+ // Cleanup
365
+ _c.sent();
366
+ return [4 /*yield*/, sdk.api.endusers.deleteOne(destination.id)];
367
+ case 7:
368
+ _c.sent();
369
+ return [2 /*return*/, sourceDeleted && ((_b = updatedDestination.mergedIds) === null || _b === void 0 ? void 0 : _b.includes(sourceId))];
370
+ }
371
+ });
372
+ }); }, { expectedResult: true })
373
+ // Test 4: No Merge - Multiple Matches
374
+ ];
375
+ case 3:
376
+ // Test 3: Happy Path - Merge by DateOfBirth Match
377
+ _b.sent();
378
+ // Test 4: No Merge - Multiple Matches
379
+ return [4 /*yield*/, (0, testing_1.async_test)("Auto-merge: No merge when multiple matches found", function () { return __awaiter(void 0, void 0, void 0, function () {
380
+ var testDOB, destination1, destination2, _a, form, fields, sourceId, sourceDeleted, dest1, dest2;
381
+ var _b, _c;
382
+ return __generator(this, function (_d) {
383
+ switch (_d.label) {
384
+ case 0:
385
+ testDOB = '1975-01-15';
386
+ return [4 /*yield*/, sdk.api.endusers.createOne({
387
+ fname: 'Multi',
388
+ lname: 'Match',
389
+ dateOfBirth: testDOB
390
+ })];
391
+ case 1:
392
+ destination1 = _d.sent();
393
+ return [4 /*yield*/, sdk.api.endusers.createOne({
394
+ fname: 'Multi',
395
+ lname: 'Match',
396
+ dateOfBirth: testDOB
397
+ })];
398
+ case 2:
399
+ destination2 = _d.sent();
400
+ return [4 /*yield*/, createAutoMergeForm(sdk, true)];
401
+ case 3:
402
+ _a = _d.sent(), form = _a.form, fields = _a.fields;
403
+ return [4 /*yield*/, submitPublicFormWithSkipMatch(form, fields, {
404
+ fname: 'Multi',
405
+ lname: 'Match',
406
+ dateOfBirth: testDOB,
407
+ })
408
+ // Merge is synchronous - no need to wait, source should still exist
409
+ ];
410
+ case 4:
411
+ sourceId = (_d.sent()).enduserId;
412
+ return [4 /*yield*/, isEnduserDeleted(sdk, sourceId)];
413
+ case 5:
414
+ sourceDeleted = _d.sent();
415
+ return [4 /*yield*/, sdk.api.endusers.getOne(destination1.id)];
416
+ case 6:
417
+ dest1 = _d.sent();
418
+ return [4 /*yield*/, sdk.api.endusers.getOne(destination2.id)
419
+ // Cleanup
420
+ ];
421
+ case 7:
422
+ dest2 = _d.sent();
423
+ // Cleanup
424
+ return [4 /*yield*/, sdk.api.forms.deleteOne(form.id)];
425
+ case 8:
426
+ // Cleanup
427
+ _d.sent();
428
+ return [4 /*yield*/, sdk.api.endusers.deleteOne(destination1.id)];
429
+ case 9:
430
+ _d.sent();
431
+ return [4 /*yield*/, sdk.api.endusers.deleteOne(destination2.id)];
432
+ case 10:
433
+ _d.sent();
434
+ if (!!sourceDeleted) return [3 /*break*/, 12];
435
+ return [4 /*yield*/, sdk.api.endusers.deleteOne(sourceId)];
436
+ case 11:
437
+ _d.sent();
438
+ _d.label = 12;
439
+ case 12: return [2 /*return*/, !sourceDeleted // Source should NOT be deleted
440
+ && !((_b = dest1.mergedIds) === null || _b === void 0 ? void 0 : _b.includes(sourceId))
441
+ && !((_c = dest2.mergedIds) === null || _c === void 0 ? void 0 : _c.includes(sourceId))];
442
+ }
443
+ });
444
+ }); }, { expectedResult: true })
445
+ // Test 5: No Merge - autoMergeOnSubmission Disabled
446
+ ];
447
+ case 4:
448
+ // Test 4: No Merge - Multiple Matches
449
+ _b.sent();
450
+ // Test 5: No Merge - autoMergeOnSubmission Disabled
451
+ return [4 /*yield*/, (0, testing_1.async_test)("Auto-merge: No merge when autoMergeOnSubmission is disabled", function () { return __awaiter(void 0, void 0, void 0, function () {
452
+ var testEmail, destination, _a, form, fields, sourceId, sourceDeleted;
453
+ return __generator(this, function (_b) {
454
+ switch (_b.label) {
455
+ case 0:
456
+ testEmail = "automerge.disabled.".concat(Date.now(), "@test.com");
457
+ return [4 /*yield*/, sdk.api.endusers.createOne({
458
+ fname: 'Disabled',
459
+ lname: 'Test',
460
+ email: testEmail
461
+ })];
462
+ case 1:
463
+ destination = _b.sent();
464
+ return [4 /*yield*/, createAutoMergeForm(sdk, false)]; // Disabled
465
+ case 2:
466
+ _a = _b.sent() // Disabled
467
+ , form = _a.form, fields = _a.fields;
468
+ return [4 /*yield*/, submitPublicFormWithSkipMatch(form, fields, {
469
+ fname: 'Disabled',
470
+ lname: 'Test',
471
+ email: testEmail,
472
+ })
473
+ // Merge is synchronous - no need to wait, source should still exist
474
+ ];
475
+ case 3:
476
+ sourceId = (_b.sent()).enduserId;
477
+ return [4 /*yield*/, isEnduserDeleted(sdk, sourceId)
478
+ // Cleanup
479
+ ];
480
+ case 4:
481
+ sourceDeleted = _b.sent();
482
+ // Cleanup
483
+ return [4 /*yield*/, sdk.api.forms.deleteOne(form.id)];
484
+ case 5:
485
+ // Cleanup
486
+ _b.sent();
487
+ return [4 /*yield*/, sdk.api.endusers.deleteOne(destination.id)];
488
+ case 6:
489
+ _b.sent();
490
+ if (!!sourceDeleted) return [3 /*break*/, 8];
491
+ return [4 /*yield*/, sdk.api.endusers.deleteOne(sourceId)];
492
+ case 7:
493
+ _b.sent();
494
+ _b.label = 8;
495
+ case 8: return [2 /*return*/, !sourceDeleted]; // Source should NOT be deleted
496
+ }
497
+ });
498
+ }); }, { expectedResult: true })
499
+ // Test 6: No Merge - No Matching Enduser
500
+ ];
501
+ case 5:
502
+ // Test 5: No Merge - autoMergeOnSubmission Disabled
503
+ _b.sent();
504
+ // Test 6: No Merge - No Matching Enduser
505
+ return [4 /*yield*/, (0, testing_1.async_test)("Auto-merge: No merge when no matching enduser exists", function () { return __awaiter(void 0, void 0, void 0, function () {
506
+ var _a, form, fields, sourceId, sourceDeleted;
507
+ return __generator(this, function (_b) {
508
+ switch (_b.label) {
509
+ case 0: return [4 /*yield*/, createAutoMergeForm(sdk, true)];
510
+ case 1:
511
+ _a = _b.sent(), form = _a.form, fields = _a.fields;
512
+ return [4 /*yield*/, submitPublicFormWithSkipMatch(form, fields, {
513
+ fname: 'NoMatch',
514
+ lname: 'Person',
515
+ email: "nomatch.".concat(Date.now(), "@test.com"),
516
+ })
517
+ // Merge is synchronous - no need to wait, source should still exist (no match found)
518
+ ];
519
+ case 2:
520
+ sourceId = (_b.sent()).enduserId;
521
+ return [4 /*yield*/, isEnduserDeleted(sdk, sourceId)
522
+ // Cleanup
523
+ ];
524
+ case 3:
525
+ sourceDeleted = _b.sent();
526
+ // Cleanup
527
+ return [4 /*yield*/, sdk.api.forms.deleteOne(form.id)];
528
+ case 4:
529
+ // Cleanup
530
+ _b.sent();
531
+ if (!!sourceDeleted) return [3 /*break*/, 6];
532
+ return [4 /*yield*/, sdk.api.endusers.deleteOne(sourceId)];
533
+ case 5:
534
+ _b.sent();
535
+ _b.label = 6;
536
+ case 6: return [2 /*return*/, !sourceDeleted]; // Source should NOT be deleted
537
+ }
538
+ });
539
+ }); }, { expectedResult: true })
540
+ // Test 7: Case Sensitive Matching - No Merge When Case Differs
541
+ ];
542
+ case 6:
543
+ // Test 6: No Merge - No Matching Enduser
544
+ _b.sent();
545
+ // Test 7: Case Sensitive Matching - No Merge When Case Differs
546
+ return [4 /*yield*/, (0, testing_1.async_test)("Auto-merge: No merge when case differs (case-sensitive matching)", function () { return __awaiter(void 0, void 0, void 0, function () {
547
+ var testEmail, destination, _a, form, fields, sourceId, sourceDeleted, updatedDestination;
548
+ var _b;
549
+ return __generator(this, function (_c) {
550
+ switch (_c.label) {
551
+ case 0:
552
+ testEmail = "automerge.case.".concat(Date.now(), "@test.com");
553
+ return [4 /*yield*/, sdk.api.endusers.createOne({
554
+ fname: 'Case',
555
+ lname: 'Test',
556
+ email: testEmail
557
+ })];
558
+ case 1:
559
+ destination = _c.sent();
560
+ return [4 /*yield*/, createAutoMergeForm(sdk, true)
561
+ // Submit with different case - should NOT match due to case-sensitive matching
562
+ ];
563
+ case 2:
564
+ _a = _c.sent(), form = _a.form, fields = _a.fields;
565
+ return [4 /*yield*/, submitPublicFormWithSkipMatch(form, fields, {
566
+ fname: 'CASE',
567
+ lname: 'TEST',
568
+ email: testEmail.toUpperCase(), // Different case
569
+ })
570
+ // Merge is case-sensitive - source should still exist (no match found)
571
+ ];
572
+ case 3:
573
+ sourceId = (_c.sent()).enduserId;
574
+ return [4 /*yield*/, isEnduserDeleted(sdk, sourceId)];
575
+ case 4:
576
+ sourceDeleted = _c.sent();
577
+ return [4 /*yield*/, sdk.api.endusers.getOne(destination.id)
578
+ // Cleanup
579
+ ];
580
+ case 5:
581
+ updatedDestination = _c.sent();
582
+ // Cleanup
583
+ return [4 /*yield*/, sdk.api.forms.deleteOne(form.id)];
584
+ case 6:
585
+ // Cleanup
586
+ _c.sent();
587
+ return [4 /*yield*/, sdk.api.endusers.deleteOne(destination.id)];
588
+ case 7:
589
+ _c.sent();
590
+ if (!!sourceDeleted) return [3 /*break*/, 9];
591
+ return [4 /*yield*/, sdk.api.endusers.deleteOne(sourceId)];
592
+ case 8:
593
+ _c.sent();
594
+ _c.label = 9;
595
+ case 9: return [2 /*return*/, !sourceDeleted // Source should NOT be deleted (no merge)
596
+ && !((_b = updatedDestination.mergedIds) === null || _b === void 0 ? void 0 : _b.includes(sourceId))];
597
+ }
598
+ });
599
+ }); }, { expectedResult: true })
600
+ // Test 8: eligibleForAutoMerge Flag Verification
601
+ ];
602
+ case 7:
603
+ // Test 7: Case Sensitive Matching - No Merge When Case Differs
604
+ _b.sent();
605
+ // Test 8: eligibleForAutoMerge Flag Verification
606
+ return [4 /*yield*/, (0, testing_1.async_test)("Auto-merge: eligibleForAutoMerge flag is set correctly", function () { return __awaiter(void 0, void 0, void 0, function () {
607
+ var _a, formEnabled, fieldsEnabled, enduserSDKEnabled, enabledEnduserId, enabledEnduser, _b, formDisabled, fieldsDisabled, enduserSDKDisabled, disabledEnduserId, disabledEnduser;
608
+ return __generator(this, function (_c) {
609
+ switch (_c.label) {
610
+ case 0: return [4 /*yield*/, createAutoMergeForm(sdk, true)];
611
+ case 1:
612
+ _a = _c.sent(), formEnabled = _a.form, fieldsEnabled = _a.fields;
613
+ enduserSDKEnabled = new sdk_1.EnduserSession({ host: host, businessId: formEnabled.businessId });
614
+ return [4 /*yield*/, enduserSDKEnabled.api.form_responses.session_for_public_form({
615
+ formId: formEnabled.id,
616
+ businessId: formEnabled.businessId,
617
+ skipMatch: true,
618
+ })];
619
+ case 2:
620
+ enabledEnduserId = (_c.sent()).enduserId;
621
+ return [4 /*yield*/, sdk.api.endusers.getOne(enabledEnduserId)
622
+ // Form with autoMergeOnSubmission: false
623
+ ];
624
+ case 3:
625
+ enabledEnduser = _c.sent();
626
+ return [4 /*yield*/, createAutoMergeForm(sdk, false)];
627
+ case 4:
628
+ _b = _c.sent(), formDisabled = _b.form, fieldsDisabled = _b.fields;
629
+ enduserSDKDisabled = new sdk_1.EnduserSession({ host: host, businessId: formDisabled.businessId });
630
+ return [4 /*yield*/, enduserSDKDisabled.api.form_responses.session_for_public_form({
631
+ formId: formDisabled.id,
632
+ businessId: formDisabled.businessId,
633
+ skipMatch: true,
634
+ })];
635
+ case 5:
636
+ disabledEnduserId = (_c.sent()).enduserId;
637
+ return [4 /*yield*/, sdk.api.endusers.getOne(disabledEnduserId)
638
+ // Cleanup
639
+ ];
640
+ case 6:
641
+ disabledEnduser = _c.sent();
642
+ // Cleanup
643
+ return [4 /*yield*/, sdk.api.forms.deleteOne(formEnabled.id)];
644
+ case 7:
645
+ // Cleanup
646
+ _c.sent();
647
+ return [4 /*yield*/, sdk.api.forms.deleteOne(formDisabled.id)];
648
+ case 8:
649
+ _c.sent();
650
+ return [4 /*yield*/, sdk.api.endusers.deleteOne(enabledEnduserId)];
651
+ case 9:
652
+ _c.sent();
653
+ return [4 /*yield*/, sdk.api.endusers.deleteOne(disabledEnduserId)];
654
+ case 10:
655
+ _c.sent();
656
+ return [2 /*return*/, enabledEnduser.eligibleForAutoMerge === true
657
+ && disabledEnduser.eligibleForAutoMerge !== true];
658
+ }
659
+ });
660
+ }); }, { expectedResult: true })
661
+ // Test 9: Files Transfer on Merge
662
+ ];
663
+ case 8:
664
+ // Test 8: eligibleForAutoMerge Flag Verification
665
+ _b.sent();
666
+ // Test 9: Files Transfer on Merge
667
+ return [4 /*yield*/, (0, testing_1.async_test)("Auto-merge: Files are transferred to destination enduser", function () { return __awaiter(void 0, void 0, void 0, function () {
668
+ var testEmail, destination, _a, form, fields, enduserSDK, _b, authToken, accessCode, sourceId, buff, _c, presignedUpload, file, authedSDK, fnameField, lnameField, emailField, sourceDeleted, updatedFile;
669
+ return __generator(this, function (_d) {
670
+ switch (_d.label) {
671
+ case 0:
672
+ testEmail = "automerge.files.".concat(Date.now(), "@test.com");
673
+ return [4 /*yield*/, sdk.api.endusers.createOne({
674
+ fname: 'Files',
675
+ lname: 'Test',
676
+ email: testEmail
677
+ })];
678
+ case 1:
679
+ destination = _d.sent();
680
+ return [4 /*yield*/, createAutoMergeForm(sdk, true)
681
+ // Create public session to get source enduser
682
+ ];
683
+ case 2:
684
+ _a = _d.sent(), form = _a.form, fields = _a.fields;
685
+ enduserSDK = new sdk_1.EnduserSession({ host: host, businessId: form.businessId });
686
+ return [4 /*yield*/, enduserSDK.api.form_responses.session_for_public_form({
687
+ formId: form.id,
688
+ businessId: form.businessId,
689
+ skipMatch: true,
690
+ })
691
+ // Create a file for the source enduser using prepare_file_upload + UPLOAD
692
+ ];
693
+ case 3:
694
+ _b = _d.sent(), authToken = _b.authToken, accessCode = _b.accessCode, sourceId = _b.enduserId;
695
+ buff = buffer.Buffer.from('test file data for auto-merge');
696
+ return [4 /*yield*/, sdk.api.files.prepare_file_upload({
697
+ name: 'test-file.txt',
698
+ type: 'text/plain',
699
+ size: buff.byteLength,
700
+ enduserId: sourceId,
701
+ })];
702
+ case 4:
703
+ _c = _d.sent(), presignedUpload = _c.presignedUpload, file = _c.file;
704
+ return [4 /*yield*/, sdk.UPLOAD(presignedUpload, buff)
705
+ // Now submit the form to trigger merge
706
+ ];
707
+ case 5:
708
+ _d.sent();
709
+ authedSDK = new sdk_1.EnduserSession({ host: host, businessId: form.businessId, authToken: authToken });
710
+ fnameField = fields.find(function (f) { return f.intakeField === 'fname'; });
711
+ lnameField = fields.find(function (f) { return f.intakeField === 'lname'; });
712
+ emailField = fields.find(function (f) { return f.intakeField === 'email'; });
713
+ return [4 /*yield*/, authedSDK.api.form_responses.submit_form_response({
714
+ accessCode: accessCode,
715
+ responses: [
716
+ { fieldId: fnameField.id, fieldTitle: fnameField.title, answer: { type: 'string', value: 'Files' } },
717
+ { fieldId: lnameField.id, fieldTitle: lnameField.title, answer: { type: 'string', value: 'Test' } },
718
+ { fieldId: emailField.id, fieldTitle: emailField.title, answer: { type: 'email', value: testEmail } },
719
+ ],
720
+ })
721
+ // Merge is synchronous - source should be deleted immediately after submission
722
+ ];
723
+ case 6:
724
+ _d.sent();
725
+ return [4 /*yield*/, isEnduserDeleted(sdk, sourceId)];
726
+ case 7:
727
+ sourceDeleted = _d.sent();
728
+ return [4 /*yield*/, sdk.api.files.getOne(file.id)
729
+ // Cleanup
730
+ ];
731
+ case 8:
732
+ updatedFile = _d.sent();
733
+ // Cleanup
734
+ return [4 /*yield*/, sdk.api.forms.deleteOne(form.id)];
735
+ case 9:
736
+ // Cleanup
737
+ _d.sent();
738
+ return [4 /*yield*/, sdk.api.files.deleteOne(file.id)];
739
+ case 10:
740
+ _d.sent();
741
+ return [4 /*yield*/, sdk.api.endusers.deleteOne(destination.id)];
742
+ case 11:
743
+ _d.sent();
744
+ return [2 /*return*/, sourceDeleted && updatedFile.enduserId === destination.id];
745
+ }
746
+ });
747
+ }); }, { expectedResult: true })
748
+ // Test 10: Calendar Events Transfer on Merge
749
+ ];
750
+ case 9:
751
+ // Test 9: Files Transfer on Merge
752
+ _b.sent();
753
+ // Test 10: Calendar Events Transfer on Merge
754
+ return [4 /*yield*/, (0, testing_1.async_test)("Auto-merge: Calendar events are transferred to destination enduser", function () { return __awaiter(void 0, void 0, void 0, function () {
755
+ var testEmail, destination, _a, form, fields, enduserSDK, _b, authToken, accessCode, sourceId, event, authedSDK, fnameField, lnameField, emailField, sourceDeleted, updatedEvent;
756
+ var _c;
757
+ return __generator(this, function (_d) {
758
+ switch (_d.label) {
759
+ case 0:
760
+ testEmail = "automerge.events.".concat(Date.now(), "@test.com");
761
+ return [4 /*yield*/, sdk.api.endusers.createOne({
762
+ fname: 'Events',
763
+ lname: 'Test',
764
+ email: testEmail
765
+ })];
766
+ case 1:
767
+ destination = _d.sent();
768
+ return [4 /*yield*/, createAutoMergeForm(sdk, true)
769
+ // Create public session to get source enduser
770
+ ];
771
+ case 2:
772
+ _a = _d.sent(), form = _a.form, fields = _a.fields;
773
+ enduserSDK = new sdk_1.EnduserSession({ host: host, businessId: form.businessId });
774
+ return [4 /*yield*/, enduserSDK.api.form_responses.session_for_public_form({
775
+ formId: form.id,
776
+ businessId: form.businessId,
777
+ skipMatch: true,
778
+ })
779
+ // Create a calendar event with source enduser as attendee
780
+ ];
781
+ case 3:
782
+ _b = _d.sent(), authToken = _b.authToken, accessCode = _b.accessCode, sourceId = _b.enduserId;
783
+ return [4 /*yield*/, sdk.api.calendar_events.createOne({
784
+ title: 'Test Event',
785
+ startTimeInMS: Date.now() + 86400000,
786
+ durationInMinutes: 30,
787
+ attendees: [{ id: sourceId, type: 'enduser' }],
788
+ })
789
+ // Now submit the form to trigger merge
790
+ ];
791
+ case 4:
792
+ event = _d.sent();
793
+ authedSDK = new sdk_1.EnduserSession({ host: host, businessId: form.businessId, authToken: authToken });
794
+ fnameField = fields.find(function (f) { return f.intakeField === 'fname'; });
795
+ lnameField = fields.find(function (f) { return f.intakeField === 'lname'; });
796
+ emailField = fields.find(function (f) { return f.intakeField === 'email'; });
797
+ return [4 /*yield*/, authedSDK.api.form_responses.submit_form_response({
798
+ accessCode: accessCode,
799
+ responses: [
800
+ { fieldId: fnameField.id, fieldTitle: fnameField.title, answer: { type: 'string', value: 'Events' } },
801
+ { fieldId: lnameField.id, fieldTitle: lnameField.title, answer: { type: 'string', value: 'Test' } },
802
+ { fieldId: emailField.id, fieldTitle: emailField.title, answer: { type: 'email', value: testEmail } },
803
+ ],
804
+ })
805
+ // Merge is synchronous - source should be deleted immediately after submission
806
+ ];
807
+ case 5:
808
+ _d.sent();
809
+ return [4 /*yield*/, isEnduserDeleted(sdk, sourceId)];
810
+ case 6:
811
+ sourceDeleted = _d.sent();
812
+ return [4 /*yield*/, sdk.api.calendar_events.getOne(event.id)
813
+ // Cleanup
814
+ ];
815
+ case 7:
816
+ updatedEvent = _d.sent();
817
+ // Cleanup
818
+ return [4 /*yield*/, sdk.api.forms.deleteOne(form.id)];
819
+ case 8:
820
+ // Cleanup
821
+ _d.sent();
822
+ return [4 /*yield*/, sdk.api.calendar_events.deleteOne(event.id)];
823
+ case 9:
824
+ _d.sent();
825
+ return [4 /*yield*/, sdk.api.endusers.deleteOne(destination.id)];
826
+ case 10:
827
+ _d.sent();
828
+ return [2 /*return*/, sourceDeleted && ((_c = updatedEvent.attendees) === null || _c === void 0 ? void 0 : _c.some(function (a) { return a.id === destination.id; }))];
829
+ }
830
+ });
831
+ }); }, { expectedResult: true })
832
+ // Test 11: Form response enduserId is updated to destination (placeholder is updated before submission completes)
833
+ ];
834
+ case 10:
835
+ // Test 10: Calendar Events Transfer on Merge
836
+ _b.sent();
837
+ // Test 11: Form response enduserId is updated to destination (placeholder is updated before submission completes)
838
+ return [4 /*yield*/, (0, testing_1.async_test)("Auto-merge: Form response enduserId is updated to destination", function () { return __awaiter(void 0, void 0, void 0, function () {
839
+ var testEmail, destination, _a, form, fields, _b, sourceId, accessCode, sourceDeleted, formResponses, createdFormResponse;
840
+ return __generator(this, function (_c) {
841
+ switch (_c.label) {
842
+ case 0:
843
+ testEmail = "automerge.directfr.".concat(Date.now(), "@test.com");
844
+ return [4 /*yield*/, sdk.api.endusers.createOne({
845
+ fname: 'Direct',
846
+ lname: 'Response',
847
+ email: testEmail
848
+ })];
849
+ case 1:
850
+ destination = _c.sent();
851
+ return [4 /*yield*/, createAutoMergeForm(sdk, true)];
852
+ case 2:
853
+ _a = _c.sent(), form = _a.form, fields = _a.fields;
854
+ return [4 /*yield*/, submitPublicFormWithSkipMatch(form, fields, {
855
+ fname: 'Direct',
856
+ lname: 'Response',
857
+ email: testEmail,
858
+ })
859
+ // Merge is synchronous - verify form response was created with destination ID
860
+ ];
861
+ case 3:
862
+ _b = _c.sent(), sourceId = _b.enduserId, accessCode = _b.accessCode;
863
+ return [4 /*yield*/, isEnduserDeleted(sdk, sourceId)
864
+ // Get form responses by accessCode to find the one we created
865
+ ];
866
+ case 4:
867
+ sourceDeleted = _c.sent();
868
+ return [4 /*yield*/, sdk.api.form_responses.getSome({ filter: { accessCode: accessCode } })];
869
+ case 5:
870
+ formResponses = _c.sent();
871
+ createdFormResponse = formResponses[0];
872
+ // Cleanup
873
+ return [4 /*yield*/, sdk.api.forms.deleteOne(form.id)];
874
+ case 6:
875
+ // Cleanup
876
+ _c.sent();
877
+ return [4 /*yield*/, sdk.api.endusers.deleteOne(destination.id)
878
+ // The form response should have been created directly with destination enduser ID
879
+ // (not transferred after creation)
880
+ ];
881
+ case 7:
882
+ _c.sent();
883
+ // The form response should have been created directly with destination enduser ID
884
+ // (not transferred after creation)
885
+ return [2 /*return*/, sourceDeleted
886
+ && createdFormResponse !== undefined
887
+ && createdFormResponse.enduserId === destination.id];
888
+ }
889
+ });
890
+ }); }, { expectedResult: true })
891
+ // Test 12: Intake fields update destination enduser directly
892
+ ];
893
+ case 11:
894
+ // Test 11: Form response enduserId is updated to destination (placeholder is updated before submission completes)
895
+ _b.sent();
896
+ // Test 12: Intake fields update destination enduser directly
897
+ return [4 /*yield*/, (0, testing_1.async_test)("Auto-merge: Intake fields update destination enduser directly", function () { return __awaiter(void 0, void 0, void 0, function () {
898
+ var testEmail, destination, _a, form, fields, newPhone, newDOB, sourceId, sourceDeleted, updatedDestination;
899
+ return __generator(this, function (_b) {
900
+ switch (_b.label) {
901
+ case 0:
902
+ testEmail = "automerge.intake.".concat(Date.now(), "@test.com");
903
+ return [4 /*yield*/, sdk.api.endusers.createOne({
904
+ fname: 'Intake',
905
+ lname: 'Test',
906
+ email: testEmail,
907
+ // No phone or DOB set initially
908
+ })];
909
+ case 1:
910
+ destination = _b.sent();
911
+ return [4 /*yield*/, createAutoMergeForm(sdk, true)];
912
+ case 2:
913
+ _a = _b.sent(), form = _a.form, fields = _a.fields;
914
+ newPhone = '+15555559876';
915
+ newDOB = '1985-03-20';
916
+ return [4 /*yield*/, submitPublicFormWithSkipMatch(form, fields, {
917
+ fname: 'Intake',
918
+ lname: 'Test',
919
+ email: testEmail,
920
+ phone: newPhone,
921
+ dateOfBirth: newDOB,
922
+ })
923
+ // Merge is synchronous - verify intake fields updated destination directly
924
+ ];
925
+ case 3:
926
+ sourceId = (_b.sent()).enduserId;
927
+ return [4 /*yield*/, isEnduserDeleted(sdk, sourceId)];
928
+ case 4:
929
+ sourceDeleted = _b.sent();
930
+ return [4 /*yield*/, sdk.api.endusers.getOne(destination.id)
931
+ // Cleanup
932
+ ];
933
+ case 5:
934
+ updatedDestination = _b.sent();
935
+ // Cleanup
936
+ return [4 /*yield*/, sdk.api.forms.deleteOne(form.id)];
937
+ case 6:
938
+ // Cleanup
939
+ _b.sent();
940
+ return [4 /*yield*/, sdk.api.endusers.deleteOne(destination.id)
941
+ // Intake fields should have been applied to the destination enduser
942
+ ];
943
+ case 7:
944
+ _b.sent();
945
+ // Intake fields should have been applied to the destination enduser
946
+ return [2 /*return*/, sourceDeleted
947
+ && updatedDestination.phone === newPhone
948
+ && updatedDestination.dateOfBirth === newDOB];
949
+ }
950
+ });
951
+ }); }, { expectedResult: true })
952
+ // Test 13: eligibleForAutoMerge is unset after submission (no merge case)
953
+ ];
954
+ case 12:
955
+ // Test 12: Intake fields update destination enduser directly
956
+ _b.sent();
957
+ // Test 13: eligibleForAutoMerge is unset after submission (no merge case)
958
+ return [4 /*yield*/, (0, testing_1.async_test)("Auto-merge: eligibleForAutoMerge is unset after submission when no merge occurs", function () { return __awaiter(void 0, void 0, void 0, function () {
959
+ var _a, form, fields, sourceId, updatedEnduser;
960
+ return __generator(this, function (_b) {
961
+ switch (_b.label) {
962
+ case 0: return [4 /*yield*/, createAutoMergeForm(sdk, true)
963
+ // Submit form - no match exists, so no merge will happen
964
+ ];
965
+ case 1:
966
+ _a = _b.sent(), form = _a.form, fields = _a.fields;
967
+ return [4 /*yield*/, submitPublicFormWithSkipMatch(form, fields, {
968
+ fname: 'Unset',
969
+ lname: 'Flag',
970
+ email: "unset.flag.".concat(Date.now(), "@test.com"),
971
+ })
972
+ // Verify enduser still exists and eligibleForAutoMerge is unset
973
+ ];
974
+ case 2:
975
+ sourceId = (_b.sent()).enduserId;
976
+ return [4 /*yield*/, sdk.api.endusers.getOne(sourceId)
977
+ // Cleanup
978
+ ];
979
+ case 3:
980
+ updatedEnduser = _b.sent();
981
+ // Cleanup
982
+ return [4 /*yield*/, sdk.api.forms.deleteOne(form.id)];
983
+ case 4:
984
+ // Cleanup
985
+ _b.sent();
986
+ return [4 /*yield*/, sdk.api.endusers.deleteOne(sourceId)
987
+ // eligibleForAutoMerge should be unset (undefined/falsy) after submission
988
+ ];
989
+ case 5:
990
+ _b.sent();
991
+ // eligibleForAutoMerge should be unset (undefined/falsy) after submission
992
+ return [2 /*return*/, updatedEnduser.eligibleForAutoMerge !== true];
993
+ }
994
+ });
995
+ }); }, { expectedResult: true })
996
+ // ============================================
997
+ // BACKWARDS COMPATIBILITY & EDGE CASE TESTS
998
+ // ============================================
999
+ // Test 14: No merge when source enduser has multiple form responses
1000
+ ];
1001
+ case 13:
1002
+ // Test 13: eligibleForAutoMerge is unset after submission (no merge case)
1003
+ _b.sent();
1004
+ // ============================================
1005
+ // BACKWARDS COMPATIBILITY & EDGE CASE TESTS
1006
+ // ============================================
1007
+ // Test 14: No merge when source enduser has multiple form responses
1008
+ return [4 /*yield*/, (0, testing_1.async_test)("Auto-merge: No merge when source enduser already has multiple form responses", function () { return __awaiter(void 0, void 0, void 0, function () {
1009
+ var testEmail, destination, _a, form1, fields1, _b, form2, fields2, enduserSDK1, session1, sourceId, authedSDK1, fnameField1, lnameField1, emailField1, enduserSDK2, session2, sourceId2, authedSDK2, fnameField2, lnameField2, emailField2, sourceStillExists;
1010
+ return __generator(this, function (_c) {
1011
+ switch (_c.label) {
1012
+ case 0:
1013
+ testEmail = "automerge.multiresponse.".concat(Date.now(), "@test.com");
1014
+ return [4 /*yield*/, sdk.api.endusers.createOne({
1015
+ fname: 'Multi',
1016
+ lname: 'Response',
1017
+ email: testEmail
1018
+ })];
1019
+ case 1:
1020
+ destination = _c.sent();
1021
+ return [4 /*yield*/, createAutoMergeForm(sdk, true)];
1022
+ case 2:
1023
+ _a = _c.sent(), form1 = _a.form, fields1 = _a.fields;
1024
+ return [4 /*yield*/, createAutoMergeForm(sdk, true)
1025
+ // Create first public session and submit (this creates first form response)
1026
+ ];
1027
+ case 3:
1028
+ _b = _c.sent(), form2 = _b.form, fields2 = _b.fields;
1029
+ enduserSDK1 = new sdk_1.EnduserSession({ host: host, businessId: form1.businessId });
1030
+ return [4 /*yield*/, enduserSDK1.api.form_responses.session_for_public_form({
1031
+ formId: form1.id,
1032
+ businessId: form1.businessId,
1033
+ skipMatch: true,
1034
+ })];
1035
+ case 4:
1036
+ session1 = _c.sent();
1037
+ sourceId = session1.enduserId;
1038
+ authedSDK1 = new sdk_1.EnduserSession({ host: host, businessId: form1.businessId, authToken: session1.authToken });
1039
+ fnameField1 = fields1.find(function (f) { return f.intakeField === 'fname'; });
1040
+ lnameField1 = fields1.find(function (f) { return f.intakeField === 'lname'; });
1041
+ emailField1 = fields1.find(function (f) { return f.intakeField === 'email'; });
1042
+ return [4 /*yield*/, authedSDK1.api.form_responses.submit_form_response({
1043
+ accessCode: session1.accessCode,
1044
+ responses: [
1045
+ { fieldId: fnameField1.id, fieldTitle: fnameField1.title, answer: { type: 'string', value: 'Different' } },
1046
+ { fieldId: lnameField1.id, fieldTitle: lnameField1.title, answer: { type: 'string', value: 'Person' } },
1047
+ { fieldId: emailField1.id, fieldTitle: emailField1.title, answer: { type: 'email', value: "different.".concat(Date.now(), "@test.com") } },
1048
+ ],
1049
+ })
1050
+ // Now create a second form response for the SAME source enduser via admin SDK
1051
+ ];
1052
+ case 5:
1053
+ _c.sent();
1054
+ // Now create a second form response for the SAME source enduser via admin SDK
1055
+ return [4 /*yield*/, sdk.api.form_responses.createOne({
1056
+ formId: form2.id,
1057
+ formTitle: 'Auto Merge Test Form',
1058
+ enduserId: sourceId,
1059
+ })
1060
+ // Re-set eligibleForAutoMerge manually to simulate another attempt
1061
+ ];
1062
+ case 6:
1063
+ // Now create a second form response for the SAME source enduser via admin SDK
1064
+ _c.sent();
1065
+ // Re-set eligibleForAutoMerge manually to simulate another attempt
1066
+ return [4 /*yield*/, sdk.api.endusers.updateOne(sourceId, { eligibleForAutoMerge: true })
1067
+ // Create another public session that would match - but source now has 2+ form responses
1068
+ ];
1069
+ case 7:
1070
+ // Re-set eligibleForAutoMerge manually to simulate another attempt
1071
+ _c.sent();
1072
+ enduserSDK2 = new sdk_1.EnduserSession({ host: host, businessId: form2.businessId });
1073
+ return [4 /*yield*/, enduserSDK2.api.form_responses.session_for_public_form({
1074
+ formId: form2.id,
1075
+ businessId: form2.businessId,
1076
+ skipMatch: true,
1077
+ })];
1078
+ case 8:
1079
+ session2 = _c.sent();
1080
+ sourceId2 = session2.enduserId;
1081
+ // Manually add another form response to sourceId2 to trigger the >1 check
1082
+ return [4 /*yield*/, sdk.api.form_responses.createOne({
1083
+ formId: form1.id,
1084
+ formTitle: 'Auto Merge Test Form',
1085
+ enduserId: sourceId2,
1086
+ })
1087
+ // Submit with matching data - should NOT merge because source has >1 form responses
1088
+ ];
1089
+ case 9:
1090
+ // Manually add another form response to sourceId2 to trigger the >1 check
1091
+ _c.sent();
1092
+ authedSDK2 = new sdk_1.EnduserSession({ host: host, businessId: form2.businessId, authToken: session2.authToken });
1093
+ fnameField2 = fields2.find(function (f) { return f.intakeField === 'fname'; });
1094
+ lnameField2 = fields2.find(function (f) { return f.intakeField === 'lname'; });
1095
+ emailField2 = fields2.find(function (f) { return f.intakeField === 'email'; });
1096
+ return [4 /*yield*/, authedSDK2.api.form_responses.submit_form_response({
1097
+ accessCode: session2.accessCode,
1098
+ responses: [
1099
+ { fieldId: fnameField2.id, fieldTitle: fnameField2.title, answer: { type: 'string', value: 'Multi' } },
1100
+ { fieldId: lnameField2.id, fieldTitle: lnameField2.title, answer: { type: 'string', value: 'Response' } },
1101
+ { fieldId: emailField2.id, fieldTitle: emailField2.title, answer: { type: 'email', value: testEmail } },
1102
+ ],
1103
+ })
1104
+ // Source should NOT be deleted because it had multiple form responses
1105
+ ];
1106
+ case 10:
1107
+ _c.sent();
1108
+ return [4 /*yield*/, isEnduserDeleted(sdk, sourceId2)];
1109
+ case 11:
1110
+ sourceStillExists = !(_c.sent());
1111
+ // Cleanup
1112
+ return [4 /*yield*/, sdk.api.forms.deleteOne(form1.id)];
1113
+ case 12:
1114
+ // Cleanup
1115
+ _c.sent();
1116
+ return [4 /*yield*/, sdk.api.forms.deleteOne(form2.id)];
1117
+ case 13:
1118
+ _c.sent();
1119
+ return [4 /*yield*/, sdk.api.endusers.deleteOne(destination.id)];
1120
+ case 14:
1121
+ _c.sent();
1122
+ return [4 /*yield*/, sdk.api.endusers.deleteOne(sourceId)];
1123
+ case 15:
1124
+ _c.sent();
1125
+ if (!sourceStillExists) return [3 /*break*/, 17];
1126
+ return [4 /*yield*/, sdk.api.endusers.deleteOne(sourceId2)];
1127
+ case 16:
1128
+ _c.sent();
1129
+ _c.label = 17;
1130
+ case 17: return [2 /*return*/, sourceStillExists];
1131
+ }
1132
+ });
1133
+ }); }, { expectedResult: true })
1134
+ // Test 15: Backwards compat - skipMatch=false does NOT set eligibleForAutoMerge
1135
+ ];
1136
+ case 14:
1137
+ // ============================================
1138
+ // BACKWARDS COMPATIBILITY & EDGE CASE TESTS
1139
+ // ============================================
1140
+ // Test 14: No merge when source enduser has multiple form responses
1141
+ _b.sent();
1142
+ // Test 15: Backwards compat - skipMatch=false does NOT set eligibleForAutoMerge
1143
+ return [4 /*yield*/, (0, testing_1.async_test)("Backwards compat: skipMatch=false does not set eligibleForAutoMerge even with autoMergeOnSubmission=true", function () { return __awaiter(void 0, void 0, void 0, function () {
1144
+ var _a, form, fields, testPhone, enduserSDK, enduserId, enduser;
1145
+ return __generator(this, function (_b) {
1146
+ switch (_b.label) {
1147
+ case 0: return [4 /*yield*/, createAutoMergeForm(sdk, true)];
1148
+ case 1:
1149
+ _a = _b.sent(), form = _a.form, fields = _a.fields;
1150
+ testPhone = "+1555555".concat(Date.now().toString().slice(-4));
1151
+ enduserSDK = new sdk_1.EnduserSession({ host: host, businessId: form.businessId });
1152
+ return [4 /*yield*/, enduserSDK.api.form_responses.session_for_public_form({
1153
+ formId: form.id,
1154
+ businessId: form.businessId,
1155
+ phone: testPhone, // Phone is required when skipMatch is not set
1156
+ // skipMatch is NOT set (defaults to false)
1157
+ })];
1158
+ case 2:
1159
+ enduserId = (_b.sent()).enduserId;
1160
+ return [4 /*yield*/, sdk.api.endusers.getOne(enduserId)
1161
+ // Cleanup
1162
+ ];
1163
+ case 3:
1164
+ enduser = _b.sent();
1165
+ // Cleanup
1166
+ return [4 /*yield*/, sdk.api.forms.deleteOne(form.id)];
1167
+ case 4:
1168
+ // Cleanup
1169
+ _b.sent();
1170
+ return [4 /*yield*/, sdk.api.endusers.deleteOne(enduserId)
1171
+ // eligibleForAutoMerge should NOT be set when skipMatch is false
1172
+ ];
1173
+ case 5:
1174
+ _b.sent();
1175
+ // eligibleForAutoMerge should NOT be set when skipMatch is false
1176
+ return [2 /*return*/, enduser.eligibleForAutoMerge !== true];
1177
+ }
1178
+ });
1179
+ }); }, { expectedResult: true })
1180
+ // Test 16: Backwards compat - Private form submission doesn't trigger auto-merge
1181
+ ];
1182
+ case 15:
1183
+ // Test 15: Backwards compat - skipMatch=false does NOT set eligibleForAutoMerge
1184
+ _b.sent();
1185
+ // Test 16: Backwards compat - Private form submission doesn't trigger auto-merge
1186
+ return [4 /*yield*/, (0, testing_1.async_test)("Backwards compat: Private form submission does not trigger auto-merge", function () { return __awaiter(void 0, void 0, void 0, function () {
1187
+ var testEmail, destination, source, _a, form, fields, fnameField, lnameField, emailField, sourceStillExists;
1188
+ return __generator(this, function (_b) {
1189
+ switch (_b.label) {
1190
+ case 0:
1191
+ testEmail = "backcompat.private.".concat(Date.now(), "@test.com");
1192
+ return [4 /*yield*/, sdk.api.endusers.createOne({
1193
+ fname: 'Private',
1194
+ lname: 'Test',
1195
+ email: testEmail
1196
+ })
1197
+ // Create source enduser with eligibleForAutoMerge manually set
1198
+ ];
1199
+ case 1:
1200
+ destination = _b.sent();
1201
+ return [4 /*yield*/, sdk.api.endusers.createOne({
1202
+ fname: 'Private',
1203
+ lname: 'Test',
1204
+ email: testEmail + '.source',
1205
+ eligibleForAutoMerge: true, // Manually set to test that private submission ignores it
1206
+ })];
1207
+ case 2:
1208
+ source = _b.sent();
1209
+ return [4 /*yield*/, createAutoMergeForm(sdk, true)
1210
+ // Create form response via admin SDK (private/non-public submission)
1211
+ ];
1212
+ case 3:
1213
+ _a = _b.sent(), form = _a.form, fields = _a.fields;
1214
+ fnameField = fields.find(function (f) { return f.intakeField === 'fname'; });
1215
+ lnameField = fields.find(function (f) { return f.intakeField === 'lname'; });
1216
+ emailField = fields.find(function (f) { return f.intakeField === 'email'; });
1217
+ return [4 /*yield*/, sdk.api.form_responses.createOne({
1218
+ formId: form.id,
1219
+ formTitle: form.title,
1220
+ enduserId: source.id,
1221
+ responses: [
1222
+ { fieldId: fnameField.id, fieldTitle: fnameField.title, answer: { type: 'string', value: 'Private' } },
1223
+ { fieldId: lnameField.id, fieldTitle: lnameField.title, answer: { type: 'string', value: 'Test' } },
1224
+ { fieldId: emailField.id, fieldTitle: emailField.title, answer: { type: 'email', value: testEmail } },
1225
+ ],
1226
+ })
1227
+ // Source should NOT be deleted because this was a private submission (not publicSubmit)
1228
+ ];
1229
+ case 4:
1230
+ _b.sent();
1231
+ return [4 /*yield*/, isEnduserDeleted(sdk, source.id)];
1232
+ case 5:
1233
+ sourceStillExists = !(_b.sent());
1234
+ // Cleanup
1235
+ return [4 /*yield*/, sdk.api.forms.deleteOne(form.id)];
1236
+ case 6:
1237
+ // Cleanup
1238
+ _b.sent();
1239
+ return [4 /*yield*/, sdk.api.endusers.deleteOne(destination.id)];
1240
+ case 7:
1241
+ _b.sent();
1242
+ if (!sourceStillExists) return [3 /*break*/, 9];
1243
+ return [4 /*yield*/, sdk.api.endusers.deleteOne(source.id)];
1244
+ case 8:
1245
+ _b.sent();
1246
+ _b.label = 9;
1247
+ case 9: return [2 /*return*/, sourceStillExists];
1248
+ }
1249
+ });
1250
+ }); }, { expectedResult: true })
1251
+ // Test 17: OR logic - matches on email even when phone differs
1252
+ ];
1253
+ case 16:
1254
+ // Test 16: Backwards compat - Private form submission doesn't trigger auto-merge
1255
+ _b.sent();
1256
+ // Test 17: OR logic - matches on email even when phone differs
1257
+ return [4 /*yield*/, (0, testing_1.async_test)("Auto-merge: Merge occurs when email matches even if phone differs (OR logic)", function () { return __awaiter(void 0, void 0, void 0, function () {
1258
+ var testEmail, destination, _a, form, fields, sourceId, sourceDeleted, updatedDestination;
1259
+ var _b;
1260
+ return __generator(this, function (_c) {
1261
+ switch (_c.label) {
1262
+ case 0:
1263
+ testEmail = "automerge.orlogic.".concat(Date.now(), "@test.com");
1264
+ return [4 /*yield*/, sdk.api.endusers.createOne({
1265
+ fname: 'OrLogic',
1266
+ lname: 'Test',
1267
+ email: testEmail,
1268
+ phone: '+15555550001', // Different phone
1269
+ })];
1270
+ case 1:
1271
+ destination = _c.sent();
1272
+ return [4 /*yield*/, createAutoMergeForm(sdk, true)
1273
+ // Submit with matching email but DIFFERENT phone
1274
+ ];
1275
+ case 2:
1276
+ _a = _c.sent(), form = _a.form, fields = _a.fields;
1277
+ return [4 /*yield*/, submitPublicFormWithSkipMatch(form, fields, {
1278
+ fname: 'OrLogic',
1279
+ lname: 'Test',
1280
+ email: testEmail,
1281
+ phone: '+15555550002', // Different phone than destination
1282
+ })
1283
+ // Should merge because email matches (OR logic, not AND)
1284
+ ];
1285
+ case 3:
1286
+ sourceId = (_c.sent()).enduserId;
1287
+ return [4 /*yield*/, isEnduserDeleted(sdk, sourceId)];
1288
+ case 4:
1289
+ sourceDeleted = _c.sent();
1290
+ return [4 /*yield*/, sdk.api.endusers.getOne(destination.id)
1291
+ // Cleanup
1292
+ ];
1293
+ case 5:
1294
+ updatedDestination = _c.sent();
1295
+ // Cleanup
1296
+ return [4 /*yield*/, sdk.api.forms.deleteOne(form.id)];
1297
+ case 6:
1298
+ // Cleanup
1299
+ _c.sent();
1300
+ return [4 /*yield*/, sdk.api.endusers.deleteOne(destination.id)];
1301
+ case 7:
1302
+ _c.sent();
1303
+ return [2 /*return*/, sourceDeleted && ((_b = updatedDestination.mergedIds) === null || _b === void 0 ? void 0 : _b.includes(sourceId))];
1304
+ }
1305
+ });
1306
+ }); }, { expectedResult: true })
1307
+ // Test 18: Partial name mismatch - fname matches but lname differs
1308
+ ];
1309
+ case 17:
1310
+ // Test 17: OR logic - matches on email even when phone differs
1311
+ _b.sent();
1312
+ // Test 18: Partial name mismatch - fname matches but lname differs
1313
+ return [4 /*yield*/, (0, testing_1.async_test)("Auto-merge: No merge when fname matches but lname differs", function () { return __awaiter(void 0, void 0, void 0, function () {
1314
+ var testEmail, destination, _a, form, fields, sourceId, sourceDeleted;
1315
+ return __generator(this, function (_b) {
1316
+ switch (_b.label) {
1317
+ case 0:
1318
+ testEmail = "automerge.partial.".concat(Date.now(), "@test.com");
1319
+ return [4 /*yield*/, sdk.api.endusers.createOne({
1320
+ fname: 'Partial',
1321
+ lname: 'Match',
1322
+ email: testEmail
1323
+ })];
1324
+ case 1:
1325
+ destination = _b.sent();
1326
+ return [4 /*yield*/, createAutoMergeForm(sdk, true)
1327
+ // Submit with same fname but DIFFERENT lname
1328
+ ];
1329
+ case 2:
1330
+ _a = _b.sent(), form = _a.form, fields = _a.fields;
1331
+ return [4 /*yield*/, submitPublicFormWithSkipMatch(form, fields, {
1332
+ fname: 'Partial',
1333
+ lname: 'Different',
1334
+ email: testEmail, // Same email
1335
+ })
1336
+ // Should NOT merge because lname differs
1337
+ ];
1338
+ case 3:
1339
+ sourceId = (_b.sent()).enduserId;
1340
+ return [4 /*yield*/, isEnduserDeleted(sdk, sourceId)
1341
+ // Cleanup
1342
+ ];
1343
+ case 4:
1344
+ sourceDeleted = _b.sent();
1345
+ // Cleanup
1346
+ return [4 /*yield*/, sdk.api.forms.deleteOne(form.id)];
1347
+ case 5:
1348
+ // Cleanup
1349
+ _b.sent();
1350
+ return [4 /*yield*/, sdk.api.endusers.deleteOne(destination.id)];
1351
+ case 6:
1352
+ _b.sent();
1353
+ if (!!sourceDeleted) return [3 /*break*/, 8];
1354
+ return [4 /*yield*/, sdk.api.endusers.deleteOne(sourceId)];
1355
+ case 7:
1356
+ _b.sent();
1357
+ _b.label = 8;
1358
+ case 8: return [2 /*return*/, !sourceDeleted]; // Source should NOT be deleted
1359
+ }
1360
+ });
1361
+ }); }, { expectedResult: true })];
1362
+ case 18:
1363
+ // Test 18: Partial name mismatch - fname matches but lname differs
1364
+ _b.sent();
1365
+ return [2 /*return*/];
1366
+ }
1367
+ });
1368
+ });
1369
+ };
1370
+ exports.auto_merge_form_submission_tests = auto_merge_form_submission_tests;
1371
+ // Allow running this test file independently
1372
+ if (require.main === module) {
1373
+ console.log("Using API URL: ".concat(host));
1374
+ var sdk_2 = new sdk_1.Session({ host: host });
1375
+ var sdkNonAdmin_1 = new sdk_1.Session({ host: host });
1376
+ var runTests = function () { return __awaiter(void 0, void 0, void 0, function () {
1377
+ return __generator(this, function (_a) {
1378
+ switch (_a.label) {
1379
+ case 0: return [4 /*yield*/, (0, setup_1.setup_tests)(sdk_2, sdkNonAdmin_1)];
1380
+ case 1:
1381
+ _a.sent();
1382
+ return [4 /*yield*/, (0, exports.auto_merge_form_submission_tests)({ sdk: sdk_2, sdkNonAdmin: sdkNonAdmin_1 })];
1383
+ case 2:
1384
+ _a.sent();
1385
+ return [2 /*return*/];
1386
+ }
1387
+ });
1388
+ }); };
1389
+ runTests()
1390
+ .then(function () {
1391
+ console.log("Auto-merge form submission test suite completed successfully");
1392
+ process.exit(0);
1393
+ })
1394
+ .catch(function (error) {
1395
+ console.error("Auto-merge form submission test suite failed:", error);
1396
+ process.exit(1);
1397
+ });
1398
+ }
1399
+ //# sourceMappingURL=auto_merge_form_submission.test.js.map