我正在尝试为包含简单提示的 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()
})
我突然意识到我可能没有正确构建我的测试。如果有人能给我指出正确的方向或提供一些伪/示例代码来说明如何测试上述钩子,那就太棒了 - 谢谢!
您尝试过:
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')
进行存根对我有用
我找到了一种方法来测试对
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()
调用即可。