通用读取多个构造函数调用的参数

时间:2016-12-13 21:27:39

标签: javascript unit-testing arguments

Read arguments from constructor call的后续问题:

接受的解决方案允许我通过定义一个捕获和公开参数的包装类来获取传递给构造函数的参数,但是这给我留下了n构造函数的n包装器的问题。

有没有办法让1个函数/包装器/任何可以用于任意数量的构造函数的东西?

我将重申,我正在专门研究这种技术来测试Webpack plugin configuration,并且我想避免为每个需要测试的插件使用单独的包装器。

寻找符合

的内容
// ------------------------------------------------------------ a wrapper function?

const someWrapper = () => { /* ... */ }

const plugin1 = new Plugin({ a: 'value' })
const plugin2 = new Plugin2(arg1, arg2, { b: 'anotherValue '})

someWrapper(plugin1).args === [{ a: 'value' }]
someWrapper(plugin2).args === [arg1, arg2, { b: 'anotherValue' }]

// --------------------------------------------------------------- a wrapper class?

class Wrapper { /* ... */ }

const plugin1 = new Wrapper(Plugin, [{ a: 'value' }])
const plugin2 = new Wrapper(Plugin2, [arg1, arg2, { b: 'anotherValue '}])

plugin1.args === [{ a: 'value' }]
plugin2.args === [arg1, arg2, { b: 'anotherValue '}]

// problem with above is the wrapper is being passed to Webpack, not the underlying
// plugin; not sure yet if this would cause webpack to break or not actually
// execute the plugin as intended with a vanilla config

// ---------------------------------------------------------------- something else?

3 个答案:

答案 0 :(得分:2)

是的,您可以创建通用包装器,它将args属性添加到任何传递的构造函数的实例中:

class Plugin {
  constructor (arg1, arg2) {
    this.arg1 = arg1
    this.arg2 = arg2    
  }
}

function wrapper(initial) {
  // Rewrite initial constructor with our function
  return function decoratedContructor(...args) {
    // Create instance of initial object
    const decorated = new initial(...args)

    // Add some additional properties, methods
    decorated.args = [...args]

    // Return instantiated and modified object
    return decorated
  }
}

const decoratedPlugin = wrapper(Plugin)
const plugin = new decoratedPlugin('argument', { 'argument2': 1 })
console.log(plugin.args)

仅供参考:添加没有前缀的属性是不安全的。考虑将__或类似的内容添加到您的属性中,因为您可能会意外地重写某些内部对象属性。

答案 1 :(得分:2)

我能够通过修改@ guest271314的建议来解决这个问题,即你需要将...initArgs传递给super(),否则webpack会因TypeError: Cannot read property '...' of undefined而失败}。

还考虑了@ terales关于确保为我的附加属性添加前缀的观点。

const exposeConstructorArgs = (Plugin, ...args) => {
  const ExposedPlugin = class extends Plugin {
    constructor(...initArgs) {
      super(...initArgs);

      this.__initArgs__ = initArgs;
    }

    get __initArgs() {
      return this.__initArgs__;
    }
  };

  return Reflect.construct(ExposedPlugin, args);
};

// ...

const dllPlugin = exposeConstructorArgs(webpack.DllPlugin, {
  name: '[name]',
  path: path.join(buildDir, '[name].json'),
});

// ...

const pluginConfig = dllPlugin.__initArgs[0];

expect(pluginConfig.name).toEqual('[name]');

答案 2 :(得分:1)

您可以使用函数体中使用class expression的通用函数。将实例中classconstructor和参数预期为arguments的参考传递给函数调用。

function Plugin() {}

function Plugin2() {}

function PluginWrapper(pluginRef, ...args) {
  let MyPlugin = class extends pluginRef {
    constructor() {
      super();
      this.args = [...arguments];
    }
    getArgs() {
      return this.args;
    }
  }
  return Reflect.construct(MyPlugin, args);
};

const anInstance = PluginWrapper(Plugin, {
  a: 'path'
});

console.log(anInstance.getArgs(), anInstance instanceof Plugin);

const aSecondInstance = PluginWrapper(Plugin2, "arg1", "arg2", {
  b: 'anotherPath'
});

console.log(aSecondInstance.getArgs(), aSecondInstance instanceof Plugin2);