masterrecord 0.3.37 → 0.3.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +2 -1
- package/FOREIGN_KEY_STRING_FIX.md +288 -0
- package/GLOBAL_REGISTRY_VERIFICATION.md +375 -0
- package/SQLLiteEngine.js +8 -0
- package/context.js +29 -4
- package/mySQLEngine.js +8 -0
- package/package.json +1 -1
- package/postgresEngine.js +8 -0
- package/readme.md +182 -0
- package/test/foreign-key-string-value-test.js +406 -0
- package/test/global-model-registry-test.js +538 -0
|
@@ -0,0 +1,538 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test: Global Model Registry
|
|
3
|
+
* Verifies that multiple context instances don't trigger duplicate warnings (CLI pattern)
|
|
4
|
+
* while genuine duplicates in constructors still warn properly.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
console.log("╔════════════════════════════════════════════════════════════════╗");
|
|
8
|
+
console.log("║ Global Model Registry Test - Context Class ║");
|
|
9
|
+
console.log("╚════════════════════════════════════════════════════════════════╝\n");
|
|
10
|
+
|
|
11
|
+
let passed = 0;
|
|
12
|
+
let failed = 0;
|
|
13
|
+
|
|
14
|
+
// Simulate context class with global model registry
|
|
15
|
+
class SimulatedContext {
|
|
16
|
+
static _globalModelRegistry = {};
|
|
17
|
+
|
|
18
|
+
constructor() {
|
|
19
|
+
this.__name = this.constructor.name;
|
|
20
|
+
this.__entities = [];
|
|
21
|
+
this.__builderEntities = [];
|
|
22
|
+
|
|
23
|
+
// Track if this is the first instance of this context class
|
|
24
|
+
const globalRegistry = SimulatedContext._globalModelRegistry[this.__name];
|
|
25
|
+
this.__isFirstInstance = !globalRegistry || globalRegistry.size === 0;
|
|
26
|
+
|
|
27
|
+
// Initialize global model registry for this context class if not exists
|
|
28
|
+
if (!SimulatedContext._globalModelRegistry[this.__name]) {
|
|
29
|
+
SimulatedContext._globalModelRegistry[this.__name] = new Set();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
dbset(model, tableName = null) {
|
|
34
|
+
const entityName = tableName || model.name;
|
|
35
|
+
|
|
36
|
+
// Create a simple model object
|
|
37
|
+
const validModel = {
|
|
38
|
+
__name: entityName,
|
|
39
|
+
...model.schema
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// Check if model is registered in this specific instance
|
|
43
|
+
const existingIndex = this.__entities.findIndex(e => e.__name === entityName);
|
|
44
|
+
|
|
45
|
+
if (existingIndex !== -1) {
|
|
46
|
+
// Model already registered in THIS instance - duplicate within same constructor
|
|
47
|
+
// Only warn on first instance (subsequent instances expected to have same pattern)
|
|
48
|
+
if (this.__isFirstInstance) {
|
|
49
|
+
console.warn(`Warning: dbset() called multiple times for table '${entityName}' in constructor - updating existing registration`);
|
|
50
|
+
}
|
|
51
|
+
// Update existing registration
|
|
52
|
+
this.__entities[existingIndex] = validModel;
|
|
53
|
+
this.__builderEntities[existingIndex] = { type: 'builder', model: validModel };
|
|
54
|
+
} else {
|
|
55
|
+
// Model not registered in this instance - add it
|
|
56
|
+
this.__entities.push(validModel);
|
|
57
|
+
this.__builderEntities.push({ type: 'builder', model: validModel });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Always mark as globally seen (after handling instance registration)
|
|
61
|
+
const globalRegistry = SimulatedContext._globalModelRegistry[this.__name];
|
|
62
|
+
globalRegistry.add(entityName);
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
seed: (data) => {} // Mock seed method
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Test entity models
|
|
71
|
+
const User = { name: 'User', schema: { id: 'int', name: 'string' } };
|
|
72
|
+
const Auth = { name: 'Auth', schema: { id: 'int', token: 'string' } };
|
|
73
|
+
const Settings = { name: 'Settings', schema: { id: 'int', key: 'string' } };
|
|
74
|
+
|
|
75
|
+
// Helper to capture console warnings
|
|
76
|
+
function captureWarnings(fn) {
|
|
77
|
+
const warnings = [];
|
|
78
|
+
const originalWarn = console.warn;
|
|
79
|
+
console.warn = (msg) => warnings.push(msg);
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
fn();
|
|
83
|
+
} finally {
|
|
84
|
+
console.warn = originalWarn;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return warnings;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Test helper
|
|
91
|
+
function test(description, fn) {
|
|
92
|
+
try {
|
|
93
|
+
// Clear registry before each test
|
|
94
|
+
SimulatedContext._globalModelRegistry = {};
|
|
95
|
+
|
|
96
|
+
fn();
|
|
97
|
+
passed++;
|
|
98
|
+
console.log(`✓ ${description}`);
|
|
99
|
+
} catch (error) {
|
|
100
|
+
failed++;
|
|
101
|
+
console.log(`✗ ${description}`);
|
|
102
|
+
console.log(` Error: ${error.message}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// ============================================================================
|
|
107
|
+
// TEST 1: Multiple Context Instances (CLI Pattern) - No Warnings
|
|
108
|
+
// ============================================================================
|
|
109
|
+
|
|
110
|
+
test('Multiple instances should not warn (CLI pattern)', () => {
|
|
111
|
+
class TestContext extends SimulatedContext {
|
|
112
|
+
constructor() {
|
|
113
|
+
super();
|
|
114
|
+
this.dbset(User);
|
|
115
|
+
this.dbset(Auth);
|
|
116
|
+
this.dbset(Settings);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const warnings = captureWarnings(() => {
|
|
121
|
+
const ctx1 = new TestContext();
|
|
122
|
+
const ctx2 = new TestContext();
|
|
123
|
+
const ctx3 = new TestContext();
|
|
124
|
+
|
|
125
|
+
if (ctx1.__entities.length !== 3) throw new Error('ctx1 should have 3 entities');
|
|
126
|
+
if (ctx2.__entities.length !== 3) throw new Error('ctx2 should have 3 entities');
|
|
127
|
+
if (ctx3.__entities.length !== 3) throw new Error('ctx3 should have 3 entities');
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
if (warnings.length !== 0) {
|
|
131
|
+
throw new Error(`Should not emit warnings, but got ${warnings.length}`);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// ============================================================================
|
|
136
|
+
// TEST 2: Models Registered in Global Registry
|
|
137
|
+
// ============================================================================
|
|
138
|
+
|
|
139
|
+
test('Models should be added to global registry on first instance', () => {
|
|
140
|
+
class TestContext extends SimulatedContext {
|
|
141
|
+
constructor() {
|
|
142
|
+
super();
|
|
143
|
+
this.dbset(User);
|
|
144
|
+
this.dbset(Auth);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const ctx1 = new TestContext();
|
|
149
|
+
|
|
150
|
+
const registry = SimulatedContext._globalModelRegistry['TestContext'];
|
|
151
|
+
if (!registry) throw new Error('Global registry should exist');
|
|
152
|
+
if (!registry.has('User')) throw new Error('Registry should have User');
|
|
153
|
+
if (!registry.has('Auth')) throw new Error('Registry should have Auth');
|
|
154
|
+
if (registry.size !== 2) throw new Error('Registry should have 2 models');
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// ============================================================================
|
|
158
|
+
// TEST 3: No Duplicates in Global Registry
|
|
159
|
+
// ============================================================================
|
|
160
|
+
|
|
161
|
+
test('Global registry should not have duplicates after multiple instances', () => {
|
|
162
|
+
class TestContext extends SimulatedContext {
|
|
163
|
+
constructor() {
|
|
164
|
+
super();
|
|
165
|
+
this.dbset(User);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const ctx1 = new TestContext();
|
|
170
|
+
const ctx2 = new TestContext();
|
|
171
|
+
const ctx3 = new TestContext();
|
|
172
|
+
|
|
173
|
+
const registry = SimulatedContext._globalModelRegistry['TestContext'];
|
|
174
|
+
if (registry.size !== 1) {
|
|
175
|
+
throw new Error('Registry should have 1 model, not ' + registry.size);
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// ============================================================================
|
|
180
|
+
// TEST 4: Genuine Duplicate in Constructor - Should Warn
|
|
181
|
+
// ============================================================================
|
|
182
|
+
|
|
183
|
+
test('Genuine duplicate in constructor should warn', () => {
|
|
184
|
+
class BuggyContext extends SimulatedContext {
|
|
185
|
+
constructor() {
|
|
186
|
+
super();
|
|
187
|
+
this.dbset(User);
|
|
188
|
+
this.dbset(User); // Duplicate
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const warnings = captureWarnings(() => {
|
|
193
|
+
const ctx = new BuggyContext();
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
if (warnings.length !== 1) {
|
|
197
|
+
throw new Error(`Should emit 1 warning, but got ${warnings.length}`);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (!warnings[0].includes('Warning: dbset() called multiple times')) {
|
|
201
|
+
throw new Error('Warning should mention duplicate dbset call');
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (!warnings[0].includes('User')) {
|
|
205
|
+
throw new Error('Warning should mention table name');
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// ============================================================================
|
|
210
|
+
// TEST 5: Warn Only Once for Duplicate
|
|
211
|
+
// ============================================================================
|
|
212
|
+
|
|
213
|
+
test('Duplicate should warn only on first instance', () => {
|
|
214
|
+
class BuggyContext extends SimulatedContext {
|
|
215
|
+
constructor() {
|
|
216
|
+
super();
|
|
217
|
+
this.dbset(User);
|
|
218
|
+
this.dbset(User);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const warnings = captureWarnings(() => {
|
|
223
|
+
const ctx1 = new BuggyContext();
|
|
224
|
+
const ctx2 = new BuggyContext();
|
|
225
|
+
const ctx3 = new BuggyContext();
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
if (warnings.length !== 1) {
|
|
229
|
+
throw new Error(`Should warn only once, but got ${warnings.length} warnings`);
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// ============================================================================
|
|
234
|
+
// TEST 6: Entity Count Correct Despite Duplicate
|
|
235
|
+
// ============================================================================
|
|
236
|
+
|
|
237
|
+
test('Entity should be registered once despite duplicate in constructor', () => {
|
|
238
|
+
class BuggyContext extends SimulatedContext {
|
|
239
|
+
constructor() {
|
|
240
|
+
super();
|
|
241
|
+
this.dbset(User);
|
|
242
|
+
this.dbset(User);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const ctx = new BuggyContext();
|
|
247
|
+
|
|
248
|
+
if (ctx.__entities.length !== 1) {
|
|
249
|
+
throw new Error('Should have 1 entity, not ' + ctx.__entities.length);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (ctx.__entities[0].__name !== 'User') {
|
|
253
|
+
throw new Error('Entity should be User');
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
// ============================================================================
|
|
258
|
+
// TEST 7: Different Context Classes - No Warnings
|
|
259
|
+
// ============================================================================
|
|
260
|
+
|
|
261
|
+
test('Same model in different context classes should not warn', () => {
|
|
262
|
+
class UserContext extends SimulatedContext {
|
|
263
|
+
constructor() {
|
|
264
|
+
super();
|
|
265
|
+
this.dbset(User);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
class AdminContext extends SimulatedContext {
|
|
270
|
+
constructor() {
|
|
271
|
+
super();
|
|
272
|
+
this.dbset(User);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const warnings = captureWarnings(() => {
|
|
277
|
+
const userCtx = new UserContext();
|
|
278
|
+
const adminCtx = new AdminContext();
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
if (warnings.length !== 0) {
|
|
282
|
+
throw new Error('Different context classes should not warn');
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
// ============================================================================
|
|
287
|
+
// TEST 8: Separate Registries Per Context Class
|
|
288
|
+
// ============================================================================
|
|
289
|
+
|
|
290
|
+
test('Different context classes should have separate registries', () => {
|
|
291
|
+
class UserContext extends SimulatedContext {
|
|
292
|
+
constructor() {
|
|
293
|
+
super();
|
|
294
|
+
this.dbset(User);
|
|
295
|
+
this.dbset(Auth);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
class AdminContext extends SimulatedContext {
|
|
300
|
+
constructor() {
|
|
301
|
+
super();
|
|
302
|
+
this.dbset(User);
|
|
303
|
+
this.dbset(Settings);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const userCtx = new UserContext();
|
|
308
|
+
const adminCtx = new AdminContext();
|
|
309
|
+
|
|
310
|
+
const userRegistry = SimulatedContext._globalModelRegistry['UserContext'];
|
|
311
|
+
const adminRegistry = SimulatedContext._globalModelRegistry['AdminContext'];
|
|
312
|
+
|
|
313
|
+
if (!userRegistry.has('User')) throw new Error('UserContext should have User');
|
|
314
|
+
if (!userRegistry.has('Auth')) throw new Error('UserContext should have Auth');
|
|
315
|
+
if (userRegistry.has('Settings')) throw new Error('UserContext should not have Settings');
|
|
316
|
+
|
|
317
|
+
if (!adminRegistry.has('User')) throw new Error('AdminContext should have User');
|
|
318
|
+
if (!adminRegistry.has('Settings')) throw new Error('AdminContext should have Settings');
|
|
319
|
+
if (adminRegistry.has('Auth')) throw new Error('AdminContext should not have Auth');
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
// ============================================================================
|
|
323
|
+
// TEST 9: Multiple Instances of Different Contexts
|
|
324
|
+
// ============================================================================
|
|
325
|
+
|
|
326
|
+
test('Multiple instances of different contexts should not warn', () => {
|
|
327
|
+
class UserContext extends SimulatedContext {
|
|
328
|
+
constructor() {
|
|
329
|
+
super();
|
|
330
|
+
this.dbset(User);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
class AdminContext extends SimulatedContext {
|
|
335
|
+
constructor() {
|
|
336
|
+
super();
|
|
337
|
+
this.dbset(User);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const warnings = captureWarnings(() => {
|
|
342
|
+
const userCtx1 = new UserContext();
|
|
343
|
+
const adminCtx1 = new AdminContext();
|
|
344
|
+
const userCtx2 = new UserContext();
|
|
345
|
+
const adminCtx2 = new AdminContext();
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
if (warnings.length !== 0) {
|
|
349
|
+
throw new Error('Multiple instances of different contexts should not warn');
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
// ============================================================================
|
|
354
|
+
// TEST 10: qaContext Pattern (dbset then dbset.seed)
|
|
355
|
+
// ============================================================================
|
|
356
|
+
|
|
357
|
+
test('qaContext pattern (dbset then dbset.seed) should warn about duplicate', () => {
|
|
358
|
+
class QAContext extends SimulatedContext {
|
|
359
|
+
constructor() {
|
|
360
|
+
super();
|
|
361
|
+
this.dbset(User);
|
|
362
|
+
// ... imagine 150 lines ...
|
|
363
|
+
this.dbset(User).seed([{ id: 1, name: 'Test' }]);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const warnings = captureWarnings(() => {
|
|
368
|
+
const ctx = new QAContext();
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
if (warnings.length !== 1) {
|
|
372
|
+
throw new Error('Should warn about duplicate in constructor');
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
// ============================================================================
|
|
377
|
+
// TEST 11: Mixed Registration (Some New, Some Duplicate)
|
|
378
|
+
// ============================================================================
|
|
379
|
+
|
|
380
|
+
test('Mixed registration should warn only about duplicates', () => {
|
|
381
|
+
class MixedContext extends SimulatedContext {
|
|
382
|
+
constructor() {
|
|
383
|
+
super();
|
|
384
|
+
this.dbset(User); // New
|
|
385
|
+
this.dbset(Auth); // New
|
|
386
|
+
this.dbset(User); // Duplicate
|
|
387
|
+
this.dbset(Settings); // New
|
|
388
|
+
this.dbset(Auth); // Duplicate
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const warnings = captureWarnings(() => {
|
|
393
|
+
const ctx = new MixedContext();
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
if (warnings.length !== 2) {
|
|
397
|
+
throw new Error(`Should warn about 2 duplicates, got ${warnings.length}`);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
const ctx = new MixedContext();
|
|
401
|
+
if (ctx.__entities.length !== 3) {
|
|
402
|
+
throw new Error('Should have 3 unique entities');
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
// ============================================================================
|
|
407
|
+
// TEST 12: Empty Context
|
|
408
|
+
// ============================================================================
|
|
409
|
+
|
|
410
|
+
test('Empty context should not warn', () => {
|
|
411
|
+
class EmptyContext extends SimulatedContext {
|
|
412
|
+
constructor() {
|
|
413
|
+
super();
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
const warnings = captureWarnings(() => {
|
|
418
|
+
const ctx1 = new EmptyContext();
|
|
419
|
+
const ctx2 = new EmptyContext();
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
if (warnings.length !== 0) {
|
|
423
|
+
throw new Error('Empty context should not warn');
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
const registry = SimulatedContext._globalModelRegistry['EmptyContext'];
|
|
427
|
+
if (!registry) throw new Error('Registry should exist');
|
|
428
|
+
if (registry.size !== 0) throw new Error('Registry should be empty');
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
// ============================================================================
|
|
432
|
+
// TEST 13: Large Context (50 models)
|
|
433
|
+
// ============================================================================
|
|
434
|
+
|
|
435
|
+
test('Large context with 50 models should not warn on multiple instances', () => {
|
|
436
|
+
class LargeContext extends SimulatedContext {
|
|
437
|
+
constructor() {
|
|
438
|
+
super();
|
|
439
|
+
for (let i = 0; i < 50; i++) {
|
|
440
|
+
this.dbset({ name: `Model${i}`, schema: { id: 'int' } });
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
const warnings = captureWarnings(() => {
|
|
446
|
+
const ctx1 = new LargeContext();
|
|
447
|
+
const ctx2 = new LargeContext();
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
if (warnings.length !== 0) {
|
|
451
|
+
throw new Error('Large context should not warn');
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
const registry = SimulatedContext._globalModelRegistry['LargeContext'];
|
|
455
|
+
if (registry.size !== 50) {
|
|
456
|
+
throw new Error(`Registry should have 50 models, got ${registry.size}`);
|
|
457
|
+
}
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
// ============================================================================
|
|
461
|
+
// TEST 14: Registry Isolation
|
|
462
|
+
// ============================================================================
|
|
463
|
+
|
|
464
|
+
test('Registry should not pollute other context classes', () => {
|
|
465
|
+
class ContextA extends SimulatedContext {
|
|
466
|
+
constructor() {
|
|
467
|
+
super();
|
|
468
|
+
this.dbset(User);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
class ContextB extends SimulatedContext {
|
|
473
|
+
constructor() {
|
|
474
|
+
super();
|
|
475
|
+
this.dbset(Auth);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
const ctxA = new ContextA();
|
|
480
|
+
const ctxB = new ContextB();
|
|
481
|
+
|
|
482
|
+
const registryA = SimulatedContext._globalModelRegistry['ContextA'];
|
|
483
|
+
const registryB = SimulatedContext._globalModelRegistry['ContextB'];
|
|
484
|
+
|
|
485
|
+
if (!registryA.has('User')) throw new Error('ContextA should have User');
|
|
486
|
+
if (registryA.has('Auth')) throw new Error('ContextA should not have Auth');
|
|
487
|
+
|
|
488
|
+
if (!registryB.has('Auth')) throw new Error('ContextB should have Auth');
|
|
489
|
+
if (registryB.has('User')) throw new Error('ContextB should not have User');
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
// ============================================================================
|
|
493
|
+
// TEST 15: Many Context Classes
|
|
494
|
+
// ============================================================================
|
|
495
|
+
|
|
496
|
+
test('Many context classes should work independently', () => {
|
|
497
|
+
const warnings = captureWarnings(() => {
|
|
498
|
+
for (let i = 0; i < 10; i++) {
|
|
499
|
+
const ContextClass = class extends SimulatedContext {
|
|
500
|
+
constructor() {
|
|
501
|
+
super();
|
|
502
|
+
this.dbset(User);
|
|
503
|
+
}
|
|
504
|
+
};
|
|
505
|
+
Object.defineProperty(ContextClass, 'name', { value: `Context${i}` });
|
|
506
|
+
|
|
507
|
+
// Create 3 instances of each
|
|
508
|
+
new ContextClass();
|
|
509
|
+
new ContextClass();
|
|
510
|
+
new ContextClass();
|
|
511
|
+
}
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
if (warnings.length !== 0) {
|
|
515
|
+
throw new Error('Multiple context classes should not warn');
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
if (Object.keys(SimulatedContext._globalModelRegistry).length !== 10) {
|
|
519
|
+
throw new Error('Should have 10 registries');
|
|
520
|
+
}
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
// ============================================================================
|
|
524
|
+
// RESULTS
|
|
525
|
+
// ============================================================================
|
|
526
|
+
|
|
527
|
+
console.log("\n" + "=".repeat(70));
|
|
528
|
+
console.log(`Tests Passed: ${passed}`);
|
|
529
|
+
console.log(`Tests Failed: ${failed}`);
|
|
530
|
+
console.log("=".repeat(70));
|
|
531
|
+
|
|
532
|
+
if (failed > 0) {
|
|
533
|
+
console.log("\n❌ Some tests failed!\n");
|
|
534
|
+
process.exit(1);
|
|
535
|
+
} else {
|
|
536
|
+
console.log("\n✅ All tests passed!\n");
|
|
537
|
+
process.exit(0);
|
|
538
|
+
}
|