Skip to content

Commit

Permalink
feat: custom jest matchers from jest-dom (#15)
Browse files Browse the repository at this point in the history
* Use custom jest matchers from jest-dom

* Fix imports in tests
  • Loading branch information
gnapse authored and Kent C. Dodds committed Apr 10, 2018
1 parent a49f959 commit f2683d9
Show file tree
Hide file tree
Showing 8 changed files with 28 additions and 278 deletions.
118 changes: 23 additions & 95 deletions README.md
Expand Up @@ -38,11 +38,11 @@ your team down.

The `dom-testing-library` is a very light-weight solution for testing DOM nodes
(whether simulated with [`JSDOM`](https://github.com/jsdom/jsdom) as provided by
default with [jest](https://facebook.github.io/jest) or in the browser). The
main utilities it provides involve querying the DOM for nodes in a way that's
similar to how the user finds elements on the page. In this way, the library
helps ensure your tests give you confidence in your UI code. The
`dom-testing-library`'s primary guiding principle is:
default with [jest][] or in the browser). The main utilities it provides involve
querying the DOM for nodes in a way that's similar to how the user finds
elements on the page. In this way, the library helps ensure your tests give you
confidence in your UI code. The `dom-testing-library`'s primary guiding
principle is:

> [The more your tests resemble the way your software is used, the more confidence they can give you.][guiding-principle]
Expand Down Expand Up @@ -80,11 +80,7 @@ when a real user uses it.
* [`waitForElement`](#waitforelement)
* [`fireEvent(node: HTMLElement, event: Event)`](#fireeventnode-htmlelement-event-event)
* [Custom Jest Matchers](#custom-jest-matchers)
* [`toBeInTheDOM`](#tobeinthedom)
* [`toHaveTextContent`](#tohavetextcontent)
* [`toHaveAttribute`](#tohaveattribute)
* [`toHaveClass`](#tohaveclass)
* [Custom Jest Matchers - Typescript](#custom-jest-matchers---typescript)
* [Using other assertion libraries](#using-other-assertion-libraries)
* [`TextMatch`](#textmatch)
* [`query` APIs](#query-apis)
* [Debugging](#debugging)
Expand Down Expand Up @@ -400,106 +396,37 @@ fireEvent.click(getElementByText('Submit'), rightClick)

## Custom Jest Matchers

There are two simple API which extend the `expect` API of jest for making assertions easier.

### `toBeInTheDOM`

This allows you to assert whether an element present in the DOM or not.
When using [jest][], we recommend that you import a set of custom matchers that
make it easier to check several aspects of the state of a DOM element. These are
provided by [jest-dom](https://github.com/gnapse/jest-dom), but are also
included for convenience to be imported from this library directly:

```javascript
// add the custom expect matchers
import 'dom-testing-library/extend-expect'
// <span data-testid="greetings">Hello World</span>
expect(queryByText(container, 'greetings')).toBeInTheDOM()
expect(queryByText(container, 'greetings')).not.toHaveTextContent('Bye bye')
// ...
// <span data-testid="count-value">2</span>
expect(queryByTestId(container, 'count-value')).toBeInTheDOM()
expect(queryByTestId(container, 'count-value1')).not.toBeInTheDOM()
// ...
```
> Note: when using `toBeInTheDOM`, make sure you use a query function
> (like `queryByTestId`) rather than a get function (like `getByTestId`).
> Otherwise the `get*` function could throw an error before your assertion.

### `toHaveTextContent`

This API allows you to check whether the given element has a text content or not.

```javascript
// add the custom expect matchers
import 'dom-testing-library/extend-expect'
// ...
// <span data-testid="count-value">2</span>
expect(getByTestId(container, 'count-value')).toHaveTextContent('2')
expect(getByTestId(container, 'count-value')).not.toHaveTextContent('21')
// ...
```

### `toHaveAttribute`

This allows you to check wether the given element has an attribute or not. You
can also optionally check that the attribute has a specific expected value.

```javascript
// add the custom expect matchers
import 'dom-testing-library/extend-expect'
// ...
// <button data-testid="ok-button" type="submit" disabled>
// OK
// </button>
expect(getByTestId(container, 'ok-button')).toHaveAttribute('disabled')
expect(getByTestId(container, 'ok-button')).toHaveAttribute('type', 'submit')
expect(getByTestId(container, 'ok-button')).not.toHaveAttribute(
'type',
'button',
)
// ...
```

### `toHaveClass`
Check out [jest-dom's documentation](https://github.com/gnapse/jest-dom#readme)
for a full list of available matchers.

This allows you to check wether the given element has certain classes within its
`class` attribute.
### Using other assertion libraries

```javascript
// add the custom expect matchers
import 'dom-testing-library/extend-expect'
If you're not using jest, you may be able to find a similar set of custom
assertions for your library of choice. Here's a list of alternatives to jest-dom
for other popular assertion libraries:

// ...
// <button data-testid="delete-button" class="btn extra btn-danger">
// Delete item
// </button>
expect(getByTestId(container, 'delete-button')).toHaveClass('extra')
expect(getByTestId(container, 'delete-button')).toHaveClass('btn-danger btn')
expect(getByTestId(container, 'delete-button')).not.toHaveClass('btn-link')
// ...
```

### Custom Jest Matchers - Typescript
* [chai-dom](https://github.com/nathanboktae/chai-dom)

When you use custom Jest Matchers with Typescript, you will need to extend the
type signature of `jest.Matchers<void>`, then cast the result of `expect`
accordingly. Here's a handy usage example:

```typescript
import {getByTestId} from 'dom-testing-library'
// this adds custom expect matchers
import 'dom-testing-library/extend-expect'
interface ExtendedMatchers extends jest.Matchers<void> {
toHaveTextContent: (htmlElement: string) => object
toBeInTheDOM: () => void
}
test('renders the tooltip as expected', async () => {
// however you render it:
// render(`<div><span data-testid="greeting">hello world</span></div>`)
;(expect(
container,
getByTestId('greeting'),
) as ExtendedMatchers).toHaveTextContent('hello world')
})
```
If you're aware of some other alternatives, please [make a pull request][prs]
and add it here!

## `TextMatch`

Expand Down Expand Up @@ -768,3 +695,4 @@ MIT
[set-immediate]: https://developer.mozilla.org/en-US/docs/Web/API/Window/setImmediate
[guiding-principle]: https://twitter.com/kentcdodds/status/977018512689455106
[data-testid-blog-post]: https://blog.kentcdodds.com/making-your-ui-tests-resilient-to-change-d37a6ee37269
[jest]: https://facebook.github.io/jest
2 changes: 1 addition & 1 deletion extend-expect.js
@@ -1,2 +1,2 @@
// eslint-disable-next-line
require('./dist/extend-expect')
require('jest-dom/extend-expect')
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -34,7 +34,7 @@
"extend-expect.js"
],
"dependencies": {
"jest-matcher-utils": "^22.4.3",
"jest-dom": "^1.0.0",
"pretty-format": "^22.4.3",
"mutationobserver-shim": "^0.3.2",
"wait-for-expect": "^0.4.0"
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/element-queries.js
@@ -1,4 +1,4 @@
import '../extend-expect'
import 'jest-dom/extend-expect'
import {render} from './helpers/test-utils'

test('query can return null', () => {
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/example.js
@@ -1,7 +1,7 @@
// query utilities:
import {getByLabelText, getByText, getByTestId, queryByTestId, wait} from '../'
// adds special assertions like toHaveTextContent
import '../extend-expect'
import 'jest-dom/extend-expect'

function getExampleDOM() {
// This is just a raw example of setting up some DOM
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/wait-for-element.js
@@ -1,6 +1,6 @@
import {waitForElement, wait} from '../'
// adds special assertions like toBeInTheDOM
import '../extend-expect'
import 'jest-dom/extend-expect'
import {render} from './helpers/test-utils'

async function skipSomeTime(delayMs) {
Expand Down
9 changes: 0 additions & 9 deletions src/extend-expect.js

This file was deleted.

169 changes: 0 additions & 169 deletions src/jest-extensions.js

This file was deleted.

0 comments on commit f2683d9

Please sign in to comment.