对不起创建一个新问题,我无法找到解决此问题的问题。
我在使用mocha测试我的依赖注入时遇到了困难,而使用babel编译的实验性es6 +装饰器也是如此。类属性装饰器在它应该被调用之前被调用。
injection.test.js(mocha test,使用--require babel-register
)
import * as DependencyInjection from '../build/decorators/DependencyInjection';
@DependencyInjection.Injectable(service => service.injected = true)
class SampleService {
property = 'default';
constructor(property, ...data) {
this.property = property || this.property;
}
}
class Dependant {
/** @type {SampleService} */
@DependencyInjection.Inject(SampleService)
sampleService;
}
describe('dependency injection', () => {
describe('is decoratored as injectable', () => {
it('should be injectable', done => done(SampleService.injectable ? void 0 : new Error('Injectable is not set')));
it('should contain a predicate', done => done(SampleService.predicate ? void 0 : new Error('Predicate is not set')));
});
describe('inject injectable', () => {
it ('should inject the injectable provider', done => {
const dependant = new Dependant();
done(!!dependant.sampleService ? void 0 : new Error('Injectable provider was not injected'));
})
});
});
运行测试时,装饰类将按照有意的方式进行转换。但是,在第二个测试中创建的sampleService
实例的Dependant
属性未定义。
一旦创建了一个类的实例,就应该调用/调用有问题的装饰器,但是在定义类并且对属性进行装饰时会调用装饰器。使用TypeScript
时会保持预期的行为。
下面我列出了(简化的)装饰者和我的babel配置。
.babelrc
{
"presets": [
"env",
"stage-0",
"es2017"
],
"plugins": [
"syntax-decorators",
"transform-decorators-legacy",
["transform-runtime", {
"polyfill": false,
"regenerator": true
}]
]
}
导出的装饰器注入(定位class property
):
exports.Inject = (typeFunction, ...data) => {
return function (target, propertyName) {
try {
const injected = target[propertyName] = new typeFunction(data);
if ('predicate' in typeFunction && typeof typeFunction.predicate === 'function') {
typeFunction.predicate(injected);
}
}
catch (err) {
throw new Error(err.message || err);
}
};
};
导出装饰器可注入(定位class
):
exports.Injectable = (predicate) => {
return function (target) {
const provider = target;
provider.injectable = true;
if (predicate && typeof predicate === 'function') {
provider.predicate = predicate;
}
};
};
答案 0 :(得分:0)
我仍然没有找到导致在装饰类属性时创建类的新实例的主要原因。但是,我找到了解决问题的有效方法。在mocha中,使用--require babel-register
和遗留装饰器插件,类属性装饰器使用PropertyDescriptor
。将简化的Inject
装饰器更改为以下解决了我没有实例化我的装饰类属性的问题。
exports.Inject = (typeFunction, ...data) => {
return function (target, propertyName, descriptor) {
let value = null;
try {
const injected = value = target[propertyName] = new typeFunction(...data);
if ('predicate' in typeFunction && typeof typeFunction.predicate === 'function') {
typeFunction.predicate(injected);
}
}
catch (err) {
throw new Error(err.message || err);
}
if (descriptor) {
delete descriptor.initializer;
delete descriptor.writable;
descriptor.value = value;
}
};
};
删除writable
属性是必要的。
以下测试......
const assert = require('assert');
const chai = require('chai');
import * as DependencyInjection from '../build/decorators/DependencyInjection';
@DependencyInjection.Injectable(service => service.injected = true)
class SampleService {
property = 'default';
constructor(property, ...data) {
this.property = property || this.property;
}
}
class Dependant {
/** @type {SampleService} */
@DependencyInjection.Inject(SampleService)
sampleService;
}
class Dependant2 {
/** @type {SampleService} */
@DependencyInjection.Inject(SampleService, 'overloaded')
sampleService;
}
describe('dependency injection', () => {
describe('is decoratored as injectable', () => {
it('should be injectable', done => done(SampleService.injectable ? void 0 : new Error('Injectable is not set')));
it('should contain a predicate', done => done(SampleService.predicate ? void 0 : new Error('Predicate is not set')));
});
describe('inject at decorated class property', () => {
it('should inject the injectable provider at the decorated property', () => {
const dependant = new Dependant();
chai.expect(dependant.sampleService).to.be.instanceof(SampleService, 'Injectable provider was not injected');
chai.assert.isTrue(dependant.sampleService.injected, 'The predicate of the injectable service was not set');
chai.expect(dependant.sampleService.property).to.equal('default', 'The initial value of \'property\' was not \'default\'');
});
it('should inject the injectable provider with overloaded constructor arguments at the decorated property', () => {
const dependant = new Dependant2();
chai.expect(dependant.sampleService).to.be.instanceOf(SampleService, 'Injectable provider was not injected');
chai.assert.isTrue(dependant.sampleService.injected, 'The predicate of the injectable service was not set');
chai.expect(dependant.sampleService.property).to.equal('overloaded', 'The value of \'property\' was not overloaded');
});
});
describe('inject at manual target and property', () => {
it('should inject the injectable provider at the targeting value', () => {
const inject = DependencyInjection.Inject(SampleService);
const target = {};
let err = null;
try {
inject(target, 'service');
} catch (e) {
err = e;
}
chai.assert.isNull(err, 'Expected injection to pass');
chai.expect(target.service).to.be.instanceOf(SampleService, 'Injectable provider was not injected');
chai.assert.isTrue(target.service.injected, 'The predicate of the injectable service was not set');
chai.expect(target.service.property).to.equal('default', 'The initial value of \'property\' was not \'default\'');
});
it('should inject the injectable provider with overloaded constructor arguments at the targeting value', () => {
const inject = DependencyInjection.Inject(SampleService, 'overloaded');
const target = {};
let err = null;
try {
inject(target, 'service');
} catch (e) {
err = e;
}
chai.assert.isNull(err, 'Expected injection to pass');
chai.expect(target.service).to.be.instanceOf(SampleService, 'Injectable provider was not injected');
chai.assert.isTrue(target.service.injected, 'The predicate of the injectable service was not set');
chai.expect(target.service.property).to.equal('overloaded', 'The value of \'property\' was not overloaded');
});
it('should not inject anything at the targeting value', () => {
const inject = DependencyInjection.Inject();
const target = {};
let err = null;
try {
inject(target, 'service');
} catch (e) {
err = e;
}
chai.expect(err).to.be.instanceof(Error);
chai.assert.notExists(target.service);
});
});
});
...输出以下结果:
dependency injection
is decoratored as injectable
√ should be injectable
√ should contain a predicate
inject at decorated class property
√ should inject the injectable provider at the decorated property
√ should inject the injectable provider with overloaded constructor arguments at the decorated property
inject at manual target and property
√ should inject the injectable provider at the targeting value
√ should inject the injectable provider with overloaded constructor arguments at the targeting value
√ should not inject anything at the targeting value
7 passing (29ms)