@tsed/di 8.0.1 → 8.0.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.
- package/package.json +10 -9
- package/src/common/constants/constants.ts +5 -0
- package/src/common/decorators/autoInjectable.spec.ts +135 -0
- package/src/common/decorators/autoInjectable.ts +59 -0
- package/src/common/decorators/configuration.spec.ts +45 -0
- package/src/common/decorators/configuration.ts +34 -0
- package/src/common/decorators/constant.spec.ts +67 -0
- package/src/common/decorators/constant.ts +72 -0
- package/src/common/decorators/controller.spec.ts +43 -0
- package/src/common/decorators/controller.ts +64 -0
- package/src/common/decorators/inject.spec.ts +298 -0
- package/src/common/decorators/inject.ts +144 -0
- package/src/common/decorators/injectable.spec.ts +43 -0
- package/src/common/decorators/injectable.ts +30 -0
- package/src/common/decorators/intercept.spec.ts +103 -0
- package/src/common/decorators/intercept.ts +77 -0
- package/src/common/decorators/interceptor.ts +17 -0
- package/src/common/decorators/lazyInject.spec.ts +53 -0
- package/src/common/decorators/lazyInject.ts +91 -0
- package/src/common/decorators/module.ts +52 -0
- package/src/common/decorators/opts.ts +51 -0
- package/src/common/decorators/overrideProvider.spec.ts +30 -0
- package/src/common/decorators/overrideProvider.ts +15 -0
- package/src/common/decorators/scope.spec.ts +25 -0
- package/src/common/decorators/scope.ts +13 -0
- package/src/common/decorators/service.ts +14 -0
- package/src/common/decorators/useOpts.spec.ts +90 -0
- package/src/common/decorators/useOpts.ts +61 -0
- package/src/common/decorators/value.spec.ts +59 -0
- package/src/common/decorators/value.ts +60 -0
- package/src/common/domain/Container.spec.ts +85 -0
- package/src/common/domain/Container.ts +80 -0
- package/src/common/domain/ControllerProvider.spec.ts +55 -0
- package/src/common/domain/ControllerProvider.ts +48 -0
- package/src/common/domain/InjectablePropertyType.ts +7 -0
- package/src/common/domain/LocalsContainer.spec.ts +20 -0
- package/src/common/domain/LocalsContainer.ts +11 -0
- package/src/common/domain/Provider.spec.ts +107 -0
- package/src/common/domain/Provider.ts +205 -0
- package/src/common/domain/ProviderScope.ts +5 -0
- package/src/common/domain/ProviderType.ts +8 -0
- package/src/common/errors/InjectionError.spec.ts +17 -0
- package/src/common/errors/InjectionError.ts +68 -0
- package/src/common/errors/InvalidPropertyTokenError.ts +13 -0
- package/src/common/fn/configuration.spec.ts +42 -0
- package/src/common/fn/configuration.ts +22 -0
- package/src/common/fn/constant.spec.ts +37 -0
- package/src/common/fn/constant.ts +7 -0
- package/src/common/fn/inject.spec.ts +54 -0
- package/src/common/fn/inject.ts +29 -0
- package/src/common/fn/injectMany.ts +16 -0
- package/src/common/fn/injectable.spec.ts +87 -0
- package/src/common/fn/injectable.ts +15 -0
- package/src/common/fn/injector.ts +26 -0
- package/src/common/fn/lazyInject.spec.ts +22 -0
- package/src/common/fn/lazyInject.ts +36 -0
- package/src/common/fn/localsContainer.ts +55 -0
- package/src/common/fn/refValue.spec.ts +47 -0
- package/src/common/fn/refValue.ts +33 -0
- package/src/common/index.ts +63 -0
- package/src/common/integration/async-factory.spec.ts +60 -0
- package/src/common/integration/di.spec.ts +153 -0
- package/src/common/integration/imports.spec.ts +39 -0
- package/src/common/integration/request.spec.ts +79 -0
- package/src/common/integration/singleton.spec.ts +125 -0
- package/src/common/interfaces/DIConfigurationOptions.ts +29 -0
- package/src/common/interfaces/DILogger.ts +13 -0
- package/src/common/interfaces/DILoggerOptions.ts +54 -0
- package/src/common/interfaces/ImportTokenProviderOpts.ts +29 -0
- package/src/common/interfaces/InterceptorContext.ts +13 -0
- package/src/common/interfaces/InterceptorMethods.ts +5 -0
- package/src/common/interfaces/InvokeOptions.ts +28 -0
- package/src/common/interfaces/OnDestroy.ts +3 -0
- package/src/common/interfaces/OnInit.ts +3 -0
- package/src/common/interfaces/ProviderOpts.ts +57 -0
- package/src/common/interfaces/RegistrySettings.ts +11 -0
- package/src/common/interfaces/ResolvedInvokeOptions.ts +14 -0
- package/src/common/interfaces/TokenProvider.ts +3 -0
- package/src/common/interfaces/TokenRoute.ts +6 -0
- package/src/common/registries/GlobalProviders.spec.ts +94 -0
- package/src/common/registries/GlobalProviders.ts +131 -0
- package/src/common/registries/ProviderRegistry.spec.ts +36 -0
- package/src/common/registries/ProviderRegistry.ts +32 -0
- package/src/common/services/DIConfiguration.spec.ts +60 -0
- package/src/common/services/DIConfiguration.ts +140 -0
- package/src/common/services/DILogger.spec.ts +22 -0
- package/src/common/services/DILogger.ts +8 -0
- package/src/common/services/InjectorService.spec.ts +793 -0
- package/src/common/services/InjectorService.ts +601 -0
- package/src/common/utils/colors.spec.ts +9 -0
- package/src/common/utils/colors.ts +11 -0
- package/src/common/utils/createContainer.spec.ts +18 -0
- package/src/common/utils/createContainer.ts +14 -0
- package/src/common/utils/discoverHooks.ts +15 -0
- package/src/common/utils/getConfiguration.spec.ts +40 -0
- package/src/common/utils/getConfiguration.ts +20 -0
- package/src/common/utils/getConstructorDependencies.ts +9 -0
- package/src/common/utils/providerBuilder.ts +81 -0
- package/src/index.ts +2 -0
- package/src/node/decorators/injectContext.spec.ts +60 -0
- package/src/node/decorators/injectContext.ts +29 -0
- package/src/node/domain/ContextLogger.spec.ts +277 -0
- package/src/node/domain/ContextLogger.ts +137 -0
- package/src/node/domain/DIContext.spec.ts +103 -0
- package/src/node/domain/DIContext.ts +115 -0
- package/src/node/fn/context.ts +24 -0
- package/src/node/fn/logger.spec.ts +46 -0
- package/src/node/fn/logger.ts +17 -0
- package/src/node/index.ts +16 -0
- package/src/node/integration/async-factory-invoke.spec.ts +58 -0
- package/src/node/integration/inject-context.spec.ts +29 -0
- package/src/node/integration/invoke-oninit.spec.ts +25 -0
- package/src/node/interfaces/AlterRunInContext.ts +3 -0
- package/src/node/services/DILogger.spec.ts +24 -0
- package/src/node/services/DILogger.ts +6 -0
- package/src/node/services/DITest.spec.ts +109 -0
- package/src/node/services/DITest.ts +119 -0
- package/src/node/utils/asyncHookContext.spec.ts +147 -0
- package/src/node/utils/asyncHookContext.ts +48 -0
- package/src/node/utils/attachLogger.spec.ts +14 -0
- package/src/node/utils/attachLogger.ts +7 -0
- package/src/node/utils/setLoggerConfiguration.spec.ts +43 -0
- package/src/node/utils/setLoggerConfiguration.ts +7 -0
- package/src/node/utils/setLoggerFormat.ts +33 -0
- package/src/node/utils/setLoggerLevel.ts +12 -0
|
@@ -0,0 +1,793 @@
|
|
|
1
|
+
import {$emit} from "@tsed/hooks";
|
|
2
|
+
|
|
3
|
+
import {Configuration} from "../decorators/configuration.js";
|
|
4
|
+
import {Inject} from "../decorators/inject.js";
|
|
5
|
+
import {Injectable} from "../decorators/injectable.js";
|
|
6
|
+
import {Container} from "../domain/Container.js";
|
|
7
|
+
import {LocalsContainer} from "../domain/LocalsContainer.js";
|
|
8
|
+
import {Provider} from "../domain/Provider.js";
|
|
9
|
+
import {ProviderScope} from "../domain/ProviderScope.js";
|
|
10
|
+
import {ProviderType} from "../domain/ProviderType.js";
|
|
11
|
+
import {inject} from "../fn/inject.js";
|
|
12
|
+
import {destroyInjector, injector} from "../fn/injector.js";
|
|
13
|
+
import {registerProvider} from "../registries/ProviderRegistry.js";
|
|
14
|
+
import {InjectorService} from "./InjectorService.js";
|
|
15
|
+
|
|
16
|
+
vi.mock("@tsed/hooks", async (importOriginal) => {
|
|
17
|
+
const mod = await importOriginal<typeof import("@tsed/hooks")>();
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
...mod,
|
|
21
|
+
$emit: vi.fn()
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
class Test {
|
|
26
|
+
@Inject()
|
|
27
|
+
prop: InjectorService;
|
|
28
|
+
|
|
29
|
+
value: any;
|
|
30
|
+
constant: any;
|
|
31
|
+
|
|
32
|
+
constructor() {}
|
|
33
|
+
|
|
34
|
+
test3(o: any) {
|
|
35
|
+
return o + " called ";
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
describe("InjectorService", () => {
|
|
40
|
+
afterEach(() => destroyInjector());
|
|
41
|
+
|
|
42
|
+
describe("has()", () => {
|
|
43
|
+
it("should return true", () => {
|
|
44
|
+
expect(injector().has(InjectorService)).toBe(true);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("should return false", () => {
|
|
48
|
+
expect(injector().has(Test)).toBe(false);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
describe("get()", () => {
|
|
52
|
+
it("should return element", () => {
|
|
53
|
+
expect(injector().get(InjectorService)).toBeInstanceOf(InjectorService);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("should return Test", () => {
|
|
57
|
+
expect(injector().get(Test)).toBeInstanceOf(Test);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
describe("getMany()", () => {
|
|
61
|
+
it("should return all instance", () => {
|
|
62
|
+
injector().addProvider("token", {
|
|
63
|
+
type: ProviderType.VALUE,
|
|
64
|
+
useValue: 1
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
expect(!!injector().getMany(ProviderType.VALUE).length).toEqual(true);
|
|
68
|
+
|
|
69
|
+
injector().delete("token");
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
describe("toArray()", () => {
|
|
73
|
+
it("should return instances", () => {
|
|
74
|
+
expect(injector().toArray()).toBeInstanceOf(Array);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
describe("invoke()", () => {
|
|
78
|
+
describe("when we call invoke with rebuild options (SINGLETON)", () => {
|
|
79
|
+
it("should invoke the provider from container", async () => {
|
|
80
|
+
// GIVEN
|
|
81
|
+
const token = class Test {};
|
|
82
|
+
|
|
83
|
+
const provider = new Provider<any>(token);
|
|
84
|
+
provider.scope = ProviderScope.SINGLETON;
|
|
85
|
+
provider.deps = [InjectorService];
|
|
86
|
+
provider.alias = "alias";
|
|
87
|
+
|
|
88
|
+
const container = new Container();
|
|
89
|
+
container.set(token, provider);
|
|
90
|
+
|
|
91
|
+
await injector().load(container);
|
|
92
|
+
|
|
93
|
+
vi.spyOn(injector() as any, "invokeToken");
|
|
94
|
+
vi.spyOn(injector() as any, "resolve");
|
|
95
|
+
vi.spyOn(injector(), "getProvider");
|
|
96
|
+
|
|
97
|
+
const locals = new LocalsContainer();
|
|
98
|
+
|
|
99
|
+
// WHEN
|
|
100
|
+
|
|
101
|
+
const result1: any = inject(token, {locals});
|
|
102
|
+
const result2: any = inject(token, {locals, rebuild: true});
|
|
103
|
+
|
|
104
|
+
// THEN
|
|
105
|
+
expect(result1 !== result2).toEqual(true);
|
|
106
|
+
expect(injector().getProvider).toHaveBeenCalledWith(token);
|
|
107
|
+
expect(injector().get("alias")).toBeInstanceOf(token);
|
|
108
|
+
|
|
109
|
+
expect((injector() as any).invokeToken).toHaveBeenCalledWith(token, {locals, rebuild: true});
|
|
110
|
+
expect(injector().resolve).toHaveBeenCalledWith(InjectorService, {
|
|
111
|
+
locals,
|
|
112
|
+
parent: token
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
describe("when provider is a REQUEST", () => {
|
|
117
|
+
it("should invoke a request from local container", async () => {
|
|
118
|
+
// GIVEN
|
|
119
|
+
const token = class Test {};
|
|
120
|
+
|
|
121
|
+
const provider = new Provider<any>(token);
|
|
122
|
+
provider.scope = ProviderScope.REQUEST;
|
|
123
|
+
|
|
124
|
+
const container = new Container();
|
|
125
|
+
container.set(token, provider);
|
|
126
|
+
|
|
127
|
+
await injector().load(container);
|
|
128
|
+
|
|
129
|
+
vi.spyOn(injector() as any, "resolve");
|
|
130
|
+
vi.spyOn(injector(), "get");
|
|
131
|
+
vi.spyOn(injector(), "getProvider");
|
|
132
|
+
|
|
133
|
+
const locals = new LocalsContainer(); // LocalContainer for the first request
|
|
134
|
+
const locals2 = new LocalsContainer(); // LocalContainer for the second request
|
|
135
|
+
|
|
136
|
+
// WHEN REQ1
|
|
137
|
+
const result1: any = inject(token, {locals});
|
|
138
|
+
const result2: any = inject(token, {locals});
|
|
139
|
+
|
|
140
|
+
// WHEN REQ2
|
|
141
|
+
const result3: any = inject(token, {locals: locals2});
|
|
142
|
+
|
|
143
|
+
// THEN
|
|
144
|
+
expect(result1).toEqual(result2);
|
|
145
|
+
expect(result2 !== result3).toEqual(true);
|
|
146
|
+
|
|
147
|
+
expect(injector().getProvider).toHaveBeenCalledWith(token);
|
|
148
|
+
expect((injector() as any).resolve).toHaveBeenCalledWith(token, {locals});
|
|
149
|
+
expect(locals.get(token)).toEqual(result1);
|
|
150
|
+
expect(locals2.get(token)).toEqual(result3);
|
|
151
|
+
|
|
152
|
+
expect(injector().get).not.toHaveBeenCalled();
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
describe("when provider is a INSTANCE", () => {
|
|
156
|
+
it("should invoke a new instance", async () => {
|
|
157
|
+
// GIVEN
|
|
158
|
+
const token = class Test {};
|
|
159
|
+
|
|
160
|
+
const provider = new Provider<any>(token);
|
|
161
|
+
provider.scope = ProviderScope.INSTANCE;
|
|
162
|
+
|
|
163
|
+
const container = new Container();
|
|
164
|
+
container.set(token, provider);
|
|
165
|
+
|
|
166
|
+
await injector().load(container);
|
|
167
|
+
|
|
168
|
+
vi.spyOn(injector() as any, "resolve");
|
|
169
|
+
vi.spyOn(injector(), "get");
|
|
170
|
+
vi.spyOn(injector(), "getProvider");
|
|
171
|
+
|
|
172
|
+
const locals = new LocalsContainer(); // LocalContainer for the first request
|
|
173
|
+
|
|
174
|
+
// WHEN REQ1
|
|
175
|
+
const result1: any = inject(token, {locals});
|
|
176
|
+
const result2: any = inject(token, {locals});
|
|
177
|
+
|
|
178
|
+
// THEN
|
|
179
|
+
expect(result1 !== result2).toEqual(true);
|
|
180
|
+
|
|
181
|
+
expect(injector().getProvider).toHaveBeenCalledWith(token);
|
|
182
|
+
expect((injector() as any).resolve).toHaveBeenCalledWith(token, {locals});
|
|
183
|
+
expect(locals.has(token)).toEqual(false);
|
|
184
|
+
expect(injector().get).not.toHaveBeenCalled();
|
|
185
|
+
|
|
186
|
+
await injector().destroy();
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
describe("when provider is a SINGLETON", () => {
|
|
190
|
+
it("should invoke the provider from container", () => {
|
|
191
|
+
// GIVEN
|
|
192
|
+
const token = class Test {};
|
|
193
|
+
const provider = new Provider<any>(token);
|
|
194
|
+
provider.scope = ProviderScope.SINGLETON;
|
|
195
|
+
|
|
196
|
+
injector().set(token, provider);
|
|
197
|
+
|
|
198
|
+
// WHEN
|
|
199
|
+
const result: any = inject(token);
|
|
200
|
+
|
|
201
|
+
// THEN
|
|
202
|
+
expect(result).toBeInstanceOf(token);
|
|
203
|
+
expect($emit).toHaveBeenCalledWith("$beforeInvoke", token, [expect.any(Object)]);
|
|
204
|
+
expect($emit).toHaveBeenCalledWith("$beforeInvoke:provider", [expect.any(Object)]);
|
|
205
|
+
expect($emit).toHaveBeenCalledWith("$afterInvoke", token, [result, expect.any(Object)]);
|
|
206
|
+
});
|
|
207
|
+
it("should invoke the provider from container (2)", async () => {
|
|
208
|
+
// GIVEN
|
|
209
|
+
const token = class Test {};
|
|
210
|
+
|
|
211
|
+
const provider = new Provider<any>(token);
|
|
212
|
+
provider.scope = ProviderScope.SINGLETON;
|
|
213
|
+
|
|
214
|
+
const container = new Container();
|
|
215
|
+
container.set(token, provider);
|
|
216
|
+
|
|
217
|
+
await injector().load(container);
|
|
218
|
+
|
|
219
|
+
vi.spyOn(injector() as any, "invokeToken");
|
|
220
|
+
vi.spyOn(injector(), "getProvider");
|
|
221
|
+
|
|
222
|
+
const locals = new LocalsContainer();
|
|
223
|
+
|
|
224
|
+
// WHEN
|
|
225
|
+
const result1: any = inject(token, {locals});
|
|
226
|
+
const result2: any = inject(token, {locals});
|
|
227
|
+
|
|
228
|
+
// THEN
|
|
229
|
+
expect(result1).toEqual(result2);
|
|
230
|
+
expect((injector() as any).invokeToken).not.toHaveBeenCalled();
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
describe("when provider is a Value (useValue)", () => {
|
|
234
|
+
it("should invoke the provider from container (1)", async () => {
|
|
235
|
+
// GIVEN
|
|
236
|
+
const token = Symbol.for("TokenValue1");
|
|
237
|
+
|
|
238
|
+
const provider = new Provider<any>(token);
|
|
239
|
+
provider.scope = ProviderScope.SINGLETON;
|
|
240
|
+
provider.useValue = "TEST";
|
|
241
|
+
|
|
242
|
+
const container = new Container();
|
|
243
|
+
container.set(token, provider);
|
|
244
|
+
|
|
245
|
+
await injector().load(container);
|
|
246
|
+
|
|
247
|
+
// WHEN
|
|
248
|
+
const result: any = inject(token);
|
|
249
|
+
|
|
250
|
+
// THEN
|
|
251
|
+
expect(result).toEqual("TEST");
|
|
252
|
+
});
|
|
253
|
+
it("should invoke the provider from container (2)", async () => {
|
|
254
|
+
// GIVEN
|
|
255
|
+
const token = Symbol.for("TokenValue2");
|
|
256
|
+
|
|
257
|
+
const provider = new Provider<any>(token);
|
|
258
|
+
provider.scope = ProviderScope.SINGLETON;
|
|
259
|
+
provider.useValue = () => "TEST";
|
|
260
|
+
|
|
261
|
+
const container = new Container();
|
|
262
|
+
container.set(token, provider);
|
|
263
|
+
|
|
264
|
+
await injector().load(container);
|
|
265
|
+
|
|
266
|
+
// WHEN
|
|
267
|
+
const result: any = inject(token);
|
|
268
|
+
|
|
269
|
+
// THEN
|
|
270
|
+
expect(result).toEqual("TEST");
|
|
271
|
+
});
|
|
272
|
+
it("should invoke the provider from container with falsy value", async () => {
|
|
273
|
+
// GIVEN
|
|
274
|
+
const token = Symbol.for("TokenValue3");
|
|
275
|
+
|
|
276
|
+
const provider = new Provider<any>(token);
|
|
277
|
+
provider.scope = ProviderScope.SINGLETON;
|
|
278
|
+
provider.useValue = null;
|
|
279
|
+
|
|
280
|
+
const container = new Container();
|
|
281
|
+
container.set(token, provider);
|
|
282
|
+
|
|
283
|
+
await injector().load(container);
|
|
284
|
+
|
|
285
|
+
// WHEN
|
|
286
|
+
const result: any = inject(token);
|
|
287
|
+
|
|
288
|
+
// THEN
|
|
289
|
+
expect(result).toEqual(null);
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
describe("when provider is a Factory (useFactory)", () => {
|
|
293
|
+
it("should invoke the provider from container", async () => {
|
|
294
|
+
// GIVEN
|
|
295
|
+
const token = Symbol.for("TokenFactory");
|
|
296
|
+
|
|
297
|
+
const provider = new Provider<any>(token);
|
|
298
|
+
provider.scope = ProviderScope.SINGLETON;
|
|
299
|
+
provider.useFactory = () => ({factory: "factory"});
|
|
300
|
+
|
|
301
|
+
const container = new Container();
|
|
302
|
+
container.set(token, provider);
|
|
303
|
+
|
|
304
|
+
await injector().load(container);
|
|
305
|
+
|
|
306
|
+
// WHEN
|
|
307
|
+
const result: any = inject(token);
|
|
308
|
+
|
|
309
|
+
// THEN
|
|
310
|
+
expect(result).toEqual({factory: "factory"});
|
|
311
|
+
});
|
|
312
|
+
});
|
|
313
|
+
describe("when provider is an AsyncFactory (useAsyncFactory)", () => {
|
|
314
|
+
it("should invoke the provider from container", async () => {
|
|
315
|
+
// GIVEN
|
|
316
|
+
const tokenChild = Symbol.for("TokenChildFactory");
|
|
317
|
+
const providerChild = new Provider<any>(tokenChild);
|
|
318
|
+
providerChild.useAsyncFactory = (dep: any) => Promise.resolve("test async");
|
|
319
|
+
|
|
320
|
+
const token = Symbol.for("TokenFactory");
|
|
321
|
+
const provider = new Provider<any>(token);
|
|
322
|
+
provider.deps = [tokenChild];
|
|
323
|
+
provider.useAsyncFactory = (dep: any) => Promise.resolve({factory: dep + " factory"});
|
|
324
|
+
provider.hooks = {
|
|
325
|
+
$onDestroy: () => {}
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
const tokenSync = Symbol.for("TokenSyncFactory");
|
|
329
|
+
const providerSync = new Provider<any>(tokenSync);
|
|
330
|
+
providerSync.deps = [token];
|
|
331
|
+
providerSync.hooks = {$onDestroy: vi.fn(), $onInit: vi.fn()};
|
|
332
|
+
providerSync.useFactory = (asyncInstance: any) => asyncInstance.factory;
|
|
333
|
+
|
|
334
|
+
const container = new Container();
|
|
335
|
+
container.set(tokenChild, providerChild);
|
|
336
|
+
container.set(token, provider);
|
|
337
|
+
container.set(tokenSync, providerSync);
|
|
338
|
+
|
|
339
|
+
await injector().load(container);
|
|
340
|
+
|
|
341
|
+
// WHEN
|
|
342
|
+
const result: any = inject(token);
|
|
343
|
+
const result2: any = inject(tokenSync);
|
|
344
|
+
|
|
345
|
+
// THEN
|
|
346
|
+
expect(result).toEqual({factory: "test async factory"});
|
|
347
|
+
expect(result2).toEqual("test async factory");
|
|
348
|
+
|
|
349
|
+
await injector().emit("$onInit");
|
|
350
|
+
|
|
351
|
+
expect(providerSync.hooks.$onInit).toHaveBeenCalledWith("test async factory");
|
|
352
|
+
});
|
|
353
|
+
it("should invoke the provider from container with nested async factory", async () => {
|
|
354
|
+
// GIVEN
|
|
355
|
+
const tokenChild = Symbol.for("TokenChildFactory");
|
|
356
|
+
const providerChild = new Provider<any>(tokenChild);
|
|
357
|
+
providerChild.useAsyncFactory = (dep: any) => Promise.resolve("test async");
|
|
358
|
+
|
|
359
|
+
const token = Symbol.for("TokenFactory");
|
|
360
|
+
const provider = new Provider<any>(token);
|
|
361
|
+
provider.deps = [tokenChild];
|
|
362
|
+
provider.useAsyncFactory = (dep: any) => Promise.resolve({factory: dep + " factory"});
|
|
363
|
+
|
|
364
|
+
const token2 = Symbol.for("TokenFactory2");
|
|
365
|
+
const provider2 = new Provider<any>(token2);
|
|
366
|
+
provider2.deps = [token];
|
|
367
|
+
provider2.useAsyncFactory = (dep: any) => {
|
|
368
|
+
return Promise.resolve({factory: dep.factory + " factory2"});
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
const container = new Container();
|
|
372
|
+
container.set(tokenChild, providerChild);
|
|
373
|
+
container.set(token, provider);
|
|
374
|
+
container.set(token2, provider2);
|
|
375
|
+
|
|
376
|
+
await injector().load(container);
|
|
377
|
+
|
|
378
|
+
// WHEN
|
|
379
|
+
const result: any = inject(token2);
|
|
380
|
+
|
|
381
|
+
// THEN
|
|
382
|
+
expect(result).toEqual({factory: "test async factory factory2"});
|
|
383
|
+
});
|
|
384
|
+
});
|
|
385
|
+
describe("when provider is an unknown provider", () => {
|
|
386
|
+
it("should invoke the class from given parameter", () => {
|
|
387
|
+
// GIVEN
|
|
388
|
+
const token = class {};
|
|
389
|
+
|
|
390
|
+
// WHEN
|
|
391
|
+
const result: any = inject(token);
|
|
392
|
+
|
|
393
|
+
// THEN
|
|
394
|
+
expect(result).toBeInstanceOf(token);
|
|
395
|
+
});
|
|
396
|
+
});
|
|
397
|
+
describe("when one of dependencies is undefined", () => {
|
|
398
|
+
it("should throw InjectionError > UndefinedTokenError", () => {
|
|
399
|
+
// GIVEN
|
|
400
|
+
const token2 = class Ctrl {
|
|
401
|
+
constructor() {}
|
|
402
|
+
};
|
|
403
|
+
const token3 = class Test {
|
|
404
|
+
constructor(test: any) {}
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
const provider2 = new Provider<any>(token2);
|
|
408
|
+
provider2.scope = ProviderScope.SINGLETON;
|
|
409
|
+
provider2.type = ProviderType.CONTROLLER;
|
|
410
|
+
provider2.useClass = token2;
|
|
411
|
+
|
|
412
|
+
const provider3 = new Provider<any>(token3);
|
|
413
|
+
provider3.scope = ProviderScope.SINGLETON;
|
|
414
|
+
provider3.deps = [undefined] as never;
|
|
415
|
+
|
|
416
|
+
injector().set(token2, provider2);
|
|
417
|
+
injector().set(token3, provider3);
|
|
418
|
+
|
|
419
|
+
// WHEN
|
|
420
|
+
let actualError;
|
|
421
|
+
try {
|
|
422
|
+
inject(token3);
|
|
423
|
+
} catch (er) {
|
|
424
|
+
actualError = er;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// THEN
|
|
428
|
+
expect(actualError.message).toContain(
|
|
429
|
+
"Injection failed on Test\nOrigin: Unable to inject dependency. Given token is undefined. Could mean a circular dependency problem. Try to use @Inject(() => Token) to solve it."
|
|
430
|
+
);
|
|
431
|
+
});
|
|
432
|
+
it("should throw InjectionError > Object", () => {
|
|
433
|
+
// GIVEN
|
|
434
|
+
const token2 = class Ctrl {
|
|
435
|
+
constructor() {}
|
|
436
|
+
};
|
|
437
|
+
const token3 = class Test {
|
|
438
|
+
constructor(test: Object) {}
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
const provider2 = new Provider<any>(token2);
|
|
442
|
+
provider2.scope = ProviderScope.SINGLETON;
|
|
443
|
+
provider2.type = ProviderType.CONTROLLER;
|
|
444
|
+
provider2.useClass = token2;
|
|
445
|
+
|
|
446
|
+
const provider3 = new Provider<any>(token3);
|
|
447
|
+
provider3.scope = ProviderScope.SINGLETON;
|
|
448
|
+
provider3.deps = [Object];
|
|
449
|
+
|
|
450
|
+
injector().set(token2, provider2);
|
|
451
|
+
injector().set(token3, provider3);
|
|
452
|
+
|
|
453
|
+
// WHEN
|
|
454
|
+
let actualError;
|
|
455
|
+
try {
|
|
456
|
+
inject(token3);
|
|
457
|
+
} catch (er) {
|
|
458
|
+
actualError = er;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// THEN
|
|
462
|
+
expect(actualError.message).toContain("Injection failed on Test\nOrigin: Unable to inject dependency.");
|
|
463
|
+
});
|
|
464
|
+
it("should try to inject string token (optional)", () => {
|
|
465
|
+
// GIVEN
|
|
466
|
+
|
|
467
|
+
// WHEN
|
|
468
|
+
const result = inject("token.not.found");
|
|
469
|
+
|
|
470
|
+
// THEN
|
|
471
|
+
expect(result).toEqual(undefined);
|
|
472
|
+
});
|
|
473
|
+
});
|
|
474
|
+
describe("when error occur", () => {
|
|
475
|
+
it("should throw InjectionError", () => {
|
|
476
|
+
// GIVEN
|
|
477
|
+
const token1 = Symbol.for("TokenValue");
|
|
478
|
+
const token2 = Symbol.for("TokenFactory");
|
|
479
|
+
const token3 = class Test {
|
|
480
|
+
constructor(dep: any) {}
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
const provider1 = new Provider<any>(token1);
|
|
484
|
+
provider1.scope = ProviderScope.SINGLETON;
|
|
485
|
+
provider1.useValue = () => undefined; // should throw error because instance is undefined
|
|
486
|
+
|
|
487
|
+
const provider2 = new Provider<any>(token2);
|
|
488
|
+
provider2.scope = ProviderScope.SINGLETON;
|
|
489
|
+
provider2.deps = [token1];
|
|
490
|
+
provider2.useFactory = () => ({});
|
|
491
|
+
|
|
492
|
+
const provider3 = new Provider<any>(token3);
|
|
493
|
+
provider3.scope = ProviderScope.SINGLETON;
|
|
494
|
+
provider3.deps = [token2];
|
|
495
|
+
|
|
496
|
+
injector().set(token1, provider1);
|
|
497
|
+
injector().set(token2, provider2);
|
|
498
|
+
injector().set(token3, provider3);
|
|
499
|
+
|
|
500
|
+
// WHEN
|
|
501
|
+
let actualError;
|
|
502
|
+
try {
|
|
503
|
+
inject(token3);
|
|
504
|
+
} catch (er) {
|
|
505
|
+
actualError = er;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// THEN
|
|
509
|
+
expect(actualError.message).toEqual(
|
|
510
|
+
"Injection failed on Test > TokenFactory > TokenValue\nOrigin: Unable to create new instance from undefined value. Check your provider declaration for TokenValue"
|
|
511
|
+
);
|
|
512
|
+
});
|
|
513
|
+
});
|
|
514
|
+
describe("when provider has Provider as dependencies", () => {
|
|
515
|
+
it("should inject Provider", () => {
|
|
516
|
+
// GIVEN
|
|
517
|
+
|
|
518
|
+
const token = Symbol.for("TokenProvider1");
|
|
519
|
+
injector().add(token, {
|
|
520
|
+
deps: [Provider],
|
|
521
|
+
configuration: {
|
|
522
|
+
test: "test"
|
|
523
|
+
},
|
|
524
|
+
useFactory(provider: any) {
|
|
525
|
+
return {to: provider};
|
|
526
|
+
}
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
// WHEN
|
|
530
|
+
const instance: any = inject(token)!;
|
|
531
|
+
|
|
532
|
+
// THEN
|
|
533
|
+
expect(instance).toEqual({to: injector().getProvider(token)});
|
|
534
|
+
});
|
|
535
|
+
});
|
|
536
|
+
describe("when provider has Configuration as dependencies", () => {
|
|
537
|
+
it("should inject Provider", () => {
|
|
538
|
+
// GIVEN
|
|
539
|
+
|
|
540
|
+
const token = Symbol.for("TokenProvider1");
|
|
541
|
+
injector().add(token, {
|
|
542
|
+
deps: [Configuration],
|
|
543
|
+
useFactory(settings: any) {
|
|
544
|
+
return {to: settings};
|
|
545
|
+
}
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
// WHEN
|
|
549
|
+
const instance: any = inject(token)!;
|
|
550
|
+
|
|
551
|
+
// THEN
|
|
552
|
+
expect(instance).toEqual({to: injector().settings});
|
|
553
|
+
});
|
|
554
|
+
});
|
|
555
|
+
});
|
|
556
|
+
describe("resolveConfiguration()", () => {
|
|
557
|
+
it("should load configuration from each providers", () => {
|
|
558
|
+
// GIVEN
|
|
559
|
+
|
|
560
|
+
injector().settings.set({
|
|
561
|
+
scopes: {
|
|
562
|
+
[ProviderType.VALUE]: ProviderScope.SINGLETON
|
|
563
|
+
}
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
expect(injector().settings.get("scopes")).toEqual({
|
|
567
|
+
[ProviderType.VALUE]: ProviderScope.SINGLETON
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
injector().add(Symbol.for("TOKEN1"), {
|
|
571
|
+
configuration: {
|
|
572
|
+
custom: "config",
|
|
573
|
+
scopes: {
|
|
574
|
+
provider_custom: ProviderScope.SINGLETON
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
injector().add(Symbol.for("TOKEN2"), {
|
|
580
|
+
configuration: {
|
|
581
|
+
scopes: {
|
|
582
|
+
provider_custom_2: ProviderScope.SINGLETON
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
// WHEN
|
|
588
|
+
injector().resolveConfiguration();
|
|
589
|
+
// should load only once the configuration
|
|
590
|
+
injector().resolveConfiguration();
|
|
591
|
+
|
|
592
|
+
// THEN
|
|
593
|
+
expect(injector().settings.get<string>("custom")).toEqual("config");
|
|
594
|
+
expect(injector().settings.get<any>("scopes")).toEqual({
|
|
595
|
+
provider_custom_2: "singleton",
|
|
596
|
+
provider_custom: "singleton",
|
|
597
|
+
value: "singleton"
|
|
598
|
+
});
|
|
599
|
+
});
|
|
600
|
+
it("should load configuration from each providers (with resolvers)", () => {
|
|
601
|
+
// GIVEN
|
|
602
|
+
|
|
603
|
+
injector().add(Symbol.for("TOKEN1"), {
|
|
604
|
+
configuration: {
|
|
605
|
+
custom: {
|
|
606
|
+
config: "1"
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
injector().add(Symbol.for("TOKEN2"), {
|
|
612
|
+
configuration: {
|
|
613
|
+
custom: {
|
|
614
|
+
config2: "1"
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
});
|
|
618
|
+
|
|
619
|
+
// WHEN
|
|
620
|
+
injector().resolveConfiguration();
|
|
621
|
+
|
|
622
|
+
// THEN
|
|
623
|
+
expect(injector().settings.get("custom")).toEqual({config: "1", config2: "1"});
|
|
624
|
+
});
|
|
625
|
+
});
|
|
626
|
+
describe("alter()", () => {
|
|
627
|
+
it("should alter value", () => {
|
|
628
|
+
@Injectable()
|
|
629
|
+
class Test {
|
|
630
|
+
$alterValue(value: any) {
|
|
631
|
+
return "alteredValue";
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
vi.spyOn(Test.prototype, "$alterValue");
|
|
636
|
+
|
|
637
|
+
// GIVEN
|
|
638
|
+
|
|
639
|
+
inject<Test>(Test);
|
|
640
|
+
|
|
641
|
+
const service = injector().get<Test>(Test)!;
|
|
642
|
+
|
|
643
|
+
const value = injector().alter("$alterValue", "value");
|
|
644
|
+
|
|
645
|
+
expect(service.$alterValue).toHaveBeenCalledWith("value");
|
|
646
|
+
expect(value).toEqual("alteredValue");
|
|
647
|
+
});
|
|
648
|
+
it("should alter value (factory)", () => {
|
|
649
|
+
registerProvider({
|
|
650
|
+
token: "TOKEN",
|
|
651
|
+
useFactory: () => {
|
|
652
|
+
return {};
|
|
653
|
+
},
|
|
654
|
+
hooks: {
|
|
655
|
+
$alterValue(instance: any, value: any) {
|
|
656
|
+
return "alteredValue";
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
});
|
|
660
|
+
|
|
661
|
+
// GIVEN
|
|
662
|
+
|
|
663
|
+
inject<any>("TOKEN");
|
|
664
|
+
|
|
665
|
+
const value = injector().alter("$alterValue", "value");
|
|
666
|
+
|
|
667
|
+
expect(value).toEqual("alteredValue");
|
|
668
|
+
});
|
|
669
|
+
});
|
|
670
|
+
describe("alterAsync()", () => {
|
|
671
|
+
it("should alter value", async () => {
|
|
672
|
+
@Injectable()
|
|
673
|
+
class Test {
|
|
674
|
+
$alterValue(value: any) {
|
|
675
|
+
return Promise.resolve(value + ":alteredValue");
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
vi.spyOn(Test.prototype, "$alterValue");
|
|
680
|
+
|
|
681
|
+
// GIVEN
|
|
682
|
+
|
|
683
|
+
inject<Test>(Test);
|
|
684
|
+
|
|
685
|
+
const value = await injector().alterAsync("$alterValue", "value");
|
|
686
|
+
|
|
687
|
+
expect(value).toEqual("value:alteredValue");
|
|
688
|
+
});
|
|
689
|
+
});
|
|
690
|
+
describe("imports", () => {
|
|
691
|
+
it("should load all provider and override by configuration a provider (use)", async () => {
|
|
692
|
+
@Injectable()
|
|
693
|
+
class TestService {
|
|
694
|
+
get() {
|
|
695
|
+
return "hello";
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
injector().settings.set("imports", [
|
|
700
|
+
{
|
|
701
|
+
token: TestService,
|
|
702
|
+
use: {
|
|
703
|
+
get: vi.fn().mockReturnValue("world")
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
]);
|
|
707
|
+
|
|
708
|
+
await injector().load();
|
|
709
|
+
|
|
710
|
+
const result = injector().get<TestService>(TestService)!.get();
|
|
711
|
+
expect(result).toEqual("world");
|
|
712
|
+
});
|
|
713
|
+
it("should load all provider and override by configuration a provider (useClass)", async () => {
|
|
714
|
+
@Injectable()
|
|
715
|
+
class TestService {
|
|
716
|
+
get() {
|
|
717
|
+
return "hello";
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
@Injectable()
|
|
722
|
+
class FsTestService {
|
|
723
|
+
get() {
|
|
724
|
+
return "fs";
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
injector().settings.set("imports", [
|
|
729
|
+
{
|
|
730
|
+
token: TestService,
|
|
731
|
+
useClass: FsTestService
|
|
732
|
+
}
|
|
733
|
+
]);
|
|
734
|
+
|
|
735
|
+
await injector().load();
|
|
736
|
+
|
|
737
|
+
const result = injector().get<TestService>(TestService)!.get();
|
|
738
|
+
expect(result).toEqual("fs");
|
|
739
|
+
});
|
|
740
|
+
it("should load all provider and override by configuration a provider (useFactory)", async () => {
|
|
741
|
+
@Injectable()
|
|
742
|
+
class TestService {
|
|
743
|
+
get() {
|
|
744
|
+
return "hello";
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
injector().settings.set("imports", [
|
|
749
|
+
{
|
|
750
|
+
token: TestService,
|
|
751
|
+
useFactory: () => {
|
|
752
|
+
return {
|
|
753
|
+
get() {
|
|
754
|
+
return "world";
|
|
755
|
+
}
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
]);
|
|
760
|
+
|
|
761
|
+
await injector().load();
|
|
762
|
+
|
|
763
|
+
const result = injector().get<TestService>(TestService)!.get();
|
|
764
|
+
expect(result).toEqual("world");
|
|
765
|
+
});
|
|
766
|
+
it("should load all provider and override by configuration a provider (useAsyncFactory)", async () => {
|
|
767
|
+
@Injectable()
|
|
768
|
+
class TestService {
|
|
769
|
+
get() {
|
|
770
|
+
return "hello";
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
injector().settings.set("imports", [
|
|
775
|
+
{
|
|
776
|
+
token: TestService,
|
|
777
|
+
useAsyncFactory: () => {
|
|
778
|
+
return Promise.resolve({
|
|
779
|
+
get() {
|
|
780
|
+
return "world";
|
|
781
|
+
}
|
|
782
|
+
});
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
]);
|
|
786
|
+
|
|
787
|
+
await injector().load();
|
|
788
|
+
|
|
789
|
+
const result = injector().get<TestService>(TestService)!.get();
|
|
790
|
+
expect(result).toEqual("world");
|
|
791
|
+
});
|
|
792
|
+
});
|
|
793
|
+
});
|