From 4ae0edad496fd3ee195c84b2a6d3ebf686a349bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Helge-Mikael=20Nordg=C3=A5rd?= Date: Tue, 6 May 2025 00:13:06 +0200 Subject: [PATCH] Made test coverage for PageBuilder controllers and models --- .../Auth/AuthenticatedSessionController.php | 2 +- .../Auth/ConfirmablePasswordController.php | 2 +- ...mailVerificationNotificationController.php | 2 +- .../EmailVerificationPromptController.php | 2 +- .../Auth/VerifyEmailController.php | 4 +- database/factories/PageFactory.php | 30 +++ database/factories/PageRevisionFactory.php | 33 ++++ tests/Feature/Auth/AuthenticationTest.php | 2 +- tests/Feature/Auth/EmailVerificationTest.php | 2 +- tests/Feature/Auth/RegistrationTest.php | 2 +- tests/Feature/DashboardTest.php | 4 +- tests/Feature/PageBuilderTest.php | 179 ++++++++++++++++++ tests/Feature/PageRenderTest.php | 93 +++++++++ tests/Unit/PageRevisionTest.php | 23 +++ tests/Unit/PageTest.php | 25 +++ 15 files changed, 394 insertions(+), 11 deletions(-) create mode 100644 database/factories/PageFactory.php create mode 100644 database/factories/PageRevisionFactory.php create mode 100644 tests/Feature/PageBuilderTest.php create mode 100644 tests/Feature/PageRenderTest.php create mode 100644 tests/Unit/PageRevisionTest.php create mode 100644 tests/Unit/PageTest.php diff --git a/app/Http/Controllers/Auth/AuthenticatedSessionController.php b/app/Http/Controllers/Auth/AuthenticatedSessionController.php index dbb9365..f184845 100644 --- a/app/Http/Controllers/Auth/AuthenticatedSessionController.php +++ b/app/Http/Controllers/Auth/AuthenticatedSessionController.php @@ -33,7 +33,7 @@ class AuthenticatedSessionController extends Controller $request->session()->regenerate(); - return redirect()->intended(route('dashboard', absolute: false)); + return redirect()->intended(route('page-builder.index', absolute: false)); } /** diff --git a/app/Http/Controllers/Auth/ConfirmablePasswordController.php b/app/Http/Controllers/Auth/ConfirmablePasswordController.php index fb7d8e0..63752d1 100644 --- a/app/Http/Controllers/Auth/ConfirmablePasswordController.php +++ b/app/Http/Controllers/Auth/ConfirmablePasswordController.php @@ -36,6 +36,6 @@ class ConfirmablePasswordController extends Controller $request->session()->put('auth.password_confirmed_at', time()); - return redirect()->intended(route('dashboard', absolute: false)); + return redirect()->intended(route('page-builder.index', absolute: false)); } } diff --git a/app/Http/Controllers/Auth/EmailVerificationNotificationController.php b/app/Http/Controllers/Auth/EmailVerificationNotificationController.php index f64fa9b..e061c2c 100644 --- a/app/Http/Controllers/Auth/EmailVerificationNotificationController.php +++ b/app/Http/Controllers/Auth/EmailVerificationNotificationController.php @@ -14,7 +14,7 @@ class EmailVerificationNotificationController extends Controller public function store(Request $request): RedirectResponse { if ($request->user()->hasVerifiedEmail()) { - return redirect()->intended(route('dashboard', absolute: false)); + return redirect()->intended(route('page-builder.index', absolute: false)); } $request->user()->sendEmailVerificationNotification(); diff --git a/app/Http/Controllers/Auth/EmailVerificationPromptController.php b/app/Http/Controllers/Auth/EmailVerificationPromptController.php index bf57a20..9c4cfc6 100644 --- a/app/Http/Controllers/Auth/EmailVerificationPromptController.php +++ b/app/Http/Controllers/Auth/EmailVerificationPromptController.php @@ -16,7 +16,7 @@ class EmailVerificationPromptController extends Controller public function __invoke(Request $request): RedirectResponse|Response { return $request->user()->hasVerifiedEmail() - ? redirect()->intended(route('dashboard', absolute: false)) + ? redirect()->intended(route('page-builder.index', absolute: false)) : Inertia::render('auth/VerifyEmail', ['status' => $request->session()->get('status')]); } } diff --git a/app/Http/Controllers/Auth/VerifyEmailController.php b/app/Http/Controllers/Auth/VerifyEmailController.php index 2477faa..c31dfde 100644 --- a/app/Http/Controllers/Auth/VerifyEmailController.php +++ b/app/Http/Controllers/Auth/VerifyEmailController.php @@ -15,7 +15,7 @@ class VerifyEmailController extends Controller public function __invoke(EmailVerificationRequest $request): RedirectResponse { if ($request->user()->hasVerifiedEmail()) { - return redirect()->intended(route('dashboard', absolute: false).'?verified=1'); + return redirect()->intended(route('page-builder.index', absolute: false).'?verified=1'); } if ($request->user()->markEmailAsVerified()) { @@ -24,6 +24,6 @@ class VerifyEmailController extends Controller event(new Verified($user)); } - return redirect()->intended(route('dashboard', absolute: false).'?verified=1'); + return redirect()->intended(route('page-builder.index', absolute: false).'?verified=1'); } } diff --git a/database/factories/PageFactory.php b/database/factories/PageFactory.php new file mode 100644 index 0000000..ef09adf --- /dev/null +++ b/database/factories/PageFactory.php @@ -0,0 +1,30 @@ + + */ +class PageFactory extends Factory +{ + protected $model = Page::class; + + public function definition(): array { + return [ + 'user_id' => User::factory(), + 'title' => $this->faker->sentence, + 'slug' => $this->faker->slug, + 'content' => ['blocks' => []], + 'is_published' => $this->faker->boolean, + 'main' => false, + 'linked' => false, + 'linkorder' => $this->faker->numberBetween(1, 10), + 'visibility' => 'public', + ]; + } +} diff --git a/database/factories/PageRevisionFactory.php b/database/factories/PageRevisionFactory.php new file mode 100644 index 0000000..1450be9 --- /dev/null +++ b/database/factories/PageRevisionFactory.php @@ -0,0 +1,33 @@ + + */ +class PageRevisionFactory extends Factory +{ + /** + * Define the model's default state. + * + * @return array + */ + public function definition(): array { + return [ + 'page_id' => Page::factory(), + 'user_id' => User::factory(), + 'version' => 1, + 'content' => ['blocks' => []], + 'title' => $this->faker->sentence, + 'slug' => $this->faker->slug, + 'label' => $this->faker->randomElement(['auto-save', 'manual-save', 'published', 'restored']), + 'active' => true, + ]; + } +} diff --git a/tests/Feature/Auth/AuthenticationTest.php b/tests/Feature/Auth/AuthenticationTest.php index c59d166..809c486 100644 --- a/tests/Feature/Auth/AuthenticationTest.php +++ b/tests/Feature/Auth/AuthenticationTest.php @@ -27,7 +27,7 @@ class AuthenticationTest extends TestCase ]); $this->assertAuthenticated(); - $response->assertRedirect(route('dashboard', absolute: false)); + $response->assertRedirect(route('page-builder.index', absolute: false)); } public function test_users_can_not_authenticate_with_invalid_password() diff --git a/tests/Feature/Auth/EmailVerificationTest.php b/tests/Feature/Auth/EmailVerificationTest.php index 627fe70..6bbf87a 100644 --- a/tests/Feature/Auth/EmailVerificationTest.php +++ b/tests/Feature/Auth/EmailVerificationTest.php @@ -38,7 +38,7 @@ class EmailVerificationTest extends TestCase Event::assertDispatched(Verified::class); $this->assertTrue($user->fresh()->hasVerifiedEmail()); - $response->assertRedirect(route('dashboard', absolute: false).'?verified=1'); + $response->assertRedirect(route('page-builder.index', absolute: false).'?verified=1'); } public function test_email_is_not_verified_with_invalid_hash() diff --git a/tests/Feature/Auth/RegistrationTest.php b/tests/Feature/Auth/RegistrationTest.php index d0c3ea2..b850508 100644 --- a/tests/Feature/Auth/RegistrationTest.php +++ b/tests/Feature/Auth/RegistrationTest.php @@ -26,6 +26,6 @@ class RegistrationTest extends TestCase ]); $this->assertAuthenticated(); - $response->assertRedirect(route('dashboard', absolute: false)); + $response->assertRedirect(route('page-builder.index', absolute: false)); } } diff --git a/tests/Feature/DashboardTest.php b/tests/Feature/DashboardTest.php index 5903f8f..947970e 100644 --- a/tests/Feature/DashboardTest.php +++ b/tests/Feature/DashboardTest.php @@ -12,7 +12,7 @@ class DashboardTest extends TestCase public function test_guests_are_redirected_to_the_login_page() { - $response = $this->get('/dashboard'); + $response = $this->get('/dashboard/page-admin'); $response->assertRedirect('/login'); } @@ -21,7 +21,7 @@ class DashboardTest extends TestCase $user = User::factory()->create(); $this->actingAs($user); - $response = $this->get('/dashboard'); + $response = $this->get('/dashboard/page-admin'); $response->assertStatus(200); } } diff --git a/tests/Feature/PageBuilderTest.php b/tests/Feature/PageBuilderTest.php new file mode 100644 index 0000000..aec9fc9 --- /dev/null +++ b/tests/Feature/PageBuilderTest.php @@ -0,0 +1,179 @@ +create(); + + $response = $this->actingAs($user)->post('/dashboard/page-admin/landing-pages/create', [ + 'title' => 'Test Page', + 'content' => json_encode(['blocks' => []]), + 'publish' => true, + 'mainpage' => false, + 'linked' => false, + 'linkorder' => 1, + 'visibility' => 'public', + ]); + + $response->assertRedirect(); + $this->assertDatabaseHas('pages', ['title' => 'Test Page']); + $this->assertDatabaseHas('page_revisions', ['title' => 'Test Page', 'label' => 'published']); + } + + public function test_authenticated_user_can_update_page() { + $user = User::factory()->create(); + + $page = Page::factory()->create(['user_id' => $user->id]); + $revision = PageRevision::factory()->create([ + 'page_id' => $page->id, + 'user_id' => $user->id, + 'active' => true, + ]); + + $response = $this->actingAs($user)->patch('/dashboard/page-admin/landing-pages/patch', [ + 'revision_uuid' => $revision->uuid, + 'title' => 'Updated Title', + 'content' => json_encode(['blocks' => [['type' => 'text', 'data' => 'updated']]]), + 'publish' => true, + 'mainpage' => false, + 'linked' => false, + 'linkorder' => 2, + 'visibility' => 'public', + ]); + + $response->assertRedirect(); + + $this->assertDatabaseHas('pages', [ + 'id' => $page->id, + 'title' => 'Updated Title', + 'is_published' => true, + ]); + + $this->assertDatabaseHas('page_revisions', [ + 'id' => $revision->id, + 'title' => 'Updated Title', + 'label' => 'published', + ]); + } + + public function test_authenticated_user_can_delete_page() { + $user = User::factory()->create(); + $page = Page::factory()->create(['user_id' => $user->id]); + + $response = $this->actingAs($user)->delete('/dashboard/page-admin/landing-pages/delete', [ + 'id' => $page->id, + ]); + + $response->assertRedirect(route('page-builder.index')); + $this->assertDatabaseMissing('pages', ['id' => $page->id]); + } + + public function test_unauthorized_user_cannot_delete_page() { + $owner = User::factory()->create(); + $otherUser = User::factory()->create(); + $page = Page::factory()->create(['user_id' => $owner->id]); + + $response = $this->actingAs($otherUser)->delete('/dashboard/page-admin/landing-pages/delete', [ + 'id' => $page->id, + ]); + + $response->assertRedirect(route('page-builder.index')); + $response->assertSessionHas('error', 'Du er ikke forfatteren av denne siden og kan derfor ikke slette den.'); + + $this->assertDatabaseHas('pages', ['id' => $page->id]); + } + + public function test_unauthenticated_user_cannot_access_pagebuilder() { + $response = $this->get('/dashboard/page-admin'); + + $response->assertRedirect('/login'); + } + + public function test_user_can_publish_existing_revision() { + $user = User::factory()->create(); + $page = Page::factory()->create([ + 'user_id' => $user->id, + 'is_published' => false, + 'main' => false, + 'visibility' => 'public', + ]); + + $revision = PageRevision::factory()->create([ + 'page_id' => $page->id, + 'user_id' => $user->id, + 'active' => true, + 'label' => 'manual-save', + 'content' => json_encode(['blocks' => [['type' => 'text', 'data' => 'initial']]]), + ]); + + $response = $this->actingAs($user)->patch('/dashboard/page-admin/landing-pages/patch', [ + 'revision_uuid' => $revision->uuid, + 'title' => 'Published Update', + 'content' => json_encode(['blocks' => [['type' => 'text', 'data' => 'updated']]]), + 'publish' => true, + 'mainpage' => false, + 'linked' => false, + 'linkorder' => 1, + 'visibility' => 'public', + ]); + + $response->assertRedirect(); + $this->assertDatabaseHas('pages', [ + 'id' => $page->id, + 'title' => 'Published Update', + 'is_published' => true, + ]); + $this->assertDatabaseHas('page_revisions', [ + 'id' => $revision->id, + 'title' => 'Published Update', + 'label' => 'published', + ]); + } + + public function test_user_can_save_as_new_revision() { + $user = User::factory()->create(); + $page = Page::factory()->create(['user_id' => $user->id]); + + PageRevision::factory()->create([ + 'page_id' => $page->id, + 'user_id' => $user->id, + 'active' => true, + 'label' => 'published', + 'content' => json_encode(['blocks' => [['type' => 'text', 'data' => 'original']]]), + ]); + + $response = $this->actingAs($user)->post('/dasboard/page-admin/landing-pages/save-as', [ + 'page_id' => $page->id, + 'title' => 'Saved As New Revision', + 'content' => json_encode(['blocks' => [['type' => 'text', 'data' => 'new version']]]), + 'publish' => false, + 'mainpage' => false, + 'linked' => false, + 'linkorder' => 1, + 'visibility' => 'public', + ]); + + $response->assertRedirect(); + + $this->assertDatabaseHas('page_revisions', [ + 'page_id' => $page->id, + 'title' => 'Saved As New Revision', + 'label' => 'manual-save', + 'active' => false, + ]); + + $this->assertDatabaseCount('page_revisions', 2); + } +} diff --git a/tests/Feature/PageRenderTest.php b/tests/Feature/PageRenderTest.php new file mode 100644 index 0000000..aea639f --- /dev/null +++ b/tests/Feature/PageRenderTest.php @@ -0,0 +1,93 @@ +create([ + 'is_published' => true, + 'main' => false, + 'visibility' => 'public', + ]); + + PageRevision::factory()->create([ + 'page_id' => $page->id, + 'user_id' => $page->user_id, + 'active' => true, + 'content' => json_encode(['blocks' => []]), + 'label' => 'published', + ]); + + $response = $this->get('/p/' . $page->slug); + + $response->assertStatus(200); + $response->assertInertia(fn ($page) => $page->component('Root')); + } + + public function test_main_page_returns_404_if_viewed_with_slug() { + $page = Page::factory()->create([ + 'is_published' => true, + 'main' => true, + 'visibility' => 'public', + ]); + + PageRevision::factory()->create([ + 'page_id' => $page->id, + 'user_id' => $page->user_id, + 'active' => true, + 'content' => json_encode(['blocks' => []]), + 'label' => 'published', + ]); + + $response = $this->get('/p/' . $page->slug); + $response->assertStatus(404); + } + + public function test_unpublished_page_returns_403() { + $page = Page::factory()->create([ + 'is_published' => false, + 'main' => false, + 'visibility' => 'public', + ]); + + PageRevision::factory()->create([ + 'page_id' => $page->id, + 'user_id' => $page->user_id, + 'active' => true, + 'content' => json_encode(['blocks' => []]), + 'label' => 'manual-save', + ]); + + $response = $this->get('/p/' . $page->slug); + $response->assertStatus(403); + } + + public function test_private_page_redirects_for_guests() { + $page = Page::factory()->create([ + 'is_published' => true, + 'main' => false, + 'visibility' => 'private', + ]); + + PageRevision::factory()->create([ + 'page_id' => $page->id, + 'user_id' => $page->user_id, + 'active' => true, + 'content' => json_encode(['blocks' => []]), + 'label' => 'published', + ]); + + $response = $this->get('/p/' . $page->slug); + $response->assertStatus(403); + } +} diff --git a/tests/Unit/PageRevisionTest.php b/tests/Unit/PageRevisionTest.php new file mode 100644 index 0000000..1c4bab6 --- /dev/null +++ b/tests/Unit/PageRevisionTest.php @@ -0,0 +1,23 @@ +create(); + $this->assertDatabaseHas('page_revisions', ['id' => $revision->id]); + } + + public function test_revision_has_uuid_and_version() { + $revision = PageRevision::factory()->create(); + $this->assertNotNull($revision->uuid); + $this->assertGreaterThan(0, $revision->version); + } +} diff --git a/tests/Unit/PageTest.php b/tests/Unit/PageTest.php new file mode 100644 index 0000000..9b3a609 --- /dev/null +++ b/tests/Unit/PageTest.php @@ -0,0 +1,25 @@ +create(); + $this->assertDatabaseHas('pages', ['id' => $page->id]); + } + + public function test_page_has_author_relationship() + { + $page = Page::factory()->create(); + $this->assertInstanceOf(User::class, $page->author); + } +}