2017-11-15 15 views
0

新しい質問を作成しています。この問題に対処するための質問は見つかりませんでした。Babel - クラスをインスタンス化する前に装飾されたクラスプロパティのデコレータが呼び出されました

私はmochaと実験的なes6 +デコレータをバベルを使って蒸散して私の依存性注入をテストするのが難しいです。クラスプロパティデコレータは呼び出される前に呼び出されています。 intededとして

injection.test.js(--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')); 
     }) 
    }); 
}); 

テストを実行して、装飾されたクラスは、形質転換されます。ただし、DependantのインスタンスのsampleServiceプロパティは、2番目のテストで作成され、未定義です。

デコレータは、クラスのインスタンスが作成されると呼び出されるべきですが、デコレータは、クラスが定義され、そのプロパティが装飾されるときに呼び出されます。 TypeScriptを使用すると、予期された動作が維持されます。

以下に、(簡略化された)デコレータと私のバベルの構成を示します。

.babelrc(class propertyをターゲット)

{ 
    "presets": [ 
     "env", 
     "stage-0", 
     "es2017" 
    ], 
    "plugins": [ 
     "syntax-decorators", 
     "transform-decorators-legacy", 
     ["transform-runtime", { 
      "polyfill": false, 
      "regenerator": true 
     }] 
    ] 
} 

エクスポートデコレータを注入:私はまだ見つかっていない

exports.Injectable = (predicate) => { 
    return function (target) { 
     const provider = target; 
     provider.injectable = true; 
     if (predicate && typeof predicate === 'function') { 
      provider.predicate = predicate; 
     } 
    }; 
}; 

答えて

0

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をターゲット)クラスの新しいインスタンスを作成する主な原因クラスプロパティを装飾するときはです。しかし、私は自分の問題を解決する方法を見つけました。 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) 
関連する問題