@navios/di 0.7.1 → 0.9.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/CHANGELOG.md +110 -0
- package/README.md +117 -17
- package/lib/browser/container/abstract-container.d.mts +112 -0
- package/lib/browser/container/abstract-container.d.mts.map +1 -0
- package/lib/browser/container/abstract-container.mjs +100 -0
- package/lib/browser/container/abstract-container.mjs.map +1 -0
- package/lib/browser/container/container.d.mts +100 -0
- package/lib/browser/container/container.d.mts.map +1 -0
- package/lib/browser/container/container.mjs +424 -0
- package/lib/browser/container/container.mjs.map +1 -0
- package/lib/browser/container/scoped-container.d.mts +93 -0
- package/lib/browser/container/scoped-container.d.mts.map +1 -0
- package/lib/browser/container/scoped-container.mjs +119 -0
- package/lib/browser/container/scoped-container.mjs.map +1 -0
- package/lib/browser/decorators/factory.decorator.d.mts +26 -0
- package/lib/browser/decorators/factory.decorator.d.mts.map +1 -0
- package/lib/browser/decorators/factory.decorator.mjs +20 -0
- package/lib/browser/decorators/factory.decorator.mjs.map +1 -0
- package/lib/browser/decorators/injectable.decorator.d.mts +38 -0
- package/lib/browser/decorators/injectable.decorator.d.mts.map +1 -0
- package/lib/browser/decorators/injectable.decorator.mjs +21 -0
- package/lib/browser/decorators/injectable.decorator.mjs.map +1 -0
- package/lib/browser/enums/injectable-scope.enum.d.mts +18 -0
- package/lib/browser/enums/injectable-scope.enum.d.mts.map +1 -0
- package/lib/browser/enums/injectable-scope.enum.mjs +20 -0
- package/lib/browser/enums/injectable-scope.enum.mjs.map +1 -0
- package/lib/browser/enums/injectable-type.enum.d.mts +8 -0
- package/lib/browser/enums/injectable-type.enum.d.mts.map +1 -0
- package/lib/browser/enums/injectable-type.enum.mjs +10 -0
- package/lib/browser/enums/injectable-type.enum.mjs.map +1 -0
- package/lib/browser/errors/di-error.d.mts +43 -0
- package/lib/browser/errors/di-error.d.mts.map +1 -0
- package/lib/browser/errors/di-error.mjs +98 -0
- package/lib/browser/errors/di-error.mjs.map +1 -0
- package/lib/browser/event-emitter.d.mts +16 -0
- package/lib/browser/event-emitter.d.mts.map +1 -0
- package/lib/browser/event-emitter.mjs +320 -0
- package/lib/browser/event-emitter.mjs.map +1 -0
- package/lib/browser/index.d.mts +37 -1508
- package/lib/browser/index.mjs +29 -2650
- package/lib/browser/interfaces/container.interface.d.mts +59 -0
- package/lib/browser/interfaces/container.interface.d.mts.map +1 -0
- package/lib/browser/interfaces/factory.interface.d.mts +14 -0
- package/lib/browser/interfaces/factory.interface.d.mts.map +1 -0
- package/lib/browser/interfaces/on-service-destroy.interface.d.mts +7 -0
- package/lib/browser/interfaces/on-service-destroy.interface.d.mts.map +1 -0
- package/lib/browser/interfaces/on-service-init.interface.d.mts +7 -0
- package/lib/browser/interfaces/on-service-init.interface.d.mts.map +1 -0
- package/lib/browser/internal/context/async-local-storage.browser.mjs +20 -0
- package/lib/browser/internal/context/async-local-storage.browser.mjs.map +1 -0
- package/lib/browser/internal/context/async-local-storage.d.mts +9 -0
- package/lib/browser/internal/context/async-local-storage.d.mts.map +1 -0
- package/lib/browser/internal/context/async-local-storage.types.d.mts +11 -0
- package/lib/browser/internal/context/async-local-storage.types.d.mts.map +1 -0
- package/lib/browser/internal/context/factory-context.d.mts +23 -0
- package/lib/browser/internal/context/factory-context.d.mts.map +1 -0
- package/lib/browser/internal/context/resolution-context.d.mts +43 -0
- package/lib/browser/internal/context/resolution-context.d.mts.map +1 -0
- package/lib/browser/internal/context/resolution-context.mjs +56 -0
- package/lib/browser/internal/context/resolution-context.mjs.map +1 -0
- package/lib/browser/internal/context/service-initialization-context.d.mts +48 -0
- package/lib/browser/internal/context/service-initialization-context.d.mts.map +1 -0
- package/lib/browser/internal/context/sync-local-storage.mjs +53 -0
- package/lib/browser/internal/context/sync-local-storage.mjs.map +1 -0
- package/lib/browser/internal/core/instance-resolver.d.mts +119 -0
- package/lib/browser/internal/core/instance-resolver.d.mts.map +1 -0
- package/lib/browser/internal/core/instance-resolver.mjs +306 -0
- package/lib/browser/internal/core/instance-resolver.mjs.map +1 -0
- package/lib/browser/internal/core/name-resolver.d.mts +52 -0
- package/lib/browser/internal/core/name-resolver.d.mts.map +1 -0
- package/lib/browser/internal/core/name-resolver.mjs +118 -0
- package/lib/browser/internal/core/name-resolver.mjs.map +1 -0
- package/lib/browser/internal/core/scope-tracker.d.mts +65 -0
- package/lib/browser/internal/core/scope-tracker.d.mts.map +1 -0
- package/lib/browser/internal/core/scope-tracker.mjs +120 -0
- package/lib/browser/internal/core/scope-tracker.mjs.map +1 -0
- package/lib/browser/internal/core/service-initializer.d.mts +44 -0
- package/lib/browser/internal/core/service-initializer.d.mts.map +1 -0
- package/lib/browser/internal/core/service-initializer.mjs +109 -0
- package/lib/browser/internal/core/service-initializer.mjs.map +1 -0
- package/lib/browser/internal/core/service-invalidator.d.mts +81 -0
- package/lib/browser/internal/core/service-invalidator.d.mts.map +1 -0
- package/lib/browser/internal/core/service-invalidator.mjs +142 -0
- package/lib/browser/internal/core/service-invalidator.mjs.map +1 -0
- package/lib/browser/internal/core/token-resolver.d.mts +54 -0
- package/lib/browser/internal/core/token-resolver.d.mts.map +1 -0
- package/lib/browser/internal/core/token-resolver.mjs +77 -0
- package/lib/browser/internal/core/token-resolver.mjs.map +1 -0
- package/lib/browser/internal/holder/holder-storage.interface.d.mts +99 -0
- package/lib/browser/internal/holder/holder-storage.interface.d.mts.map +1 -0
- package/lib/browser/internal/holder/instance-holder.d.mts +101 -0
- package/lib/browser/internal/holder/instance-holder.d.mts.map +1 -0
- package/lib/browser/internal/holder/instance-holder.mjs +19 -0
- package/lib/browser/internal/holder/instance-holder.mjs.map +1 -0
- package/lib/browser/internal/holder/unified-storage.d.mts +53 -0
- package/lib/browser/internal/holder/unified-storage.d.mts.map +1 -0
- package/lib/browser/internal/holder/unified-storage.mjs +144 -0
- package/lib/browser/internal/holder/unified-storage.mjs.map +1 -0
- package/lib/browser/internal/lifecycle/circular-detector.d.mts +39 -0
- package/lib/browser/internal/lifecycle/circular-detector.d.mts.map +1 -0
- package/lib/browser/internal/lifecycle/circular-detector.mjs +55 -0
- package/lib/browser/internal/lifecycle/circular-detector.mjs.map +1 -0
- package/lib/browser/internal/lifecycle/lifecycle-event-bus.d.mts +18 -0
- package/lib/browser/internal/lifecycle/lifecycle-event-bus.d.mts.map +1 -0
- package/lib/browser/internal/lifecycle/lifecycle-event-bus.mjs +43 -0
- package/lib/browser/internal/lifecycle/lifecycle-event-bus.mjs.map +1 -0
- package/lib/browser/internal/stub-factory-class.d.mts +14 -0
- package/lib/browser/internal/stub-factory-class.d.mts.map +1 -0
- package/lib/browser/internal/stub-factory-class.mjs +18 -0
- package/lib/browser/internal/stub-factory-class.mjs.map +1 -0
- package/lib/browser/symbols/injectable-token.d.mts +5 -0
- package/lib/browser/symbols/injectable-token.d.mts.map +1 -0
- package/lib/browser/symbols/injectable-token.mjs +6 -0
- package/lib/browser/symbols/injectable-token.mjs.map +1 -0
- package/lib/browser/token/injection-token.d.mts +55 -0
- package/lib/browser/token/injection-token.d.mts.map +1 -0
- package/lib/browser/token/injection-token.mjs +100 -0
- package/lib/browser/token/injection-token.mjs.map +1 -0
- package/lib/browser/token/registry.d.mts +37 -0
- package/lib/browser/token/registry.d.mts.map +1 -0
- package/lib/browser/token/registry.mjs +86 -0
- package/lib/browser/token/registry.mjs.map +1 -0
- package/lib/browser/utils/default-injectors.d.mts +12 -0
- package/lib/browser/utils/default-injectors.d.mts.map +1 -0
- package/lib/browser/utils/default-injectors.mjs +13 -0
- package/lib/browser/utils/default-injectors.mjs.map +1 -0
- package/lib/browser/utils/get-injectable-token.d.mts +9 -0
- package/lib/browser/utils/get-injectable-token.d.mts.map +1 -0
- package/lib/browser/utils/get-injectable-token.mjs +13 -0
- package/lib/browser/utils/get-injectable-token.mjs.map +1 -0
- package/lib/browser/utils/get-injectors.d.mts +55 -0
- package/lib/browser/utils/get-injectors.d.mts.map +1 -0
- package/lib/browser/utils/get-injectors.mjs +121 -0
- package/lib/browser/utils/get-injectors.mjs.map +1 -0
- package/lib/browser/utils/types.d.mts +23 -0
- package/lib/browser/utils/types.d.mts.map +1 -0
- package/lib/{container-Pb_Y4Z4x.mjs → container-8-z89TyQ.mjs} +1269 -1305
- package/lib/container-8-z89TyQ.mjs.map +1 -0
- package/lib/{container-BuAutHGg.d.mts → container-CNiqesCL.d.mts} +600 -569
- package/lib/container-CNiqesCL.d.mts.map +1 -0
- package/lib/{container-DnzgpfBe.cjs → container-CaY2fDuk.cjs} +1287 -1329
- package/lib/container-CaY2fDuk.cjs.map +1 -0
- package/lib/{container-oGTgX2iX.d.cts → container-D-0Ho3qL.d.cts} +601 -565
- package/lib/container-D-0Ho3qL.d.cts.map +1 -0
- package/lib/index.cjs +13 -15
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +58 -223
- package/lib/index.d.cts.map +1 -1
- package/lib/index.d.mts +62 -222
- package/lib/index.d.mts.map +1 -1
- package/lib/index.mjs +5 -6
- package/lib/index.mjs.map +1 -1
- package/lib/testing/index.cjs +569 -311
- package/lib/testing/index.cjs.map +1 -1
- package/lib/testing/index.d.cts +370 -41
- package/lib/testing/index.d.cts.map +1 -1
- package/lib/testing/index.d.mts +370 -41
- package/lib/testing/index.d.mts.map +1 -1
- package/lib/testing/index.mjs +568 -305
- package/lib/testing/index.mjs.map +1 -1
- package/package.json +2 -1
- package/src/__tests__/circular-detector.spec.mts +193 -0
- package/src/__tests__/concurrent.spec.mts +368 -0
- package/src/__tests__/container.spec.mts +32 -30
- package/src/__tests__/di-error.spec.mts +351 -0
- package/src/__tests__/e2e.browser.spec.mts +0 -4
- package/src/__tests__/e2e.spec.mts +10 -19
- package/src/__tests__/event-emitter.spec.mts +232 -109
- package/src/__tests__/get-injectors.spec.mts +250 -39
- package/src/__tests__/injection-token.spec.mts +293 -349
- package/src/__tests__/library-findings.spec.mts +8 -8
- package/src/__tests__/registry.spec.mts +358 -210
- package/src/__tests__/resolution-context.spec.mts +255 -0
- package/src/__tests__/scope-tracker.spec.mts +598 -0
- package/src/__tests__/scope-upgrade.spec.mts +808 -0
- package/src/__tests__/scoped-container.spec.mts +595 -0
- package/src/__tests__/test-container.spec.mts +293 -0
- package/src/__tests__/token-resolver.spec.mts +207 -0
- package/src/__tests__/unified-storage.spec.mts +535 -0
- package/src/__tests__/unit-test-container.spec.mts +405 -0
- package/src/__type-tests__/container.spec-d.mts +180 -0
- package/src/__type-tests__/factory.spec-d.mts +15 -3
- package/src/__type-tests__/inject.spec-d.mts +115 -20
- package/src/__type-tests__/injectable.spec-d.mts +69 -52
- package/src/__type-tests__/injection-token.spec-d.mts +176 -0
- package/src/__type-tests__/scoped-container.spec-d.mts +212 -0
- package/src/container/abstract-container.mts +327 -0
- package/src/container/container.mts +142 -170
- package/src/container/scoped-container.mts +126 -208
- package/src/decorators/factory.decorator.mts +16 -11
- package/src/decorators/injectable.decorator.mts +20 -16
- package/src/enums/index.mts +2 -2
- package/src/enums/injectable-scope.enum.mts +1 -0
- package/src/enums/injectable-type.enum.mts +1 -0
- package/src/errors/di-error.mts +96 -0
- package/src/event-emitter.mts +3 -27
- package/src/index.mts +6 -153
- package/src/interfaces/container.interface.mts +13 -0
- package/src/interfaces/factory.interface.mts +1 -1
- package/src/interfaces/index.mts +1 -1
- package/src/internal/context/async-local-storage.mts +3 -2
- package/src/internal/context/async-local-storage.types.mts +1 -0
- package/src/internal/context/factory-context.mts +1 -0
- package/src/internal/context/index.mts +3 -1
- package/src/internal/context/resolution-context.mts +1 -0
- package/src/internal/context/service-initialization-context.mts +43 -0
- package/src/internal/core/index.mts +5 -4
- package/src/internal/core/instance-resolver.mts +461 -292
- package/src/internal/core/name-resolver.mts +196 -0
- package/src/internal/core/scope-tracker.mts +242 -0
- package/src/internal/core/{instantiator.mts → service-initializer.mts} +51 -29
- package/src/internal/core/service-invalidator.mts +290 -0
- package/src/internal/core/{token-processor.mts → token-resolver.mts} +17 -88
- package/src/internal/holder/holder-storage.interface.mts +11 -5
- package/src/internal/holder/index.mts +2 -5
- package/src/internal/holder/instance-holder.mts +1 -3
- package/src/internal/holder/unified-storage.mts +245 -0
- package/src/internal/index.mts +2 -1
- package/src/internal/lifecycle/circular-detector.mts +1 -0
- package/src/internal/lifecycle/index.mts +1 -1
- package/src/internal/lifecycle/lifecycle-event-bus.mts +1 -0
- package/src/internal/stub-factory-class.mts +16 -0
- package/src/symbols/injectable-token.mts +3 -1
- package/src/testing/index.mts +2 -0
- package/src/testing/test-container.mts +546 -85
- package/src/testing/types.mts +117 -0
- package/src/testing/unit-test-container.mts +509 -0
- package/src/token/injection-token.mts +41 -4
- package/src/token/registry.mts +75 -9
- package/src/utils/default-injectors.mts +16 -0
- package/src/utils/get-injectable-token.mts +2 -3
- package/src/utils/get-injectors.mts +26 -15
- package/src/utils/index.mts +3 -1
- package/src/utils/types.mts +1 -0
- package/tsdown.config.mts +11 -1
- package/lib/browser/index.d.mts.map +0 -1
- package/lib/browser/index.mjs.map +0 -1
- package/lib/container-BuAutHGg.d.mts.map +0 -1
- package/lib/container-DnzgpfBe.cjs.map +0 -1
- package/lib/container-Pb_Y4Z4x.mjs.map +0 -1
- package/lib/container-oGTgX2iX.d.cts.map +0 -1
- package/src/__tests__/async-local-storage.browser.spec.mts +0 -166
- package/src/__tests__/async-local-storage.spec.mts +0 -333
- package/src/__tests__/errors.spec.mts +0 -87
- package/src/__tests__/factory.spec.mts +0 -137
- package/src/__tests__/injectable.spec.mts +0 -246
- package/src/__tests__/request-scope.spec.mts +0 -416
- package/src/__tests__/service-instantiator.spec.mts +0 -410
- package/src/__tests__/service-locator-event-bus.spec.mts +0 -242
- package/src/__tests__/service-locator-manager.spec.mts +0 -300
- package/src/__tests__/service-locator.spec.mts +0 -966
- package/src/__tests__/unified-api.spec.mts +0 -130
- package/src/browser.mts +0 -11
- package/src/injectors.mts +0 -18
- package/src/internal/context/request-context.mts +0 -214
- package/src/internal/core/invalidator.mts +0 -437
- package/src/internal/core/service-locator.mts +0 -202
- package/src/internal/holder/base-holder-manager.mts +0 -238
- package/src/internal/holder/holder-manager.mts +0 -85
- package/src/internal/holder/request-storage.mts +0 -134
- package/src/internal/holder/singleton-storage.mts +0 -105
- package/src/testing/README.md +0 -80
- package/src/testing/__tests__/test-container.spec.mts +0 -173
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["Container","Injectable","InjectableScope","InjectableType","globalRegistry","getInjectableToken","TestBindingBuilder","container","token","toValue","value","instanceName","getServiceLocator","getInstanceIdentifier","getManager","storeCreatedHolder","Class","Singleton","toClass","target","set","TestContainer","registry","logger","injectors","undefined","bind","realToken","bindValue","bindClass","createChild"],"sources":["../../src/testing/test-container.mts"],"sourcesContent":["import type { ClassType, InjectionToken } from '../token/injection-token.mjs'\nimport type { Registry } from '../token/registry.mjs'\nimport type { Injectors } from '../utils/index.mjs'\n\nimport { Container } from '../container/container.mjs'\nimport { Injectable } from '../decorators/injectable.decorator.mjs'\nimport { InjectableScope, InjectableType } from '../enums/index.mjs'\nimport { globalRegistry } from '../token/registry.mjs'\nimport { getInjectableToken } from '../utils/index.mjs'\n\n/**\n * A binding builder for the TestContainer that allows chaining binding operations.\n */\nexport class TestBindingBuilder<T> {\n constructor(\n private readonly container: TestContainer,\n private readonly token: InjectionToken<T, any>,\n ) {}\n\n /**\n * Binds the token to a specific value.\n * This is useful for testing with mock values or constants.\n * @param value The value to bind to the token\n */\n toValue(value: T): TestContainer {\n const instanceName = this.container\n .getServiceLocator()\n .getInstanceIdentifier(this.token)\n this.container\n .getServiceLocator()\n .getManager()\n .storeCreatedHolder(\n instanceName,\n value,\n InjectableType.Class,\n InjectableScope.Singleton,\n )\n return this.container\n }\n\n /**\n * Binds the token to a class constructor.\n * @param target The class constructor to bind to\n */\n toClass(target: ClassType): TestContainer {\n this.container['registry'].set(\n this.token,\n InjectableScope.Singleton,\n target,\n InjectableType.Class,\n )\n return this.container\n }\n}\n\n/**\n * TestContainer extends the base Container with additional methods useful for testing.\n * It provides a simplified API for binding values and classes during test setup.\n */\n@Injectable()\nexport class TestContainer extends Container {\n constructor(\n registry: Registry = globalRegistry,\n logger: Console | null = null,\n injectors: Injectors = undefined as any,\n ) {\n super(registry, logger, injectors)\n }\n\n /**\n * Creates a binding builder for the given token.\n * This allows chaining binding operations like bind(Token).toValue(value).\n * @param token The injection token to bind\n * @returns A TestBindingBuilder for chaining binding operations\n */\n bind<T>(token: ClassType): TestBindingBuilder<T>\n bind<T>(token: InjectionToken<T, any>): TestBindingBuilder<T>\n bind(token: any): TestBindingBuilder<any> {\n let realToken = token\n if (typeof token === 'function') {\n realToken = getInjectableToken(token)\n }\n return new TestBindingBuilder(this, realToken)\n }\n\n /**\n * Binds a value directly to a token.\n * This is a convenience method equivalent to bind(token).toValue(value).\n * @param token The injection token to bind\n * @param value The value to bind to the token\n * @returns The TestContainer instance for chaining\n */\n bindValue<T>(token: ClassType, value: T): TestContainer\n bindValue<T>(token: InjectionToken<T, any>, value: T): TestContainer\n bindValue(token: any, value: any): TestContainer {\n return this.bind(token).toValue(value)\n }\n\n /**\n * Binds a class to a token.\n * This is a convenience method equivalent to bind(token).toClass(target).\n * @param token The injection token to bind\n * @param target The class constructor to bind to\n * @returns The TestContainer instance for chaining\n */\n bindClass(token: ClassType, target: ClassType): TestContainer\n bindClass<T>(token: InjectionToken<T, any>, target: ClassType): TestContainer\n bindClass(token: any, target: any): TestContainer {\n return this.bind(token).toClass(target)\n }\n\n /**\n * Creates a new TestContainer instance with the same configuration.\n * This is useful for creating isolated test containers.\n * @returns A new TestContainer instance\n */\n createChild(): TestContainer {\n return new TestContainer(this.registry, this.logger, this.injectors)\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sBA4DmCA;;;GA/CnC,IAAaM,qBAAb,MAAaA;;;CACX,YACE,WACA,OACA;OAFiBC,YAAAA;OACAC,QAAAA;;;;;;IAQnBC,QAAQC,OAAyB;EAC/B,MAAMC,eAAe,KAAKJ,UACvBK,mBAAiB,CACjBC,sBAAsB,KAAKL,MAAK;AACnC,OAAKD,UACFK,mBAAiB,CACjBE,YAAU,CACVC,mBACCJ,cACAD,OACAP,iCAAea,OACfd,kCAAgBe,UAAS;AAE7B,SAAO,KAAKV;;;;;IAOdW,QAAQC,QAAkC;AACxC,OAAKZ,UAAU,YAAYa,IACzB,KAAKZ,OACLN,kCAAgBe,WAChBE,QACAhB,iCAAea,MAAK;AAEtB,SAAO,KAAKT;;;;OAQfN,8BAAAA;AACM,IAAMoB,gBAAN,eAA4BrB,aAAAA,8BAAAA;;4EAAAA,WAAAA;;CACjC,YACEsB,WAAqBlB,kCACrBmB,SAAyB,MACzBC,YAAuBC,QACvB;AACA,QAAMH,UAAUC,QAAQC,UAAAA;;CAW1BE,KAAKlB,OAAqC;EACxC,IAAImB,YAAYnB;AAChB,MAAI,OAAOA,UAAU,WACnBmB,aAAYtB,qCAAmBG,MAAAA;AAEjC,SAAO,IAAIF,mBAAmB,MAAMqB,UAAAA;;CAYtCC,UAAUpB,OAAYE,OAA2B;AAC/C,SAAO,KAAKgB,KAAKlB,MAAAA,CAAOC,QAAQC,MAAAA;;CAYlCmB,UAAUrB,OAAYW,QAA4B;AAChD,SAAO,KAAKO,KAAKlB,MAAAA,CAAOU,QAAQC,OAAAA;;;;;;IAQlCW,cAA6B;AAC3B,SAAO,IAAIT,eAAc,KAAKC,UAAU,KAAKC,QAAQ,KAAKC,UAAS"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["Container","InjectableScope","InjectableType","globalRegistry","Registry","getInjectableToken","defaultInjectors","TestContainer","testRegistry","methodCalls","Map","lifecycleEvents","instanceCounts","boundTokens","Set","options","parentRegistry","logger","bind","token","realToken","resolveToken","tokenId","id","toValue","value","add","registerValueBinding","toClass","cls","registerClassBinding","toFactory","factory","registerFactoryBinding","clear","dispose","expectResolved","storage","getStorage","names","getAllNames","found","some","name","includes","Error","toString","expectNotResolved","expectSingleton","registry","getRegistry","has","record","get","scope","Singleton","expectTransient","Transient","expectRequestScoped","Request","expectSameInstance","instance1","instance2","expectDifferentInstances","expectInitialized","events","initialized","e","event","expectDestroyed","destroyed","expectNotDestroyed","recordMethodCall","method","args","result","error","calls","push","timestamp","Date","now","set","recordLifecycleEvent","instanceName","count","expectCalled","c","expectCalledWith","expectedArgs","argsMatch","JSON","stringify","expectCallCount","actualCount","filter","length","getMethodCalls","getServiceStats","instanceCount","clearMethodCalls","getDependencyGraph","nodes","rootTokens","forEach","holder","tokenMatch","match","dependencies","Array","from","deps","dependents","findDependents","getSimplifiedDependencyGraph","graph","dep","depTokenMatch","depTokenId","key","Object","keys","sort","ValueHolder","instance","Class","nameResolver","getNameResolver","generateInstanceName","undefined","storeInstance","FactoryWrapper","create","Factory","actual","expected","every","arg","index","exp","Container","InjectableScope","InjectableType","DIError","InjectionToken","Registry","getInjectableToken","defaultInjectors","createTrackingProxy","target","tokenId","methodCalls","Proxy","get","obj","prop","value","Reflect","args","calls","record","method","timestamp","Date","now","result","apply","undefined","Promise","then","res","push","set","catch","err","error","createAutoMockProxy","_","Error","UnitTestContainer","testRegistry","Map","lifecycleEvents","instanceCounts","registeredTokenIds","Set","autoMockedTokenIds","allowUnregistered","options","logger","provider","providers","registerProvider","enableAutoMocking","disableAutoMocking","token","realToken","resolveToken","has","id","factoryNotFound","toString","add","instance","clear","dispose","expectResolved","storage","getStorage","names","getAllNames","found","some","name","includes","expectNotResolved","expectAutoMocked","expectNotAutoMocked","recordLifecycleEvent","event","instanceName","events","count","expectInitialized","initialized","e","expectDestroyed","destroyed","expectNotDestroyed","expectCalled","c","expectNotCalled","expectCalledWith","expectedArgs","argsMatch","filter","actualArgs","map","JSON","stringify","join","expectCallCount","actualCount","length","getMethodCalls","getServiceStats","instanceCount","clearMethodCalls","getRegisteredTokenIds","getAutoMockedTokenIds","create","useValue","registerValueBinding","useClass","registerClassBinding","useFactory","registerFactoryBinding","Singleton","Class","ValueHolder","nameResolver","getNameResolver","generateInstanceName","storeInstance","cls","factory","FactoryWrapper","Factory","actual","expected","every","arg","index","exp"],"sources":["../../src/testing/test-container.mts","../../src/testing/unit-test-container.mts"],"sourcesContent":["import type {\n BindingBuilder,\n DependencyGraph,\n DependencyNode,\n LifecycleRecord,\n MethodCallRecord,\n MockServiceStats,\n TestContainerOptions,\n} from './types.mjs'\n\nimport { Container } from '../container/container.mjs'\nimport { InjectableScope, InjectableType } from '../enums/index.mjs'\nimport { InjectionToken } from '../token/injection-token.mjs'\nimport { globalRegistry, Registry } from '../token/registry.mjs'\nimport { getInjectableToken } from '../utils/get-injectable-token.mjs'\nimport { defaultInjectors } from '../utils/index.mjs'\n\ntype AnyToken = InjectionToken<any, any> | (new (...args: any[]) => any)\n\n/**\n * TestContainer extends Container with testing utilities.\n *\n * Provides simple value/class binding for integration/e2e tests,\n * plus assertion helpers and dependency graph inspection.\n *\n * @example\n * ```ts\n * const container = new TestContainer()\n *\n * // Bind mock values\n * container.bind(DatabaseToken).toValue(mockDatabase)\n * container.bind(UserService).toClass(MockUserService)\n *\n * // Use container normally\n * const service = await container.get(MyService)\n *\n * // Assert on container state\n * container.expectResolved(MyService)\n * container.expectSingleton(MyService)\n * ```\n */\nexport class TestContainer extends Container {\n private readonly testRegistry: Registry\n private readonly methodCalls = new Map<string, MethodCallRecord[]>()\n private readonly lifecycleEvents = new Map<string, LifecycleRecord[]>()\n private readonly instanceCounts = new Map<string, number>()\n private readonly boundTokens = new Set<string>()\n\n /**\n * Creates a new TestContainer.\n *\n * @param options - Configuration options\n * @param options.parentRegistry - Parent registry. Defaults to globalRegistry.\n * Pass `null` for a completely isolated container.\n * @param options.logger - Optional logger for debugging.\n *\n * @example\n * ```ts\n * // Uses globalRegistry as parent (default)\n * const container = new TestContainer()\n *\n * // Isolated container (no access to @Injectable classes)\n * const isolated = new TestContainer({ parentRegistry: null })\n *\n * // Custom parent registry\n * const custom = new TestContainer({ parentRegistry: myRegistry })\n * ```\n */\n constructor(options: TestContainerOptions = {}) {\n const { parentRegistry = globalRegistry, logger = null } = options\n const testRegistry = parentRegistry\n ? new Registry(parentRegistry)\n : new Registry()\n super(testRegistry, logger, defaultInjectors)\n this.testRegistry = testRegistry\n }\n\n // ============================================================================\n // BINDING API\n // ============================================================================\n\n /**\n * Creates a binding builder for the given token.\n *\n * @example\n * ```ts\n * container.bind(UserService).toValue(mockUserService)\n * container.bind(DatabaseToken).toClass(MockDatabase)\n * container.bind(ConfigToken).toFactory(() => ({ apiKey: 'test' }))\n * ```\n */\n bind<T>(\n token: InjectionToken<T, any> | (new (...args: any[]) => T),\n ): BindingBuilder<T> {\n const realToken = this.resolveToken(token)\n const tokenId = realToken.id\n\n return {\n toValue: (value: T) => {\n this.boundTokens.add(tokenId)\n this.registerValueBinding(realToken, value)\n },\n toClass: <C extends new (...args: any[]) => T>(cls: C) => {\n this.boundTokens.add(tokenId)\n this.registerClassBinding(realToken, cls)\n },\n toFactory: (factory: () => T | Promise<T>) => {\n this.boundTokens.add(tokenId)\n this.registerFactoryBinding(realToken, factory)\n },\n }\n }\n\n /**\n * Clears all bindings and resets container state.\n */\n async clear(): Promise<void> {\n await this.dispose()\n this.methodCalls.clear()\n this.lifecycleEvents.clear()\n this.instanceCounts.clear()\n this.boundTokens.clear()\n }\n\n // ============================================================================\n // ASSERTION HELPERS\n // ============================================================================\n\n /**\n * Asserts that a service has been resolved at least once.\n */\n expectResolved(token: AnyToken): void {\n const realToken = this.resolveToken(token)\n const storage = this.getStorage()\n const names = storage.getAllNames()\n const found = names.some((name) => name.includes(realToken.id))\n\n if (!found) {\n throw new Error(\n `Expected ${realToken.toString()} to be resolved, but it was not`,\n )\n }\n }\n\n /**\n * Asserts that a service has NOT been resolved.\n */\n expectNotResolved(token: AnyToken): void {\n const realToken = this.resolveToken(token)\n const storage = this.getStorage()\n const names = storage.getAllNames()\n const found = names.some((name) => name.includes(realToken.id))\n\n if (found) {\n throw new Error(\n `Expected ${realToken.toString()} to NOT be resolved, but it was`,\n )\n }\n }\n\n /**\n * Asserts that a service is registered as singleton scope.\n */\n expectSingleton(token: AnyToken): void {\n const realToken = this.resolveToken(token)\n const registry = this.getRegistry()\n\n if (!registry.has(realToken)) {\n throw new Error(\n `Expected ${realToken.toString()} to be registered, but it was not`,\n )\n }\n\n const record = registry.get(realToken)\n if (record.scope !== InjectableScope.Singleton) {\n throw new Error(\n `Expected ${realToken.toString()} to be Singleton scope, but it was ${record.scope}`,\n )\n }\n }\n\n /**\n * Asserts that a service is registered as transient scope.\n */\n expectTransient(token: AnyToken): void {\n const realToken = this.resolveToken(token)\n const registry = this.getRegistry()\n\n if (!registry.has(realToken)) {\n throw new Error(\n `Expected ${realToken.toString()} to be registered, but it was not`,\n )\n }\n\n const record = registry.get(realToken)\n if (record.scope !== InjectableScope.Transient) {\n throw new Error(\n `Expected ${realToken.toString()} to be Transient scope, but it was ${record.scope}`,\n )\n }\n }\n\n /**\n * Asserts that a service is registered as request scope.\n */\n expectRequestScoped(token: AnyToken): void {\n const realToken = this.resolveToken(token)\n const registry = this.getRegistry()\n\n if (!registry.has(realToken)) {\n throw new Error(\n `Expected ${realToken.toString()} to be registered, but it was not`,\n )\n }\n\n const record = registry.get(realToken)\n if (record.scope !== InjectableScope.Request) {\n throw new Error(\n `Expected ${realToken.toString()} to be Request scope, but it was ${record.scope}`,\n )\n }\n }\n\n /**\n * Asserts that two service resolutions return the same instance.\n */\n async expectSameInstance(token: AnyToken): Promise<void> {\n const instance1 = await this.get(token as any)\n const instance2 = await this.get(token as any)\n\n if (instance1 !== instance2) {\n const realToken = this.resolveToken(token)\n throw new Error(\n `Expected ${realToken.toString()} to return same instance, but got different instances`,\n )\n }\n }\n\n /**\n * Asserts that two service resolutions return different instances.\n */\n async expectDifferentInstances(token: AnyToken): Promise<void> {\n const instance1 = await this.get(token as any)\n const instance2 = await this.get(token as any)\n\n if (instance1 === instance2) {\n const realToken = this.resolveToken(token)\n throw new Error(\n `Expected ${realToken.toString()} to return different instances, but got same instance`,\n )\n }\n }\n\n // ============================================================================\n // LIFECYCLE ASSERTIONS\n // ============================================================================\n\n /**\n * Asserts that a service's onServiceInit was called.\n */\n expectInitialized(token: AnyToken): void {\n const realToken = this.resolveToken(token)\n const events = this.lifecycleEvents.get(realToken.id) || []\n const initialized = events.some((e) => e.event === 'initialized')\n\n if (!initialized) {\n throw new Error(\n `Expected ${realToken.toString()} to be initialized, but onServiceInit was not called`,\n )\n }\n }\n\n /**\n * Asserts that a service's onServiceDestroy was called.\n */\n expectDestroyed(token: AnyToken): void {\n const realToken = this.resolveToken(token)\n const events = this.lifecycleEvents.get(realToken.id) || []\n const destroyed = events.some((e) => e.event === 'destroyed')\n\n if (!destroyed) {\n throw new Error(\n `Expected ${realToken.toString()} to be destroyed, but onServiceDestroy was not called`,\n )\n }\n }\n\n /**\n * Asserts that a service has NOT been destroyed.\n */\n expectNotDestroyed(token: AnyToken): void {\n const realToken = this.resolveToken(token)\n const events = this.lifecycleEvents.get(realToken.id) || []\n const destroyed = events.some((e) => e.event === 'destroyed')\n\n if (destroyed) {\n throw new Error(\n `Expected ${realToken.toString()} to NOT be destroyed, but onServiceDestroy was called`,\n )\n }\n }\n\n // ============================================================================\n // CALL TRACKING\n // ============================================================================\n\n /**\n * Records a method call for tracking.\n * Call this from your mock implementations.\n */\n recordMethodCall(\n token: AnyToken,\n method: string,\n args: unknown[],\n result?: unknown,\n error?: Error,\n ): void {\n const realToken = this.resolveToken(token)\n const calls = this.methodCalls.get(realToken.id) || []\n calls.push({\n method,\n args,\n timestamp: Date.now(),\n result,\n error,\n })\n this.methodCalls.set(realToken.id, calls)\n }\n\n /**\n * Records a lifecycle event for tracking.\n */\n recordLifecycleEvent(\n token: AnyToken,\n event: 'created' | 'initialized' | 'destroyed',\n instanceName: string,\n ): void {\n const realToken = this.resolveToken(token)\n const events = this.lifecycleEvents.get(realToken.id) || []\n events.push({\n event,\n timestamp: Date.now(),\n instanceName,\n })\n this.lifecycleEvents.set(realToken.id, events)\n\n if (event === 'created') {\n const count = this.instanceCounts.get(realToken.id) || 0\n this.instanceCounts.set(realToken.id, count + 1)\n }\n }\n\n /**\n * Asserts that a method was called on a service.\n */\n expectCalled(token: AnyToken, method: string): void {\n const realToken = this.resolveToken(token)\n const calls = this.methodCalls.get(realToken.id) || []\n const found = calls.some((c) => c.method === method)\n\n if (!found) {\n throw new Error(\n `Expected ${realToken.toString()}.${method}() to be called, but it was not`,\n )\n }\n }\n\n /**\n * Asserts that a method was called with specific arguments.\n */\n expectCalledWith(\n token: AnyToken,\n method: string,\n expectedArgs: unknown[],\n ): void {\n const realToken = this.resolveToken(token)\n const calls = this.methodCalls.get(realToken.id) || []\n const found = calls.some(\n (c) => c.method === method && this.argsMatch(c.args, expectedArgs),\n )\n\n if (!found) {\n throw new Error(\n `Expected ${realToken.toString()}.${method}() to be called with ${JSON.stringify(expectedArgs)}, but it was not`,\n )\n }\n }\n\n /**\n * Asserts that a method was called a specific number of times.\n */\n expectCallCount(token: AnyToken, method: string, count: number): void {\n const realToken = this.resolveToken(token)\n const calls = this.methodCalls.get(realToken.id) || []\n const actualCount = calls.filter((c) => c.method === method).length\n\n if (actualCount !== count) {\n throw new Error(\n `Expected ${realToken.toString()}.${method}() to be called ${count} times, but was called ${actualCount} times`,\n )\n }\n }\n\n /**\n * Gets all recorded method calls for a service.\n */\n getMethodCalls(token: AnyToken): MethodCallRecord[] {\n const realToken = this.resolveToken(token)\n return this.methodCalls.get(realToken.id) || []\n }\n\n /**\n * Gets statistics about a mocked service.\n */\n getServiceStats(token: AnyToken): MockServiceStats {\n const realToken = this.resolveToken(token)\n return {\n instanceCount: this.instanceCounts.get(realToken.id) || 0,\n methodCalls: this.methodCalls.get(realToken.id) || [],\n lifecycleEvents: this.lifecycleEvents.get(realToken.id) || [],\n }\n }\n\n /**\n * Clears all recorded method calls.\n */\n clearMethodCalls(): void {\n this.methodCalls.clear()\n }\n\n // ============================================================================\n // DEPENDENCY GRAPH\n // ============================================================================\n\n /**\n * Gets the dependency graph for snapshot testing.\n * Returns a serializable structure that can be used with vitest snapshots.\n */\n getDependencyGraph(): DependencyGraph {\n const storage = this.getStorage()\n const nodes: Record<string, DependencyNode> = {}\n const rootTokens: string[] = []\n\n storage.forEach((name, holder) => {\n const tokenMatch = name.match(/^([^:]+)/)\n const tokenId = tokenMatch ? tokenMatch[1] : name\n\n nodes[name] = {\n token: tokenId,\n instanceName: name,\n scope: holder.scope,\n dependencies: Array.from(holder.deps),\n dependents: storage.findDependents(name),\n }\n\n // Root tokens have no dependents\n if (storage.findDependents(name).length === 0) {\n rootTokens.push(name)\n }\n })\n\n return { nodes, rootTokens }\n }\n\n /**\n * Gets a simplified dependency graph showing only token relationships.\n * Useful for cleaner snapshot comparisons.\n */\n getSimplifiedDependencyGraph(): Record<string, string[]> {\n const storage = this.getStorage()\n const graph: Record<string, string[]> = {}\n\n storage.forEach((name, holder) => {\n const tokenMatch = name.match(/^([^:]+)/)\n const tokenId = tokenMatch ? tokenMatch[1] : name\n\n if (!graph[tokenId]) {\n graph[tokenId] = []\n }\n\n for (const dep of holder.deps) {\n const depTokenMatch = dep.match(/^([^:]+)/)\n const depTokenId = depTokenMatch ? depTokenMatch[1] : dep\n if (!graph[tokenId].includes(depTokenId)) {\n graph[tokenId].push(depTokenId)\n }\n }\n })\n\n // Sort for consistent snapshots\n for (const key of Object.keys(graph)) {\n graph[key].sort()\n }\n\n return graph\n }\n\n // ============================================================================\n // INTERNAL HELPERS\n // ============================================================================\n\n private resolveToken(token: AnyToken): InjectionToken<any, any> {\n if (typeof token === 'function') {\n return getInjectableToken(token)\n }\n return token\n }\n\n private registerValueBinding<T>(\n token: InjectionToken<T, any>,\n value: T,\n ): void {\n // Create a simple class that returns the value\n const ValueHolder = class {\n static instance = value\n }\n\n this.testRegistry.set(\n token,\n InjectableScope.Singleton,\n ValueHolder,\n InjectableType.Class,\n )\n\n // Store the instance directly\n const nameResolver = this.getNameResolver()\n const instanceName = nameResolver.generateInstanceName(\n token,\n undefined,\n undefined,\n InjectableScope.Singleton,\n )\n this.getStorage().storeInstance(instanceName, value)\n this.recordLifecycleEvent(token, 'created', instanceName)\n }\n\n private registerClassBinding<T>(\n token: InjectionToken<T, any>,\n cls: new (...args: any[]) => T,\n ): void {\n this.testRegistry.set(\n token,\n InjectableScope.Singleton,\n cls,\n InjectableType.Class,\n )\n }\n\n private registerFactoryBinding<T>(\n token: InjectionToken<T, any>,\n factory: () => T | Promise<T>,\n ): void {\n // Create a factory class wrapper\n const FactoryWrapper = class {\n static factory = factory\n async create(): Promise<T> {\n return await factory()\n }\n }\n\n this.testRegistry.set(\n token,\n InjectableScope.Singleton,\n FactoryWrapper,\n InjectableType.Factory,\n )\n }\n\n private argsMatch(actual: unknown[], expected: unknown[]): boolean {\n if (actual.length !== expected.length) {\n return false\n }\n return actual.every((arg, index) => {\n const exp = expected[index]\n if (typeof exp === 'object' && exp !== null) {\n return JSON.stringify(arg) === JSON.stringify(exp)\n }\n return arg === exp\n })\n }\n}\n","import type { LifecycleRecord, MethodCallRecord, MockServiceStats, ProviderConfig, UnitTestContainerOptions } from './types.mjs'\n\nimport { Container } from '../container/container.mjs'\nimport { InjectableScope, InjectableType } from '../enums/index.mjs'\nimport { DIError } from '../errors/index.mjs'\nimport { InjectionToken } from '../token/injection-token.mjs'\nimport { Registry } from '../token/registry.mjs'\nimport { getInjectableToken } from '../utils/get-injectable-token.mjs'\nimport { defaultInjectors } from '../utils/index.mjs'\n\ntype AnyToken = InjectionToken<any, any> | (new (...args: any[]) => any)\n\n/**\n * Creates a tracking proxy that records method calls.\n */\nfunction createTrackingProxy<T extends object>(\n target: T,\n tokenId: string,\n methodCalls: Map<string, MethodCallRecord[]>,\n): T {\n return new Proxy(target, {\n get(obj, prop) {\n const value = Reflect.get(obj, prop)\n\n if (typeof value === 'function' && typeof prop === 'string') {\n return function (this: unknown, ...args: unknown[]) {\n const calls = methodCalls.get(tokenId) || []\n const record: MethodCallRecord = {\n method: prop,\n args,\n timestamp: Date.now(),\n }\n\n try {\n const result = value.apply(this === undefined ? obj : this, args)\n\n if (result instanceof Promise) {\n return result\n .then((res) => {\n record.result = res\n calls.push(record)\n methodCalls.set(tokenId, calls)\n return res\n })\n .catch((err) => {\n record.error = err\n calls.push(record)\n methodCalls.set(tokenId, calls)\n throw err\n })\n }\n\n record.result = result\n calls.push(record)\n methodCalls.set(tokenId, calls)\n return result\n } catch (err) {\n record.error = err as Error\n calls.push(record)\n methodCalls.set(tokenId, calls)\n throw err\n }\n }\n }\n\n return value\n },\n })\n}\n\n/**\n * Creates an auto-mock proxy that throws on method access.\n */\nfunction createAutoMockProxy(tokenId: string): object {\n return new Proxy(\n {},\n {\n get(_, prop) {\n if (prop === 'then' || prop === 'catch' || prop === 'finally') {\n return undefined\n }\n if (typeof prop === 'symbol') {\n return undefined\n }\n throw new Error(\n `[UnitTestContainer] Attempted to access '${prop}' on auto-mocked service '${tokenId}'. ` +\n `This service was not provided in the providers list. ` +\n `Add it to providers or use allowUnregistered: false to catch this earlier.`,\n )\n },\n },\n )\n}\n\n/**\n * UnitTestContainer for isolated unit testing.\n *\n * Only services explicitly listed in `providers` can be resolved.\n * All method calls are automatically tracked via proxies.\n * Unregistered dependencies throw by default, or can be auto-mocked.\n *\n * @example\n * ```ts\n * const container = new UnitTestContainer({\n * providers: [\n * { token: UserService, useClass: MockUserService },\n * { token: ConfigToken, useValue: { apiUrl: 'test' } },\n * ],\n * })\n *\n * const service = await container.get(UserService)\n *\n * // All method calls are automatically tracked\n * await service.findUser('123')\n *\n * container.expectCalled(UserService, 'findUser')\n * container.expectCalledWith(UserService, 'findUser', ['123'])\n * ```\n */\nexport class UnitTestContainer extends Container {\n private readonly testRegistry: Registry\n private readonly methodCalls = new Map<string, MethodCallRecord[]>()\n private readonly lifecycleEvents = new Map<string, LifecycleRecord[]>()\n private readonly instanceCounts = new Map<string, number>()\n private readonly registeredTokenIds = new Set<string>()\n private readonly autoMockedTokenIds = new Set<string>()\n private allowUnregistered: boolean\n\n constructor(options: UnitTestContainerOptions) {\n const testRegistry = new Registry()\n super(testRegistry, options.logger ?? null, defaultInjectors)\n this.testRegistry = testRegistry\n this.allowUnregistered = options.allowUnregistered ?? false\n\n // Register all providers\n for (const provider of options.providers) {\n this.registerProvider(provider)\n }\n }\n\n /**\n * Enables auto-mocking for unregistered dependencies.\n * Call this to switch from strict mode to auto-mock mode.\n */\n enableAutoMocking(): this {\n this.allowUnregistered = true\n return this\n }\n\n /**\n * Disables auto-mocking (strict mode).\n * Unregistered dependencies will throw.\n */\n disableAutoMocking(): this {\n this.allowUnregistered = false\n return this\n }\n\n /**\n * Override get to wrap instances in tracking proxies.\n */\n override async get(token: any, args?: unknown): Promise<any> {\n const realToken = this.resolveToken(token)\n\n // Check if this is a registered provider\n if (!this.registeredTokenIds.has(realToken.id)) {\n if (!this.allowUnregistered) {\n throw DIError.factoryNotFound(\n `${realToken.toString()} is not in the providers list. ` +\n `Add it to providers or enable allowUnregistered.`,\n )\n }\n\n // Auto-mock unregistered dependency\n if (!this.autoMockedTokenIds.has(realToken.id)) {\n this.autoMockedTokenIds.add(realToken.id)\n }\n\n return createAutoMockProxy(realToken.id)\n }\n\n const instance = await super.get(token, args)\n\n // Wrap in tracking proxy if it's an object\n if (instance && typeof instance === 'object') {\n return createTrackingProxy(instance, realToken.id, this.methodCalls)\n }\n\n return instance\n }\n\n /**\n * Clears all state and disposes the container.\n */\n async clear(): Promise<void> {\n await this.dispose()\n this.methodCalls.clear()\n this.lifecycleEvents.clear()\n this.instanceCounts.clear()\n this.autoMockedTokenIds.clear()\n }\n\n // ============================================================================\n // ASSERTION HELPERS\n // ============================================================================\n\n /**\n * Asserts that a service has been resolved at least once.\n */\n expectResolved(token: AnyToken): void {\n const realToken = this.resolveToken(token)\n const storage = this.getStorage()\n const names = storage.getAllNames()\n const found = names.some((name) => name.includes(realToken.id))\n\n if (!found) {\n throw new Error(`Expected ${realToken.toString()} to be resolved, but it was not`)\n }\n }\n\n /**\n * Asserts that a service has NOT been resolved.\n */\n expectNotResolved(token: AnyToken): void {\n const realToken = this.resolveToken(token)\n const storage = this.getStorage()\n const names = storage.getAllNames()\n const found = names.some((name) => name.includes(realToken.id))\n\n if (found) {\n throw new Error(`Expected ${realToken.toString()} to NOT be resolved, but it was`)\n }\n }\n\n /**\n * Asserts that a service was auto-mocked (not in providers list).\n */\n expectAutoMocked(token: AnyToken): void {\n const realToken = this.resolveToken(token)\n\n if (!this.autoMockedTokenIds.has(realToken.id)) {\n throw new Error(\n `Expected ${realToken.toString()} to be auto-mocked, but it was not. ` +\n `Either it's in the providers list or hasn't been resolved.`,\n )\n }\n }\n\n /**\n * Asserts that a service was NOT auto-mocked (is in providers list).\n */\n expectNotAutoMocked(token: AnyToken): void {\n const realToken = this.resolveToken(token)\n\n if (this.autoMockedTokenIds.has(realToken.id)) {\n throw new Error(\n `Expected ${realToken.toString()} to NOT be auto-mocked, but it was.`,\n )\n }\n }\n\n // ============================================================================\n // LIFECYCLE ASSERTIONS\n // ============================================================================\n\n /**\n * Records a lifecycle event for tracking.\n */\n recordLifecycleEvent(token: AnyToken, event: 'created' | 'initialized' | 'destroyed', instanceName: string): void {\n const realToken = this.resolveToken(token)\n const events = this.lifecycleEvents.get(realToken.id) || []\n events.push({\n event,\n timestamp: Date.now(),\n instanceName,\n })\n this.lifecycleEvents.set(realToken.id, events)\n\n if (event === 'created') {\n const count = this.instanceCounts.get(realToken.id) || 0\n this.instanceCounts.set(realToken.id, count + 1)\n }\n }\n\n /**\n * Asserts that a service's onServiceInit was called.\n */\n expectInitialized(token: AnyToken): void {\n const realToken = this.resolveToken(token)\n const events = this.lifecycleEvents.get(realToken.id) || []\n const initialized = events.some((e) => e.event === 'initialized')\n\n if (!initialized) {\n throw new Error(`Expected ${realToken.toString()} to be initialized, but onServiceInit was not called`)\n }\n }\n\n /**\n * Asserts that a service's onServiceDestroy was called.\n */\n expectDestroyed(token: AnyToken): void {\n const realToken = this.resolveToken(token)\n const events = this.lifecycleEvents.get(realToken.id) || []\n const destroyed = events.some((e) => e.event === 'destroyed')\n\n if (!destroyed) {\n throw new Error(`Expected ${realToken.toString()} to be destroyed, but onServiceDestroy was not called`)\n }\n }\n\n /**\n * Asserts that a service has NOT been destroyed.\n */\n expectNotDestroyed(token: AnyToken): void {\n const realToken = this.resolveToken(token)\n const events = this.lifecycleEvents.get(realToken.id) || []\n const destroyed = events.some((e) => e.event === 'destroyed')\n\n if (destroyed) {\n throw new Error(`Expected ${realToken.toString()} to NOT be destroyed, but onServiceDestroy was called`)\n }\n }\n\n // ============================================================================\n // CALL TRACKING (AUTO-TRACKED VIA PROXY)\n // ============================================================================\n\n /**\n * Asserts that a method was called on a service.\n */\n expectCalled(token: AnyToken, method: string): void {\n const realToken = this.resolveToken(token)\n const calls = this.methodCalls.get(realToken.id) || []\n const found = calls.some((c) => c.method === method)\n\n if (!found) {\n throw new Error(`Expected ${realToken.toString()}.${method}() to be called, but it was not`)\n }\n }\n\n /**\n * Asserts that a method was NOT called on a service.\n */\n expectNotCalled(token: AnyToken, method: string): void {\n const realToken = this.resolveToken(token)\n const calls = this.methodCalls.get(realToken.id) || []\n const found = calls.some((c) => c.method === method)\n\n if (found) {\n throw new Error(`Expected ${realToken.toString()}.${method}() to NOT be called, but it was`)\n }\n }\n\n /**\n * Asserts that a method was called with specific arguments.\n */\n expectCalledWith(token: AnyToken, method: string, expectedArgs: unknown[]): void {\n const realToken = this.resolveToken(token)\n const calls = this.methodCalls.get(realToken.id) || []\n const found = calls.some(\n (c) => c.method === method && this.argsMatch(c.args, expectedArgs),\n )\n\n if (!found) {\n const methodCalls = calls.filter((c) => c.method === method)\n const actualArgs = methodCalls.map((c) => JSON.stringify(c.args)).join(', ')\n throw new Error(\n `Expected ${realToken.toString()}.${method}() to be called with ${JSON.stringify(expectedArgs)}. ` +\n `Actual calls: [${actualArgs}]`,\n )\n }\n }\n\n /**\n * Asserts that a method was called a specific number of times.\n */\n expectCallCount(token: AnyToken, method: string, count: number): void {\n const realToken = this.resolveToken(token)\n const calls = this.methodCalls.get(realToken.id) || []\n const actualCount = calls.filter((c) => c.method === method).length\n\n if (actualCount !== count) {\n throw new Error(\n `Expected ${realToken.toString()}.${method}() to be called ${count} times, but was called ${actualCount} times`,\n )\n }\n }\n\n /**\n * Gets all recorded method calls for a service.\n */\n getMethodCalls(token: AnyToken): MethodCallRecord[] {\n const realToken = this.resolveToken(token)\n return this.methodCalls.get(realToken.id) || []\n }\n\n /**\n * Gets statistics about a service.\n */\n getServiceStats(token: AnyToken): MockServiceStats {\n const realToken = this.resolveToken(token)\n return {\n instanceCount: this.instanceCounts.get(realToken.id) || 0,\n methodCalls: this.methodCalls.get(realToken.id) || [],\n lifecycleEvents: this.lifecycleEvents.get(realToken.id) || [],\n }\n }\n\n /**\n * Clears all recorded method calls.\n */\n clearMethodCalls(): void {\n this.methodCalls.clear()\n }\n\n /**\n * Gets list of all registered provider token IDs.\n */\n getRegisteredTokenIds(): ReadonlySet<string> {\n return this.registeredTokenIds\n }\n\n /**\n * Gets list of all auto-mocked token IDs.\n */\n getAutoMockedTokenIds(): ReadonlySet<string> {\n return this.autoMockedTokenIds\n }\n\n // ============================================================================\n // INTERNAL HELPERS\n // ============================================================================\n\n private resolveToken(token: AnyToken): InjectionToken<any, any> {\n if (typeof token === 'function') {\n try {\n return getInjectableToken(token)\n } catch {\n // Class doesn't have @Injectable, create a token for it\n return InjectionToken.create(token)\n }\n }\n return token\n }\n\n private registerProvider<T>(provider: ProviderConfig<T>): void {\n const realToken = this.resolveToken(provider.token as AnyToken)\n this.registeredTokenIds.add(realToken.id)\n\n if (provider.useValue !== undefined) {\n this.registerValueBinding(realToken, provider.useValue)\n } else if (provider.useClass) {\n this.registerClassBinding(realToken, provider.useClass)\n } else if (provider.useFactory) {\n this.registerFactoryBinding(realToken, provider.useFactory)\n } else {\n // Just the token - register as itself\n if (typeof provider.token === 'function') {\n this.testRegistry.set(realToken, InjectableScope.Singleton, provider.token, InjectableType.Class)\n }\n }\n }\n\n private registerValueBinding<T>(token: InjectionToken<T, any>, value: T): void {\n const ValueHolder = class {\n static instance = value\n }\n\n this.testRegistry.set(token, InjectableScope.Singleton, ValueHolder, InjectableType.Class)\n\n const nameResolver = this.getNameResolver()\n const instanceName = nameResolver.generateInstanceName(\n token,\n undefined,\n undefined,\n InjectableScope.Singleton,\n )\n this.getStorage().storeInstance(instanceName, value)\n this.recordLifecycleEvent(token, 'created', instanceName)\n }\n\n private registerClassBinding<T>(token: InjectionToken<T, any>, cls: new (...args: any[]) => T): void {\n this.testRegistry.set(token, InjectableScope.Singleton, cls, InjectableType.Class)\n }\n\n private registerFactoryBinding<T>(token: InjectionToken<T, any>, factory: () => T | Promise<T>): void {\n const FactoryWrapper = class {\n static factory = factory\n async create(): Promise<T> {\n return await factory()\n }\n }\n\n this.testRegistry.set(token, InjectableScope.Singleton, FactoryWrapper, InjectableType.Factory)\n }\n\n private argsMatch(actual: unknown[], expected: unknown[]): boolean {\n if (actual.length !== expected.length) {\n return false\n }\n return actual.every((arg, index) => {\n const exp = expected[index]\n if (typeof exp === 'object' && exp !== null) {\n return JSON.stringify(arg) === JSON.stringify(exp)\n }\n return arg === exp\n })\n }\n}\n"],"mappings":"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"}
|
package/lib/testing/index.d.cts
CHANGED
|
@@ -1,65 +1,394 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { T as Registry, t as Container, tt as InjectionToken } from "../container-D-0Ho3qL.cjs";
|
|
2
2
|
|
|
3
|
-
//#region src/testing/
|
|
3
|
+
//#region src/testing/types.d.mts
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* Tracks method calls on a mocked service.
|
|
7
|
+
*/
|
|
8
|
+
interface MethodCallRecord {
|
|
9
|
+
method: string;
|
|
10
|
+
args: unknown[];
|
|
11
|
+
timestamp: number;
|
|
12
|
+
result?: unknown;
|
|
13
|
+
error?: Error;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Tracks lifecycle events for a service.
|
|
17
|
+
*/
|
|
18
|
+
interface LifecycleRecord {
|
|
19
|
+
event: 'created' | 'initialized' | 'destroyed';
|
|
20
|
+
timestamp: number;
|
|
21
|
+
instanceName: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Statistics about a mocked service.
|
|
25
|
+
*/
|
|
26
|
+
interface MockServiceStats {
|
|
27
|
+
instanceCount: number;
|
|
28
|
+
methodCalls: MethodCallRecord[];
|
|
29
|
+
lifecycleEvents: LifecycleRecord[];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* A node in the dependency graph.
|
|
33
|
+
*/
|
|
34
|
+
interface DependencyNode {
|
|
35
|
+
token: string;
|
|
36
|
+
instanceName: string;
|
|
37
|
+
scope: string;
|
|
38
|
+
dependencies: string[];
|
|
39
|
+
dependents: string[];
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Serializable dependency graph for snapshot testing.
|
|
43
|
+
*/
|
|
44
|
+
interface DependencyGraph {
|
|
45
|
+
nodes: Record<string, DependencyNode>;
|
|
46
|
+
rootTokens: string[];
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Binding configuration for TestContainer.
|
|
50
|
+
*/
|
|
51
|
+
interface BindingBuilder<T> {
|
|
52
|
+
/**
|
|
53
|
+
* Bind to a concrete value.
|
|
54
|
+
*/
|
|
55
|
+
toValue(value: T): void;
|
|
56
|
+
/**
|
|
57
|
+
* Bind to a class implementation.
|
|
58
|
+
*/
|
|
59
|
+
toClass<C extends new (...args: any[]) => T>(cls: C): void;
|
|
60
|
+
/**
|
|
61
|
+
* Bind to a factory function.
|
|
62
|
+
*/
|
|
63
|
+
toFactory(factory: () => T | Promise<T>): void;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Provider configuration for UnitTestContainer.
|
|
67
|
+
*/
|
|
68
|
+
interface ProviderConfig<T = any> {
|
|
69
|
+
token: InjectionToken<T, any> | (new (...args: any[]) => T);
|
|
70
|
+
useValue?: T;
|
|
71
|
+
useClass?: new (...args: any[]) => T;
|
|
72
|
+
useFactory?: () => T | Promise<T>;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Options for TestContainer.
|
|
76
|
+
*/
|
|
77
|
+
interface TestContainerOptions {
|
|
78
|
+
/**
|
|
79
|
+
* Parent registry. Defaults to globalRegistry.
|
|
80
|
+
* Pass `null` to create a completely isolated container.
|
|
81
|
+
*/
|
|
82
|
+
parentRegistry?: Registry | null;
|
|
83
|
+
/**
|
|
84
|
+
* Logger for debugging.
|
|
85
|
+
*/
|
|
86
|
+
logger?: Console | null;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Options for UnitTestContainer.
|
|
7
90
|
*/
|
|
8
|
-
|
|
9
|
-
private readonly container;
|
|
10
|
-
private readonly token;
|
|
11
|
-
constructor(container: TestContainer, token: InjectionToken<T, any>);
|
|
91
|
+
interface UnitTestContainerOptions {
|
|
12
92
|
/**
|
|
13
|
-
*
|
|
14
|
-
* This is useful for testing with mock values or constants.
|
|
15
|
-
* @param value The value to bind to the token
|
|
93
|
+
* List of providers to register. Only these services can be resolved.
|
|
16
94
|
*/
|
|
17
|
-
|
|
95
|
+
providers: ProviderConfig[];
|
|
18
96
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
97
|
+
* If true, unregistered dependencies will be auto-mocked instead of throwing.
|
|
98
|
+
* Default: false (throws on unregistered dependencies)
|
|
21
99
|
*/
|
|
22
|
-
|
|
100
|
+
allowUnregistered?: boolean;
|
|
101
|
+
/**
|
|
102
|
+
* Logger for debugging.
|
|
103
|
+
*/
|
|
104
|
+
logger?: Console | null;
|
|
23
105
|
}
|
|
106
|
+
//#endregion
|
|
107
|
+
//#region src/testing/test-container.d.mts
|
|
108
|
+
type AnyToken$1 = InjectionToken<any, any> | (new (...args: any[]) => any);
|
|
24
109
|
/**
|
|
25
|
-
* TestContainer extends
|
|
26
|
-
*
|
|
110
|
+
* TestContainer extends Container with testing utilities.
|
|
111
|
+
*
|
|
112
|
+
* Provides simple value/class binding for integration/e2e tests,
|
|
113
|
+
* plus assertion helpers and dependency graph inspection.
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```ts
|
|
117
|
+
* const container = new TestContainer()
|
|
118
|
+
*
|
|
119
|
+
* // Bind mock values
|
|
120
|
+
* container.bind(DatabaseToken).toValue(mockDatabase)
|
|
121
|
+
* container.bind(UserService).toClass(MockUserService)
|
|
122
|
+
*
|
|
123
|
+
* // Use container normally
|
|
124
|
+
* const service = await container.get(MyService)
|
|
125
|
+
*
|
|
126
|
+
* // Assert on container state
|
|
127
|
+
* container.expectResolved(MyService)
|
|
128
|
+
* container.expectSingleton(MyService)
|
|
129
|
+
* ```
|
|
27
130
|
*/
|
|
28
131
|
declare class TestContainer extends Container {
|
|
29
|
-
|
|
132
|
+
private readonly testRegistry;
|
|
133
|
+
private readonly methodCalls;
|
|
134
|
+
private readonly lifecycleEvents;
|
|
135
|
+
private readonly instanceCounts;
|
|
136
|
+
private readonly boundTokens;
|
|
137
|
+
/**
|
|
138
|
+
* Creates a new TestContainer.
|
|
139
|
+
*
|
|
140
|
+
* @param options - Configuration options
|
|
141
|
+
* @param options.parentRegistry - Parent registry. Defaults to globalRegistry.
|
|
142
|
+
* Pass `null` for a completely isolated container.
|
|
143
|
+
* @param options.logger - Optional logger for debugging.
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```ts
|
|
147
|
+
* // Uses globalRegistry as parent (default)
|
|
148
|
+
* const container = new TestContainer()
|
|
149
|
+
*
|
|
150
|
+
* // Isolated container (no access to @Injectable classes)
|
|
151
|
+
* const isolated = new TestContainer({ parentRegistry: null })
|
|
152
|
+
*
|
|
153
|
+
* // Custom parent registry
|
|
154
|
+
* const custom = new TestContainer({ parentRegistry: myRegistry })
|
|
155
|
+
* ```
|
|
156
|
+
*/
|
|
157
|
+
constructor(options?: TestContainerOptions);
|
|
30
158
|
/**
|
|
31
159
|
* Creates a binding builder for the given token.
|
|
32
|
-
*
|
|
33
|
-
* @
|
|
34
|
-
*
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* ```ts
|
|
163
|
+
* container.bind(UserService).toValue(mockUserService)
|
|
164
|
+
* container.bind(DatabaseToken).toClass(MockDatabase)
|
|
165
|
+
* container.bind(ConfigToken).toFactory(() => ({ apiKey: 'test' }))
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
bind<T>(token: InjectionToken<T, any> | (new (...args: any[]) => T)): BindingBuilder<T>;
|
|
169
|
+
/**
|
|
170
|
+
* Clears all bindings and resets container state.
|
|
171
|
+
*/
|
|
172
|
+
clear(): Promise<void>;
|
|
173
|
+
/**
|
|
174
|
+
* Asserts that a service has been resolved at least once.
|
|
175
|
+
*/
|
|
176
|
+
expectResolved(token: AnyToken$1): void;
|
|
177
|
+
/**
|
|
178
|
+
* Asserts that a service has NOT been resolved.
|
|
179
|
+
*/
|
|
180
|
+
expectNotResolved(token: AnyToken$1): void;
|
|
181
|
+
/**
|
|
182
|
+
* Asserts that a service is registered as singleton scope.
|
|
183
|
+
*/
|
|
184
|
+
expectSingleton(token: AnyToken$1): void;
|
|
185
|
+
/**
|
|
186
|
+
* Asserts that a service is registered as transient scope.
|
|
187
|
+
*/
|
|
188
|
+
expectTransient(token: AnyToken$1): void;
|
|
189
|
+
/**
|
|
190
|
+
* Asserts that a service is registered as request scope.
|
|
191
|
+
*/
|
|
192
|
+
expectRequestScoped(token: AnyToken$1): void;
|
|
193
|
+
/**
|
|
194
|
+
* Asserts that two service resolutions return the same instance.
|
|
195
|
+
*/
|
|
196
|
+
expectSameInstance(token: AnyToken$1): Promise<void>;
|
|
197
|
+
/**
|
|
198
|
+
* Asserts that two service resolutions return different instances.
|
|
199
|
+
*/
|
|
200
|
+
expectDifferentInstances(token: AnyToken$1): Promise<void>;
|
|
201
|
+
/**
|
|
202
|
+
* Asserts that a service's onServiceInit was called.
|
|
203
|
+
*/
|
|
204
|
+
expectInitialized(token: AnyToken$1): void;
|
|
205
|
+
/**
|
|
206
|
+
* Asserts that a service's onServiceDestroy was called.
|
|
207
|
+
*/
|
|
208
|
+
expectDestroyed(token: AnyToken$1): void;
|
|
209
|
+
/**
|
|
210
|
+
* Asserts that a service has NOT been destroyed.
|
|
211
|
+
*/
|
|
212
|
+
expectNotDestroyed(token: AnyToken$1): void;
|
|
213
|
+
/**
|
|
214
|
+
* Records a method call for tracking.
|
|
215
|
+
* Call this from your mock implementations.
|
|
216
|
+
*/
|
|
217
|
+
recordMethodCall(token: AnyToken$1, method: string, args: unknown[], result?: unknown, error?: Error): void;
|
|
218
|
+
/**
|
|
219
|
+
* Records a lifecycle event for tracking.
|
|
220
|
+
*/
|
|
221
|
+
recordLifecycleEvent(token: AnyToken$1, event: 'created' | 'initialized' | 'destroyed', instanceName: string): void;
|
|
222
|
+
/**
|
|
223
|
+
* Asserts that a method was called on a service.
|
|
224
|
+
*/
|
|
225
|
+
expectCalled(token: AnyToken$1, method: string): void;
|
|
226
|
+
/**
|
|
227
|
+
* Asserts that a method was called with specific arguments.
|
|
228
|
+
*/
|
|
229
|
+
expectCalledWith(token: AnyToken$1, method: string, expectedArgs: unknown[]): void;
|
|
230
|
+
/**
|
|
231
|
+
* Asserts that a method was called a specific number of times.
|
|
232
|
+
*/
|
|
233
|
+
expectCallCount(token: AnyToken$1, method: string, count: number): void;
|
|
234
|
+
/**
|
|
235
|
+
* Gets all recorded method calls for a service.
|
|
236
|
+
*/
|
|
237
|
+
getMethodCalls(token: AnyToken$1): MethodCallRecord[];
|
|
238
|
+
/**
|
|
239
|
+
* Gets statistics about a mocked service.
|
|
240
|
+
*/
|
|
241
|
+
getServiceStats(token: AnyToken$1): MockServiceStats;
|
|
242
|
+
/**
|
|
243
|
+
* Clears all recorded method calls.
|
|
244
|
+
*/
|
|
245
|
+
clearMethodCalls(): void;
|
|
246
|
+
/**
|
|
247
|
+
* Gets the dependency graph for snapshot testing.
|
|
248
|
+
* Returns a serializable structure that can be used with vitest snapshots.
|
|
249
|
+
*/
|
|
250
|
+
getDependencyGraph(): DependencyGraph;
|
|
251
|
+
/**
|
|
252
|
+
* Gets a simplified dependency graph showing only token relationships.
|
|
253
|
+
* Useful for cleaner snapshot comparisons.
|
|
254
|
+
*/
|
|
255
|
+
getSimplifiedDependencyGraph(): Record<string, string[]>;
|
|
256
|
+
private resolveToken;
|
|
257
|
+
private registerValueBinding;
|
|
258
|
+
private registerClassBinding;
|
|
259
|
+
private registerFactoryBinding;
|
|
260
|
+
private argsMatch;
|
|
261
|
+
}
|
|
262
|
+
//#endregion
|
|
263
|
+
//#region src/testing/unit-test-container.d.mts
|
|
264
|
+
type AnyToken = InjectionToken<any, any> | (new (...args: any[]) => any);
|
|
265
|
+
/**
|
|
266
|
+
* UnitTestContainer for isolated unit testing.
|
|
267
|
+
*
|
|
268
|
+
* Only services explicitly listed in `providers` can be resolved.
|
|
269
|
+
* All method calls are automatically tracked via proxies.
|
|
270
|
+
* Unregistered dependencies throw by default, or can be auto-mocked.
|
|
271
|
+
*
|
|
272
|
+
* @example
|
|
273
|
+
* ```ts
|
|
274
|
+
* const container = new UnitTestContainer({
|
|
275
|
+
* providers: [
|
|
276
|
+
* { token: UserService, useClass: MockUserService },
|
|
277
|
+
* { token: ConfigToken, useValue: { apiUrl: 'test' } },
|
|
278
|
+
* ],
|
|
279
|
+
* })
|
|
280
|
+
*
|
|
281
|
+
* const service = await container.get(UserService)
|
|
282
|
+
*
|
|
283
|
+
* // All method calls are automatically tracked
|
|
284
|
+
* await service.findUser('123')
|
|
285
|
+
*
|
|
286
|
+
* container.expectCalled(UserService, 'findUser')
|
|
287
|
+
* container.expectCalledWith(UserService, 'findUser', ['123'])
|
|
288
|
+
* ```
|
|
289
|
+
*/
|
|
290
|
+
declare class UnitTestContainer extends Container {
|
|
291
|
+
private readonly testRegistry;
|
|
292
|
+
private readonly methodCalls;
|
|
293
|
+
private readonly lifecycleEvents;
|
|
294
|
+
private readonly instanceCounts;
|
|
295
|
+
private readonly registeredTokenIds;
|
|
296
|
+
private readonly autoMockedTokenIds;
|
|
297
|
+
private allowUnregistered;
|
|
298
|
+
constructor(options: UnitTestContainerOptions);
|
|
299
|
+
/**
|
|
300
|
+
* Enables auto-mocking for unregistered dependencies.
|
|
301
|
+
* Call this to switch from strict mode to auto-mock mode.
|
|
302
|
+
*/
|
|
303
|
+
enableAutoMocking(): this;
|
|
304
|
+
/**
|
|
305
|
+
* Disables auto-mocking (strict mode).
|
|
306
|
+
* Unregistered dependencies will throw.
|
|
307
|
+
*/
|
|
308
|
+
disableAutoMocking(): this;
|
|
309
|
+
/**
|
|
310
|
+
* Override get to wrap instances in tracking proxies.
|
|
311
|
+
*/
|
|
312
|
+
get(token: any, args?: unknown): Promise<any>;
|
|
313
|
+
/**
|
|
314
|
+
* Clears all state and disposes the container.
|
|
315
|
+
*/
|
|
316
|
+
clear(): Promise<void>;
|
|
317
|
+
/**
|
|
318
|
+
* Asserts that a service has been resolved at least once.
|
|
319
|
+
*/
|
|
320
|
+
expectResolved(token: AnyToken): void;
|
|
321
|
+
/**
|
|
322
|
+
* Asserts that a service has NOT been resolved.
|
|
323
|
+
*/
|
|
324
|
+
expectNotResolved(token: AnyToken): void;
|
|
325
|
+
/**
|
|
326
|
+
* Asserts that a service was auto-mocked (not in providers list).
|
|
327
|
+
*/
|
|
328
|
+
expectAutoMocked(token: AnyToken): void;
|
|
329
|
+
/**
|
|
330
|
+
* Asserts that a service was NOT auto-mocked (is in providers list).
|
|
331
|
+
*/
|
|
332
|
+
expectNotAutoMocked(token: AnyToken): void;
|
|
333
|
+
/**
|
|
334
|
+
* Records a lifecycle event for tracking.
|
|
335
|
+
*/
|
|
336
|
+
recordLifecycleEvent(token: AnyToken, event: 'created' | 'initialized' | 'destroyed', instanceName: string): void;
|
|
337
|
+
/**
|
|
338
|
+
* Asserts that a service's onServiceInit was called.
|
|
339
|
+
*/
|
|
340
|
+
expectInitialized(token: AnyToken): void;
|
|
341
|
+
/**
|
|
342
|
+
* Asserts that a service's onServiceDestroy was called.
|
|
343
|
+
*/
|
|
344
|
+
expectDestroyed(token: AnyToken): void;
|
|
345
|
+
/**
|
|
346
|
+
* Asserts that a service has NOT been destroyed.
|
|
347
|
+
*/
|
|
348
|
+
expectNotDestroyed(token: AnyToken): void;
|
|
349
|
+
/**
|
|
350
|
+
* Asserts that a method was called on a service.
|
|
351
|
+
*/
|
|
352
|
+
expectCalled(token: AnyToken, method: string): void;
|
|
353
|
+
/**
|
|
354
|
+
* Asserts that a method was NOT called on a service.
|
|
355
|
+
*/
|
|
356
|
+
expectNotCalled(token: AnyToken, method: string): void;
|
|
357
|
+
/**
|
|
358
|
+
* Asserts that a method was called with specific arguments.
|
|
359
|
+
*/
|
|
360
|
+
expectCalledWith(token: AnyToken, method: string, expectedArgs: unknown[]): void;
|
|
361
|
+
/**
|
|
362
|
+
* Asserts that a method was called a specific number of times.
|
|
363
|
+
*/
|
|
364
|
+
expectCallCount(token: AnyToken, method: string, count: number): void;
|
|
365
|
+
/**
|
|
366
|
+
* Gets all recorded method calls for a service.
|
|
367
|
+
*/
|
|
368
|
+
getMethodCalls(token: AnyToken): MethodCallRecord[];
|
|
369
|
+
/**
|
|
370
|
+
* Gets statistics about a service.
|
|
35
371
|
*/
|
|
36
|
-
|
|
37
|
-
bind<T>(token: InjectionToken<T, any>): TestBindingBuilder<T>;
|
|
372
|
+
getServiceStats(token: AnyToken): MockServiceStats;
|
|
38
373
|
/**
|
|
39
|
-
*
|
|
40
|
-
* This is a convenience method equivalent to bind(token).toValue(value).
|
|
41
|
-
* @param token The injection token to bind
|
|
42
|
-
* @param value The value to bind to the token
|
|
43
|
-
* @returns The TestContainer instance for chaining
|
|
374
|
+
* Clears all recorded method calls.
|
|
44
375
|
*/
|
|
45
|
-
|
|
46
|
-
bindValue<T>(token: InjectionToken<T, any>, value: T): TestContainer;
|
|
376
|
+
clearMethodCalls(): void;
|
|
47
377
|
/**
|
|
48
|
-
*
|
|
49
|
-
* This is a convenience method equivalent to bind(token).toClass(target).
|
|
50
|
-
* @param token The injection token to bind
|
|
51
|
-
* @param target The class constructor to bind to
|
|
52
|
-
* @returns The TestContainer instance for chaining
|
|
378
|
+
* Gets list of all registered provider token IDs.
|
|
53
379
|
*/
|
|
54
|
-
|
|
55
|
-
bindClass<T>(token: InjectionToken<T, any>, target: ClassType): TestContainer;
|
|
380
|
+
getRegisteredTokenIds(): ReadonlySet<string>;
|
|
56
381
|
/**
|
|
57
|
-
*
|
|
58
|
-
* This is useful for creating isolated test containers.
|
|
59
|
-
* @returns A new TestContainer instance
|
|
382
|
+
* Gets list of all auto-mocked token IDs.
|
|
60
383
|
*/
|
|
61
|
-
|
|
384
|
+
getAutoMockedTokenIds(): ReadonlySet<string>;
|
|
385
|
+
private resolveToken;
|
|
386
|
+
private registerProvider;
|
|
387
|
+
private registerValueBinding;
|
|
388
|
+
private registerClassBinding;
|
|
389
|
+
private registerFactoryBinding;
|
|
390
|
+
private argsMatch;
|
|
62
391
|
}
|
|
63
392
|
//#endregion
|
|
64
|
-
export {
|
|
393
|
+
export { BindingBuilder, DependencyGraph, DependencyNode, LifecycleRecord, MethodCallRecord, MockServiceStats, ProviderConfig, TestContainer, TestContainerOptions, UnitTestContainer, UnitTestContainerOptions };
|
|
65
394
|
//# sourceMappingURL=index.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/testing/test-container.mts"],"sourcesContent":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/testing/types.mts","../../src/testing/test-container.mts","../../src/testing/unit-test-container.mts"],"sourcesContent":[],"mappings":"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"}
|