diff options
Diffstat (limited to 'tests/Feature/WritingTest.php')
| -rw-r--r-- | tests/Feature/WritingTest.php | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/tests/Feature/WritingTest.php b/tests/Feature/WritingTest.php new file mode 100644 index 0000000..5a88b17 --- /dev/null +++ b/tests/Feature/WritingTest.php @@ -0,0 +1,279 @@ +<?php + +namespace Tests\Feature; + +use App\Models\User; +use App\Models\Writing; +use Illuminate\Foundation\Testing\RefreshDatabase; +use Tests\TestCase; + +class WritingTest extends TestCase +{ + use RefreshDatabase; + + // ─── Index ─────────────────────────────────────────────────────────────── + + public function test_guests_can_view_index(): void + { + $response = $this->get(route('w.index')); + $response->assertOk(); + } + + public function test_index_lists_writings(): void + { + $writing = Writing::factory()->create(); + + $response = $this->get(route('w.index')); + $response->assertSee($writing->title); + } + + // ─── Show ───────────────────────────────────────────────────────────────── + + public function test_guests_can_view_a_writing(): void + { + $writing = Writing::factory()->create(); + + $response = $this->get(route('w.show', $writing)); + $response->assertOk()->assertSee($writing->title); + } + + public function test_show_404s_for_missing_writing(): void + { + $response = $this->get(route('w.show', 99999)); + $response->assertNotFound(); + } + + // ─── Create ─────────────────────────────────────────────────────────────── + + public function test_guest_is_redirected_from_create(): void + { + $response = $this->get(route('w.create')); + $response->assertRedirect(route('login')); + } + + public function test_authenticated_user_can_see_create_form(): void + { + $user = User::factory()->create(); + + $response = $this->actingAs($user)->get(route('w.create')); + $response->assertOk(); + } + + // ─── Store ──────────────────────────────────────────────────────────────── + + public function test_guest_cannot_store_writing(): void + { + $response = $this->post(route('w.store'), [ + 'title' => 'Guest Writing', + 'content' => 'Should not be stored at all.', + ]); + $response->assertRedirect(route('login')); + $this->assertDatabaseMissing('writings', ['title' => 'Guest Writing']); + } + + public function test_user_can_store_writing(): void + { + $user = User::factory()->create(); + + $response = $this->actingAs($user)->post(route('w.store'), [ + 'title' => 'My New Writing', + 'content' => 'This is content that is long enough to pass validation.', + ]); + + $response->assertRedirect(); + $this->assertDatabaseHas('writings', [ + 'title' => 'My New Writing', + 'user_id' => $user->id, + ]); + } + + public function test_store_requires_title(): void + { + $user = User::factory()->create(); + + $response = $this->actingAs($user)->post(route('w.store'), [ + 'title' => '', + 'content' => 'Content long enough to pass.', + ]); + $response->assertSessionHasErrors('title'); + } + + public function test_store_requires_title_min_3_chars(): void + { + $user = User::factory()->create(); + + $response = $this->actingAs($user)->post(route('w.store'), [ + 'title' => 'AB', + 'content' => 'Content long enough to pass.', + ]); + $response->assertSessionHasErrors('title'); + } + + public function test_store_requires_content(): void + { + $user = User::factory()->create(); + + $response = $this->actingAs($user)->post(route('w.store'), [ + 'title' => 'Valid Title', + 'content' => '', + ]); + $response->assertSessionHasErrors('content'); + } + + public function test_store_requires_content_min_10_chars(): void + { + $user = User::factory()->create(); + + $response = $this->actingAs($user)->post(route('w.store'), [ + 'title' => 'Valid Title', + 'content' => 'Too short', + ]); + $response->assertSessionHasErrors('content'); + } + + // ─── Edit ───────────────────────────────────────────────────────────────── + + public function test_guest_is_redirected_from_edit(): void + { + $writing = Writing::factory()->create(); + + $response = $this->get(route('w.edit', $writing)); + $response->assertRedirect(route('login')); + } + + public function test_owner_can_access_edit_form(): void + { + $user = User::factory()->create(); + $writing = Writing::factory()->create(['user_id' => $user->id]); + + $response = $this->actingAs($user)->get(route('w.edit', $writing)); + $response->assertOk(); + } + + public function test_non_owner_cannot_access_edit_form(): void + { + $owner = User::factory()->create(); + $other = User::factory()->create(); + $writing = Writing::factory()->create(['user_id' => $owner->id]); + + $response = $this->actingAs($other)->get(route('w.edit', $writing)); + $response->assertForbidden(); + } + + public function test_admin_can_access_any_edit_form(): void + { + $owner = User::factory()->create(); + $admin = User::factory()->create(['role' => 0]); + $writing = Writing::factory()->create(['user_id' => $owner->id]); + + $response = $this->actingAs($admin)->get(route('w.edit', $writing)); + $response->assertOk(); + } + + // ─── Update ─────────────────────────────────────────────────────────────── + + public function test_owner_can_update_writing(): void + { + $user = User::factory()->create(); + $writing = Writing::factory()->create(['user_id' => $user->id]); + + $response = $this->actingAs($user)->put(route('w.update', $writing), [ + 'title' => 'Updated Title', + 'content' => 'Updated content that is long enough to pass validation.', + ]); + + $response->assertRedirect(route('w.show', $writing)); + $this->assertDatabaseHas('writings', [ + 'id' => $writing->id, + 'title' => 'Updated Title', + ]); + } + + public function test_non_owner_cannot_update_writing(): void + { + $owner = User::factory()->create(); + $other = User::factory()->create(); + $writing = Writing::factory()->create(['user_id' => $owner->id, 'title' => 'Original Title']); + + $response = $this->actingAs($other)->put(route('w.update', $writing), [ + 'title' => 'Hijacked Title', + 'content' => 'Hijacked content that is long enough.', + ]); + + $response->assertForbidden(); + $this->assertDatabaseHas('writings', ['id' => $writing->id, 'title' => 'Original Title']); + } + + public function test_admin_can_update_any_writing(): void + { + $owner = User::factory()->create(); + $admin = User::factory()->create(['role' => 0]); + $writing = Writing::factory()->create(['user_id' => $owner->id]); + + $response = $this->actingAs($admin)->put(route('w.update', $writing), [ + 'title' => 'Admin Updated Title', + 'content' => 'Admin updated content that is long enough.', + ]); + + $response->assertRedirect(route('w.show', $writing)); + $this->assertDatabaseHas('writings', ['id' => $writing->id, 'title' => 'Admin Updated Title']); + } + + public function test_update_validates_title(): void + { + $user = User::factory()->create(); + $writing = Writing::factory()->create(['user_id' => $user->id]); + + $response = $this->actingAs($user)->put(route('w.update', $writing), [ + 'title' => 'AB', + 'content' => 'Content long enough to pass.', + ]); + $response->assertSessionHasErrors('title'); + } + + // ─── Destroy ───────────────────────────────────────────────────────────── + + public function test_guest_cannot_delete_writing(): void + { + $writing = Writing::factory()->create(); + + $response = $this->delete(route('w.destroy', $writing)); + $response->assertRedirect(route('login')); + $this->assertDatabaseHas('writings', ['id' => $writing->id]); + } + + public function test_owner_can_delete_writing(): void + { + $user = User::factory()->create(); + $writing = Writing::factory()->create(['user_id' => $user->id]); + + $response = $this->actingAs($user)->delete(route('w.destroy', $writing)); + + $response->assertRedirect(route('w.index')); + $this->assertDatabaseMissing('writings', ['id' => $writing->id]); + } + + public function test_non_owner_cannot_delete_writing(): void + { + $owner = User::factory()->create(); + $other = User::factory()->create(); + $writing = Writing::factory()->create(['user_id' => $owner->id]); + + $response = $this->actingAs($other)->delete(route('w.destroy', $writing)); + + $response->assertForbidden(); + $this->assertDatabaseHas('writings', ['id' => $writing->id]); + } + + public function test_admin_can_delete_any_writing(): void + { + $owner = User::factory()->create(); + $admin = User::factory()->create(['role' => 0]); + $writing = Writing::factory()->create(['user_id' => $owner->id]); + + $response = $this->actingAs($admin)->delete(route('w.destroy', $writing)); + + $response->assertRedirect(route('w.index')); + $this->assertDatabaseMissing('writings', ['id' => $writing->id]); + } +} |
