Skip to content

Commit

Permalink
[DOCS]: Improve installation and setup guide (#91)
Browse files Browse the repository at this point in the history
* docs: improve installation and setup guide

- add command to install via `pnpm`.
- change commands to install package as a dev dependency.
- use `setupFilesAfterEnv` instead of `setupTestFrameworkScriptFile`, which
  was deprecated in Jest v24.0.0.

* meta: add `@gamemaker1` to contributors list

* style: use spaces in `readme.md` like the rest of project
  • Loading branch information
gamemaker1 authored Dec 10, 2021
1 parent 3f59690 commit 1b1bfc4
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 44 deletions.
112 changes: 68 additions & 44 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,48 @@
[![codecov](https://codecov.io/gh/Dean177/jest-to-match-shape-of/branch/master/graph/badge.svg)](https://codecov.io/gh/Dean177/jest-to-match-shape-of)
[![Npm](https://badge.fury.io/js/jest-to-match-shape-of.svg)](https://www.npmjs.com/package/jest-to-match-shape-of)


A [Jest matcher](https://facebook.github.io/jest/docs/en/using-matchers.html) to verify the structure of an object, particularly useful for api integration tests
A [Jest matcher](https://facebook.github.io/jest/docs/en/using-matchers.html) to verify the structure of an object, particularly useful for API integration tests.

![example-gif](./example/huge-demo-gif.gif)

## Installation

First install the package via `npm`, `pnpm` or `yarn`:

```bash
yarn add jest-to-match-shape-of
npm install --save-dev jest-to-match-shape-of
```

```bash
npm install jest-to-match-shape-of --save
pnpm add --dev jest-to-match-shape-of
```

In your setupTests.js
```bash
yarn add --dev jest-to-match-shape-of
```

Then create a file to setup your tests. This guide uses `test/setup.js` (for Javascript projects) or `test/setup.ts` (for Typescript projects), but it should still work if you place it somewhere else.

Add the following to `test/setup.js` file (if you are using CommonJS):

```javascript
// src/setupTests.js
// /test/setup.js
// Setup your test environment

const { toMatchOneOf, toMatchShapeOf } = require('jest-to-match-shape-of')

expect.extend({
toMatchOneOf,
toMatchShapeOf,
})
```
or if you are using Typescript

If you are using ESM or Typescript, use the following instead:

```typescript
// src/setupTests.ts
// /test/setup.ts
// Setup your test environment

import { toMatchOneOf, toMatchShapeOf } from 'jest-to-match-shape-of'

expect.extend({
Expand All @@ -41,19 +54,22 @@ expect.extend({
})
```

Then in the "jest" section of your package.json add the following:
`"setupTestFrameworkScriptFile": "<rootDir>/src/setupTests.js"`
Then add the following to your [Jest configuration](https://jestjs.io/docs/configuration):

or for typescript:
`"setupTestFrameworkScriptFile": "<rootDir>/src/setupTests.ts"`

### Installation with create-react-app
For project created using CRA (create-react-app) you need to add setup code to the `setupTests.js` file, there is no need to modify `package.json`.
```jsonc
// CommonJS/ESM
"setupFilesAfterEnv": ["./test/setup.js"]

// Typescript
"setupFilesAfterEnv": ["./test/setup.ts"]
```
// src/setupTests.js
const { toMatchOneOf, toMatchShapeOf } = require('jest-to-match-shape-of')
// or with ES6 module import { toMatchOneOf, toMatchShapeOf } from 'jest-to-match-shape-of';

For usage in a project created using CRA ([`create-react-app`](https://create-react-app.dev/)) you simply need to add the above setup code to the test setup file (usually `src/setupTests.js` or `src/setupTests.ts`), there is no need to modify your Jest configuration.

```javascript
import '@testing-library/jest-dom'

import { toMatchOneOf, toMatchShapeOf } from 'jest-to-match-shape-of'

expect.extend({
toMatchOneOf,
Expand All @@ -63,17 +79,21 @@ expect.extend({

## Usage

```javascript
expect(someThing).toMatchOneOf([someOtherThingA, someOtherThingB, someOtherThingC])
```typescript
expect(someThing).toMatchOneOf([
someOtherThingA,
someOtherThingB,
someOtherThingC,
])
expect(someThing).toMatchShapeOf(someOtherThing)
```

Works particularly well when being used with [Typescript](https://www.typescriptlang.org/) to write integration tests e.g.

```typescript
type Resource = {
maybeNumber: number | null,
someString: string,
maybeNumber: number | null
someString: string
}

const testResource: Resource = {
Expand All @@ -88,48 +108,52 @@ const testResourceAlt: Resource = {

describe('an api', () => {
it('returns what I was expecting', () => {
return fetch('/resources/1').then(response => response.json()).then((data) => {
expect(data).toMatchShapeOf(testResource)
})
return fetch('/resources/1')
.then((response) => response.json())
.then((data) => {
expect(data).toMatchShapeOf(testResource)
})
})

it('could return a couple of different things', () => {
return fetch('/resources/1').then(response => response.json()).then((data) => {
expect(data).toMatchOneOf([testResource, testResourceAlt])
})
return fetch('/resources/1')
.then((response) => response.json())
.then((data) => {
expect(data).toMatchOneOf([testResource, testResourceAlt])
})
})
})

```

### How to match a shape with optional fields?
### Matching Optional Fields

Sometimes, the expected shape may vary during integration tests. (e.g: A field may be missing)
Sometimes, the expected shape may vary during integration tests (for example, a field may be missing).

If you want to make a shape allow optional fields, the simplest way is to remove those fields from the expected shape, as follow:

```ts
toMatchOneOf([{ ant: 17 }]) // bat is optional here
```typescript
toMatchShapeOf({ ant: 17 }) // `bat` is optional here
```

A more robust alternative is to define all possible shapes, this way you still test the types of the properties:
A more robust alternative is to define all possible shapes, this way you still test the types of the properties:

```ts
toMatchOneOf([{ ant: 17, bat: 176 }, { ant: 17 }]) // bat is still optional, but must be numeric
```typescript
toMatchOneOf([{ ant: 17, bat: 176 }, { ant: 17 }]) // `bat` is still optional, but must be numeric
```

## Motivation

I wanted to write integration test for my frontend code but found it was tedious, brittle and
hard to debug when I encountered a legitimate failure.
I wanted to write integration test for my frontend code but found it was tedious, brittle and
hard to debug when I encountered a legitimate failure.

I realised that

- Almost all of the errors were due to bad data from the API, most often missing data
- I did not care about *exactly* what data came back, but more about the *shape* of the data.
- I did not care about _exactly_ what data came back, but more about the _shape_ of the data.
- Since I was using React and Typescript I could be confident my app would work as intended if the types were correct
- Thanks to [Enzyme](https://github.com/airbnb/enzyme) I already had a great way to test my component interactions
`toMatchShapeOf` hopefully achieves a lot of the value of full blown integration test written with something like
- Thanks to [Enzyme](https://github.com/airbnb/enzyme), I already had a great way to test my component interactions

`toMatchShapeOf` hopefully achieves a lot of the value of full blown integration test written with something like
[Nightwatch](http://nightwatchjs.org/) whilst being simpler to write, understand and debug.

Additionally I found that the test data I created for use with this matcher were useful for other unit tests in my application.
I also found out that the test data I created for use with this matcher was useful for other unit tests in my application.
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
"name": "Christian Cuna",
"email": "[email protected]",
"url": "https://github.com/christian-cuna"
},
{
"name": "Vedant K",
"email": "[email protected]",
"url": "https://github.com/gamemaker1"
}
],
"dependencies": {
Expand Down

0 comments on commit 1b1bfc4

Please sign in to comment.