CLI Testing Library
, despite taking clear inspiration from, does not re-export
anything from
DOM Testing Library
.
Likewise, while we've done our best to match the API names of
Testing Library's Core API, because of the
inherent differences between CLI apps and web apps, we're unable to match all of
them.
Know of a Testing Library Core API that you think would fit here that isn't present? Let us know!
Instead, the following API is what CLI Testing Library
provides the following.
function render(
command: string,
args: string[],
options?: {
/* You won't often use this, expand below for docs on options */
},
): RenderResult
Run the CLI application in a newly spawned process.
import {render} from 'cli-testing-library'
render('node', ['./path/to/script.js'])
import {render} from 'cli-testing-library'
test('renders a message', () => {
const {getByText} = render('node', ['./console-out.js'])
expect(getByText('Hello, world!')).toBeTruthy()
})
You won't often need to specify options, but if you ever do, here are the
available options which you could provide as a third argument to render
.
By default, CLI Testing Library
will run the new process in the working
directory of your project's root, as defined by your testing framework. If you
provide your own working directory via this option, it will change the execution
directory of your process.
For example: If you are end-to-end testing a file moving script, you don't want
to have to specify the absolute path every time. In this case, you can specify a
directory as the render cwd
.
const containingPath = path.resolve(__dirname, './movables')
const {getByText} = render('node', ['mover.js'], {
cwd: containingPath,
})
Oftentimes, you want to modify the behavior of the spawn environment. This may include things like changing the shell that's used to run scripts or more.
This argument allows you to configure the options that are passed to the
underlying
child_process.spawn
NodeJS API.
const {getByText} = render('script.ps1', {
spawnOpts: {
shell: 'powershell.exe',
},
})
The render
method returns an object that has a few properties:
The most important feature of render is that the queries from CLI Testing Library are automatically returned with their first argument bound to the testInstance.
See Queries to learn more about how to use these queries and the philosophy behind them.
getByText, queryByText, findByText
getByText(
// If you're using `screen`, then skip the container argument:
instance: TestInstance,
text: TextMatch,
options?: {
exact?: boolean = true,
trim?: boolean = false,
stripAnsi?: boolean = false,
collapseWhitespace?: boolean = false,
normalizer?: NormalizerFn,
suggest?: boolean,
}): TestInstance
Queries for test instance stdout
results with the given text (and it also
accepts a TextMatch).
These options are all standard for text matching. To learn more, see our Queries page.
userEvent[eventName](...eventProps)
While
userEvent
isn't usually returned onrender
in, say,React Testing Library
, we're able to do so because of our differences in implementation with upstream. See our Differences doc for more.
This object is the same as described with
userEvent
documentation with the key difference that
instance
is not expected to be passed when bound to render
.
This method is a shortcut for console.log(prettyCLI(instance)).
import {render} from 'cli-testing-library'
const {debug} = render('command')
debug()
// Hello, world! How are you?
//
// you can also pass an instance: debug(getByText('message'))
// and you can pass all the same arguments to debug as you can
// to prettyCLI:
// const maxLengthToPrint = 10000
// debug(getByText('message'), maxLengthToPrint)
This is a simple wrapper around prettyCLI
which is also exposed and comes from
CLI Testing Library.
This method allows you to check if the spawned process has exit, and if so, what exit code it closed with.
const instance = render('command')
await waitFor(() => expect(instance.hasExit()).toMatchObject({exitCode: 1}))
This method returns null
if still running, but {exitCode: number}
if it has
exit
The spawned process created by your rendered TestInstnace
. It's a
child_instance
. This is a
regularly spawned process,
so you can call process.pid
etc. to inspect the process.
Each of these is an array of what's output by their respective std
* pipe.
This is used internally to create the debug
methods and more.
They're defined as:
interface TestInstance {
stdoutArr: Array<{contents: Buffer | string; timestamp: number}>
stderrArr: Array<{contents: Buffer | string; timestamp: number}>
}
This method acts as the terminal clear
command might on most systems. It
allows you to clear out the buffers for stdoutArr
and stderrArr
- even in
the middle of processing - in order to do more narrowed queries.
SIGKILL
s processes that were spawned with render and have not halted by the
end of the test.
Please note that this is done automatically if the testing framework you're using supports the
afterEach
global and it is injected to your testing environment (like mocha, Jest, and Jasmine). If not, you will need to do manual cleanups after each test.
For example, if you're using the ava testing
framework, then you would need to use the test.afterEach
hook like so:
import {cleanup, render} from 'cli-testing-library'
import test from 'ava'
test.afterEach(cleanup)
test('renders into document', () => {
render('long-running-command')
// ...
})
// ... more tests ...
Failing to call cleanup when you've called render could result in Jest failing to close due to unclosed handles and tests which are not "idempotent" (which can lead to difficult to debug errors in your tests).