Oclif 提示测试

问题描述 投票:0回答:2

我正在尝试为包含简单提示的 Oclif 挂钩编写单元测试。我想测试钩子的输出,对提示给出“Y”或“N”响应。

import {Hook} from '@oclif/config'
import cli from 'cli-ux'

const hook: Hook<'init'> = async function () {

  const answer = await cli.prompt("Y or N?")

  if(answer === 'Y') {
    this.log('yes')
  }
  else {
    this.log('no')
  }
}

export default hook

我正在使用此处描述的“fancy-test”和“@oclif/test”测试框架: https://oclif.io/docs/testing

我尝试过对提示进行存根并模拟标准输入,但都不起作用 - 要么存根函数不可用,要么输出是空字符串。

这是一次测试尝试(不起作用,因为“cli.prompt 不是函数”):

import {expect, test} from '@oclif/test'
import cli from 'cli-ux'
import * as sinon from 'sinon';

describe('it should test the "configure telemetry" hook', () => {
  test
  .stub(cli, 'prompt', sinon.stub().resolves('Y'))
  .stdout()
  .hook('init')
  .do(output => expect(output.stdout).to.contain('yes'))
  .it()
})

我突然意识到我可能没有正确构建我的测试。如果有人能给我指出正确的方向或提供一些伪/示例代码来说明如何测试上述钩子,那就太棒了 - 谢谢!

node.js unit-testing command-line-interface prompt oclif
2个回答
9
投票

您尝试过:

import {expect, test} from '@oclif/test'
import cli from 'cli-ux'
import * as sinon from 'sinon';

describe('it should test the "configure telemetry" hook', () => {
  test
  .stub(cli, 'prompt', () => async () => 'Y')
  .stdout()
  .hook('init')
  .do(output => expect(output.stdout).to.contain('yes'))
  .it()
})

.stub(cli, 'prompt', () => async () => 'Y')
进行存根对我有用


0
投票

我找到了一种方法来测试对

ux.prompt
的多次调用,除了默认的
@oclif/core
(实际上是
fancy-test
的扩展)之外不需要额外的库:

假设我们有一个单命令 cli

Hello
,那么我们的
src/index.ts
文件将如下所示:

import {Command, Flags, ux} from '@oclif/core'

export default class Hello extends Command {
  static description = 'describe the command here'

  static examples = [
    `$ myplugin hello
hello world from ./src/hello.ts!
`,
  ]

  static flags = {
    help: Flags.help({char: 'h'}),
    // add --version flag to show CLI version
    version: Flags.version({char: 'v'}),
  }

  interactive = async () => {
    const object = {
      email: '',
      name: '',
      phone: '',
    }

    const name = await ux.prompt('What is your name?')
    const email = await ux.prompt('What is your email?')
    const phone = await ux.prompt('What is your phone number?')

    object.name = name
    object.email = email
    object.phone = phone

    return object
  }

  async run(): Promise<void> {
    const object = await this.interactive()

    console.log(`Hello ${object.name}!`)
    console.log(`Your email is ${object.email}`)
    console.log(`Your phone number is ${object.phone}`)
  }
}

我们的

test/index.test.tes
文件将如下所示:


import {ux} from '@oclif/core'
import {expect, test} from '@oclif/test'

import Hello from '../src/index'

const promptStub = (stub) => {
  stub.onFirstCall().resolves('John Doe') // Alias for stub.onCall(0).resolves('John Doe')
  stub.onSecondCall().resolves('[email protected]') // Alias for stub.onCall(1).resolves('[email protected]') 
  stub.onThirdCall().resolves('123-456-7890') // Alias for stub.onCall(2).resolves('123-456-7890')
  return stub
}

describe('basic usage', () => {
  test
    .stdout({print: true})
    .stub(ux, 'prompt', promptStub)
    .do(() => Hello.run([]))
    .it('runs hello', (ctx) => {
      expect(ctx.stdout).to.contain('Hello John Doe!')
      expect(ctx.stdout).to.contain('Your email is [email protected]')
      expect(ctx.stdout).to.contain('Your phone number is 123-456-7890')
    })
})


我们需要了解

stub
Sinon.JS 库的一部分,并且我们可以在
stub
测试中使用一些
oclif
功能。如果我们使用 TypeScript,数据类型尤其重要。

此外,要测试多命令 cli,只需将

.do(() => Hello.run([]))
替换为常规
.command()
调用即可。

© www.soinside.com 2019 - 2024. All rights reserved.