factory-stories icon indicating copy to clipboard operation
factory-stories copied to clipboard

Add 'with' to allow chaining of methods

Open Ben-Russell opened this issue 7 years ago • 3 comments

This will allow use such as:

(new UserStory)->with(['isAdmin'])->create([ 'Full Name' => 'Ben Russell' ]);

Where your story looks like:

class UserStory extends FactoryStory
{
    public function build($params = [])
    {
        return factory(User::class)->create($params);
    }
    public function isAdmin(User $user)
    {
        $user->isAdmin = true;
        $user->save();
        return $user;
    }
}

This should let you create story "states" kinda similar to factory "states".

Let me know if you like the idea and have any suggestions or feel free to take it and implement a different way. Just currently I seem to have to make a new story for each different state, and would really like this kind of functionality in my project.

Ben-Russell avatar Aug 05 '17 00:08 Ben-Russell

The idea is cool, but i think the problem described in your example could be solved just by using model factory states.

I the other hand, you can pass in the "params" array something like ['is_admin' => true ] and then handle that situation in the build() of the story class.

Do you have any other user case?

jeffochoa avatar Aug 12 '17 22:08 jeffochoa

Yeah, to keep my example short, you are right that they could be done in model factory states.

One main use for factory stories I am doing is for different states of a shopping cart. I use the factory story to attach different relationships to the cart that I couldn't in a model factory, as well as other logic that's needed to create a working cart. So currently I have different factory stories for cart states such as a cart that is ready to start going through the checkout of choosing shipping options and one that has already gone through this process. Instead of having to nest a factory story, I was hoping to just be able to use one factory story, with states.

I hope that makes sense. Let me know if you have another question.

Ben-Russell avatar Aug 25 '17 17:08 Ben-Russell

Even though states can be handled via a model factory, I think FactoryStory should too for the convenience that build() brings. However I think the method should be called states() instead of with() to mimic the model factory method .

So to reuse Ben's example, I suggest:

(new UserStory)->states('admin')->create([ 'Full Name' => 'Ben Russell' ]);

where the story is:

class UserStory extends FactoryStory
{
    public function build($params = [])
    {
        return $this->factory(User::class)->create($params);
    }
 }

and we add something like this to FactoryStory (untested) to delegate the states handling to the model factory:

class FactoryStory
{
    protected $states = [];

    // ...

    public function states($states)
    {
        $this->states = is_array($states) ? $states : func_get_args();

        return $this;
    }

    public function factory()
    {
        return factory(func_get_args())->states($this->states);
    } 

    //...
}

then you just define the actual "admin" state in the model factory allowing it to be used by both the model factory and FactoryStory

the other advantage is that FactoryStory::factory() gives us a hook to modify the call to the model factory on the fly, maybe we could use that to handle times() as well

stephanecoinon avatar Nov 12 '17 00:11 stephanecoinon