brenolf/factory-granny

View on GitHub
README.md

Summary

Maintainability
Test Coverage
<h1 align="center">
    <br>
    <img width="400" src="./logo.png" alt="Factory Granny">
    <br>
    <br>
    <br>
</h1>


[![Build Status](https://travis-ci.org/brenolf/factory-granny.svg)](https://travis-ci.org/brenolf/factory-granny)
[![Coverage Status](https://coveralls.io/repos/brenolf/factory-granny/badge.svg?branch=master&service=github)](https://coveralls.io/github/brenolf/factory-granny?branch=master)
[![Code Climate](https://codeclimate.com/github/brenolf/factory-granny/badges/gpa.svg)](https://codeclimate.com/github/brenolf/factory-granny)
[![npm version](https://badge.fury.io/js/factory-granny.svg)](http://badge.fury.io/js/factory-granny)
> Who were you expecting, Pocahontas?

Factory Granny is a JavaScript library for Factories that is different from the others because it also allows you to build functions instead of objects; This little feature eases test development by allowing you to directly use a Factory instance instead of needing to stub many functions.

## Install
`$ npm install --save-dev factory-granny`

## Usage

### Static methods

```js
var Factory = require('factory-granny')

var sinon = require('sinon')

Factory('User')
.attr('name', 'brenolf')
.static('sayMyName', sinon.stub)

var instance = Factory('User').get()
```

In this example `instance` is a function that always returns an object `{username: 'brenolf'}` when called with `new`. Also, this function will have a `sayMyName` property that is a stub. As simple as that!

Static attributes may also have dependencies over other fields:

```js
Factory('User')
.attr('name', 'brenolf')
.static('sayMyName', ['name'], function (name) {
    return 'Hello ' + name
})
```

Ultimately you can track the changes of the instance being returned on every `get` called, and thus, spy on them.

```js
// user-factory.js
module.exports = Factory('User')
.attr('name', 'brenolf')
.attr('spy', sinon.stub)
.static('sayMyName', ['name'], function (name) {
    return 'Hello ' + name
})

// test.js
var UserFactory = require('user-factory.js')

var user = UserFactory.get()
var instance = user._instance

// ...

expect(instance.spy).to.have.been.calledOnce
```

You can also call `build` instead of `get` in order to get an object with all the attributes given, but not needing to instantiate the returned function.

```js
var UserFactory = require('user-factory.js')

/*
    user_fn = function () {
        return {
            name: 'brenolf',
            spy: sinon.stub()
        }
    }
*/
var user_fn = UserFactory.get()

/*
    user = {
        name: 'brenolf',
        spy: sinon.stub()
    }
*/
var user = UserFactory.build()
```

### Traits

Factory Granny makes it super easy to use traits in your development.

```js
Factory('User.ABQ')
.attr('name', 'heisenberg')

Factory('User.ABQ').get().sayMyName
```

As a matter of fact, you don't need to first write the parent factory. You can define a trait first and later its parent just by calling `propagate`.

```js
Factory('Name.trait')
.attr('name', 'This is my name')

Factory('Name')
.attr('name', 'Main name')
.attr('parent', true)
.propagate()

Factory('Name').build() // { name: 'Main name', parent: true }

Factory('Name.trait').build() // { name: 'This is my name', parent: true }
```

If you don't call `propagate` at the end of the parents' chain, then all of its traits will not inherit its attributes.

### Factory box

Factory Granny comes with a handful of stubs to make writing you factories even faster. For example:

```js
Factory('User')
.attr('name', 'brenolf')
.static('sayMyName', Factory.box.true())
.static('find', Factory.box.chain('User.ABQ'))
```

There are many other aliases to make writing you factories a fun work:

| Method                   | Equivalent                                                                           |
|--------------------------|--------------------------------------------------------------------------------------|
| `simple()`              | `sinon.stub()`                                                                       |
| `true()`                 | `sinon.stub().returns(true)`                                                         |
| `false()`                | `sinon.stub().returns(false)`                                                        |
| `returns(value)`         | `sinon.stub().returns(value)`                                                        |
| `throws()`               | `sinon.stub().throws()`                                                              |
| `resolves(value)`        | A sinon promise stub which resolves to a given value (`{}` if none given) |
| `rejects()`              | A sinon promise stub that rejects |
| `build(Factory)` | Returns an instance of the class provided (last factory created if none given) |
| `chain(Factory)` | A sinon stub that returns a `.build()` of the given factory (last factory created if none given) |
| `chainAsync(Factory)` | A sinon stub that resolves a `.build()` of the given factory (last factory created if none given) |

The functions that receives a factory string as parameter are all lazy loaded. Therefore, you can use factories that are not created yet but will be available when `build` is later called.

The greatest advantage of using `Factory.box` is when working with the factories. Since every function is evaluated on each `build` and `get` calls, if you wanted to have an attribute evaluated to a function value (using `sinon` stubs, for instance) you would need to write down a function that returns a function pointer. Factory Granny does that for you under the hood!

Note that Factory Granny is opinionated using `sinon` for its stubs.

## Basic Usage

Factory Granny uses [Rosie](https://github.com/rosiejs/rosie) as its basis. Any valid formation for Rosie is also valid for Factory Granny.

## License

 Apache License