@navios/di 0.3.0 → 0.4.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 (96) hide show
  1. package/README.md +67 -6
  2. package/coverage/base.css +224 -0
  3. package/coverage/block-navigation.js +87 -0
  4. package/coverage/clover.xml +2659 -0
  5. package/coverage/coverage-final.json +46 -0
  6. package/coverage/docs/examples/basic-usage.mts.html +376 -0
  7. package/coverage/docs/examples/factory-pattern.mts.html +1039 -0
  8. package/coverage/docs/examples/index.html +176 -0
  9. package/coverage/docs/examples/injection-tokens.mts.html +760 -0
  10. package/coverage/docs/examples/request-scope-example.mts.html +847 -0
  11. package/coverage/docs/examples/service-lifecycle.mts.html +1162 -0
  12. package/coverage/favicon.png +0 -0
  13. package/coverage/index.html +236 -0
  14. package/coverage/lib/_tsup-dts-rollup.d.mts.html +2806 -0
  15. package/coverage/lib/index.d.mts.html +310 -0
  16. package/coverage/lib/index.html +131 -0
  17. package/coverage/prettify.css +1 -0
  18. package/coverage/prettify.js +2 -0
  19. package/coverage/sort-arrow-sprite.png +0 -0
  20. package/coverage/sorter.js +196 -0
  21. package/coverage/src/container.mts.html +586 -0
  22. package/coverage/src/decorators/factory.decorator.mts.html +322 -0
  23. package/coverage/src/decorators/index.html +146 -0
  24. package/coverage/src/decorators/index.mts.html +91 -0
  25. package/coverage/src/decorators/injectable.decorator.mts.html +394 -0
  26. package/coverage/src/enums/index.html +146 -0
  27. package/coverage/src/enums/index.mts.html +91 -0
  28. package/coverage/src/enums/injectable-scope.enum.mts.html +127 -0
  29. package/coverage/src/enums/injectable-type.enum.mts.html +97 -0
  30. package/coverage/src/errors/errors.enum.mts.html +109 -0
  31. package/coverage/src/errors/factory-not-found.mts.html +109 -0
  32. package/coverage/src/errors/factory-token-not-resolved.mts.html +115 -0
  33. package/coverage/src/errors/index.html +221 -0
  34. package/coverage/src/errors/index.mts.html +106 -0
  35. package/coverage/src/errors/instance-destroying.mts.html +109 -0
  36. package/coverage/src/errors/instance-expired.mts.html +109 -0
  37. package/coverage/src/errors/instance-not-found.mts.html +109 -0
  38. package/coverage/src/errors/unknown-error.mts.html +130 -0
  39. package/coverage/src/event-emitter.mts.html +400 -0
  40. package/coverage/src/factory-context.mts.html +109 -0
  41. package/coverage/src/index.html +296 -0
  42. package/coverage/src/index.mts.html +139 -0
  43. package/coverage/src/injection-token.mts.html +571 -0
  44. package/coverage/src/injector.mts.html +133 -0
  45. package/coverage/src/interfaces/factory.interface.mts.html +121 -0
  46. package/coverage/src/interfaces/index.html +161 -0
  47. package/coverage/src/interfaces/index.mts.html +94 -0
  48. package/coverage/src/interfaces/on-service-destroy.interface.mts.html +94 -0
  49. package/coverage/src/interfaces/on-service-init.interface.mts.html +94 -0
  50. package/coverage/src/registry.mts.html +247 -0
  51. package/coverage/src/request-context-holder.mts.html +607 -0
  52. package/coverage/src/service-instantiator.mts.html +559 -0
  53. package/coverage/src/service-locator-event-bus.mts.html +289 -0
  54. package/coverage/src/service-locator-instance-holder.mts.html +307 -0
  55. package/coverage/src/service-locator-manager.mts.html +604 -0
  56. package/coverage/src/service-locator.mts.html +2911 -0
  57. package/coverage/src/symbols/index.html +131 -0
  58. package/coverage/src/symbols/index.mts.html +88 -0
  59. package/coverage/src/symbols/injectable-token.mts.html +88 -0
  60. package/coverage/src/utils/defer.mts.html +304 -0
  61. package/coverage/src/utils/get-injectable-token.mts.html +142 -0
  62. package/coverage/src/utils/get-injectors.mts.html +691 -0
  63. package/coverage/src/utils/index.html +176 -0
  64. package/coverage/src/utils/index.mts.html +97 -0
  65. package/coverage/src/utils/types.mts.html +241 -0
  66. package/docs/README.md +5 -2
  67. package/docs/api-reference.md +38 -0
  68. package/docs/container.md +75 -0
  69. package/docs/getting-started.md +4 -3
  70. package/docs/injectable.md +4 -3
  71. package/docs/migration.md +177 -0
  72. package/docs/request-contexts.md +364 -0
  73. package/lib/_tsup-dts-rollup.d.mts +180 -35
  74. package/lib/_tsup-dts-rollup.d.ts +180 -35
  75. package/lib/index.d.mts +1 -0
  76. package/lib/index.d.ts +1 -0
  77. package/lib/index.js +485 -279
  78. package/lib/index.js.map +1 -1
  79. package/lib/index.mjs +485 -280
  80. package/lib/index.mjs.map +1 -1
  81. package/package.json +1 -1
  82. package/src/__tests__/defer.spec.mts +166 -0
  83. package/src/__tests__/errors.spec.mts +61 -0
  84. package/src/__tests__/event-emitter.spec.mts +163 -0
  85. package/src/__tests__/get-injectors.spec.mts +70 -0
  86. package/src/__tests__/registry.spec.mts +335 -0
  87. package/src/__tests__/request-scope.spec.mts +167 -4
  88. package/src/__tests__/service-instantiator.spec.mts +408 -0
  89. package/src/__tests__/service-locator-event-bus.spec.mts +242 -0
  90. package/src/__tests__/service-locator-manager.spec.mts +370 -0
  91. package/src/__tests__/unified-api.spec.mts +130 -0
  92. package/src/base-instance-holder-manager.mts +175 -0
  93. package/src/index.mts +1 -0
  94. package/src/request-context-holder.mts +85 -27
  95. package/src/service-locator-manager.mts +12 -70
  96. package/src/service-locator.mts +421 -226
