hefty

Easy, unopinionated and intuitive Typescript fixtures.

Usage no npm install needed!

<script type="module">
  import hefty from 'https://cdn.skypack.dev/hefty';
</script>

README

Hefty

Easy, unopinionated and intuitive Typescript fixtures.

Installation

yarn add hefty --dev

Usage

Hefty lets you create factories, chain multiple states and override those states too. Check out the tests for more examples.

Create a Factory

States need to be registered in the constructor of your factory. States (and with()) are called with the same params you get with Array.map().

// User.ts
class User {
  email: string
  emailConfirmed: boolean
  onboarded: boolean
}

// UserFactory.ts
import { Factory } from 'hefty'

class UserFactory extends Factory<User> {
  constructor() {
    super(User)

    this.register('email confirmed', this.hasConfirmed)
    this.register('onboarded', this.hasOnboarded)
  }

  hasConfirmed(): Partial<User> {
    return {
      emailConfirmed: true
    }
  }

  hasOnboarded(): Partial<User> {
    return {
      onboarded: true
    }
  }
}

Create some users

const factory = new UserFactory()

const user1: User = await factory.one()
// -> emailConfirmed = false

const user2: User = await factory.state('email confirmed').one()
// -> emailConfirmed = true

const user3: User = await factory.state('email confirmed').state('onboarded').one()
// -> emailConfirmed = true, onboarded = true

const user4: User = await factory.state('email confirmed').with(() => ({ email: hello@web.site })).one()
// -> emailConfirmed = true, email = hello@web.site

const users: User[] = await factory.state('email confirmed').many(3)
// -> generates 3 users with emailConfirmed = true

state() and with() can be chained as many times as you like in any order. They'll all be applied sequentially when one() or many() is called.

Entities with constructors

const factory = new UserFactory()
const user: User = await factory.construct(new Company(), 'Jane Doe').state('email confirmed').one()

Any params passed to construct() are passed to the constructor for each entity.

Factories with default states

export default class UserFactory extends Factory<User> {
  constructor() {
    super(User, 'base', 'email confirmed')

    this.register('base', this.base)
    this.register('onboarded', this.onboarded)
    this.register('email confirmed', this.emailConfirmed)
  }

  base(): Partial<User> {
    return {
      createdAt: 'today'
    }
  }

  onboarded(): Partial<User> {
    return {
      onboarded: true
    }
  }

  emailConfirmed(): Partial<User> {
    return {
      emailConfirmed: true
    }
  }
}

const factory = await new UserFactory().one()
// => createdAt = today, emailConfirmed: true 

Any extra strings you pass to the factory base class will be treated as default states. These will be applied before any other states/overrides.

Async functions

export default class UserFactory extends Factory<User> {
  constructor() {
    super(User, 'loginable')
    this.register('loginable', this.loginable)
  }

  async loginable(): Promise<Partial<User>> {
    return {
      password: await bcrypt.hash('password', 10)
    }
  }
}

Hefty will automatically resolve any promise-based states or with() callbacks.