Skip to content

Commit

Permalink
chore: update doctoc
Browse files Browse the repository at this point in the history
  • Loading branch information
crutchcorn committed Dec 13, 2021
1 parent eb7fc3c commit 9d6b311
Show file tree
Hide file tree
Showing 5 changed files with 217 additions and 145 deletions.
91 changes: 52 additions & 39 deletions docs/api.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,43 @@
# API

`CLI Testing Library`, despite taking clear inspiration from, does not re-export anything
from [`DOM Testing Library`](https://testing-library.com/docs/dom-testing-library/). Likewise,
while we've done our best to match the API names of [Testing Library's Core API](https://testing-library.com/docs/),
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!](https://github.com/crutchcorn/cli-testing-library/issues)
`CLI Testing Library`, despite taking clear inspiration from, does not re-export
anything from
[`DOM Testing Library`](https://testing-library.com/docs/dom-testing-library/).
Likewise, while we've done our best to match the API names of
[Testing Library's Core API](https://testing-library.com/docs/), 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!](https://github.com/crutchcorn/cli-testing-library/issues)
Instead, the following API is what `CLI Testing Library` provides the following.

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->


- [`render`](#render)
- [`render` Options](#render-options)
- [`cwd`](#cwd)
- [`spawnOpts`](#spawnopts)
- [`render` Result](#render-result)
- [`...queries`](#queries)
- [ByText](#bytext)
- [`fireEvent`](#fireevent)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

# `render`

```typescript
function render(
command: string,
args: string[],
options?: {
/* You won't often use this, expand below for docs on options */
},
): RenderResult;
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.
Expand All @@ -43,51 +48,53 @@ import {render} from 'cli-testing-library'
render('node', ['./path/to/script.js'])
```


```javascript
import {render} from 'cli-testing-library'
test('renders a message', () => {
const {getByText} = render('node', ['./console-out.js']);
expect(getByText('Hello, world!')).toBeTruthy();
});
const {getByText} = render('node', ['./console-out.js'])
expect(getByText('Hello, world!')).toBeTruthy()
})
```

# `render` Options

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`.
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`.

## `cwd`

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.
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`.
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`.

```javascript
const containingPath = path.resolve(__dirname, './movables');
const containingPath = path.resolve(__dirname, './movables')
const {getByText} = render('node', ['mover.js'], {
cwd: containingPath
cwd: containingPath,
})
```

## `spawnOpts`

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.
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
This argument allows you to configure the options that are passed to the
underlying
[`child_process.spawn` NodeJS API](https://nodejs.org/api/child_process.html#child_processspawncommand-args-options).

```javascript
const {getByText} = render('script.ps1', {
spawnOpts: {
shell: 'powershell.exe'
}
spawnOpts: {
shell: 'powershell.exe',
},
})
```

Expand All @@ -97,10 +104,12 @@ The `render` method returns an object that has a few properties:

## `...queries`

The most important feature of render is that the queries from [CLI Testing Library](https://github.com/crutchcorn/cli-testing-library)
are automatically returned with their first argument bound to the testInstance.
The most important feature of render is that the queries from
[CLI Testing Library](https://github.com/crutchcorn/cli-testing-library) are
automatically returned with their first argument bound to the testInstance.

See [Queries](./queries.md) to learn more about how to use these queries and the philosophy behind them.
See [Queries](./queries.md) to learn more about how to use these queries and the
philosophy behind them.

### ByText

Expand All @@ -121,15 +130,19 @@ getByText(
}): TestInstance
```

Queries for test instance `stdout` results with the given text (and it also accepts a TextMatch).
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](./queries.md).
These options are all standard for text matching. To learn more, see our
[Queries page](./queries.md).

## `fireEvent`

```javascript
fireEvent(instance: TestInstace, event: Event)
```

> While `fireEvent` isn't usually returned on `render` in, say, `React Testing Library`, we're able to do
> so because of our differences in implementation with upstream. See our [Differences](./differences.md) doc for more.
> While `fireEvent` isn't usually returned on `render` in, say,
> `React Testing Library`, we're able to do so because of our differences in
> implementation with upstream. See our [Differences](./differences.md) doc for
> more.
132 changes: 81 additions & 51 deletions docs/differences.md
Original file line number Diff line number Diff line change
@@ -1,118 +1,148 @@
# Differences Between `cli-testing-library` & Testing Library

While we clearly take inspiration from [`DOM Testing Library`](https://github.com/testing-library/dom-testing-library)
and [`React Testing Library`](https://github.com/testing-library/react-testing-library),
and try to do our best to align as much as possible, there are some major distinctions between
the project's APIs.
While we clearly take inspiration from
[`DOM Testing Library`](https://github.com/testing-library/dom-testing-library)
and
[`React Testing Library`](https://github.com/testing-library/react-testing-library),
and try to do our best to align as much as possible, there are some major
distinctions between the project's APIs.

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->


- [Instances](#instances)
- [Queries](#queries)
- [Events](#events)
- [FireEvent](#fireevent)
- [UserEvent](#userevent)
- [Matchers](#matchers)
- [Similarities](#similarities)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

# Instances

While the `DOM Testing Library` and it's descendants have a concept of both a `container` and `element`, `CLI Testing Library`
only has a single concept to replace them both: a `TestInstance`.
While the `DOM Testing Library` and it's descendants have a concept of both a
`container` and `element`, `CLI Testing Library` only has a single concept to
replace them both: a `TestInstance`.

This is because, while the DOM makes a clear distinction between different elements (say, [`HTMLBodyElement`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLBodyElement)
and [`HTMLDivElement`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement)), there is no such distinction between
processes in the CLI as far as I'm aware.
This is because, while the DOM makes a clear distinction between different
elements (say,
[`HTMLBodyElement`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLBodyElement)
and
[`HTMLDivElement`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement)),
there is no such distinction between processes in the CLI as far as I'm aware.

While this may change in the future (maybe `container` can be a sort of `TestProcess` of some kind), there are
While this may change in the future (maybe `container` can be a sort of
`TestProcess` of some kind), there are
[unanswered questions around what that API looks like and whether we can meaningfully handle the distinction](https://github.com/crutchcorn/cli-testing-library/issues/2).

# Queries

Similarly, `HTMLElement`s provide clean lines between user input items. Meanwhile, the CLI only has the concepts of `stdin`, `stdout`, and `stderr`.
It's unclear how matching a single line of `stdout` would help in a beneficial matter, much less how APIs like `fireEvent`
would utilize this seemingly extraneous metadata.
Similarly, `HTMLElement`s provide clean lines between user input items.
Meanwhile, the CLI only has the concepts of `stdin`, `stdout`, and `stderr`.
It's unclear how matching a single line of `stdout` would help in a beneficial
matter, much less how APIs like `fireEvent` would utilize this seemingly
extraneous metadata.

As a result, we don't have any `*AllBy` queries that `DOM Testing Library` does. All of our queries are non-plural (`*By`)
and will simply return either the test instance the query was called on, or `null` depending on the query.
As a result, we don't have any `*AllBy` queries that `DOM Testing Library` does.
All of our queries are non-plural (`*By`) and will simply return either the test
instance the query was called on, or `null` depending on the query.

While we would be happy to reconsider, there are once again
[lots of questions around what `*AllBy` queries would like and whether we can meaningfully use that concept](https://github.com/crutchcorn/cli-testing-library/issues/2).

# Events

Another area where we diverge from the DOM is in our event system (as implemented via `fireEvent` and `userEvent`).
Another area where we diverge from the DOM is in our event system (as
implemented via `fireEvent` and `userEvent`).

Despite our APIs' naming indicating an actual event system (complete with bubbling and more, like the DOM),
the CLI has no such concept.
Despite our APIs' naming indicating an actual event system (complete with
bubbling and more, like the DOM), the CLI has no such concept.

### FireEvent

This means that, while `fireEvent` in the `DOM Testing Library` has the ability to inherent from all
baked-into-browser events, we must hard-code a list of "events" and actions a user may take.
This means that, while `fireEvent` in the `DOM Testing Library` has the ability
to inherent from all baked-into-browser events, we must hard-code a list of
"events" and actions a user may take.

We try our best to implement ones that make sense:

- `fireEvent.write({value: str})` to write `str` into stdin
- `fireEvent.sigkill()` to send a [sigkill](https://en.wikipedia.org/wiki/Signal_(IPC)#SIGKILL) to the process
- `fireEvent.sigint()` to send a [sigint](https://en.wikipedia.org/wiki/Signal_(IPC)#SIGINT) to the process
- `fireEvent.sigkill()` to send a
[sigkill](<https://en.wikipedia.org/wiki/Signal_(IPC)#SIGKILL>) to the process
- `fireEvent.sigint()` to send a
[sigint](<https://en.wikipedia.org/wiki/Signal_(IPC)#SIGINT>) to the process

There is a missing API for that might make sense in `keypress`. It's unclear what this behavior would do that `write` wouldn't
be able to.
There is a missing API for that might make sense in `keypress`. It's unclear
what this behavior would do that `write` wouldn't be able to.

### UserEvent

There's also the API of `userEvent` that allows us to implement a fairly similar `keyboard` event
[to upstream](https://testing-library.com/docs/ecosystem-user-event/#keyboardtext-options). However, there are a few differences
here as well:

1) `userEvent` can be bound to the `render` output. This is due to limitations of not having a `screen` API. It's unclear how
this would work in practice, due to a lack of the `window` API.
2) `userEvent.keyboard` does not support modifier keys. It's only key-presses, no holding. This is because of API
differences that would require us to figure out a manual binding system for every single key using ANSI AFAIK.
3) Relatedly, we've remove the `{` syntax support, since there is no standard keybinding for the CLI, [like there is for the DOM](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code). Instead, we only support `[` and `]` syntax.
There's also the API of `userEvent` that allows us to implement a fairly similar
`keyboard` event
[to upstream](https://testing-library.com/docs/ecosystem-user-event/#keyboardtext-options).
However, there are a few differences here as well:

1. `userEvent` can be bound to the `render` output. This is due to limitations
of not having a `screen` API. It's unclear how this would work in practice,
due to a lack of the `window` API.
2. `userEvent.keyboard` does not support modifier keys. It's only key-presses,
no holding. This is because of API differences that would require us to
figure out a manual binding system for every single key using ANSI AFAIK.
3. Relatedly, we've remove the `{` syntax support, since there is no standard
keybinding for the CLI,
[like there is for the DOM](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code).
Instead, we only support `[` and `]` syntax.

# Matchers

While most of this document has been talking about `DOM Testing Library` and `React Testing Library`,
let's take a moment to talk about [`jest-dom`](https://github.com/testing-library/jest-dom) matchers.
While most of this document has been talking about `DOM Testing Library` and
`React Testing Library`, let's take a moment to talk about
[`jest-dom`](https://github.com/testing-library/jest-dom) matchers.

Usually, in a Testing Library testbed, you'd expect a `getByText` to look something like this:
Usually, in a Testing Library testbed, you'd expect a `getByText` to look
something like this:

```javascript
const {getByText} = render(/* Something */)

expect(getByText('Hello World')).toBeInTheDocument();
expect(getByText('Hello World')).toBeInTheDocument()
```

However, in today's version of `CLI Testing Library`, the same would look something like this:
However, in today's version of `CLI Testing Library`, the same would look
something like this:

```javascript
const {getByText} = render(/* Something */)

expect(getByText('Hello World')).toBeTruthy();
expect(getByText('Hello World')).toBeTruthy()
```

This is because, unlike `DOM Testing Library`, our TestInstances do not have parental relationships. As
a result, what would be a fitting replacement for `document`?
This is because, unlike `DOM Testing Library`, our TestInstances do not have
parental relationships. As a result, what would be a fitting replacement for
`document`?

That said, because `toBeInTheDocument` is implemented by `jest-dom`, we can absolutely implement something
similar in our codebase if requested. We have some thoughts around the technical aspects, but [we'd love to jump
deeper into that discussion with others](https://github.com/crutchcorn/cli-testing-library/issues/2)
That said, because `toBeInTheDocument` is implemented by `jest-dom`, we can
absolutely implement something similar in our codebase if requested. We have
some thoughts around the technical aspects, but
[we'd love to jump deeper into that discussion with others](https://github.com/crutchcorn/cli-testing-library/issues/2)

# Similarities

None of this is to say that we're not dedicated to being aligned with upstream. We would love to work with the broader Testing Library
community to figure out these problems and adjust our usage.
None of this is to say that we're not dedicated to being aligned with upstream.
We would love to work with the broader Testing Library community to figure out
these problems and adjust our usage.

This is the primary reason the library is still published as an `@alpha`, despite being stable enough to successfully
power [a popular CLI application](https://github.com/plopjs/plop/)'s testbed.
This is the primary reason the library is still published as an `@alpha`,
despite being stable enough to successfully power
[a popular CLI application](https://github.com/plopjs/plop/)'s testbed.

What's more, we're dedicated enough to making this happen that we've made sure to:
What's more, we're dedicated enough to making this happen that we've made sure
to:

- Use the same source code organization (as much as possible) as `DOM Testing Library` and `React Testing Library`
- Use the same source code organization (as much as possible) as
`DOM Testing Library` and `React Testing Library`
- Use the same deployment process as `DOM Testing Library`
- Use similar documentation styles

Expand Down
Loading

0 comments on commit 9d6b311

Please sign in to comment.