import Injector from '../../src/injector' ; import { FastifyToken } from '../../src/symbols' ; import { Samurai , Ninja , Weapon , Katana , Shuriken , Naginata , Nunchaku , Tanto , Wakizashi , FastifyDecorated } from '../data/injectables' ; import type { FastifyInstance } from 'fastify' ; class BaseModel { } describe ( 'Injector' , ( ) => { let injector ; const fastifyInstance = { schema : { id : { type : 'number' } } , steel : 'real steel' , [ FastifyDecorated ] : 'FastifyDecoratedValue' , BaseModel } as any ; beforeEach ( ( ) => { injector = new Injector ( ) ; injector . registerInstance ( FastifyToken , fastifyInstance ) ; } ) ; it ( 'Should use singleton instances' , ( ) => { const samuraiFirst = injector . getInstance ( Samurai ) ; const samuraiSecond = injector . getInstance ( Samurai ) ; expect ( samuraiFirst ) . toBe ( samuraiSecond ) ; expect ( samuraiFirst . katana ) . toBe ( samuraiSecond . katana ) ; expect ( samuraiFirst . shuriken ) . toBe ( samuraiSecond . shuriken ) ; expect ( samuraiFirst . naginata ) . toBe ( samuraiSecond . naginata ) ; expect ( samuraiFirst . nunchaku ) . toBe ( samuraiSecond . nunchaku ) ; expect ( samuraiFirst . tanto ) . toBe ( samuraiSecond . tanto ) ; expect ( samuraiFirst . wakizashi ) . toBe ( samuraiSecond . wakizashi ) ; expect ( samuraiFirst . fastifyInstance ) . toBe ( samuraiSecond . fastifyInstance ) ; expect ( samuraiFirst . shuriken ) . toBe ( Samurai . shuriken ) ; expect ( samuraiFirst . shuriken ) . toBe ( Samurai . shuriken ) ; expect ( samuraiFirst . wakizashi ) . toBe ( Samurai . wakizashi ) ; expect ( samuraiFirst . wakizashi ) . toBe ( Samurai . wakizashi ) ; expect ( samuraiFirst . tanto ) . toBe ( Samurai . tanto ) ; expect ( samuraiFirst . tanto ) . toBe ( Samurai . tanto ) ; const katana = injector . getInstance ( Katana ) ; expect ( samuraiFirst . katana ) . toBe ( katana ) ; expect ( samuraiSecond . katana ) . toBe ( katana ) ; const shuriken = injector . getInstance ( Shuriken ) ; expect ( samuraiFirst . shuriken ) . toBe ( shuriken ) ; expect ( samuraiSecond . shuriken ) . toBe ( shuriken ) ; const naginata = injector . getInstance ( Naginata ) ; expect ( samuraiFirst . naginata ) . toBe ( naginata ) ; expect ( samuraiSecond . naginata ) . toBe ( naginata ) ; const nunchaku = injector . getInstance ( Nunchaku ) ; expect ( samuraiFirst . nunchaku ) . toBe ( nunchaku ) ; expect ( samuraiSecond . nunchaku ) . toBe ( nunchaku ) ; const tanto = injector . getInstance ( Tanto ) ; expect ( samuraiFirst . tanto ) . toBe ( tanto ) ; expect ( samuraiSecond . tanto ) . toBe ( tanto ) ; const wakizashi = injector . getInstance ( Wakizashi ) ; expect ( samuraiFirst . wakizashi ) . toBe ( wakizashi ) ; expect ( samuraiSecond . wakizashi ) . toBe ( wakizashi ) ; } ) ; describe ( 'Resolve instance by type' , ( ) => { it ( 'Should inject constructor parameter by type' , ( ) => { const samurai = injector . getInstance ( Samurai ) ; expect ( samurai . katana ) . toBeDefined ( ) ; expect ( samurai . katana . hit ) . toBeDefined ( ) ; const ninja = injector . getInstance ( Ninja ) ; expect ( ninja . katana ) . toBeDefined ( ) ; expect ( ninja . katana . hit ) . toBeDefined ( ) ; const weapon = injector . getInstance ( Weapon ) ; expect ( weapon . katana ) . toBeDefined ( ) ; expect ( weapon . katana . hit ) . toBeDefined ( ) ; } ) ; it ( 'Should inject class property by type' , ( ) => { const samurai = injector . getInstance ( Samurai ) ; expect ( samurai . shuriken ) . toBeDefined ( ) ; expect ( samurai . shuriken . cast ) . toBeDefined ( ) ; const ninja = injector . getInstance ( Ninja ) ; expect ( ninja . shuriken ) . toBeDefined ( ) ; expect ( ninja . shuriken . cast ) . toBeDefined ( ) ; const weapon = injector . getInstance ( Weapon ) ; expect ( weapon . shuriken ) . toBeDefined ( ) ; expect ( weapon . shuriken . cast ) . toBeDefined ( ) ; } ) ; it ( 'Should inject class static property by type' , ( ) => { injector . getInstance ( Samurai ) ; expect ( Samurai . shuriken ) . toBeDefined ( ) ; expect ( Samurai . shuriken . cast ) . toBeDefined ( ) ; injector . getInstance ( Ninja ) ; expect ( Ninja . shuriken ) . toBeDefined ( ) ; expect ( Ninja . shuriken . cast ) . toBeDefined ( ) ; injector . getInstance ( Weapon ) ; expect ( Weapon . shuriken ) . toBeDefined ( ) ; expect ( Weapon . shuriken . cast ) . toBeDefined ( ) ; } ) ; it ( 'Should ignore empty token if type is defined' , ( ) => { const samurai = injector . getInstance ( Samurai ) ; expect ( samurai . naginata ) . toBeDefined ( ) ; expect ( samurai . naginata . size ) . toBeDefined ( ) ; const ninja = injector . getInstance ( Ninja ) ; expect ( ninja . naginata ) . toBeDefined ( ) ; expect ( ninja . naginata . size ) . toBeDefined ( ) ; const weapon = injector . getInstance ( Weapon ) ; expect ( weapon . naginata ) . toBeDefined ( ) ; expect ( weapon . naginata . size ) . toBeDefined ( ) ; } ) ; } ) ; describe ( 'Resolve instance by token' , ( ) => { describe ( 'String token' , ( ) => { it ( 'Should inject constructor parameter by string token' , ( ) => { const samurai = injector . getInstance ( Samurai ) ; expect ( samurai . schema ) . toBeDefined ( ) ; expect ( samurai . schema ) . toEqual ( ( fastifyInstance as any ) . schema ) ; const ninja = injector . getInstance ( Ninja ) ; expect ( ninja . schema ) . toBeDefined ( ) ; expect ( ninja . schema ) . toEqual ( ( fastifyInstance as any ) . schema ) ; const weapon = injector . getInstance ( Weapon ) ; expect ( weapon . schema ) . toBeDefined ( ) ; expect ( weapon . schema ) . toEqual ( ( fastifyInstance as any ) . schema ) ; } ) ; it ( 'Should inject decorated value into class property by string token' , ( ) => { const samurai = injector . getInstance ( Samurai ) ; expect ( samurai . steel ) . toBeDefined ( ) ; expect ( samurai . steel ) . toBe ( 'real steel' ) ; const ninja = injector . getInstance ( Ninja ) ; expect ( ninja . steel ) . toBeDefined ( ) ; expect ( ninja . steel ) . toBe ( 'real steel' ) ; const weapon = injector . getInstance ( Weapon ) ; expect ( weapon . steel ) . toBeDefined ( ) ; expect ( weapon . steel ) . toBe ( 'real steel' ) ; } ) ; it ( 'Should inject decorated value into class static property by string token' , ( ) => { injector . getInstance ( Samurai ) ; expect ( Samurai . steel ) . toBeDefined ( ) ; expect ( Samurai . steel ) . toBe ( 'real steel' ) ; injector . getInstance ( Ninja ) ; expect ( Ninja . steel ) . toBeDefined ( ) ; expect ( Ninja . steel ) . toBe ( 'real steel' ) ; injector . getInstance ( Weapon ) ; expect ( Weapon . steel ) . toBeDefined ( ) ; expect ( Weapon . steel ) . toBe ( 'real steel' ) ; } ) ; it ( 'Should inject Service into class property by string token' , ( ) => { const samurai = injector . getInstance ( Samurai ) ; expect ( samurai . wakizashi ) . toBeDefined ( ) ; expect ( samurai . wakizashi . fight ) . toBeDefined ( ) ; const ninja = injector . getInstance ( Ninja ) ; expect ( ninja . wakizashi ) . toBeDefined ( ) ; expect ( ninja . wakizashi . fight ) . toBeDefined ( ) ; const weapon = injector . getInstance ( Weapon ) ; expect ( weapon . wakizashi ) . toBeDefined ( ) ; expect ( weapon . wakizashi . fight ) . toBeDefined ( ) ; } ) ; it ( 'Should inject Service into class static property by string token' , ( ) => { injector . getInstance ( Samurai ) ; expect ( Samurai . wakizashi ) . toBeDefined ( ) ; expect ( Samurai . wakizashi . fight ) . toBeDefined ( ) ; injector . getInstance ( Ninja ) ; expect ( Ninja . wakizashi ) . toBeDefined ( ) ; expect ( Ninja . wakizashi . fight ) . toBeDefined ( ) ; injector . getInstance ( Weapon ) ; expect ( Weapon . wakizashi ) . toBeDefined ( ) ; expect ( Weapon . wakizashi . fight ) . toBeDefined ( ) ; } ) ; } ) ; describe ( 'Symbol token' , ( ) => { it ( 'Should inject Fastify instance by token' , ( ) => { const samurai = injector . getInstance ( Samurai ) ; expect ( samurai . fastifyInstance ) . toBeDefined ( ) ; const ninja = injector . getInstance ( Ninja ) ; expect ( ninja . fastifyInstance ) . toBeDefined ( ) ; const weapon = injector . getInstance ( Weapon ) ; expect ( weapon . fastifyInstance ) . toBeDefined ( ) ; } ) ; it ( 'Should inject Fastify decorated symbol by token' , ( ) => { const samurai = injector . getInstance ( Samurai ) ; expect ( samurai . fastifyDecorated ) . toBe ( 'FastifyDecoratedValue' ) ; const ninja = injector . getInstance ( Ninja ) ; expect ( ninja . fastifyDecorated ) . toBe ( 'FastifyDecoratedValue' ) ; const weapon = injector . getInstance ( Weapon ) ; expect ( weapon . fastifyDecorated ) . toBe ( 'FastifyDecoratedValue' ) ; } ) ; it ( 'Should inject Service into class property by Symbol token' , ( ) => { const samurai = injector . getInstance ( Samurai ) ; expect ( samurai . tanto ) . toBeDefined ( ) ; expect ( samurai . tanto . use ) . toBeDefined ( ) ; const ninja = injector . getInstance ( Ninja ) ; expect ( ninja . tanto ) . toBeDefined ( ) ; expect ( ninja . tanto . use ) . toBeDefined ( ) ; const weapon = injector . getInstance ( Weapon ) ; expect ( weapon . tanto ) . toBeDefined ( ) ; expect ( weapon . tanto . use ) . toBeDefined ( ) ; } ) ; it ( 'Should inject Service into class static property by Symbol token' , ( ) => { injector . getInstance ( Samurai ) ; expect ( Samurai . tanto ) . toBeDefined ( ) ; expect ( Samurai . tanto . use ) . toBeDefined ( ) ; injector . getInstance ( Ninja ) ; expect ( Ninja . tanto ) . toBeDefined ( ) ; expect ( Ninja . tanto . use ) . toBeDefined ( ) ; injector . getInstance ( Weapon ) ; expect ( Weapon . tanto ) . toBeDefined ( ) ; expect ( Weapon . tanto . use ) . toBeDefined ( ) ; } ) ; it ( 'Should inject Service into constructor by Symbol token' , ( ) => { const samurai = injector . getInstance ( Samurai ) ; expect ( samurai . nunchaku ) . toBeDefined ( ) ; expect ( samurai . nunchaku . brandish ) . toBeDefined ( ) ; const ninja = injector . getInstance ( Ninja ) ; expect ( ninja . nunchaku ) . toBeDefined ( ) ; expect ( ninja . nunchaku . brandish ) . toBeDefined ( ) ; const weapon = injector . getInstance ( Weapon ) ; expect ( weapon . nunchaku ) . toBeDefined ( ) ; expect ( weapon . nunchaku . brandish ) . toBeDefined ( ) ; } ) ; } ) ; } ) ; describe ( 'Construct injected model' , ( ) => { it ( 'Should construct model from constructor parameter' , ( ) => { const samurai = injector . getInstance ( Samurai ) ; expect ( samurai . backpackModel ) . toBeDefined ( ) ; expect ( samurai . backpackModel ) . toBeInstanceOf ( BaseModel ) ; const ninja = injector . getInstance ( Ninja ) ; expect ( ninja . backpackModel ) . toBeDefined ( ) ; expect ( ninja . backpackModel ) . toBeInstanceOf ( BaseModel ) ; const weapon = injector . getInstance ( Weapon ) ; expect ( weapon . backpackModel ) . toBeDefined ( ) ; expect ( weapon . backpackModel ) . toBeInstanceOf ( BaseModel ) ; } ) ; it ( 'Should construct model from class property' , ( ) => { const samurai = injector . getInstance ( Samurai ) ; expect ( samurai . backpack ) . toBeDefined ( ) ; expect ( samurai . backpack ) . toBeInstanceOf ( BaseModel ) ; const ninja = injector . getInstance ( Ninja ) ; expect ( ninja . backpack ) . toBeDefined ( ) ; expect ( ninja . backpack ) . toBeInstanceOf ( BaseModel ) ; const weapon = injector . getInstance ( Weapon ) ; expect ( weapon . backpack ) . toBeDefined ( ) ; expect ( weapon . backpack ) . toBeInstanceOf ( BaseModel ) ; } ) ; it ( 'Should construct model from class static property' , ( ) => { injector . getInstance ( Samurai ) ; expect ( Samurai . backpack ) . toBeDefined ( ) ; expect ( Samurai . backpack ) . toBeInstanceOf ( BaseModel ) ; injector . getInstance ( Ninja ) ; expect ( Ninja . backpack ) . toBeDefined ( ) ; expect ( Ninja . backpack ) . toBeInstanceOf ( BaseModel ) ; injector . getInstance ( Weapon ) ; expect ( Weapon . backpack ) . toBeDefined ( ) ; expect ( Weapon . backpack ) . toBeInstanceOf ( BaseModel ) ; } ) ; it ( 'Should construct different instances of same Entity' , ( ) => { const samurai = injector . getInstance ( Samurai ) ; expect ( samurai . backpackModel ) . not . toBe ( samurai . backpack ) ; expect ( samurai . backpack ) . not . toBe ( Samurai . backpack ) ; const ninja = injector . getInstance ( Ninja ) ; expect ( ninja . backpackModel ) . not . toBe ( ninja . backpack ) ; expect ( ninja . backpack ) . not . toBe ( Ninja . backpack ) ; const weapon = injector . getInstance ( Weapon ) ; expect ( weapon . backpackModel ) . not . toBe ( weapon . backpack ) ; expect ( weapon . backpack ) . not . toBe ( Weapon . backpack ) ; expect ( samurai . backpackModel ) . not . toBe ( ninja . backpackModel ) ; expect ( ninja . backpackModel ) . not . toBe ( weapon . backpackModel ) ; expect ( samurai . backpack ) . not . toBe ( ninja . backpack ) ; expect ( ninja . backpack ) . not . toBe ( weapon . backpack ) ; expect ( Samurai . backpack ) . not . toBe ( Ninja . backpack ) ; expect ( Ninja . backpack ) . not . toBe ( Weapon . backpack ) ; } ) ; } ) ; } ) ;