get(route('post.index'))->assertRedirect(route('login')); $this->get(route('post.create'))->assertRedirect(route('login')); }); it('shows only the authenticated users own posts', function () { $user = User::factory()->create(); $otherUser = User::factory()->create(); $ownPost = Post::factory()->for($user)->create(); $otherPost = Post::factory()->for($otherUser)->create(); $this->actingAs($user) ->get(route('post.index')) ->assertOk() ->assertSee($ownPost->title) ->assertDontSee($otherPost->title); }); it('can create a post', function () { $user = User::factory()->create(); $this->actingAs($user) ->post(route('post.store'), [ 'title' => 'Hello World', 'content' => 'Some content here.', 'slug' => 'hello-world', 'status' => PostStatus::Published->value, ]) ->assertRedirect(route('post.index')); expect(Post::where('slug', 'hello-world')->where('user_id', $user->id)->exists())->toBeTrue(); }); it('validates required fields on create', function () { $user = User::factory()->create(); $this->actingAs($user) ->post(route('post.store'), []) ->assertSessionHasErrors(['title', 'content', 'slug', 'status']); }); it('enforces unique slug on create', function () { $user = User::factory()->create(); Post::factory()->for($user)->create(['slug' => 'taken-slug']); $this->actingAs($user) ->post(route('post.store'), [ 'title' => 'Another Post', 'content' => 'Content.', 'slug' => 'taken-slug', 'status' => PostStatus::Draft->value, ]) ->assertSessionHasErrors('slug'); }); it('can edit own post', function () { $user = User::factory()->create(); $post = Post::factory()->for($user)->published()->create(); $this->actingAs($user) ->get(route('post.edit', $post)) ->assertOk() ->assertSee($post->title); }); it('cannot edit another users post', function () { $user = User::factory()->create(); $otherPost = Post::factory()->create(); $this->actingAs($user) ->get(route('post.edit', $otherPost)) ->assertForbidden(); }); it('can update own post', function () { $user = User::factory()->create(); $post = Post::factory()->for($user)->draft()->create(); $this->actingAs($user) ->patch(route('post.update', $post), [ 'title' => 'Updated Title', 'content' => 'Updated content.', 'slug' => 'updated-slug', 'status' => PostStatus::Published->value, ]) ->assertRedirect(route('post.edit', $post)); expect($post->fresh()->title)->toBe('Updated Title') ->and($post->fresh()->status)->toBe(PostStatus::Published); }); it('cannot update another users post', function () { $user = User::factory()->create(); $otherPost = Post::factory()->create(['slug' => 'original-slug']); $this->actingAs($user) ->patch(route('post.update', $otherPost), [ 'title' => 'Hacked', 'content' => 'Hacked content.', 'slug' => 'hacked-slug', 'status' => PostStatus::Published->value, ]) ->assertForbidden(); }); it('can delete own post', function () { $user = User::factory()->create(); $post = Post::factory()->for($user)->create(); $this->actingAs($user) ->delete(route('post.destroy', $post)) ->assertRedirect(route('post.index')); $this->assertModelMissing($post); }); it('cannot delete another users post', function () { $user = User::factory()->create(); $otherPost = Post::factory()->create(); $this->actingAs($user) ->delete(route('post.destroy', $otherPost)) ->assertForbidden(); $this->assertModelExists($otherPost); });