UNPKG

@e22m4u/js-service

Version:

Реализация принципа инверсии управления для JavaScript

227 lines (208 loc) 8.71 kB
/* eslint-disable chai-expect/no-inner-literal */ import {expect} from 'chai'; import {Service} from './service.js'; import {format} from '@e22m4u/js-format'; import {Debuggable} from '@e22m4u/js-debug'; import {ServiceContainer} from './service-container.js'; import {DebuggableService} from './debuggable-service.js'; describe('DebuggableService', function () { it('should have the static property "kinds" extended from the base class', function () { expect(DebuggableService.kinds).to.be.eql(Service.kinds); }); describe('constructor', function () { it('should require the first parameter to be a correct value', function () { const throwable = v => () => { new DebuggableService(v); }; const error = s => format( 'First parameter must be an Object or an instance ' + 'of ServiceContainer, but %s was given.', s, ); expect(throwable('str')).to.throw(error('"str"')); expect(throwable('')).to.throw(error('""')); expect(throwable(10)).to.throw(error('10')); expect(throwable(0)).to.throw(error('0')); expect(throwable(true)).to.throw(error('true')); expect(throwable(false)).to.throw(error('false')); expect(throwable([])).to.throw(error('Array')); expect(throwable(null)).to.throw(error('null')); throwable(new ServiceContainer())(); throwable({})(); throwable(undefined)(); }); it('should require the second parameter to be an Object', function () { const throwable = v => () => { new DebuggableService(undefined, v); }; const error = s => format('Second parameter must be an Object, but %s was given.', s); expect(throwable('str')).to.throw(error('"str"')); expect(throwable('')).to.throw(error('""')); expect(throwable(10)).to.throw(error('10')); expect(throwable(0)).to.throw(error('0')); expect(throwable(true)).to.throw(error('true')); expect(throwable(false)).to.throw(error('false')); expect(throwable([])).to.throw(error('Array')); expect(throwable(null)).to.throw(error('null')); throwable({})(); throwable(undefined)(); }); it('should instantiate properly without arguments', function () { const debuggableService = new DebuggableService(); expect(debuggableService).to.be.an.instanceOf(DebuggableService); expect(debuggableService).to.be.an.instanceOf(Debuggable); expect(debuggableService.container).to.be.an.instanceOf(ServiceContainer); }); it('should use a provided ServiceContainer instance', function () { const container = new ServiceContainer(); const debuggableService = new DebuggableService(container); expect(debuggableService.container).to.be.eq(container); }); it('should pass options from the first parameter to the base constructor', function () { const options = {namespace: 'myNamespace'}; const debuggableService = new DebuggableService(options); expect(debuggableService.debug.state.nsSegments).to.be.eql([ 'myNamespace', 'debuggableService', ]); }); it('should pass options from the second parameter to the base constructor', function () { const options = {namespace: 'myNamespace'}; const debuggableService = new DebuggableService(undefined, options); expect(debuggableService.debug.state.nsSegments).to.be.eql([ 'myNamespace', 'debuggableService', ]); }); it('should not register the current instance in the internal container', function () { const service = new DebuggableService(); expect(service.container.has(DebuggableService)).to.be.false; }); describe('for an extended classes', function () { it('should register the current instance in the service container', function () { class ServiceA extends DebuggableService {} class ServiceB extends DebuggableService {} const serviceA = new ServiceA(); expect(serviceA.container.has(ServiceA)).to.be.true; expect(serviceA.container.has(ServiceB)).to.be.false; }); it('should register the current instance even when the options is provided to the first argument', function () { class ServiceA extends DebuggableService {} class ServiceB extends DebuggableService {} const serviceA = new ServiceA({namespace: 'app'}); expect(serviceA.container.has(ServiceA)).to.be.true; expect(serviceA.container.has(ServiceB)).to.be.false; }); it('should not register the current instance in a custom container', function () { class ServiceA extends DebuggableService {} class ServiceB extends DebuggableService {} const container = new ServiceContainer(); const serviceA = new ServiceA(container); expect(serviceA).to.be.instanceOf(DebuggableService); expect(container.has(ServiceA)).to.be.false; expect(container.has(ServiceB)).to.be.false; }); }); }); describe('service method delegation', function () { it('should delegate the "container" getter to the container of an internal service', function () { const S = new DebuggableService(); expect(S.container).to.be.eq(S._service.container); }); it('should delegate the "getService" method to the internal service', function () { const S = new DebuggableService(); const methodName = 'getService'; const result = 'OK'; const testArgs = [1, 2, 3, 4, 5]; let invoked = false; S._service[methodName] = function (...args) { expect(args).to.be.eql(testArgs); expect(this).to.be.eq(S._service); invoked = true; return result; }; const res = S[methodName](...testArgs); expect(res).to.be.eq(result); expect(invoked).to.be.true; }); it('should delegate the "getRegisteredService" method to the internal service', function () { const S = new DebuggableService(); const methodName = 'getRegisteredService'; const result = 'OK'; const testArgs = [1, 2, 3, 4, 5]; let invoked = false; S._service[methodName] = function (...args) { expect(args).to.be.eql(testArgs); expect(this).to.be.eq(S._service); invoked = true; return result; }; const res = S[methodName](...testArgs); expect(res).to.be.eq(result); expect(invoked).to.be.true; }); it('should delegate the "hasService" method to the internal service', function () { const S = new DebuggableService(); const methodName = 'hasService'; const result = 'OK'; const testArgs = [1]; let invoked = false; S._service[methodName] = function (...args) { expect(args).to.be.eql(testArgs); expect(this).to.be.eq(S._service); invoked = true; return result; }; const res = S[methodName](...testArgs); expect(res).to.be.eq(result); expect(invoked).to.be.true; }); it('should delegate the "addService" method to the internal service', function () { const S = new DebuggableService(); const methodName = 'addService'; const testArgs = [1, 2, 3, 4, 5]; let invoked = false; S._service[methodName] = function (...args) { expect(args).to.be.eql(testArgs); expect(this).to.be.eq(S._service); invoked = true; return 'OK'; }; const res = S[methodName](...testArgs); expect(res).to.be.eq(S); expect(invoked).to.be.true; }); it('should delegate the "useService" method to the internal service', function () { const S = new DebuggableService(); const methodName = 'useService'; const testArgs = [1, 2, 3, 4, 5]; let invoked = false; S._service[methodName] = function (...args) { expect(args).to.be.eql(testArgs); expect(this).to.be.eq(S._service); invoked = true; return 'OK'; }; const res = S[methodName](...testArgs); expect(res).to.be.eq(S); expect(invoked).to.be.true; }); it('should delegate the "setService" method to the internal service', function () { const S = new DebuggableService(); const methodName = 'setService'; const testArgs = [1, 2]; let invoked = false; S._service[methodName] = function (...args) { expect(args).to.be.eql(testArgs); expect(this).to.be.eq(S._service); invoked = true; return 'OK'; }; const res = S[methodName](...testArgs); expect(res).to.be.eq(S); expect(invoked).to.be.true; }); }); });