A simple library for setting up TypeScript objects as test data - heavily inspired by the awesome Ruby's factory_bot.
- Fully written in TypeScript
- With (optional) type checking
- With no persistence layer
- And no promises.
☺️
1. Add to your project
npm i -D factory-bot-ts
yarn add factory-bot-ts --dev
1. Ok, suppose we've got a Ninja model..
// ../src/models/ninja.model.ts
export enum NinjaRank {
GENIN = 'Genin',
CHUUNIN = 'Chuunin',
JONIN = 'Jonin'
}
export class Ninja {
id?: number
name?: string
username?: string
level?: NinjaRank
sensor?: boolean
constructor(attrs?: Partial<Ninja>) {
Object.assign(this, attrs)
}
}
2. We would define our factories..
// ../src/tests/index.ts
import * as Faker from 'faker'
import { sample } from 'lodash'
import { FactoryBot } from 'factory-bot-ts'
import { Ninja, NinjaRank, Village } from '../src/models'
FactoryBot.define('ninja', {
id: () => Faker.random.number(),
name: () => Faker.name.findName(),
username: () => FactoryBot.seq(seq => `${Faker.internet.userName()}_${seq}`),
level: () => FactoryBot.rand(NinjaRank),
sensor: () => sample([true, false])
}, Ninja)
FactoryBot.define('village', {
id: () => Faker.random.uuid(),
name: () => Faker.name.findName(),
members: () => FactoryBot.buildList<Ninja>('ninja', 2)
}, Village)
export {
FactoryBot
}
3. And then we'd just use them on our tests!
// ../src/models/ninja.model.spec.ts
import { FactoryBot } from '../src/tests'
import { Ninja, NinjaRank, Village } from '.'
export class NinjaSpec {
let instance: Ninja
before(() => {
instance = FactoryBot.build('ninja', { name: 'Kakashi Hatake' })
})
it('builds a Ninja! 👹', () => {
expect(instance).to.be.an
.instanceof(Ninja)
})
}
Factory-bot-ts also allow us to..
1. Define untyped factories with static data
FactoryBot.define('ninja', {
id: 1,
name: 'Sasuke Uchiha',
username: 'sasuke',
level: NinjaRank.GENIN,
sensor: false,
sharingan: true
})
FactoryBot.build('ninja') /* => {
id: 1,
name: 'Sasuke Uchiha',
username: 'sasuke',
level: 'Genin',
sensor: false,
sharingan: true
} */
2. Define factories with type checking
FactoryBot.define<Ninja>('ninja', {
id: 1,
name: 'Sasuke Uchiha',
username: 'sasuke',
level: NinjaRank.GENIN,
sensor: false
}, Ninja)
FactoryBot.build('ninja') /* => Ninja {
id: 1,
name: 'Sasuke Uchiha',
username: 'sasuke',
level: 'Genin',
sensor: false
} */
3. Define factories with Dynamic data
FactoryBot.define('ninja', {
id: () => Faker.random.number(),
name: () => Faker.name.findName(),
username: () => Faker.internet.userName(),
level: () => FactoryBot.rand(NinjaRank),
sensor: () => sample([true, false])
}, Ninja)
FactoryBot.build('ninja') /* => Ninja {
id: 43748,
name: 'Martine Romaguera MD',
username: 'Kaleb_Homenick',
level: 'Jonin',
sensor: true
} */
4. Define factories with custom, random and sequenced data
FactoryBot.define('ninja', {
id: () => Faker.random.number(),
name: () => Faker.name.findName(),
username: () => FactoryBot.seq(seq => `${Faker.internet.userName()}_${seq}`),
level: () => FactoryBot.rand(NinjaRank),
sensor: () => sample([true, false])
}, Ninja)
FactoryBot.build<Ninja>('ninja', { name: 'Uzimaki Naruto' }) /* => Ninja {
id: 11941,
name: 'Uzimaki Naruto',
username: 'Art_Crist36_1',
level: 'Genin',
sensor: true
} */
FactoryBot.build<Ninja>('ninja', { name: 'Sasuke Uchiha', username: 'sasuke-kun' }) /* => Ninja {
id: 52565,
name: 'Sasuke Uchiha',
username: 'sasuke-kun',
level: 'Chuunin',
sensor: false
} */
5. Define chained factories
FactoryBot.define('ninja', {
id: () => Faker.random.number(),
name: () => Faker.name.findName(),
username: () => FactoryBot.seq(seq => `${Faker.internet.userName()}_${seq}`),
level: () => FactoryBot.rand(NinjaRank),
sensor: () => sample([true, false])
}, Ninja)
FactoryBot.define('village', {
id: () => Faker.random.uuid(),
name: 'Leaf',
members: () => FactoryBot.buildList<Ninja>('ninja', 2)
}, Village)
FactoryBot.build('village') /* => Village {
id: '7ec17407-cfdb-4a3f-b434-de788eb41591',
name: 'Leaf',
members: [ Ninja {
id: 11941,
name: 'Herta Hane',
username: 'Kaleb_Homenick_5',
level: 'Genin',
sensor: true
}, Ninja {
id: 52565,
name: 'Corbin Koss',
username: 'Art_Crist36_6',
level: 'Genin',
sensor: false
}]
} */
6. Extend existing factories in order to generate specialized data
FactoryBot.define<Ninja>('ninja', {
id: 1,
name: 'Kakashi Hatake',
username: 'kakashi',
level: NinjaRank.GENIN,
sensor: false
}, Ninja)
FactoryBot.extend<Ninja>('ninja', 'jōnin', {
level: NinjaRank.JONIN
})
FactoryBot.build<Ninja>('ninja') /* => Ninja {
id: 1,
name: 'Kakashi Hatake',
username: 'kakashi',
level: Genin,
sensor: false
} */
FactoryBot.build<Ninja>('jōnin') /* => Ninja {
id: 1,
name: 'Kakashi Hatake',
username: 'kakashi',
level: Jōnin,
sensor: false
} */
For more examples, please, check out the project's specs.
To run this project we need to have:
- Install the dependencies above
$ git clone https://github.com/roalcantara/factory-bot-ts.git
- Clone the project$ cd factory-bot-ts
- Go into the project folder$ yarn
- Run the setup script
$ yarn test
to run the specs
- Bug reports and pull requests are welcome on GitHub
- Follow the Semantic Versioning Specification
- Follow the GitHub Flow
- Follow the 5 Useful Tips For A Better Commit Message article and the How to Write a Git Commit Message post
- Use Commitizen cli when committing
Everyone interacting in the factory-bot-ts project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.
The package is available as open source under the terms of the CC BY-SA 4.0.