krispy
Version:
Basic synchronous dependency injector
159 lines • 7.11 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const chai_1 = require("chai");
const Injector_1 = __importDefault(require("../lib/Injector"));
const UnresolvableDependencyException_1 = __importDefault(require("../lib/exception/UnresolvableDependencyException"));
const CannotRegisterDependencyException_1 = __importDefault(require("../lib/exception/CannotRegisterDependencyException"));
const UnexpectedStateException_1 = __importDefault(require("../lib/exception/UnexpectedStateException"));
const InjectorUtil_1 = __importDefault(require("../lib/util/InjectorUtil"));
function getInjectorData(injector) {
return injector['_items'];
}
describe('InjectorUtil', function () {
describe('isInheritedFrom', function () {
it('returns false when the classes are not descended from one another', function () {
class ClassA {
}
class ClassB {
}
chai_1.expect(InjectorUtil_1.default.isInheritedFrom(ClassA, ClassB)).to.be.false;
});
it('returns true when the inherited class is a direct descendant', function () {
class Base {
}
class Inherited extends Base {
}
chai_1.expect(InjectorUtil_1.default.isInheritedFrom(Base, Inherited)).to.be.true;
});
it('returns true when the inherited class is a second-level descendant', function () {
class BaseA {
}
class BaseB extends BaseA {
}
class Inherited extends BaseB {
}
chai_1.expect(InjectorUtil_1.default.isInheritedFrom(BaseB, Inherited)).to.be.true;
chai_1.expect(InjectorUtil_1.default.isInheritedFrom(BaseA, Inherited)).to.be.true;
});
it('returns false when the prototype of the inherited is null', function () {
class Base {
}
class Inherited extends Base {
}
Reflect.setPrototypeOf(Inherited, null);
chai_1.expect(InjectorUtil_1.default.isInheritedFrom(Base, Inherited)).to.be.false;
});
});
});
describe('Injector', function () {
let injector;
beforeEach(function () {
injector = new Injector_1.default();
});
describe('global', function () {
it('does not instantiate global upon module loading', function () {
chai_1.expect(Injector_1.default['_globalInjector'] == null, 'global injector was instantiated already').to.be.true;
});
it('returns an instance of the Injector upon first call', function () {
chai_1.expect(Injector_1.default.global).to.be.an.instanceOf(Injector_1.default);
});
it('always returns the same global instance', function () {
chai_1.expect(Injector_1.default.global).to.equal(Injector_1.default.global);
});
});
describe('add', function () {
it('adds to data when registering dependency', function () {
class Base {
}
class Sub extends Base {
}
injector.addSingleton(Base, Sub);
const injectorData = getInjectorData(injector);
chai_1.expect(injectorData.has(Base), 'Injector data did not add dependency to data').to.be.true;
});
it('throws CannotRegisterDependencyException when subclass does not inherit from base class', function () {
class Base {
}
class Sub {
}
chai_1.expect(() => injector.addSingleton(Base, Sub)).to.throw(CannotRegisterDependencyException_1.default);
});
});
describe('resolve', function () {
it('Successfully resolves a registered instance', function () {
class Base {
}
class Sub extends Base {
}
injector.addSingleton(Base, Sub);
const sub = injector.resolve(Base);
chai_1.expect(sub).to.be.an.instanceOf(Base);
chai_1.expect(sub).to.be.an.instanceOf(Sub);
});
it('Only constructs singletons once', function () {
class Base {
}
let constructCount = 0;
class Singleton extends Base {
constructor() {
super();
constructCount++;
}
}
injector.addSingleton(Base, Singleton);
for (let i = 0; i < 5; ++i) {
const instance = injector.resolve(Base);
chai_1.expect(instance).to.be.an.instanceOf(Base);
chai_1.expect(instance).to.be.an.instanceOf(Singleton);
}
chai_1.expect(constructCount).to.equal(1);
});
it('Constructs transient every single time', function () {
class Base {
}
let constructCount = 0;
class Transient extends Base {
constructor() {
super();
constructCount++;
}
}
injector.addTransient(Base, Transient);
const resolveCount = 5;
for (let i = 0; i < resolveCount; ++i) {
const instance = injector.resolve(Base);
chai_1.expect(instance).to.be.an.instanceOf(Base);
chai_1.expect(instance).to.be.an.instanceOf(Transient);
}
chai_1.expect(constructCount).to.equal(resolveCount);
});
it('throws UnresolvableDependencyException when dependency is not registered', function () {
class Base {
}
chai_1.expect(() => injector.resolve(Base)).to.throw(UnresolvableDependencyException_1.default);
});
it('throws UnresolvableDependencyInjection when dependency data is null', function () {
class Base {
}
const injectorData = getInjectorData(injector);
// @ts-ignore - We know null is not a valid type to be setting, but this is the test
injectorData.set(Base, null);
chai_1.expect(() => injector.resolve(Base)).to.throw(UnresolvableDependencyException_1.default);
});
it('throws UnexpectedStateException when the injector type is unknown', function () {
class Base {
}
class Sub extends Base {
}
injector.addSingleton(Base, Sub);
const injectorData = getInjectorData(injector);
// @ts-ignore - Don't care if it can be null, other tests should have checked for that
injectorData.get(Base).type = -1;
chai_1.expect(() => injector.resolve(Base)).to.throw(UnexpectedStateException_1.default);
});
});
});
//# sourceMappingURL=injector.test.js.map