@isthatcentered/charlies-factory

Makes making objects easy

Usage no npm install needed!

<script type="module">
  import isthatcenteredCharliesFactory from 'https://cdn.skypack.dev/@isthatcentered/charlies-factory';
</script>

README

Make your tests obvious

Only show the data that matters in your fixtures.

// Before: What data do you think matters about this card ? ๐Ÿ˜ฌ
const card = {
    title:    "Batman rocks",
    comments: [],
    owner:   {
        username: "batman",
        picture: "some-picture-of-batman.png"
    }
} 

// After: It's obvious, it's about the empty comments ๐Ÿ˜Š
import {factory} from "@isthatcentered/charlies-factory"

const makeCardResource = factory({
    // ...define your defaults 
})

const card = makeCardResource( { comments: [] } )  

Table of content

Installation

npm i @isthatcentered/charlies-factory 

How to use

Basic use

At the end of the day, this thing makes objects.

You set up a default once and it feeds it back to you with a simple function call every time you need it.

Here's how to do that (keep on reading though, basic use is nice but it's intended to be way more usefull/powerfull thant that ๐Ÿ˜‡)

import {factory} from "@isthatcentered/charlies-factory"

export const makeCard = factory({
    title:    "Title",
    status: "done",
    comments: [],
    owner:    makeUser(  ), // You can totally nest factories 
})

// Then enjoy the simplicity of it all
const wrapper = shallow(<KanbanCard card={makeCard()} />)

Overriding default data

This is the selling point of this thing. Overrides are what will make your tests obvious by explicitely stating what data matters.

Let's say I want to test how my <KanbanCard/> component from earlier behaves when the card has no comments.

import { makeCard } from "some-file-where-i-set-up-the-default-as-shown-in-basic-use"

test( `Comment indicator is hidden when card has no comments`, () => {
    const card    = makeCard( { comments: [] } ),
          wrapper = shallow(<KanbanCard card={card} />)
    
    expect( wrapper.find( CardCommentsIndicator ).props().display ).toBe( false )
} )

And just for kicks, here's how the test would look like without charlies-factory. Try to find the data that matters ๐Ÿ˜ณ

// (This is WITHOUT charlies-factory)
test( `Comment indicator is hidden when card has no comments`, () => {
    const card    = {
            title:    "Batman rocks",
            comments: [],
            owner:   {
                username: "batman",
                picture: "some-picture-of-batman.png"
            }
        },
         wrapper = shallow(<KanbanCard card={card} />)
    
    expect( wrapper.find( CardCommentsIndicator ).props().display ).toBe( false )
} )

Dynamic data

I've shown earlier (see basic use) that you can totally nest factories inside factories. But the way we did this earlier (by providing an object as default), the nested factory will only be executed once and therefore always return the same data.

You might not want that or might need to compute some data for the defaults.

It's easy, you can actually pass a function as default.

const seedFunction = (generator: FakerStatic, index: seedId) => { // Yes, we give you a data generator (Faker) because we're nice like that but more on that later ๐Ÿ˜‡
    
    const someComputedStuff  = computeMeSomeStuffFromCurrentAppState(appState)
    
    return {
        id: index, // each factory you define starts it's own index sequence
        status: someComputedStuff,
        email: generator.internet.email()
        // ... you get the ide
    } 	
}

const makeThing = factory( seedFunction )

// The function will be executed every time you call the factory ๐Ÿ˜™
console.log(makeThing()) // {id: 1, status: "active", email: "whatever.com", ... }
console.log(makeThing()) // {id: 2, status: "disabled", email: "newEmail.com", ... }   

The seed as function also work for the overrides and the states.

For overrides

const makeThing = factory({id: 0})

const overrides = (generator, index) => ({id: generator.random.number()})

console.log(makeThing(overrides)) // {id: 45 } (or whatever number has been generated) 

For states

const states = {
    "discounted": (generator, index) => ({
        discount: generator.random.number()
    }),
    "inStock": (generator, index) => ({
        stockCount: generator.random.number() // (I'm not doing Faker justice, it can do way much more than generate random numbers)
    })
}
const makeThing = factory({stockCount: 1, discount: 0}, states)

console.log(makeThing({}, "discounted", "inStock")) // {discount: 20, stockCount: 42} 

Dynamic data extravaganza

// Erh... @todo, sorry. But you get the idea, your factory can have a function as default, for a or every state you define, and for your last minute overrides if you want.

States

You can define default states for the generated objects like active, done or whatever you fancy.

I haven't had time to add docs for this yet but you can checkout the example right above or the src/features.spec.ts for the how to use.

Generating multiple items at a time

Sometimes, you need a bunch of objects. We got you covered with the pack function. Think you want a pack of things from the factory.

Here's the how to

// We provide the loop index in case you need some ID ๐Ÿ‘ฎโ€
const cards = pack(3, index => makeCard({id: index})) // Remember, you still have acces to overrides

Give feedback

You're enjoying the package ?

Let me know at e.peninb@gmail.com or ๐ŸŒŸthe repo.

Found a bug ?

You ๐ŸคŸ, let me know by opening an issue

Need a new feature ?

Nice, open an issue and let's talk about this ! ๐Ÿ‘ฉโ€๐Ÿš€