@navios/di 0.3.1 → 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.
- package/README.md +67 -6
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/clover.xml +2659 -0
- package/coverage/coverage-final.json +46 -0
- package/coverage/docs/examples/basic-usage.mts.html +376 -0
- package/coverage/docs/examples/factory-pattern.mts.html +1039 -0
- package/coverage/docs/examples/index.html +176 -0
- package/coverage/docs/examples/injection-tokens.mts.html +760 -0
- package/coverage/docs/examples/request-scope-example.mts.html +847 -0
- package/coverage/docs/examples/service-lifecycle.mts.html +1162 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +236 -0
- package/coverage/lib/_tsup-dts-rollup.d.mts.html +2806 -0
- package/coverage/lib/index.d.mts.html +310 -0
- package/coverage/lib/index.html +131 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +196 -0
- package/coverage/src/container.mts.html +586 -0
- package/coverage/src/decorators/factory.decorator.mts.html +322 -0
- package/coverage/src/decorators/index.html +146 -0
- package/coverage/src/decorators/index.mts.html +91 -0
- package/coverage/src/decorators/injectable.decorator.mts.html +394 -0
- package/coverage/src/enums/index.html +146 -0
- package/coverage/src/enums/index.mts.html +91 -0
- package/coverage/src/enums/injectable-scope.enum.mts.html +127 -0
- package/coverage/src/enums/injectable-type.enum.mts.html +97 -0
- package/coverage/src/errors/errors.enum.mts.html +109 -0
- package/coverage/src/errors/factory-not-found.mts.html +109 -0
- package/coverage/src/errors/factory-token-not-resolved.mts.html +115 -0
- package/coverage/src/errors/index.html +221 -0
- package/coverage/src/errors/index.mts.html +106 -0
- package/coverage/src/errors/instance-destroying.mts.html +109 -0
- package/coverage/src/errors/instance-expired.mts.html +109 -0
- package/coverage/src/errors/instance-not-found.mts.html +109 -0
- package/coverage/src/errors/unknown-error.mts.html +130 -0
- package/coverage/src/event-emitter.mts.html +400 -0
- package/coverage/src/factory-context.mts.html +109 -0
- package/coverage/src/index.html +296 -0
- package/coverage/src/index.mts.html +139 -0
- package/coverage/src/injection-token.mts.html +571 -0
- package/coverage/src/injector.mts.html +133 -0
- package/coverage/src/interfaces/factory.interface.mts.html +121 -0
- package/coverage/src/interfaces/index.html +161 -0
- package/coverage/src/interfaces/index.mts.html +94 -0
- package/coverage/src/interfaces/on-service-destroy.interface.mts.html +94 -0
- package/coverage/src/interfaces/on-service-init.interface.mts.html +94 -0
- package/coverage/src/registry.mts.html +247 -0
- package/coverage/src/request-context-holder.mts.html +607 -0
- package/coverage/src/service-instantiator.mts.html +559 -0
- package/coverage/src/service-locator-event-bus.mts.html +289 -0
- package/coverage/src/service-locator-instance-holder.mts.html +307 -0
- package/coverage/src/service-locator-manager.mts.html +604 -0
- package/coverage/src/service-locator.mts.html +2911 -0
- package/coverage/src/symbols/index.html +131 -0
- package/coverage/src/symbols/index.mts.html +88 -0
- package/coverage/src/symbols/injectable-token.mts.html +88 -0
- package/coverage/src/utils/defer.mts.html +304 -0
- package/coverage/src/utils/get-injectable-token.mts.html +142 -0
- package/coverage/src/utils/get-injectors.mts.html +691 -0
- package/coverage/src/utils/index.html +176 -0
- package/coverage/src/utils/index.mts.html +97 -0
- package/coverage/src/utils/types.mts.html +241 -0
- package/docs/README.md +5 -2
- package/docs/api-reference.md +38 -0
- package/docs/container.md +75 -0
- package/docs/getting-started.md +4 -3
- package/docs/injectable.md +4 -3
- package/docs/migration.md +177 -0
- package/docs/request-contexts.md +364 -0
- package/lib/_tsup-dts-rollup.d.mts +177 -36
- package/lib/_tsup-dts-rollup.d.ts +177 -36
- package/lib/index.d.mts +1 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +480 -294
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +480 -295
- package/lib/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/defer.spec.mts +166 -0
- package/src/__tests__/errors.spec.mts +61 -0
- package/src/__tests__/event-emitter.spec.mts +163 -0
- package/src/__tests__/get-injectors.spec.mts +70 -0
- package/src/__tests__/registry.spec.mts +335 -0
- package/src/__tests__/request-scope.spec.mts +34 -35
- package/src/__tests__/service-instantiator.spec.mts +408 -0
- package/src/__tests__/service-locator-event-bus.spec.mts +242 -0
- package/src/__tests__/service-locator-manager.spec.mts +370 -0
- package/src/__tests__/unified-api.spec.mts +130 -0
- package/src/base-instance-holder-manager.mts +175 -0
- package/src/index.mts +1 -0
- package/src/request-context-holder.mts +73 -44
- package/src/service-locator-manager.mts +12 -70
- package/src/service-locator.mts +421 -226
package/package.json
CHANGED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import { createDeferred, Deferred } from '../utils/defer.mjs'
|
|
4
|
+
|
|
5
|
+
describe('Deferred', () => {
|
|
6
|
+
describe('constructor', () => {
|
|
7
|
+
it('should create a deferred promise', () => {
|
|
8
|
+
const deferred = new Deferred<string>()
|
|
9
|
+
|
|
10
|
+
expect(deferred.promise).toBeInstanceOf(Promise)
|
|
11
|
+
expect(deferred.isResolved).toBe(false)
|
|
12
|
+
expect(deferred.isRejected).toBe(false)
|
|
13
|
+
expect(deferred.isSettled).toBe(false)
|
|
14
|
+
})
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
describe('resolve', () => {
|
|
18
|
+
it('should resolve the promise with given value', async () => {
|
|
19
|
+
const deferred = new Deferred<string>()
|
|
20
|
+
const testValue = 'test value'
|
|
21
|
+
|
|
22
|
+
deferred.resolve(testValue)
|
|
23
|
+
const result = await deferred.promise
|
|
24
|
+
|
|
25
|
+
expect(result).toBe(testValue)
|
|
26
|
+
expect(deferred.isResolved).toBe(true)
|
|
27
|
+
expect(deferred.isRejected).toBe(false)
|
|
28
|
+
expect(deferred.isSettled).toBe(true)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('should throw error if already resolved', () => {
|
|
32
|
+
const deferred = new Deferred<string>()
|
|
33
|
+
|
|
34
|
+
deferred.resolve('test')
|
|
35
|
+
|
|
36
|
+
expect(() => {
|
|
37
|
+
deferred.resolve('test2')
|
|
38
|
+
}).toThrow('Deferred promise has already been resolved or rejected')
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('should throw error if already rejected', async () => {
|
|
42
|
+
const deferred = new Deferred<string>()
|
|
43
|
+
|
|
44
|
+
deferred.reject(new Error('test error'))
|
|
45
|
+
|
|
46
|
+
// Catch the rejection to avoid unhandled promise rejection
|
|
47
|
+
try {
|
|
48
|
+
await deferred.promise
|
|
49
|
+
} catch (error) {
|
|
50
|
+
// Expected to fail
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
expect(() => {
|
|
54
|
+
deferred.resolve('test')
|
|
55
|
+
}).toThrow('Deferred promise has already been resolved or rejected')
|
|
56
|
+
})
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
describe('reject', () => {
|
|
60
|
+
it('should reject the promise with given reason', async () => {
|
|
61
|
+
const deferred = new Deferred<string>()
|
|
62
|
+
const testError = new Error('test error')
|
|
63
|
+
|
|
64
|
+
deferred.reject(testError)
|
|
65
|
+
|
|
66
|
+
await expect(deferred.promise).rejects.toThrow('test error')
|
|
67
|
+
expect(deferred.isResolved).toBe(false)
|
|
68
|
+
expect(deferred.isRejected).toBe(true)
|
|
69
|
+
expect(deferred.isSettled).toBe(true)
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it('should reject with string reason', async () => {
|
|
73
|
+
const deferred = new Deferred<string>()
|
|
74
|
+
|
|
75
|
+
deferred.reject('string error')
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
await deferred.promise
|
|
79
|
+
expect.fail('Should have rejected')
|
|
80
|
+
} catch (error) {
|
|
81
|
+
expect(error).toBe('string error')
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
it('should throw error if already resolved', () => {
|
|
86
|
+
const deferred = new Deferred<string>()
|
|
87
|
+
|
|
88
|
+
deferred.resolve('test')
|
|
89
|
+
|
|
90
|
+
expect(() => {
|
|
91
|
+
deferred.reject(new Error('test error'))
|
|
92
|
+
}).toThrow('Deferred promise has already been resolved or rejected')
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
it('should throw error if already rejected', async () => {
|
|
96
|
+
const deferred = new Deferred<string>()
|
|
97
|
+
|
|
98
|
+
deferred.reject(new Error('first error'))
|
|
99
|
+
|
|
100
|
+
// Catch the rejection to avoid unhandled promise rejection
|
|
101
|
+
try {
|
|
102
|
+
await deferred.promise
|
|
103
|
+
} catch (error) {
|
|
104
|
+
// Expected to fail
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
expect(() => {
|
|
108
|
+
deferred.reject(new Error('second error'))
|
|
109
|
+
}).toThrow('Deferred promise has already been resolved or rejected')
|
|
110
|
+
})
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
describe('status getters', () => {
|
|
114
|
+
it('should return correct status for unresolved promise', () => {
|
|
115
|
+
const deferred = new Deferred<string>()
|
|
116
|
+
|
|
117
|
+
expect(deferred.isResolved).toBe(false)
|
|
118
|
+
expect(deferred.isRejected).toBe(false)
|
|
119
|
+
expect(deferred.isSettled).toBe(false)
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
it('should return correct status after resolve', () => {
|
|
123
|
+
const deferred = new Deferred<string>()
|
|
124
|
+
|
|
125
|
+
deferred.resolve('test')
|
|
126
|
+
|
|
127
|
+
expect(deferred.isResolved).toBe(true)
|
|
128
|
+
expect(deferred.isRejected).toBe(false)
|
|
129
|
+
expect(deferred.isSettled).toBe(true)
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
it('should return correct status after reject', async () => {
|
|
133
|
+
const deferred = new Deferred<string>()
|
|
134
|
+
|
|
135
|
+
deferred.reject(new Error('test'))
|
|
136
|
+
|
|
137
|
+
// Catch the rejection to avoid unhandled promise rejection
|
|
138
|
+
try {
|
|
139
|
+
await deferred.promise
|
|
140
|
+
} catch (error) {
|
|
141
|
+
// Expected to fail
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
expect(deferred.isResolved).toBe(false)
|
|
145
|
+
expect(deferred.isRejected).toBe(true)
|
|
146
|
+
expect(deferred.isSettled).toBe(true)
|
|
147
|
+
})
|
|
148
|
+
})
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
describe('createDeferred', () => {
|
|
152
|
+
it('should create a new Deferred instance', () => {
|
|
153
|
+
const deferred = createDeferred<string>()
|
|
154
|
+
|
|
155
|
+
expect(deferred).toBeInstanceOf(Deferred)
|
|
156
|
+
expect(deferred.promise).toBeInstanceOf(Promise)
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
it('should create independent instances', () => {
|
|
160
|
+
const deferred1 = createDeferred<string>()
|
|
161
|
+
const deferred2 = createDeferred<string>()
|
|
162
|
+
|
|
163
|
+
expect(deferred1).not.toBe(deferred2)
|
|
164
|
+
expect(deferred1.promise).not.toBe(deferred2.promise)
|
|
165
|
+
})
|
|
166
|
+
})
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import { ErrorsEnum } from '../errors/errors.enum.mjs'
|
|
4
|
+
import {
|
|
5
|
+
FactoryNotFound,
|
|
6
|
+
InstanceDestroying,
|
|
7
|
+
InstanceExpired,
|
|
8
|
+
} from '../errors/index.mjs'
|
|
9
|
+
|
|
10
|
+
describe('Error Classes', () => {
|
|
11
|
+
describe('FactoryNotFound', () => {
|
|
12
|
+
it('should create error with proper message and code', () => {
|
|
13
|
+
const error = new FactoryNotFound('TestFactory')
|
|
14
|
+
|
|
15
|
+
expect(error.message).toBe('Factory TestFactory not found')
|
|
16
|
+
expect(error.code).toBe(ErrorsEnum.FactoryNotFound)
|
|
17
|
+
expect(error.name).toBe('TestFactory')
|
|
18
|
+
expect(error).toBeInstanceOf(Error)
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('should be throwable', () => {
|
|
22
|
+
expect(() => {
|
|
23
|
+
throw new FactoryNotFound('SomeFactory')
|
|
24
|
+
}).toThrow('Factory SomeFactory not found')
|
|
25
|
+
})
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
describe('InstanceDestroying', () => {
|
|
29
|
+
it('should create error with proper message and code', () => {
|
|
30
|
+
const error = new InstanceDestroying('TestInstance')
|
|
31
|
+
|
|
32
|
+
expect(error.message).toBe('Instance TestInstance destroying')
|
|
33
|
+
expect(error.code).toBe(ErrorsEnum.InstanceDestroying)
|
|
34
|
+
expect(error.name).toBe('TestInstance')
|
|
35
|
+
expect(error).toBeInstanceOf(Error)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('should be throwable', () => {
|
|
39
|
+
expect(() => {
|
|
40
|
+
throw new InstanceDestroying('SomeInstance')
|
|
41
|
+
}).toThrow('Instance SomeInstance destroying')
|
|
42
|
+
})
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
describe('InstanceExpired', () => {
|
|
46
|
+
it('should create error with proper message and code', () => {
|
|
47
|
+
const error = new InstanceExpired('TestInstance')
|
|
48
|
+
|
|
49
|
+
expect(error.message).toBe('Instance TestInstance expired')
|
|
50
|
+
expect(error.code).toBe(ErrorsEnum.InstanceExpired)
|
|
51
|
+
expect(error.name).toBe('TestInstance')
|
|
52
|
+
expect(error).toBeInstanceOf(Error)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it('should be throwable', () => {
|
|
56
|
+
expect(() => {
|
|
57
|
+
throw new InstanceExpired('SomeInstance')
|
|
58
|
+
}).toThrow('Instance SomeInstance expired')
|
|
59
|
+
})
|
|
60
|
+
})
|
|
61
|
+
})
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import { EventEmitter } from '../event-emitter.mjs'
|
|
4
|
+
|
|
5
|
+
describe('EventEmitter', () => {
|
|
6
|
+
it('should create an instance', () => {
|
|
7
|
+
const emitter = new EventEmitter()
|
|
8
|
+
expect(emitter).toBeDefined()
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
it('should add and trigger event listeners', async () => {
|
|
12
|
+
const emitter = new EventEmitter<{ test: [string] }>()
|
|
13
|
+
const mockListener = vi.fn()
|
|
14
|
+
|
|
15
|
+
emitter.on('test', mockListener)
|
|
16
|
+
await emitter.emit('test', 'hello')
|
|
17
|
+
|
|
18
|
+
expect(mockListener).toHaveBeenCalledWith('hello')
|
|
19
|
+
expect(mockListener).toHaveBeenCalledTimes(1)
|
|
20
|
+
emitter.off('test', mockListener)
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('should support multiple listeners for the same event', async () => {
|
|
24
|
+
const emitter = new EventEmitter<{ test: [string] }>()
|
|
25
|
+
const mockListener1 = vi.fn()
|
|
26
|
+
const mockListener2 = vi.fn()
|
|
27
|
+
|
|
28
|
+
emitter.on('test', mockListener1)
|
|
29
|
+
emitter.on('test', mockListener2)
|
|
30
|
+
await emitter.emit('test', 'hello')
|
|
31
|
+
|
|
32
|
+
expect(mockListener1).toHaveBeenCalledWith('hello')
|
|
33
|
+
expect(mockListener2).toHaveBeenCalledWith('hello')
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it('should return unsubscribe function from on()', async () => {
|
|
37
|
+
const emitter = new EventEmitter<{ test: [string] }>()
|
|
38
|
+
const mockListener = vi.fn()
|
|
39
|
+
|
|
40
|
+
const unsubscribe = emitter.on('test', mockListener)
|
|
41
|
+
await emitter.emit('test', 'hello1')
|
|
42
|
+
|
|
43
|
+
unsubscribe()
|
|
44
|
+
await emitter.emit('test', 'hello2')
|
|
45
|
+
|
|
46
|
+
expect(mockListener).toHaveBeenCalledTimes(1)
|
|
47
|
+
expect(mockListener).toHaveBeenCalledWith('hello1')
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it('should support off() method to remove listeners', async () => {
|
|
51
|
+
const emitter = new EventEmitter<{ test: [string] }>()
|
|
52
|
+
const mockListener = vi.fn()
|
|
53
|
+
|
|
54
|
+
emitter.on('test', mockListener)
|
|
55
|
+
await emitter.emit('test', 'hello1')
|
|
56
|
+
|
|
57
|
+
emitter.off('test', mockListener)
|
|
58
|
+
await emitter.emit('test', 'hello2')
|
|
59
|
+
|
|
60
|
+
expect(mockListener).toHaveBeenCalledTimes(1)
|
|
61
|
+
expect(mockListener).toHaveBeenCalledWith('hello1')
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
it('should handle off() for non-existent event', () => {
|
|
65
|
+
const emitter = new EventEmitter<{ test: [string] }>()
|
|
66
|
+
const mockListener = vi.fn()
|
|
67
|
+
|
|
68
|
+
expect(() => {
|
|
69
|
+
emitter.off('test', mockListener)
|
|
70
|
+
}).not.toThrow()
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('should clean up empty listener sets after removing all listeners', async () => {
|
|
74
|
+
const emitter = new EventEmitter<{ test: [string] }>()
|
|
75
|
+
const mockListener1 = vi.fn()
|
|
76
|
+
const mockListener2 = vi.fn()
|
|
77
|
+
|
|
78
|
+
emitter.on('test', mockListener1)
|
|
79
|
+
emitter.on('test', mockListener2)
|
|
80
|
+
|
|
81
|
+
emitter.off('test', mockListener1)
|
|
82
|
+
emitter.off('test', mockListener2)
|
|
83
|
+
|
|
84
|
+
// After removing all listeners, emitting should not call anything
|
|
85
|
+
await emitter.emit('test', 'hello')
|
|
86
|
+
|
|
87
|
+
expect(mockListener1).not.toHaveBeenCalled()
|
|
88
|
+
expect(mockListener2).not.toHaveBeenCalled()
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
it('should support once() method for one-time listeners', async () => {
|
|
92
|
+
const emitter = new EventEmitter<{ test: [string] }>()
|
|
93
|
+
const mockListener = vi.fn()
|
|
94
|
+
|
|
95
|
+
emitter.once('test', mockListener)
|
|
96
|
+
await emitter.emit('test', 'hello1')
|
|
97
|
+
await emitter.emit('test', 'hello2')
|
|
98
|
+
|
|
99
|
+
expect(mockListener).toHaveBeenCalledTimes(1)
|
|
100
|
+
expect(mockListener).toHaveBeenCalledWith('hello1')
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
it('should return unsubscribe function from once()', async () => {
|
|
104
|
+
const emitter = new EventEmitter<{ test: [string] }>()
|
|
105
|
+
const mockListener = vi.fn()
|
|
106
|
+
|
|
107
|
+
const unsubscribe = emitter.once('test', mockListener)
|
|
108
|
+
unsubscribe() // Remove before emitting
|
|
109
|
+
await emitter.emit('test', 'hello')
|
|
110
|
+
|
|
111
|
+
expect(mockListener).not.toHaveBeenCalled()
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it('should handle emit() for non-existent event', async () => {
|
|
115
|
+
const emitter = new EventEmitter<{ test: [string] }>()
|
|
116
|
+
|
|
117
|
+
const result = await emitter.emit('test', 'hello')
|
|
118
|
+
expect(result).toBeUndefined()
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
it('should handle multiple arguments in events', async () => {
|
|
122
|
+
const emitter = new EventEmitter<{ test: [string, number, boolean] }>()
|
|
123
|
+
const mockListener = vi.fn()
|
|
124
|
+
|
|
125
|
+
emitter.on('test', mockListener)
|
|
126
|
+
await emitter.emit('test', 'hello', 42, true)
|
|
127
|
+
|
|
128
|
+
expect(mockListener).toHaveBeenCalledWith('hello', 42, true)
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
it('should handle async listeners', async () => {
|
|
132
|
+
const emitter = new EventEmitter<{ test: [string] }>()
|
|
133
|
+
const mockAsyncListener = vi.fn().mockResolvedValue('async result')
|
|
134
|
+
|
|
135
|
+
emitter.on('test', mockAsyncListener)
|
|
136
|
+
const results = await emitter.emit('test', 'hello')
|
|
137
|
+
|
|
138
|
+
expect(mockAsyncListener).toHaveBeenCalledWith('hello')
|
|
139
|
+
expect(results).toEqual(['async result'])
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
it('should handle multiple async listeners and return all results', async () => {
|
|
143
|
+
const emitter = new EventEmitter<{ test: [string] }>()
|
|
144
|
+
const mockAsyncListener1 = vi.fn().mockResolvedValue('result1')
|
|
145
|
+
const mockAsyncListener2 = vi.fn().mockResolvedValue('result2')
|
|
146
|
+
|
|
147
|
+
emitter.on('test', mockAsyncListener1)
|
|
148
|
+
emitter.on('test', mockAsyncListener2)
|
|
149
|
+
const results = await emitter.emit('test', 'hello')
|
|
150
|
+
|
|
151
|
+
expect(results).toEqual(['result1', 'result2'])
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
it('should work with no-argument events', async () => {
|
|
155
|
+
const emitter = new EventEmitter<{ test: [] }>()
|
|
156
|
+
const mockListener = vi.fn()
|
|
157
|
+
|
|
158
|
+
emitter.on('test', mockListener)
|
|
159
|
+
await emitter.emit('test')
|
|
160
|
+
|
|
161
|
+
expect(mockListener).toHaveBeenCalledWith()
|
|
162
|
+
})
|
|
163
|
+
})
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import { Injectable, InjectableScope, InjectionToken } from '../index.mjs'
|
|
4
|
+
import { getInjectors } from '../utils/get-injectors.mjs'
|
|
5
|
+
|
|
6
|
+
@Injectable({ scope: InjectableScope.Singleton })
|
|
7
|
+
class TestService {
|
|
8
|
+
constructor() {}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
describe('getInjectors', () => {
|
|
12
|
+
it('should return injectors object with correct methods', () => {
|
|
13
|
+
const injectors = getInjectors()
|
|
14
|
+
|
|
15
|
+
expect(injectors).toBeDefined()
|
|
16
|
+
expect(typeof injectors.inject).toBe('function')
|
|
17
|
+
expect(typeof injectors.asyncInject).toBe('function')
|
|
18
|
+
expect(typeof injectors.wrapSyncInit).toBe('function')
|
|
19
|
+
expect(typeof injectors.provideFactoryContext).toBe('function')
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it('should handle wrapSyncInit with simple function', () => {
|
|
23
|
+
const injectors = getInjectors()
|
|
24
|
+
|
|
25
|
+
const testFn = () => 'test result'
|
|
26
|
+
const wrappedFn = injectors.wrapSyncInit(testFn)
|
|
27
|
+
|
|
28
|
+
const result = wrappedFn()
|
|
29
|
+
expect(result).toHaveLength(3) // [result, promises, injectState]
|
|
30
|
+
expect(result[0]).toBe('test result')
|
|
31
|
+
expect(result[1]).toEqual([]) // no promises
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('should handle inject method when called outside context', () => {
|
|
35
|
+
const injectors = getInjectors()
|
|
36
|
+
|
|
37
|
+
// This should throw when called outside of injection context
|
|
38
|
+
expect(() => injectors.inject(TestService)).toThrow()
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('should handle asyncInject method when called outside context', async () => {
|
|
42
|
+
const injectors = getInjectors()
|
|
43
|
+
const testToken = new InjectionToken<string>('TestToken', undefined)
|
|
44
|
+
|
|
45
|
+
// This should throw since we're calling outside of an injectable context
|
|
46
|
+
try {
|
|
47
|
+
await injectors.asyncInject(testToken)
|
|
48
|
+
expect.fail('Should have thrown an error')
|
|
49
|
+
} catch (error) {
|
|
50
|
+
expect(error).toBeInstanceOf(Error)
|
|
51
|
+
expect((error as Error).message).toBe(
|
|
52
|
+
'[Injector] Trying to access inject outside of a injectable context',
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it('should handle provideFactoryContext without context', () => {
|
|
58
|
+
const injectors = getInjectors()
|
|
59
|
+
|
|
60
|
+
const mockContext = {
|
|
61
|
+
inject: injectors.asyncInject,
|
|
62
|
+
locator: {} as any,
|
|
63
|
+
addDestroyListener: () => {},
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// This should work but not have much effect without a real context
|
|
67
|
+
const result = injectors.provideFactoryContext(mockContext)
|
|
68
|
+
expect(result).toBeNull()
|
|
69
|
+
})
|
|
70
|
+
})
|