【问题标题】:Come up with Better Module Pattern for Node/ES6 Module为 Node/ES6 模块提出更好的模块模式
【发布时间】:2017-06-16 19:41:18
【问题描述】:

我正在努力想出一个既能满足我的测试又能满足 Travis 运行我的脚本能力的模式。

我首先要说我让 Travis 运行我的脚本的方式是我在我的 travis.yml 中指定要通过 node-babel 命令运行的脚本,如下所示:

script:
  - babel-node ./src/client/deploy/deploy-feature-branch.js

这意味着当 babel-node 运行它时,我需要一个在我拥有的 deploy-feature-branch.js 中自动运行的方法。那是let { failure, success, payload } = deployFeatureBranch() 的行。这强制 deployFeatureBranch() 运行,因为它设置为解构命令。

在那里我还有一个options 对象:

let options = {
  localBuildFolder: 'build',
  domain: 'ourdomain',
  branch: process.env.TRAVIS_PULL_REQUEST_BRANCH
}

在 PR 构建期间,travis 自动设置 process.env.TRAVIS_PULL_REQUEST_BRANCH 的值。那太棒了!但是,我设置此模块的方式对于测试来说效果不佳。我遇到的问题是,如果我尝试从测试中设置选项,由于某种原因未设置选项对象

我想我首先要解决的问题是,为什么当我尝试从测试中设置选项时没有设置选项。那么有没有更好的方法来整体设计这个模块。

测试

import {options, deployFeatureBranch } from '../../../client/deploy/deploy-feature-branch'

    it.only('creates a S3 test environment for a pull request', async () => {
      options.branch = 'feature-100'
      options.domain = 'ourdomain'
      options.localDeployFolder = 'build'

      const result = await deployFeatureBranch()
      expect(result.success).to.be.true
    })
})

deployFeatureBranch()在我的测试上面运行时,执行 试图引用options.branch,但它最终是undefined,即使我将它设置为'feature-100'。分支默认为 process.env.TRAVIS_PULL_REQUEST_BRANCH 但我希望能够覆盖它并从测试中设置它。

deploy-feature-branch.js

import * as deployApi from './deployApi'

let options = {
  localBuildFolder: 'build',
  domain: 'ourdomain',
  branch: process.env.TRAVIS_PULL_REQUEST_BRANCH
}

const deployFeatureBranch = async (options) => {
    console.log(green(`Deploying feature branch: ${options.branch}`))
    let { failure, success, payload } = await deployApi.run(options)
    return { failure, success, payload }
}

let { failure, success, payload } = deployFeatureBranch(options)

export {
  options,
  deployFeatureBranch
}

我真的想不出更好的方法来构建它并解决设置选项问题。我也不限于使用节点模块,我也可以使用 ES6 导出。

【问题讨论】:

    标签: javascript node.js ecmascript-6


    【解决方案1】:

    不要导出 options 并对其进行修改,只需在测试中调用函数时传入新的 options 对象即可:

    import {deployFeatureBranch } from '../../../client/deploy/deploy-feature-branch'
    
        it.only('creates a S3 test environment for a pull request', async () => {
          const options = {
            branch: 'feature-100',
            domain: 'ourdomain',
            localDeployFolder: 'build'
          };
    
          const result = await deployFeatureBranch(options)
          expect(result.success).to.be.true
        })
    });
    

    它不起作用的原因是因为您的 deployFeatureBranch() 函数期望在您调用它时传入 options,而您没有这样做。

    此外,导出和更改对象虽然可能有效,但也很奇怪,应该避免。创建一个新对象(或克隆导出的对象)绝对是要走的路。

    【讨论】:

    • 我知道,但我想执行合同。我只想允许某些字段
    • 我以为我正在向它传递选项:const deployFeatureBranch = async (options)
    • async (options) => {} 只是声明了一个函数,该函数接受一个您在该函数内部调用的参数 options。你解构的那一行是你实际调用函数并传递你的选项的那一行。此外,导出和修改对象并不是真正执行合同。你可以很容易地说option.crazyCookieMonsters,它会工作得很好。但实际上,没有理由明确禁止其他参数。在 99.9% 的情况下,它不会造成任何伤害。
    • 至于克隆,您不应该修改导出,因为它可能会导致不可靠的事情发生。这是该导出的唯一版本,并且对于导入它的所有内容都会进行更改。如果您需要修改该对象,一个更好的解决方案是先克隆它,然后修改克隆。这只是一个很好的做法,可以避免奇怪且难以跟踪的错误。
    • 如果你真的想强制执行合同,而不是接受选项:async (options) => {},在参数进入时解构它们并只用这些参数构建一个新对象。然后任何额外的东西都会被扔掉:async ({ a, b, c}) => { myFunc({ a, b, c}); }
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-23
    • 1970-01-01
    • 2020-11-08
    • 1970-01-01
    相关资源
    最近更新 更多