---
title: Announcing Fishery – a JavaScript and TypeScript Factory Library
teaser: 'We have just released Fishery, a TypeScript-compatible library for setting
  up JavaScript objects for use in tests and anywhere else you need to set up data.

  '
tags: typescript,javascript,testing,web
author: Stephen Hanson
published_on: 2020-02-05
---

I’m pleased to announce the release of [Fishery], a library for setting
up JavaScript objects for use in tests and anywhere else you need to set up
data. Fishery is influenced by our popular Ruby factory library, [factory_bot].

Fishery is built with TypeScript in mind. Factories, which build objects, accept
typed parameters and return typed objects, so you can be confident that the data
used in your tests is valid. If you aren’t using TypeScript, that’s fine too.
Fishery still works, just without the extra type-checking that comes with
TypeScript.

## Why factories?

Any test suite needs to have the ability to create objects that simulate the
objects used by your app. For example, if you have a function called
`sendNotification(user)` or a React component `<UserAvatar user={user} />`, you
need a `user` object in order to test it.

Manually creating this data in each of your tests is not ideal for several
reasons. First, it creates unnecessary code duplication. Each test that uses
your objects shouldn’t have to know how to build them. Keeping the logic for how
to build your objects in one place makes it easier to maintain your code as your
data changes over time. 

Another benefit of factories is that they keep irrelevant noise out of your test
suite. For example, the following test includes data that might be necessary for
your test to work or compile but is not directly relevant to what is being
tested — much of it is just noise:

```javascript
const user = {
  id: 1,
  firstName: "Sonia",
  lastName: "Gutierrez",
  email: "sonia@example.com",
  phone: "123-555-5555",
  avatarUrl: "https://example.com/avatar.png",
}

expect(getFullName(user)).toEqual("Sonia Gutierrez")
```

Using factories, you define your factory in one central place and then only need
to specify the information that is necessary for the test when using the
factory. This makes your tests easier to read and maintain:

```typescript
const user = factories.user.build({
  firstName: "Sonia",
  lastName: "Gutierrez",
}

expect(getFullName(user)).toEqual("Sonia Gutierrez")
```

You could argue in this contrived example that `getFullName` wouldn’t need a
full `User` object. Real-world examples are usually more complex, however. Your
function might require a full object because it is typed that way (if
using TypeScript) or because it accesses other properties that aren’t
directly under test.

## Installation

First, install fishery with:

```
npm install --save fishery
```

or

```
yarn add fishery
```

## Basic usage

To use Fishery, define your factories and then call `build()` on them
whenever you need to build your object. A factory is just a function that
returns your object. Fishery provides several arguments to your factory
function to help with common situations. Here’s a quick example:

### Define factories

```typescript
// factories/user.ts
import { Factory } from 'fishery';
import { User } from '../my-types';

export default Factory.define<User>(({ sequence }) => ({
  id: sequence,
  name: 'Bob',
  address: {
    city: 'Austin',
    state: 'TX',
  },
}));
```

### Use factories

Now you can use your factory to build objects:

```typescript
// my-test.test.ts
import { factories } from './factories';

const user = factories.user.build({ 
  name: 'Susan', 
  address: { city: 'El Paso' } 
});

user.id // 1 (autoincrementing sequence)
user.address.city // El Paso (argument passed to build)
user.address.state // TX (default defined in factory)
```

Check out [the documentation][fishery] for more information on defining
factories and building objects.

## Typechecking

Factories are fully typed, both when defining your factories and when using them
to build objects, so you can be confident the data you are working with is
correct.

The return value of `build` is type-checked:

```typescript
const user = factories.user.build();
user.age; // type error! Property 'age' does not exist on type 'User'
```

The arguments you pass when calling `build` on your factory are type-checked:

```typescript
const user = factories.user.build({ age: 10 }); // type error! Argument of type '{ age: number; }' is not assignable to parameter of type 'Partial<User>'.
```

The arguments that your factory function uses are also typed. Here's a complex
example:

```typescript
export default Factory.define<User, Factories, UserTransientParams>(
  ({ sequence, params, transientParams, associations, afterCreate }) => {
    params.age; // Property 'age' does not exist on type 'DeepPartial<User>
    transientParams.isAdmin; // Property 'isAdmin' does not exist on type 'Partial<UserTransientParams>'
    associations.posts; // Property 'posts' does not exist on type 'Partial<User>'

    afterCreate(user => {
      user.age; // Property 'age' does not exist on type 'User'
    });

    return {
      id: `user-${sequence}`,
      name: 'Bob',
      post: null,
    };
  },
);
```

## Looking for feedback

[Check out the project][fishery] and let us know what you think. It is still in
its early stages, so we are looking for feedback. Contact us [on
Twitter][twitter] or open a [GitHub issue][github-issues] if you have thoughts
on how we could make it better. Happy testing!

[factory_bot]: https://github.com/thoughtbot/factory_bot
[fishery]: https://github.com/thoughtbot/fishery
[github-issues]: https://github.com/thoughtbot/fishery/issues
[twitter]: https://twitter.com/thoughtbot
