units
Version:
Module-like system with two-step initialization
462 lines (387 loc) • 8.23 kB
JavaScript
;
const test = require('ava');
const Units = require('./index');
test('checks if unit is empty', t => {
const units = new Units();
t.true(units.isEmpty());
});
test('fails to add undefined unit', t => {
const units = new Units();
try {
units.add({ unit: undefined });
t.fail();
} catch (e) {
t.pass();
}
units.init();
});
test('creates a simple unit and adds it to root unit set', t => {
class Unit {
init({ unit }) {
t.is(unit, this);
}
}
const units = new Units();
units.add({ unit: new Unit() });
units.init();
});
test('creates units from object with different types of data', t => {
class Unit {
init({ 'test.deep.unit': unit }) {
t.is(unit, this);
}
}
const units = new Units({
test: {
string: 'string',
number: 123,
boolean: false,
array: [ 1, 2, 3 ],
deep: {
unit: new Unit()
}
}
});
units.init();
t.is(units.require('test.string'), 'string');
t.is(units.require('test.number'), 123);
t.is(units.require('test.boolean'), false);
t.deepEqual(units.require('test.array'), [ 1, 2, 3 ]);
});
test('expose object', t => {
const units = new Units();
const testObject = { test: 'test' };
units.expose(testObject);
units.init();
t.is(units.get(), testObject);
});
test('extends undefined object', t => {
const units = new Units();
const testObject = { test: 'test' };
units.extend(testObject);
units.init();
t.is(units.get(), testObject);
});
test('extends defined object', t => {
const units = new Units();
const testObject = { test: 'test' };
units.expose(testObject);
const extendObject = { extend: 'extend' };
units.extend(extendObject);
units.init();
const obj = units.get();
t.is(obj.test, 'test');
t.is(obj.extend, 'extend');
});
test('all units from single configuration object', t => {
class Unit {
init({ 'test.unit': unit }) {
t.is(unit, this);
}
}
const units = new Units();
units.add({
test: {
unit: new Unit()
},
expose: {
'@expose': true,
test1: 'test1'
}
});
units.add({
expose: {
'@extend': true,
test2: 'test2'
}
});
units.init();
const obj = units.require('expose');
t.is(obj.test1, 'test1');
t.is(obj.test2, 'test2');
});
test('fails require undefined unit', t => {
const units = new Units();
try {
units.require('test');
t.fail();
} catch (e) {
t.pass();
}
});
test('gets optional method', t => {
class Unit {
init({ 'notexists?': unit }) {
t.is(unit, undefined);
}
}
const units = new Units({
test: new Unit()
});
units.init();
});
test('adds and require \'@\' unit and checks "instance" method', t => {
class Unit {
init({ 'test': unit }) {
t.is(unit, 'test');
}
instance() {
return 'test'
}
}
const units = new Units({
test: {
'@': new Unit()
}
});
units.init();
const res = units.require('test');
t.is(res, 'test');
});
test('adds and require \'@\' unit and checks "instance" property', t => {
class Unit {
constructor() {
this.instance = 'test'
}
init({ 'test': unit }) {
t.is(unit, 'test');
}
}
const units = new Units({
test: {
'@': new Unit()
}
});
units.init();
const res = units.require('test');
t.is(res, 'test');
});
test('adds a unit then adds another unit under the same namespace', t => {
class Unit1 {
constructor() {
this.name = 'unit 1';
}
init({ 'test.test1': unit }) {
t.is(unit, this);
}
}
class Unit2 {
constructor() {
this.name = 'unit 2';
}
init({ 'test.test2': unit }) {
t.is(unit, this);
}
}
const units = new Units({
test: {
test1: new Unit1()
}
});
units.add({ test: { 'test2': new Unit2() } });
units.init();
const res = units.require('test');
t.true(res instanceof Units);
t.truthy(res.get('test1'));
t.truthy(res.get('test2'));
});
test('extends object', t => {
const units = new Units();
units.add({
level1: {
level2: {
'@expose': true,
test1: 'test1'
}
}
});
units.add({
level1: {
level2: {
'@extend': true,
test2: 'test2'
}
}
});
const res = units.require('level1.level2');
t.is(res.test1, 'test1');
t.is(res.test2, 'test2');
});
test('tests match method', t => {
const units = new Units();
units.add({
level10: {
level21: {
level3: 'level3 string'
},
level22: 'level2 string'
},
level11: {
level2: true
}
});
units.match('(.*2$)', (unit, key) => {
if (key === 'level10.level22') {
t.is(unit, 'level2 string');
}
if (key === 'level11.level2') {
t.is(unit, true);
}
});
units.match(/3$/, unit => {
t.is(unit, 'level3 string');
});
});
test('tests forEach method', t => {
const units = new Units({
level10: {
level21: 'level2 string',
level22: 'level2 string'
},
level11: {
level23: true
}
});
t.plan(5)
units.forEach(() => t.pass());
});
test('inits unts two times', t => {
class Unit {
init() {
t.pass();
}
}
t.plan(1);
const units = new Units();
units.add('unit', new Unit());
units.init();
units.init();
});
test('requires initRequired unit', t => {
class Unit {
constructor() {
this.initRequired = true;
}
init() {
this.inited = true;
t.pass();
}
}
t.plan(2);
const units = new Units({
unit: new Unit()
});
t.is(units.require('unit').inited, true);
units.init();
});
test('joins two units', t => {
const units1 = new Units({ unit1: 1 });
const units2 = new Units({ unit2: 2 });
units1.join(units2);
t.is(units1.require('unit1'), 1);
t.is(units1.require('unit2'), 2);
});
test('fails to joins two units', t => {
const units1 = new Units({ unit: 1 });
const units2 = new Units({ unit: 2 });
try {
units1.join(units2);
t.fail();
} catch (e) {
t.is(e.message, 'Units duplicate key: unit')
}
});
test('adds units to units', t => {
const units1 = new Units();
const units2 = new Units();
units1.add({ units: units2 });
t.is(units1.require('units'), units2);
});
test('adds function that returns units declaration', t => {
const units = new Units();
units.add(() => ({
unit: () => ({
deep: 'level'
})
}));
t.is(units.require('unit.deep'), 'level');
});
test('checks has method', t => {
const units = new Units({
'@': 'self',
test1: 'test',
test2: false
});
t.true(units.has());
t.true(units.has('test1'));
t.true(units.has('test2'));
t.false(units.has('non'));
});
test('checks \'@\' unit with subunits', t => {
const units = new Units({
root: {
'@': 'self',
test: {
test1: 'test',
test2: false
}
}
});
t.true(units.has('root'));
t.true(units.has('root.test'));
t.true(units.has('root.test.test1'));
t.true(units.has('root.test.test2'));
});
test('adds a sub unit to init required unit with custom instance', t => {
class Unit {
constructor() {
this.initRequired = true;
}
init() {
this.inited = true;
t.pass();
}
instance() {
return { i: this.inited }
}
}
class SubUnit {
init({ test }) {
this.inited = test.i;
t.true(this.inited);
}
}
t.plan(3);
const units = new Units({ test: new Unit() });
units.add({ test: { sub: new SubUnit() } })
units.init();
const sub = units.require('test.sub');
t.true(sub.inited);
});
test('adds a unit and creates an alias for it', t => {
class Unit {
init() {
this.inited = true;
t.pass();
}
}
t.plan(4);
const units = new Units({ test: new Unit() });
try {
units.alias('alias', 'alias');
t.fail();
} catch (e) {
t.pass();
}
try {
units.alias('test', 'test');
t.fail();
} catch (e) {
t.pass();
}
units.alias('alias', 'test');
units.init();
const test = units.require('test');
const alias = units.require('alias');
t.is(test, alias);
});