@@ -0,0 +1,335 @@
1
+ import { beforeEach, describe, expect, it } from 'vitest'
2
+
3
+ import { InjectableScope, InjectableType } from '../enums/index.mjs'
4
+ import { InjectionToken } from '../injection-token.mjs'
5
+ import { globalRegistry, Registry } from '../registry.mjs'
6
+
7
+ class TestService {}
8
+ class AnotherService {}
9
+
10
+ describe('Registry', () => {
11
+ let registry: Registry
12
+ let token1: InjectionToken<TestService, undefined>
13
+ let token2: InjectionToken<AnotherService, undefined>
14
+
15
+ beforeEach(() => {
16
+ registry = new Registry()
17
+ token1 = new InjectionToken<TestService, undefined>(
18
+ 'TestService',
19
+ undefined,
20
+ )
21
+ token2 = new InjectionToken<AnotherService, undefined>(
22
+ 'AnotherService',
23
+ undefined,
24
+ )
25
+ })
26
+
27
+ describe('constructor', () => {
28
+ it('should create registry without parent', () => {
29
+ const reg = new Registry()
30
+ expect(reg).toBeDefined()
31
+ })
32
+
33
+ it('should create registry with parent', () => {
34
+ const parentRegistry = new Registry()
35
+ const childRegistry = new Registry(parentRegistry)
36
+ expect(childRegistry).toBeDefined()
37
+ })
38
+ })
39
+
40
+ describe('set', () => {
41
+ it('should set factory record for token', () => {
42
+ registry.set(
43
+ token1,
44
+ InjectableScope.Singleton,
45
+ TestService,
46
+ InjectableType.Class,
47
+ )
48
+
49
+ expect(registry.has(token1)).toBe(true)
50
+ })
51
+
52
+ it('should set multiple factory records', () => {
53
+ registry.set(
54
+ token1,
55
+ InjectableScope.Singleton,
56
+ TestService,
57
+ InjectableType.Class,
58
+ )
59
+ registry.set(
60
+ token2,
61
+ InjectableScope.Transient,
62
+ AnotherService,
63
+ InjectableType.Factory,
64
+ )
65
+
66
+ expect(registry.has(token1)).toBe(true)
67
+ expect(registry.has(token2)).toBe(true)
68
+ })
69
+
70
+ it('should overwrite existing factory record', () => {
71
+ registry.set(
72
+ token1,
73
+ InjectableScope.Singleton,
74
+ TestService,
75
+ InjectableType.Class,
76
+ )
77
+ registry.set(
78
+ token1,
79
+ InjectableScope.Transient,
80
+ TestService,
81
+ InjectableType.Factory,
82
+ )
83
+
84
+ const record = registry.get(token1)
85
+ expect(record.scope).toBe(InjectableScope.Transient)
86
+ expect(record.type).toBe(InjectableType.Factory)
87
+ })
88
+ })
89
+
90
+ describe('has', () => {
91
+ it('should return false for non-existent token', () => {
92
+ expect(registry.has(token1)).toBe(false)
93
+ })
94
+
95
+ it('should return true for existing token', () => {
96
+ registry.set(
97
+ token1,
98
+ InjectableScope.Singleton,
99
+ TestService,
100
+ InjectableType.Class,
101
+ )
102
+ expect(registry.has(token1)).toBe(true)
103
+ })
104
+
105
+ it('should check parent registry when token not found locally', () => {
106
+ const parentRegistry = new Registry()
107
+ const childRegistry = new Registry(parentRegistry)
108
+
109
+ parentRegistry.set(
110
+ token1,
111
+ InjectableScope.Singleton,
112
+ TestService,
113
+ InjectableType.Class,
114
+ )
115
+
116
+ expect(childRegistry.has(token1)).toBe(true)
117
+ })
118
+
119
+ it('should return false when token not found in parent chain', () => {
120
+ const parentRegistry = new Registry()
121
+ const childRegistry = new Registry(parentRegistry)
122
+
123
+ expect(childRegistry.has(token1)).toBe(false)
124
+ })
125
+
126
+ it('should prioritize local registry over parent', () => {
127
+ const parentRegistry = new Registry()
128
+ const childRegistry = new Registry(parentRegistry)
129
+
130
+ parentRegistry.set(
131
+ token1,
132
+ InjectableScope.Singleton,
133
+ TestService,
134
+ InjectableType.Class,
135
+ )
136
+ childRegistry.set(
137
+ token1,
138
+ InjectableScope.Transient,
139
+ TestService,
140
+ InjectableType.Factory,
141
+ )
142
+
143
+ expect(childRegistry.has(token1)).toBe(true)
144
+ const record = childRegistry.get(token1)
145
+ expect(record.scope).toBe(InjectableScope.Transient) // From child registry
146
+ })
147
+ })
148
+
149
+ describe('get', () => {
150
+ it('should return factory record for existing token', () => {
151
+ registry.set(
152
+ token1,
153
+ InjectableScope.Singleton,
154
+ TestService,
155
+ InjectableType.Class,
156
+ )
157
+
158
+ const record = registry.get(token1)
159
+ expect(record.scope).toBe(InjectableScope.Singleton)
160
+ expect(record.target).toBe(TestService)
161
+ expect(record.type).toBe(InjectableType.Class)
162
+ expect(record.originalToken).toBe(token1)
163
+ })
164
+
165
+ it('should throw error for non-existent token', () => {
166
+ expect(() => {
167
+ registry.get(token1)
168
+ }).toThrow(`[Registry] No factory found for ${token1.toString()}`)
169
+ })
170
+
171
+ it('should get from parent registry when not found locally', () => {
172
+ const parentRegistry = new Registry()
173
+ const childRegistry = new Registry(parentRegistry)
174
+
175
+ parentRegistry.set(
176
+ token1,
177
+ InjectableScope.Singleton,
178
+ TestService,
179
+ InjectableType.Class,
180
+ )
181
+
182
+ const record = childRegistry.get(token1)
183
+ expect(record.scope).toBe(InjectableScope.Singleton)
184
+ expect(record.target).toBe(TestService)
185
+ })
186
+
187
+ it('should throw error when token not found in parent chain', () => {
188
+ const parentRegistry = new Registry()
189
+ const childRegistry = new Registry(parentRegistry)
190
+
191
+ expect(() => {
192
+ childRegistry.get(token1)
193
+ }).toThrow(`[Registry] No factory found for ${token1.toString()}`)
194
+ })
195
+
196
+ it('should prioritize local registry over parent', () => {
197
+ const parentRegistry = new Registry()
198
+ const childRegistry = new Registry(parentRegistry)
199
+
200
+ parentRegistry.set(
201
+ token1,
202
+ InjectableScope.Singleton,
203
+ TestService,
204
+ InjectableType.Class,
205
+ )
206
+ childRegistry.set(
207
+ token1,
208
+ InjectableScope.Transient,
209
+ AnotherService,
210
+ InjectableType.Factory,
211
+ )
212
+
213
+ const record = childRegistry.get(token1)
214
+ expect(record.scope).toBe(InjectableScope.Transient)
215
+ expect(record.target).toBe(AnotherService)
216
+ expect(record.type).toBe(InjectableType.Factory)
217
+ })
218
+ })
219
+
220
+ describe('delete', () => {
221
+ it('should delete existing token', () => {
222
+ registry.set(
223
+ token1,
224
+ InjectableScope.Singleton,
225
+ TestService,
226
+ InjectableType.Class,
227
+ )
228
+ expect(registry.has(token1)).toBe(true)
229
+
230
+ registry.delete(token1)
231
+ expect(registry.has(token1)).toBe(false)
232
+ })
233
+
234
+ it('should not affect parent registry when deleting from child', () => {
235
+ const parentRegistry = new Registry()
236
+ const childRegistry = new Registry(parentRegistry)
237
+
238
+ parentRegistry.set(
239
+ token1,
240
+ InjectableScope.Singleton,
241
+ TestService,
242
+ InjectableType.Class,
243
+ )
244
+ childRegistry.set(
245
+ token1,
246
+ InjectableScope.Transient,
247
+ AnotherService,
248
+ InjectableType.Factory,
249
+ )
250
+
251
+ childRegistry.delete(token1)
252
+
253
+ // Child should no longer have it
254
+ expect(childRegistry.has(token1)).toBe(true) // Still true because it exists in parent
255
+ // But getting it should return parent's version
256
+ const record = childRegistry.get(token1)
257
+ expect(record.scope).toBe(InjectableScope.Singleton) // From parent
258
+ })
259
+
260
+ it('should handle delete for non-existent token gracefully', () => {
261
+ expect(() => {
262
+ registry.delete(token1)
263
+ }).not.toThrow()
264
+ })
265
+ })
266
+
267
+ describe('complex parent-child scenarios', () => {
268
+ it('should handle deep hierarchy', () => {
269
+ const grandParent = new Registry()
270
+ const parent = new Registry(grandParent)
271
+ const child = new Registry(parent)
272
+
273
+ grandParent.set(
274
+ token1,
275
+ InjectableScope.Singleton,
276
+ TestService,
277
+ InjectableType.Class,
278
+ )
279
+
280
+ expect(child.has(token1)).toBe(true)
281
+ const record = child.get(token1)
282
+ expect(record.scope).toBe(InjectableScope.Singleton)
283
+ })
284
+
285
+ it('should handle overriding at different levels', () => {
286
+ const grandParent = new Registry()
287
+ const parent = new Registry(grandParent)
288
+ const child = new Registry(parent)
289
+
290
+ grandParent.set(
291
+ token1,
292
+ InjectableScope.Singleton,
293
+ TestService,
294
+ InjectableType.Class,
295
+ )
296
+ parent.set(
297
+ token1,
298
+ InjectableScope.Transient,
299
+ AnotherService,
300
+ InjectableType.Factory,
301
+ )
302
+
303
+ const record = child.get(token1)
304
+ expect(record.scope).toBe(InjectableScope.Transient) // From parent, not grandparent
305
+ expect(record.target).toBe(AnotherService)
306
+ })
307
+ })
308
+ })
309
+
310
+ describe('globalRegistry', () => {
311
+ it('should be a Registry instance', () => {
312
+ expect(globalRegistry).toBeInstanceOf(Registry)
313
+ })
314
+
315
+ it('should be able to store and retrieve tokens', () => {
316
+ const token = new InjectionToken<TestService, undefined>(
317
+ 'GlobalTest',
318
+ undefined,
319
+ )
320
+
321
+ globalRegistry.set(
322
+ token,
323
+ InjectableScope.Singleton,
324
+ TestService,
325
+ InjectableType.Class,
326
+ )
327
+ expect(globalRegistry.has(token)).toBe(true)
328
+
329
+ const record = globalRegistry.get(token)
330
+ expect(record.target).toBe(TestService)
331
+
332
+ // Clean up
333
+ globalRegistry.delete(token)
334
+ })
335
+ })
@@ -4,6 +4,7 @@ import { Container } from '../container.mjs'
4
4
  import { Injectable } from '../decorators/injectable.decorator.mjs'
