thoughtbot / fishery

A library for setting up JavaScript objects as test data
MIT License
876 stars 36 forks source link

Support for required values typing on build/create, not on define #115

Open KieranP opened 1 year ago

KieranP commented 1 year ago

We have a bunch of factories mapped to various DB structures. As is the case for most projects, the DB has some required fields and some optional ones. So we created a Typescript type indicating which were required/optional, and passed them into Fishery.

However, the factory definition can't specify some of these attributes up front (e.g. a post factory might have an author_id which needs to be passed into it). However, the author_id is still required when we create the record. But fishery doesn't seem to support this case.

e.g.

type User = {
  title: string
  author_id: string
}

const userFactory = Factory.define<User>(({ onCreate }) => {
  onCreate(attrs => User.create(attrs));

  return {
    title: 'Testing'
  }
})

const author = { id: 123 } // normally created via another factory

const user = await userFactory.create({ author_id: author.id })

We are providing the title for the post, but the author_id needs to be passed in on create.

However, the Factory typing barfs and as a result, the create call also complains.

It would be great if fishery types could accept any attributes when defining the factory, and only check typing on build/create

In the meantime, to get everything working, I have to make all values optional:

type User = {
  title?: string
  author_id?: string
}

but this obviously leads to issues where required attributes are missed

stevehanson commented 1 year ago

The return value of your factory must be a valid User. Instead of updating your User type, I recommend updating your factory to return a valid User:

const userFactory = Factory.define<User>(({ onCreate }) => {
  onCreate(attrs => User.create(attrs));

  return {
    title: 'Testing',
    author_id: '1' // add this line
  }
})

Your suggestion of having the factory return only part of the object and build or create supplying the rest is not something that is currently supported or on the roadmap.