decorator-dependency-injection 1.0.3 → 1.0.5

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.
@@ -1,249 +0,0 @@
1
- import {Factory, InjectLazy, resetMocks, Singleton} from '../index.js'
2
-
3
- describe('Lazy Injection via fields', () => {
4
- @Singleton()
5
- class TestLazySingleton {
6
- static calls = 0
7
-
8
- constructor() {
9
- TestLazySingleton.calls++
10
- }
11
- }
12
-
13
- it('should lazily inject singleton', () => {
14
- class TestLazySingletonInjection {
15
- @InjectLazy(TestLazySingleton) testSingleton
16
-
17
- constructor() {
18
- }
19
- }
20
-
21
- const instance = new TestLazySingletonInjection()
22
- expect(TestLazySingleton.calls).toBe(0) // Not constructed until access
23
- const first = instance.testSingleton
24
- expect(first).toBeInstanceOf(TestLazySingleton)
25
- expect(TestLazySingleton.calls).toBe(1)
26
- // Repeated access returns the same instance.
27
- const second = instance.testSingleton
28
- expect(first).toBe(second)
29
- })
30
-
31
- @Factory()
32
- class TestLazyFactory {
33
- static calls = 0
34
- params
35
-
36
- constructor(...params) {
37
- TestLazyFactory.calls++
38
- this.params = params
39
- }
40
- }
41
-
42
- afterEach(() => {
43
- TestLazyFactory.calls = 0
44
- TestLazySingleton.calls = 0
45
- resetMocks()
46
- })
47
-
48
- it('should lazily inject factory with caching on first access per field', () => {
49
- class TestLazyFactoryInjection {
50
- @InjectLazy(TestLazyFactory) testFactory
51
-
52
- constructor() {
53
- }
54
- }
55
-
56
- const inst = new TestLazyFactoryInjection()
57
- expect(TestLazyFactory.calls).toBe(0)
58
- const first = inst.testFactory
59
- expect(first).toBeInstanceOf(TestLazyFactory)
60
- expect(TestLazyFactory.calls).toBe(1)
61
- expect(inst.testFactory).toBe(first)
62
- })
63
-
64
- it('should create distinct factory instances for different fields', () => {
65
- class TestMultipleLazyFactoryInjection {
66
- @InjectLazy(TestLazyFactory) testFactory1
67
- @InjectLazy(TestLazyFactory) testFactory2
68
-
69
- constructor() {
70
- }
71
- }
72
-
73
- const instance = new TestMultipleLazyFactoryInjection()
74
- expect(TestLazyFactory.calls).toBe(0)
75
- const one = instance.testFactory1
76
- const two = instance.testFactory2
77
- expect(one).toBeInstanceOf(TestLazyFactory)
78
- expect(two).toBeInstanceOf(TestLazyFactory)
79
- expect(one).not.toBe(two)
80
- })
81
-
82
- it('should pass constructor parameters when using lazy injection', () => {
83
- class TestLazyFactoryParamsInjection {
84
- @InjectLazy(TestLazyFactory, 'param1', 'param2') testFactory
85
-
86
- constructor() {
87
- }
88
- }
89
-
90
- TestLazyFactory.calls = 0
91
- const instance = new TestLazyFactoryParamsInjection()
92
- expect(TestLazyFactory.calls).toBe(0)
93
- const factoryInst = instance.testFactory
94
- expect(factoryInst).toBeInstanceOf(TestLazyFactory)
95
- expect(factoryInst.params).toEqual(['param1', 'param2'])
96
- })
97
-
98
- it('should not initialize dependency if property is never accessed', () => {
99
- class TestNeverAccess {
100
- @InjectLazy(TestLazySingleton) testSingleton
101
-
102
- constructor() {
103
- }
104
- }
105
-
106
- TestLazySingleton.calls = 0
107
- new TestNeverAccess() // Do not access testSingleton.
108
- expect(TestLazySingleton.calls).toBe(0)
109
- })
110
-
111
- @Singleton('lazyNamedSingleton')
112
- class NamedLazySingleton {
113
- static calls = 0
114
-
115
- constructor() {
116
- NamedLazySingleton.calls++
117
- }
118
- }
119
-
120
- it('should lazily inject named singleton', () => {
121
- class TestLazyNamedSingletonInjection {
122
- @InjectLazy('lazyNamedSingleton') namedSingleton
123
-
124
- constructor() {
125
- }
126
- }
127
-
128
- const instance = new TestLazyNamedSingletonInjection()
129
- expect(NamedLazySingleton.calls).toBe(0)
130
- const first = instance.namedSingleton
131
- expect(first).toBeInstanceOf(NamedLazySingleton)
132
- expect(NamedLazySingleton.calls).toBe(1)
133
- expect(instance.namedSingleton).toBe(first)
134
- })
135
-
136
- @Factory('lazyNamedFactory')
137
- class NamedLazyFactory {
138
- static calls = 0
139
- params
140
-
141
- constructor(...params) {
142
- NamedLazyFactory.calls++
143
- this.params = params
144
- }
145
- }
146
-
147
- it('should lazily inject named factory', () => {
148
- class TestLazyNamedFactoryInjection {
149
- @InjectLazy('lazyNamedFactory') namedFactory
150
-
151
- constructor() {
152
- }
153
- }
154
-
155
- NamedLazyFactory.calls = 0
156
- const instance = new TestLazyNamedFactoryInjection()
157
- expect(NamedLazyFactory.calls).toBe(0)
158
- const first = instance.namedFactory
159
- expect(first).toBeInstanceOf(NamedLazyFactory)
160
- expect(NamedLazyFactory.calls).toBe(1)
161
- expect(instance.namedFactory).toBe(first)
162
- })
163
-
164
- it('should not expose any internal caching artifacts', () => {
165
- class TestLazyEnum {
166
- @InjectLazy(TestLazySingleton) lazyProp
167
-
168
- constructor() {
169
- }
170
- }
171
-
172
- const inst = new TestLazyEnum()
173
- // noinspection JSUnusedLocalSymbols: Force lazy initialization.
174
- const _ = inst.lazyProp
175
- const keys = Object.keys(inst)
176
- expect(keys).toContain('lazyProp')
177
- expect(keys.length).toBe(1)
178
- const symbols = Object.getOwnPropertySymbols(inst)
179
- expect(symbols.length).toBe(0)
180
- })
181
-
182
- it('should throw if @InjectLazy is applied to a method', () => {
183
- expect(() => {
184
- // noinspection JSUnusedLocalSymbols
185
- class BadLazy {
186
- @InjectLazy('something')
187
- someMethod() {
188
- }
189
- }
190
- }).toThrow()
191
- })
192
-
193
- it('should handle circular dependencies (lazy)', () => {
194
- @Singleton()
195
- class A {
196
- @InjectLazy('B') b
197
- }
198
-
199
- @Singleton('B')
200
- class B {
201
- @InjectLazy(A) a
202
- }
203
-
204
- expect(() => new A()).not.toThrow()
205
- })
206
-
207
- it('should inject into symbol-named fields (lazy)', () => {
208
- const sym = Symbol('sym')
209
-
210
- @Singleton()
211
- class S {
212
- }
213
-
214
- class Test {
215
- @InjectLazy(S) [sym]
216
- }
217
-
218
- const t = new Test()
219
- expect(t[sym]).toBeInstanceOf(S)
220
- })
221
-
222
- it('should not leak lazy injected properties to prototype', () => {
223
- @Singleton()
224
- class S {
225
- }
226
-
227
- class Test {
228
- @InjectLazy(S) dep
229
- }
230
-
231
- // noinspection JSUnusedLocalSymbols
232
- const t = new Test()
233
- expect(Object.prototype.hasOwnProperty.call(Test.prototype, 'dep')).toBe(false)
234
- })
235
-
236
- it('should allow circular dependencies with lazy injection', () => {
237
- @Singleton()
238
- class A1 {
239
- @InjectLazy('B1') b
240
- }
241
-
242
- @Factory('B1')
243
- class B1 {
244
- @InjectLazy(A1) a
245
- }
246
-
247
- expect(() => new A1()).not.toThrow()
248
- })
249
- })
package/test/mock.test.js DELETED
@@ -1,295 +0,0 @@
1
- import {Factory, Inject, InjectLazy, Mock, resetMock, resetMocks, Singleton} from '../index.js'
2
-
3
- describe('Mocking', () => {
4
- @Singleton()
5
- class ToBeMockedSingleton {
6
- op() {
7
- return 'original'
8
- }
9
-
10
- op2() {
11
- return 'original2'
12
- }
13
- }
14
-
15
- class TestInjection {
16
- @Inject(ToBeMockedSingleton) toBeMockedSingleton
17
- }
18
-
19
- afterEach(() => {
20
- resetMocks()
21
- })
22
-
23
- it('should inject a mock singleton', () => {
24
- @Mock(ToBeMockedSingleton)
25
- class MockedSingleton {
26
- op() {
27
- return 'mocked1'
28
- }
29
- }
30
-
31
- const result = new TestInjection()
32
- expect(result.toBeMockedSingleton.op()).toBe('mocked1')
33
- expect(result.toBeMockedSingleton.op2).toBe.undefined
34
-
35
- resetMocks()
36
- const result2 = new TestInjection()
37
- expect(result2.toBeMockedSingleton.op()).toBe('original')
38
- expect(result2.toBeMockedSingleton.op2()).toBe('original2')
39
- })
40
-
41
- // New tests for lazy injection with mocks (non-proxied)
42
- it('should inject a lazy mock singleton', () => {
43
- @Mock(ToBeMockedSingleton)
44
- class MockedSingletonLazy {
45
- op() {
46
- return 'mocked2'
47
- }
48
- }
49
-
50
- class TestInjectionLazy {
51
- @InjectLazy(ToBeMockedSingleton) lazyMockedSingleton
52
- }
53
-
54
- const instance = new TestInjectionLazy()
55
- const result = instance.lazyMockedSingleton
56
- expect(result.op()).toBe('mocked2')
57
- expect(result.op2).toBe.undefined
58
-
59
- resetMocks()
60
- const instance2 = new TestInjectionLazy()
61
- expect(instance2.lazyMockedSingleton.op()).toBe('original')
62
- expect(instance2.lazyMockedSingleton.op2()).toBe('original2')
63
- })
64
-
65
- @Factory()
66
- class ToBeMockedFactory {
67
- op() {
68
- return 'original'
69
- }
70
- }
71
-
72
- class TestInjectionFactory {
73
- @Inject(ToBeMockedFactory) toBeMockedFactory
74
- }
75
-
76
- it('should inject a mock factory', () => {
77
- @Mock(ToBeMockedFactory)
78
- class MockedFactory {
79
- op() {
80
- return 'mocked'
81
- }
82
- }
83
-
84
- const result = new TestInjectionFactory()
85
- expect(result.toBeMockedFactory.op()).toBe('mocked')
86
-
87
- resetMocks()
88
- const result2 = new TestInjectionFactory()
89
- expect(result2.toBeMockedFactory.op()).toBe('original')
90
- })
91
-
92
- // New tests for lazy injection with mock factory
93
- it('should inject a lazy mock factory', () => {
94
- @Mock(ToBeMockedFactory)
95
- class MockedFactoryLazy {
96
- op() {
97
- return 'mocked'
98
- }
99
- }
100
-
101
- class TestInjectionFactoryLazy {
102
- @InjectLazy(ToBeMockedFactory) lazyMockedFactory
103
- }
104
-
105
- const instance = new TestInjectionFactoryLazy()
106
- const result = instance.lazyMockedFactory
107
- expect(result.op()).toBe('mocked')
108
-
109
- resetMocks()
110
- const instance2 = new TestInjectionFactoryLazy()
111
- expect(instance2.lazyMockedFactory.op()).toBe('original')
112
- })
113
-
114
- it('should throw an error if a mock is not a singleton or factory', () => {
115
- expect(() => {
116
- @Mock(ToBeMockedFactory)
117
- class Mocked1 {
118
- }
119
-
120
- @Mock(ToBeMockedFactory)
121
- class Mocked2 {
122
- }
123
- }).toThrow('Mock already defined, reset before mocking again')
124
- })
125
-
126
- // Edge case: Resetting specific mocks
127
- it('should reset only the specified mock', () => {
128
- @Singleton()
129
- class A {
130
- value() {
131
- return 'A'
132
- }
133
- }
134
-
135
- @Singleton()
136
- class B {
137
- value() {
138
- return 'B'
139
- }
140
- }
141
-
142
- @Mock(A)
143
- class MockA {
144
- value() {
145
- return 'mockA'
146
- }
147
- }
148
-
149
- @Mock(B)
150
- class MockB {
151
- value() {
152
- return 'mockB'
153
- }
154
- }
155
-
156
- class Test {
157
- @Inject(A) a
158
- @Inject(B) b
159
- }
160
-
161
- const t = new Test()
162
- expect(t.a.value()).toBe('mockA')
163
- expect(t.b.value()).toBe('mockB')
164
-
165
- resetMock(A)
166
- const t2 = new Test()
167
- expect(t2.a.value()).toBe('A')
168
- expect(t2.b.value()).toBe('mockB')
169
- })
170
-
171
- it('should use the latest mock when multiple mocks are applied', () => {
172
- @Singleton()
173
- class Original {
174
- }
175
-
176
- @Mock(Original)
177
- class Mock1 {
178
- }
179
-
180
- resetMock(Original)
181
-
182
- @Mock(Original)
183
- class Mock2 {
184
- }
185
-
186
- class Test {
187
- @Inject(Original) dep
188
- }
189
-
190
- const t = new Test()
191
- expect(t.dep).toBeInstanceOf(Mock2)
192
- })
193
-
194
- it('should restore the original after unmocking', () => {
195
- @Singleton()
196
- class Orig {
197
- }
198
-
199
- @Mock(Orig)
200
- class Mocked {
201
- }
202
-
203
- resetMock(Orig)
204
-
205
- class Test {
206
- @Inject(Orig) dep
207
- }
208
-
209
- const t = new Test()
210
- expect(t.dep).toBeInstanceOf(Orig)
211
- })
212
-
213
- it('should inject subclass correctly', () => {
214
- @Singleton()
215
- class Base {
216
- }
217
-
218
- class Sub extends Base {
219
- }
220
-
221
- @Mock(Base)
222
- class SubMock extends Sub {
223
- }
224
-
225
- class Test {
226
- @Inject(Base) dep
227
- }
228
-
229
- const t = new Test()
230
- expect(t.dep).toBeInstanceOf(Sub)
231
- })
232
-
233
- it('should use latest mock for lazy injection', () => {
234
- @Singleton()
235
- class Orig {
236
- }
237
-
238
- @Mock(Orig)
239
- class Mock1 {
240
- }
241
-
242
- resetMock(Orig)
243
-
244
- @Mock(Orig)
245
- class Mock2 {
246
- }
247
-
248
- class Test {
249
- @InjectLazy(Orig) dep
250
- }
251
-
252
- const t = new Test()
253
- expect(t.dep).toBeInstanceOf(Mock2)
254
- })
255
-
256
- it('should restore original after unmocking (lazy)', () => {
257
- @Singleton()
258
- class Orig {
259
- }
260
-
261
- @Mock(Orig)
262
- class Mocked {
263
- }
264
-
265
- resetMock(Orig)
266
-
267
- class Test {
268
- @InjectLazy(Orig) dep
269
- }
270
-
271
- const t = new Test()
272
- expect(t.dep).toBeInstanceOf(Orig)
273
- })
274
-
275
- it('should inject subclass correctly (lazy)', () => {
276
- @Singleton()
277
- class Base {
278
- }
279
-
280
- class Sub extends Base {
281
- }
282
-
283
- @Mock(Base)
284
- class SubMock extends Sub {
285
- }
286
-
287
- class Test {
288
- @InjectLazy(Base) dep
289
- }
290
-
291
- const t = new Test()
292
- expect(t.dep).toBeInstanceOf(Sub)
293
- })
294
- })
295
-
@@ -1,130 +0,0 @@
1
- import {Factory, Inject, InjectLazy, Mock, resetMocks, Singleton} from '../index.js'
2
-
3
- describe('Proxy Mocking', () => {
4
- @Singleton()
5
- class ToBeProxiedSingleton {
6
- op() {
7
- return 'original'
8
- }
9
-
10
- op2() {
11
- return 'original2'
12
- }
13
- }
14
-
15
- class TestInjection {
16
- @Inject(ToBeProxiedSingleton) toBeProxiedSingleton
17
- }
18
-
19
- afterEach(() => {
20
- resetMocks()
21
- })
22
-
23
- it('should inject a proxy singleton', () => {
24
- @Mock(ToBeProxiedSingleton, true)
25
- class ProxiedSingleton {
26
- op() {
27
- return 'mocked'
28
- }
29
- }
30
-
31
- const result = new TestInjection()
32
- expect(result.toBeProxiedSingleton.op()).toBe('mocked')
33
- expect(result.toBeProxiedSingleton.op2()).toBe('original2')
34
-
35
- resetMocks()
36
- const result2 = new TestInjection()
37
- expect(result2.toBeProxiedSingleton.op()).toBe('original')
38
- expect(result2.toBeProxiedSingleton.op2()).toBe('original2')
39
- })
40
-
41
- @Factory()
42
- class ToBeProxiedFactory {
43
- op() {
44
- return 'original'
45
- }
46
-
47
- op2() {
48
- return 'original2'
49
- }
50
- }
51
-
52
- class TestInjectionFactory {
53
- @Inject(ToBeProxiedFactory) toBeProxiedFactory
54
- }
55
-
56
- it('should inject a proxy factory', () => {
57
- @Mock(ToBeProxiedFactory, true)
58
- class ProxiedFactory {
59
- op() {
60
- return 'mocked'
61
- }
62
- }
63
-
64
- const result = new TestInjectionFactory()
65
- expect(result.toBeProxiedFactory.op()).toBe('mocked')
66
- expect(result.toBeProxiedFactory.op2()).toBe('original2')
67
-
68
- resetMocks()
69
- const result2 = new TestInjectionFactory()
70
- expect(result2.toBeProxiedFactory.op()).toBe('original')
71
- expect(result2.toBeProxiedFactory.op2()).toBe('original2')
72
- })
73
-
74
- it('should inject a lazy proxy singleton', () => {
75
- @Mock(ToBeProxiedSingleton, true)
76
- class ProxiedSingletonLazy {
77
- op() {
78
- return 'mocked'
79
- }
80
- }
81
-
82
- class TestInjectionLazy {
83
- @InjectLazy(ToBeProxiedSingleton) lazyProxiedSingleton
84
- }
85
-
86
- const instance = new TestInjectionLazy()
87
- const result = instance.lazyProxiedSingleton
88
- expect(result.op()).toBe('mocked')
89
- expect(result.op2()).toBe('original2')
90
-
91
- resetMocks()
92
- const instance2 = new TestInjectionLazy()
93
- expect(instance2.lazyProxiedSingleton.op()).toBe('original')
94
- expect(instance2.lazyProxiedSingleton.op2()).toBe('original2')
95
- })
96
-
97
- it('should inject a lazy proxy factory', () => {
98
- @Factory()
99
- class ToBeProxiedFactoryLazy {
100
- op() {
101
- return 'original'
102
- }
103
-
104
- op2() {
105
- return 'original2'
106
- }
107
- }
108
-
109
- class TestInjectionFactoryLazy {
110
- @InjectLazy(ToBeProxiedFactoryLazy) lazyProxiedFactory
111
- }
112
-
113
- @Mock(ToBeProxiedFactoryLazy, true)
114
- class ProxiedFactoryLazy {
115
- op() {
116
- return 'mocked'
117
- }
118
- }
119
-
120
- const instance = new TestInjectionFactoryLazy()
121
- const result = instance.lazyProxiedFactory
122
- expect(result.op()).toBe('mocked')
123
- expect(result.op2()).toBe('original2')
124
-
125
- resetMocks()
126
- const instance2 = new TestInjectionFactoryLazy()
127
- expect(instance2.lazyProxiedFactory.op()).toBe('original')
128
- expect(instance2.lazyProxiedFactory.op2()).toBe('original2')
129
- })
130
- })