5
5
  import { InjectableScope } from '../enums/index.mjs'
6
6
  import { inject } from '../index.mjs'
7
+ import { InjectionToken } from '../injection-token.mjs'
7
8
  import { Registry } from '../registry.mjs'
8
9
  import { createRequestContextHolder } from '../request-context-holder.mjs'
9
10
 
@@ -237,13 +238,12 @@ describe('Request Scope', () => {
237
238
 
238
239
  holder.addInstance('test-instance', mockInstance, mockHolder)
239
240
 
240
- expect(holder.hasInstance('test-instance')).toBe(true)
241
- expect(holder.getInstance('test-instance')).toBe(mockInstance)
242
- expect(holder.getHolder('test-instance')).toBe(mockHolder)
241
+ expect(holder.has('test-instance')).toBe(true)
242
+ expect(holder.get('test-instance')).toBe(mockHolder)
243
243
 
244
244
  // Clear instances
245
245
  holder.clear()
246
- expect(holder.hasInstance('test-instance')).toBe(false)
246
+ expect(holder.has('test-instance')).toBe(false)
247
247
  })
248
248
 
249
249
  it('should handle metadata correctly', () => {
@@ -259,5 +259,168 @@ describe('Request Scope', () => {
259
259
  holder.clear()
260
260
  expect(holder.getMetadata('key1')).toBeUndefined()
261
261
  })
262
+
263
+ it('should store instances by InjectionToken', () => {
264
+ const holder = createRequestContextHolder('test-request')
265
+ const token = InjectionToken.create<string>('TestService')
266
+ const instance = { id: 'test-instance', data: 'test-data' }
267
+
268
+ // Store instance by InjectionToken
269
+ holder.addInstance(token, instance)
270
+
271
+ // Verify instance is stored and retrievable
272
+ expect(holder.has(token.toString())).toBe(true)
273
+ expect(holder.get(token.toString())?.instance).toBe(instance)
274
+
275
+ // Verify holder is created with correct properties
276
+ const holderInfo = holder.get(token.toString())
277
+ expect(holderInfo).toBeDefined()
278
+ expect(holderInfo?.instance).toBe(instance)
279
+ expect(holderInfo?.name).toBe(token.toString())
280
+ })
281
+
282
+ it('should store multiple instances by different InjectionTokens', () => {
283
+ const holder = createRequestContextHolder('test-request')
284
+
285
+ const token1 = InjectionToken.create<string>('Service1')
286
+ const token2 = InjectionToken.create<number>('Service2')
287
+ const token3 = InjectionToken.create<boolean>('Service3')
288
+
289
+ const instance1 = { id: 'instance1', type: 'string' }
290
+ const instance2 = { id: 'instance2', type: 'number' }
291
+ const instance3 = { id: 'instance3', type: 'boolean' }
292
+
293
+ // Store multiple instances
294
+ holder.addInstance(token1, instance1)
295
+ holder.addInstance(token2, instance2)
296
+ holder.addInstance(token3, instance3)
297
+
298
+ // Verify all instances are stored correctly
299
+ expect(holder.has(token1.toString())).toBe(true)
300
+ expect(holder.has(token2.toString())).toBe(true)
301
+ expect(holder.has(token3.toString())).toBe(true)
302
+
303
+ expect(holder.get(token1.toString())?.instance).toBe(instance1)
304
+ expect(holder.get(token2.toString())?.instance).toBe(instance2)
305
+ expect(holder.get(token3.toString())?.instance).toBe(instance3)
306
+
307
+ // Verify each has its own holder
308
+ const holder1 = holder.get(token1.toString())
309
+ const holder2 = holder.get(token2.toString())
310
+ const holder3 = holder.get(token3.toString())
311
+
312
+ expect(holder1?.instance).toBe(instance1)
313
+ expect(holder2?.instance).toBe(instance2)
314
+ expect(holder3?.instance).toBe(instance3)
315
+ })
316
+
317
+ it('should override instances stored by InjectionToken', () => {
318
+ const holder = createRequestContextHolder('test-request')
319
+ const token = InjectionToken.create<string>('TestService')
320
+
321
+ const originalInstance = { id: 'original', data: 'original-data' }
322
+ const newInstance = { id: 'new', data: 'new-data' }
323
+
324
+ // Store original instance
325
+ holder.addInstance(token, originalInstance)
326
+ expect(holder.get(token.toString())?.instance).toBe(originalInstance)
327
+
328
+ // Override with new instance
329
+ holder.addInstance(token, newInstance)
330
+ expect(holder.get(token.toString())?.instance).toBe(newInstance)
331
+ expect(holder.get(token.toString())?.instance).not.toBe(originalInstance)
332
+
333
+ // Verify holder is updated
334
+ const holderInfo = holder.get(token.toString())
335
+ expect(holderInfo?.instance).toBe(newInstance)
336
+ })
337
+
338
+ it('should handle InjectionToken with different name types', () => {
339
+ const holder = createRequestContextHolder('test-request')
340
+
341
+ // Test with string name
342
+ const stringToken = InjectionToken.create<string>('StringService')
343
+ const stringInstance = { type: 'string' }
344
+
345
+ // Test with symbol name
346
+ const symbolToken = InjectionToken.create<number>(Symbol('SymbolService'))
347
+ const symbolInstance = { type: 'symbol' }
348
+
349
+ // Test with class name
350
+ class TestClass {}
351
+ const classToken = InjectionToken.create(TestClass)
352
+ const classInstance = { type: 'class' }
353
+
354
+ holder.addInstance(stringToken, stringInstance)
355
+ holder.addInstance(symbolToken, symbolInstance)
356
+ holder.addInstance(classToken, classInstance)
357
+
358
+ expect(holder.get(stringToken.toString())?.instance).toBe(stringInstance)
359
+ expect(holder.get(symbolToken.toString())?.instance).toBe(symbolInstance)
360
+ expect(holder.get(classToken.toString())?.instance).toBe(classInstance)
361
+ })
362
+
363
+ it('should clear instances stored by InjectionToken', () => {
364
+ const holder = createRequestContextHolder('test-request')
365
+ const token1 = InjectionToken.create<string>('Service1')
366
+ const token2 = InjectionToken.create<number>('Service2')
367
+
368
+ const instance1 = { id: 'instance1' }
369
+ const instance2 = { id: 'instance2' }
370
+
371
+ holder.addInstance(token1, instance1)
372
+ holder.addInstance(token2, instance2)
373
+
374
+ expect(holder.has(token1.toString())).toBe(true)
375
+ expect(holder.has(token2.toString())).toBe(true)
376
+
377
+ // Clear all instances
378
+ holder.clear()
379
+
380
+ expect(holder.has(token1.toString())).toBe(false)
381
+ expect(holder.has(token2.toString())).toBe(false)
382
+ expect(holder.get(token1.toString())?.instance).toBeUndefined()
383
+ expect(holder.get(token2.toString())?.instance).toBeUndefined()
384
+ })
385
+
386
+ it('should handle mixed storage by InjectionToken and string name', () => {
387
+ const holder = createRequestContextHolder('test-request')
388
+
389
+ const token = InjectionToken.create<string>('TokenService')
390
+ const tokenInstance = { id: 'token-instance' }
391
+
392
+ const stringName = 'string-service'
393
+ const stringInstance = { id: 'string-instance' }
394
+
395
+ // Store by InjectionToken
396
+ holder.addInstance(token, tokenInstance)
397
+
398
+ // Store by string name (requires holder)
399
+ const mockHolder = {
400
+ status: 'Created' as any,
401
+ name: stringName,
402
+ instance: stringInstance,
403
+ creationPromise: null,
404
+ destroyPromise: null,
405
+ type: 'Class' as any,
406
+ scope: 'Singleton' as any,
407
+ deps: new Set<string>(),
408
+ destroyListeners: [],
409
+ createdAt: Date.now(),
410
+ ttl: Infinity,
411
+ }
412
+ holder.addInstance(stringName, stringInstance, mockHolder)
413
+
414
+ // Verify both are stored correctly
415
+ expect(holder.has(token.toString())).toBe(true)
416
+ expect(holder.has(stringName)).toBe(true)
417
+
418
+ expect(holder.get(token.toString())?.instance).toBe(tokenInstance)
419
+ expect(holder.get(stringName)?.instance).toBe(stringInstance)
420
+
421
+ // Verify holders
422
+ expect(holder.get(token.toString())?.instance).toBe(tokenInstance)
423
+ expect(holder.get(stringName)?.instance).toBe(stringInstance)
424
+ })
262
425
  })
263
426
  })