Skip to content

Commit

Permalink
♻️ rename buildOne to build
Browse files Browse the repository at this point in the history
  • Loading branch information
quirk0o committed Jan 17, 2020
1 parent 4060224 commit 1e6743e
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 45 deletions.
80 changes: 46 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Inspired heavily by [factory_bot](https://github.com/thoughtbot/factory_bot).
```bash
npm install --save-dev @quirk0.o/infact
```

or

```bash
Expand All @@ -18,19 +19,21 @@ yarn install --save-dev @quirk0.o/infact
## Usage

### Basic usage

```js
const CatFactory = Factory.create()
.seq('id')((n) => n)
.seq('id')(n => n)
.attr('name')(() => 'Fluffy')
const fluffy = CatFactory.buildOne()

const fluffy = CatFactory.build()
// { id: 0, name: 'Fluffy' }

const fluffies = CatFactory.buildList(2)
// [{ id: 0, name: 'Fluffy' }, { id: 1, name: 'Fluffy' }]
```

### Creating a factory

Below methods are equivalent.

```js
Expand All @@ -39,19 +42,20 @@ const DogFactory = Factory.create()
```

### Building objects

You can build a single entity or an array of entities. Each time `buildList` is called all sequences are restarted.

```js
const CatFactory = Factory.create().attr('name')(() => 'Fluffy')

const cat = CatFactory.buildOne()
const cat = CatFactory.build()
// { name: 'Fluffy' }
const cats = CatFactory.buildList(3)
// [{ name: 'Fluffy' }, { name: 'Fluffy' }, { name: 'Fluffy' }]
```


### Attributes

To define a static attribute on the object provide a string key and a function that returns the value of the attribute.
If you want to make sure that the attribute is never modified you can also use `Object.freeze` as a safety precaution.

Expand All @@ -62,86 +66,91 @@ const CatFactory = Factory.create()
.attr('meta')(() => Object.freeze({ color: 'black', gait: 'lively' }))
```

You can also override attributes by passing them to `buildOne`.
You can also override attributes by passing them to `build`.

```js
const CatFactory = Factory.create()
.attr('name')(() => 'Fury')
.attr('age')(() => 3)
const cat = CatFactory.buildOne({ age: 4 })

const cat = CatFactory.build({ age: 4 })
// { name: 'Fury', age: 4 }
```

NOTE: Each call to `attr` returns a new factory so this will not work:

```js
const CatFactory = Factory.create()
CatFactory.attr('name')(() => 'Fury')
```

`CatFactory` will have no attributes in this case.

### Sequences

Sequence attributes are incremented when building multiple objects.

```js
const CatFactory = Factory.create()
.seq('name')((n) => `Cat #${n + 1}`)

const CatFactory = Factory.create().seq('name')(n => `Cat #${n + 1}`)

const cats = CatFactory.buildList(2)
// [{ name: 'Cat #1' }, { name: 'Cat #1 }]
```

Note that sequences will not be incremented when building a single object. For this usage check [Advanced Usage](#advanced-usage).

```js
const CatFactory = Factory.create()

CatFactory.buildOne()
CatFactory.build()
// { name: 'Cat #1' }

CatFactory.buildOne()
CatFactory.build()
// { name: 'Cat #1' }
```

### Transient attributes

These are attributes that will not be put on the resulting object but will be available as an argument to all the attribute and sequence functions.
You can also override options just like attributes by passing them to `buildOne`.
You can also override options just like attributes by passing them to `build`.

```js
const CatFactory = Factory.create()
.opt('hungry')(() => false)
.attr('name')(({ hungry }) => hungry ? 'Fury' : 'Fluffy')
const cat = CatFactory.buildOne()
.attr('name')(({ hungry }) => (hungry ? 'Fury' : 'Fluffy'))

const cat = CatFactory.build()
// { name: 'Fluffy' }
const hungryCat = CatFactory.buildOne({ hungry: true })
const hungryCat = CatFactory.build({ hungry: true })
// { name: 'Fury' }
```

### Composing factories

You can create more complex factories by composing multiple factories.

```js
const CatFactory = Factory.create()
.attr('name')(() => 'Fluffy')
const SpiderFactory = Factory.create()
.attr('canSwing')(() => true)

const CatFactory = Factory.create().attr('name')(() => 'Fluffy')
const SpiderFactory = Factory.create().attr('canSwing')(() => true)

const SpiderCatFactory = Factory.compose(CatFactory, SpiderFactory)
const spiderCat = SpiderCatFactory.buildOne()
const spiderCat = SpiderCatFactory.build()
// { name: 'Fluffy' canSwing: true }

// or
const SpiderCatFactory = CatFactory.compose(SpiderFactory)
```

### Callbacks

If you want to add properties/methods or compute something after the object is build you can use a callback.

```js
const CatFactory = Factory.create()
.attr('name')(() => 'Fluffy')
.after((entity) => console.log(`I'm a cat named ${entity.name}`))
const cat = CatFactory.buildOne()
.after(entity => console.log(`I'm a cat named ${entity.name}`))

const cat = CatFactory.build()
// I am a cat named Fluffy
// { name: 'Fluffy' }
```
Expand All @@ -152,23 +161,26 @@ The entire object of attributes and options is also available as a second parame
const CatFactory = Factory.create()
.opt('hungry')(() => false)
.attr('name')(() => 'Fluffy')
.after((entity, evaluator) => console.log(`I'm a cat named ${entity.name} and I am ${evaluator.hungry ? 'hungry' : 'not hungry'}`))

const cat = CatFactory.buildOne({ hungry: true })
.after((entity, evaluator) =>
console.log(
`I'm a cat named ${entity.name} and I am ${evaluator.hungry ? 'hungry' : 'not hungry'}`
)
)

const cat = CatFactory.build({ hungry: true })
// I am a cat named Fluffy and I am hungry
// { name: 'Fluffy' }
```

## Advanced Usage

The method `gen` returns a generator that provides a `next` method which will return a new entity on every call.
Notice that the generator is idempotent meaning it will return the same object every time it is called. The `next` method
Notice that the generator is idempotent meaning it will return the same object every time it is called. The `next` method
provides a way to iterate over the results.

```js
const CatFactory = Factory.create()
.seq('id')((n) => n)

const CatFactory = Factory.create().seq('id')(n => n)

const catGenerator = CatFactory.gen()
catGenerator.next().value
// { id: 0 }
Expand Down
20 changes: 10 additions & 10 deletions src/factory.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@ describe('Factory', () => {
const SpiderFactory = new Factory().attr('canItSwing')(() => true)
const SpiderCatFactory = Factory.compose(CatFactory, SpiderFactory)

const spiderCat = SpiderCatFactory.buildOne()
const spiderCat = SpiderCatFactory.build()

expect(spiderCat).toEqual({ name: 'Bibi', canItSwing: true })
})
})

