test helpers for oclif CLIs
@oclif/test
is an extension of fancy-test. Please see the fancy-test documentation for all the features that are available.
The following are the features that @oclif/test
adds to fancy-test
.
.loadConfig()
creates and returns a new Config
instance. This instance will be available on the ctx
variable that's provided in the callback.
import {join} from 'node:path'
import {expect, test} from '@oclif/test'
const root = join(__dirname, 'fixtures/test-cli')
test
.loadConfig({root})
.stdout()
.command(['foo:bar'])
.it('should run the command from the given directory', (ctx) => {
expect(ctx.stdout).to.equal('hello world!\n')
expect(ctx.config.root).to.equal(root)
const {name} = ctx.returned as {name: string}
expect(name).to.equal('world')
})
If you would like to run the same test without using @oclif/test
:
import {Config, ux} from '@oclif/core'
import {expect} from 'chai'
import {join} from 'node:path'
import {SinonSandbox, SinonStub, createSandbox} from 'sinon'
const root = join(__dirname, 'fixtures/test-cli')
describe('non-fancy test', () => {
let sandbox: SinonSandbox
let config: Config
let stdoutStub: SinonStub
beforeEach(async () => {
sandbox = createSandbox()
stdoutStub = sandbox.stub(ux.write, 'stdout')
config = await Config.load({root})
})
afterEach(async () => {
sandbox.restore()
})
it('should run command from the given directory', async () => {
const {name} = await config.runCommand<{name: string}>('foo:bar')
expect(stdoutStub.calledWith('hello world!\n')).to.be.true
expect(config.root).to.equal(root)
expect(name).to.equal('world')
})
})
.command()
let's you run a command from your CLI.
import {expect, test} from '@oclif/test'
describe('hello world', () => {
test
.stdout()
.command(['hello:world'])
.it('runs hello world cmd', (ctx) => {
expect(ctx.stdout).to.contain('hello world!')
})
})
For a single command cli you would provide '.'
as the command. For instance:
import {expect, test} from '@oclif/test'
describe('hello world', () => {
test
.stdout()
.command(['.'])
.it('runs hello world cmd', (ctx) => {
expect(ctx.stdout).to.contain('hello world!')
})
})
If you would like to run the same test without using @oclif/test
:
import {Config, ux} from '@oclif/core'
import {expect} from 'chai'
import {SinonSandbox, SinonStub, createSandbox} from 'sinon'
describe('non-fancy test', () => {
let sandbox: SinonSandbox
let config: Config
let stdoutStub: SinonStub
beforeEach(async () => {
sandbox = createSandbox()
stdoutStub = sandbox.stub(ux.write, 'stdout')
config = await Config.load({root: process.cwd()})
})
afterEach(async () => {
sandbox.restore()
})
it('should run command', async () => {
// use '.' for a single command CLI
const {name} = await config.runCommand<{name: string}>('hello:world')
expect(stdoutStub.calledWith('hello world!\n')).to.be.true
expect(name).to.equal('world')
})
})
.exit()
let's you test that a command exited with a certain exit code.
import {join} from 'node:path'
import {expect, test} from '@oclif/test'
describe('exit', () => {
test
.loadConfig()
.stdout()
.command(['hello:world', '--code=101'])
.exit(101)
.do((output) => expect(output.stdout).to.equal('exiting with code 101\n'))
.it('should exit with code 101')
})
If you would like to run the same test without using @oclif/test
:
import {Config, Errors, ux} from '@oclif/core'
import {expect} from 'chai'
import {SinonSandbox, createSandbox} from 'sinon'
describe('non-fancy test', () => {
let sandbox: SinonSandbox
let config: Config
beforeEach(async () => {
sandbox = createSandbox()
sandbox.stub(ux.write, 'stdout')
config = await Config.load({root: process.cwd()})
})
afterEach(async () => {
sandbox.restore()
})
it('should run command from the given directory', async () => {
try {
await config.runCommand('.')
throw new Error('Expected CLIError to be thrown')
} catch (error) {
if (error instanceof Errors.CLIError) {
expect(error.oclif.exit).to.equal(101)
} else {
throw error
}
}
})
})
.hook()
let's you test a hook in your CLI.
import {join} from 'node:path'
import {expect, test} from '@oclif/test'
const root = join(__dirname, 'fixtures/test-cli')
describe('hooks', () => {
test
.loadConfig({root})
.stdout()
.hook('foo', {argv: ['arg']}, {root})
.do((output) => expect(output.stdout).to.equal('foo hook args: arg\n'))
.it('should run hook')
})
If you would like to run the same test without using @oclif/test
:
import {Config, ux} from '@oclif/core'
import {expect} from 'chai'
import {SinonSandbox, SinonStub, createSandbox} from 'sinon'
describe('non-fancy test', () => {
let sandbox: SinonSandbox
let config: Config
let stdoutStub: SinonStub
beforeEach(async () => {
sandbox = createSandbox()
stdoutStub = sandbox.stub(ux.write, 'stdout')
config = await Config.load({root: process.cwd()})
})
afterEach(async () => {
sandbox.restore()
})
it('should run hook', async () => {
const {name} = await config.runHook('foo', {argv: ['arg']})
expect(stdoutStub.calledWith('foo hook args: arg\n')).to.be.true
})
})