cviebrock / eloquent-sluggable

Easy creation of slugs for your Eloquent models in Laravel
MIT License
3.91k stars 461 forks source link

Issue when testing a model factory using make() #597

Closed CamKem closed 1 year ago

CamKem commented 1 year ago

I have a Thread model, that has Sluggable property on it & the sluggable() function for creating the slug.

When I create a test, using the factory for that Thread model & I use $thread = Thread::factory()->make() it is not generating the slug. This is my test (as below), when I try to assertNotNull($thread->slug) I get null is not null. I took me quite a while to figure out that the slug was causing the issue. Do you have any suggestions for how I can do testing on models that have sluggable?

    /** @test */
    public function an_authenticated_user_can_create_a_new_forum_thread()
    {

        $user = User::factory()->create();

        // Given we have a signed-in user
        $this->withExceptionHandling()->signIn($user);

        // Make a thread
        $thread = Thread::factory()->make();

        // Post the thread
        $this->post(route('discuss.store'), $thread->toArray())
            ->assertStatus(302)
            ->assertRedirect(route('discuss.show', $thread->slug))
            ->assertSessionHas('success', 'Post created successfully!');

        $this->assertNotNull($thread->slug);

        // Then their reply should be visible on the page
        $this->get(route('discuss.show', $thread->slug))
            // check to see if the thread creator's name is present
            ->assertSee($thread->creator->name)
            // check the inertia response
            ->assertInertia(function (AssertableInertia $page) use ($thread) {
                // check the component
                $page->component('Discussion/Index')
                    // check the component's data is present
                    ->has('conversations.data', 1)
                    // check the thread's title is present
                    ->where('conversations.data.0.title', $thread->title)
                    // check the thread's body is present
                    ->where('conversations.data.0.body', $thread->body);
            });

    }
CamKem commented 1 year ago

Update: I found a work around (after reading the docs), but I am not sure it is how I should be handling testing with Sluggable. I would still like your response on how I should go about it?

Work around:

    public function an_authenticated_user_can_create_a_new_forum_thread()
    {

        $user = User::factory()->create();

        // Given we have a signed-in user
        $this->withExceptionHandling()->signIn($user);

        // Make a thread
        $thread = Thread::factory()->make();

        $thread->slug = SlugService::createSlug(Thread::class, 'slug', $thread->title);

        $topic = Topic::factory()->create();

        $thread->topic = $topic->slug;

        // Post the thread
        $this->post(route('discuss.store'), $thread->toArray())
            ->assertStatus(302)
            ->assertRedirect(route('discuss.show', $thread->slug))
            ->assertSessionHas('success', 'Post created successfully!');

        $this->assertNotNull($thread->slug);

        // Then their reply should be visible on the page
        $this->get(route('discuss.show', $thread->slug))
            // check to see if the thread creator's name is present
            ->assertSee($thread->creator->name)
            // check the inertia response
            ->assertInertia(function (AssertableInertia $page) use ($thread) {
                // check the component
                $page->component('Discussion/Show')
                    // check the component's data is present
                    ->has('conversation', 12)
                    // check the thread's title is present
                    ->where('conversation.title', $thread->title)
                    // check the thread's body is present
                    ->where('conversation.body', $thread->body);
            });

    }
cviebrock commented 1 year ago

Models are slugged when they are persisted to a database, i.e. on $model->save().

It looks like the make() method on a factory just instantiates the model, but doesn't persist it ... so those models won't yet be slugged. If you used create() instead, I think things would work:

$thread = Thread::factory()->create();

Let me know if that works?

CamKem commented 1 year ago

Yeah that works, but for this test I need to use make so it gets persisted when I post the data in the test. So i think just for testing purposes I need to keep using the SlugService::createSlug(Thread::class, 'slug', $thread->title); which is OK, I don't mind for testing. Thanks for your response.