describe('.buildOne', () => {
describe('.build', () => {
it('builds object with set attributes', () => {
const CatFactory = new Factory()
.attr('name')(() => 'Bibi')
.attr('age')(() => 3)

const cat = CatFactory.buildOne()
const cat = CatFactory.build()

expect(cat).toEqual({
name: 'Bibi',
Expand All @@ -38,7 +38,7 @@ describe('Factory', () => {
.attr('name')(() => 'Bibi')
.attr('age')(() => 3)

const cat = CatFactory.buildOne({ age: 4 })
const cat = CatFactory.build({ age: 4 })

expect(cat).toEqual({
name: 'Bibi',
Expand All @@ -55,7 +55,7 @@ describe('Factory', () => {
(new Date(2019, 7, 13).getTime() - birthday.getTime()) / 1000 / 60 / 60 / 24 / 365
)

const cat = CatFactory.buildOne()
const cat = CatFactory.build()

expect(cat).toEqual({
name: 'Bibi',
Expand All @@ -68,7 +68,7 @@ describe('Factory', () => {
.attr('name')(() => 'Bibi')
.attr('fullName')(({ name }) => `${name} The Cat`)

const cat = CatFactory.buildOne()
const cat = CatFactory.build()

expect(cat).toEqual({
name: 'Bibi',
Expand All @@ -81,7 +81,7 @@ describe('Factory', () => {
.seq('name')(n => `Cat #${n + 1}`)
.attr('fullName')(({ name }) => `${name} Potato`)

const cat = CatFactory.buildOne()
const cat = CatFactory.build()

expect(cat).toEqual({
name: 'Cat #1',
Expand Down Expand Up @@ -110,7 +110,7 @@ describe('Factory', () => {
(new Date(2019, 7, 13).getTime() - birthday.getTime()) / 1000 / 60 / 60 / 24 / 365
)

const cat = CatFactory.buildOne({ birthday: new Date(2016, 7, 13) })
const cat = CatFactory.build({ birthday: new Date(2016, 7, 13) })

expect(cat).toEqual({
name: 'Bibi',
Expand All @@ -132,7 +132,7 @@ describe('Factory', () => {
.opt('hungry')(() => true)
.after(afterCallback)

const cat = CatFactory.buildOne()
const cat = CatFactory.build()

expect(afterCallback).toHaveBeenCalled()
expect(cat).toEqual({ name: 'Bibi', meowing: true })
Expand Down Expand Up @@ -161,7 +161,7 @@ describe('Factory', () => {
.after(afterCallbackMeowing)
.after(afterCallbackName)

const cat = CatFactory.buildOne()
const cat = CatFactory.build()

expect(afterCallbackMeowing).toHaveBeenCalled()
expect(afterCallbackName).toHaveBeenCalled()
Expand Down
2 changes: 1 addition & 1 deletion src/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ export class Factory<TRes extends object = Dict, TTrans extends object = Dict> {
)
}

buildOne(overrides?: TRes & TTrans): TRes {
build(overrides?: TRes & TTrans): TRes {
return this.gen(overrides).next().value
}

Expand Down

0 comments on commit 1e6743e

Please sign in to comment.