seed(\Database\Seeders\PermissionSeeder::class); // 2. Create the 'Theme Manager' role $role = Role::create([ 'name' => 'Theme Manager', 'slug' => 'theme-manager', 'description' => 'Can manage themes', ]); // 3. Assign theme related permissions $themePermissions = Permission::whereIn('slug', [ 'view-themes', 'activate-themes', 'upload-themes', 'edit-themes' ])->pluck('id'); $role->permissions()->sync($themePermissions); // 4. Create user and assign the role $user = User::factory()->create([ 'email' => 'themes@siteweaver.test' ]); $user->roles()->attach($role); // 5. Try to access the admin dashboard $adminPath = env('ADMIN_PATH', 'loom'); $response = $this->actingAs($user)->get('/' . $adminPath); $response->assertStatus(200); // 6. Try to access the themes index $response = $this->actingAs($user)->get('/' . $adminPath . '/themes'); $response->assertStatus(200); // 7. Try to access the theme editor $response = $this->actingAs($user)->get('/' . $adminPath . '/themes/editor'); $response->assertStatus(200); // 8. Try to access pages (should fail as they don't have view-pages) $response = $this->actingAs($user)->get('/' . $adminPath . '/pages'); $response->assertStatus(403); } public function test_editor_can_access_dashboard_and_pages(): void { $this->seed(\Database\Seeders\PermissionSeeder::class); $this->seed(\Database\Seeders\RoleSeeder::class); $user = User::factory()->create(); $user->roles()->attach(Role::where('slug', 'editor')->first()); $adminPath = env('ADMIN_PATH', 'loom'); $response = $this->actingAs($user)->get('/' . $adminPath); $response->assertStatus(200); $response = $this->actingAs($user)->get('/' . $adminPath . '/pages'); $response->assertStatus(200); // Editor cannot view users $response = $this->actingAs($user)->get('/' . $adminPath . '/users'); $response->assertStatus(403); } public function test_admin_has_global_access_via_middleware_bypass(): void { $this->seed(\Database\Seeders\PermissionSeeder::class); $this->seed(\Database\Seeders\RoleSeeder::class); // Create an admin user - note that in the seeder, 'admin' role might have permissions, // but we want to test the bypass specifically. $user = User::factory()->create(); $user->roles()->attach(Role::where('slug', 'admin')->first()); $adminPath = env('ADMIN_PATH', 'loom'); // Admin can access everything $this->actingAs($user)->get('/' . $adminPath)->assertStatus(200); $this->actingAs($user)->get('/' . $adminPath . '/pages')->assertStatus(200); $this->actingAs($user)->get('/' . $adminPath . '/users')->assertStatus(200); $this->actingAs($user)->get('/' . $adminPath . '/roles')->assertStatus(200); $this->actingAs($user)->get('/' . $adminPath . '/analytics')->assertStatus(200); } public function test_editor_loses_access_when_permission_is_removed(): void { $this->seed(\Database\Seeders\PermissionSeeder::class); $this->seed(\Database\Seeders\RoleSeeder::class); $user = User::factory()->create(); $role = Role::where('slug', 'editor')->first(); $user->roles()->attach($role); $adminPath = env('ADMIN_PATH', 'loom'); // Initially has access $this->actingAs($user)->get('/' . $adminPath . '/pages')->assertStatus(200); // Remove the permission from the role $permission = Permission::where('slug', 'view-pages')->first(); $role->permissions()->detach($permission->id); // Now should be forbidden (403) $this->actingAs($user)->get('/' . $adminPath . '/pages')->assertStatus(403); } public function test_navigation_and_dashboard_items_hidden_based_on_permissions(): void { $this->seed(\Database\Seeders\PermissionSeeder::class); // Create a role with ONLY view-pages permission $role = Role::create([ 'name' => 'Page Viewer', 'slug' => 'page-viewer', ]); $permission = Permission::where('slug', 'view-pages')->first(); $role->permissions()->attach($permission->id); $user = User::factory()->create(); $user->roles()->attach($role); $adminPath = env('ADMIN_PATH', 'loom'); $response = $this->actingAs($user)->get('/' . $adminPath); $response->assertStatus(200); // Verify "Pages" is visible in navigation $response->assertSee('Pages'); $response->assertSee('file icon'); // Verify "Users", "Themes", "Backups", "Navigation" are NOT visible in navigation $response->assertDontSee('Users'); $response->assertDontSee('Themes'); $response->assertDontSee('Backups'); $response->assertDontSee('Navigation'); // Verify Dashboard cards visibility (Svelte component data) // Check for the data-permissions attribute in the dashboard view $response->assertSee('data-permissions'); $response->assertSee('view-pages', false); $response->assertSee('true', false); $response->assertSee('view-themes', false); $response->assertSee('false', false); } public function test_admin_sees_all_cards_in_dashboard_data(): void { $this->seed(\Database\Seeders\PermissionSeeder::class); $this->seed(\Database\Seeders\RoleSeeder::class); $user = User::factory()->create(); $user->roles()->attach(Role::where('slug', 'admin')->first()); $adminPath = env('ADMIN_PATH', 'loom'); $response = $this->actingAs($user)->get('/' . $adminPath); $response->assertStatus(200); // All permissions should be true for admin in data-permissions attribute $response->assertSee('data-permissions'); $response->assertSee('"view-pages":true', false); $response->assertSee('"view-themes":true', false); $response->assertSee('"view-users":true', false); $response->assertSee('"view-roles":true', false); $response->assertSee('"manage-settings":true', false); } public function test_media_manager_buttons_visibility_based_on_permissions(): void { $this->seed(\Database\Seeders\PermissionSeeder::class); // Create a role with view-media but NO upload-media or delete-media $role = Role::create([ 'name' => 'Media Viewer', 'slug' => 'media-viewer', ]); $role->permissions()->attach(Permission::where('slug', 'view-media')->first()->id); $user = User::factory()->create(); $user->roles()->attach($role); $adminPath = env('ADMIN_PATH', 'loom'); $response = $this->actingAs($user)->get('/' . $adminPath . '/media'); $response->assertStatus(200); // Verify "upload-media" is false in Svelte component data $response->assertSee('"upload-media":false', false); $response->assertSee('"delete-media":false', false); $response->assertSee('"update-media":false', false); // Verify "view-media" is true $response->assertSee('"view-media":true', false); // Create a role with upload-media $role2 = Role::create([ 'name' => 'Media Creator', 'slug' => 'media-creator', ]); $role2->permissions()->attach(Permission::where('slug', 'view-media')->first()->id); $role2->permissions()->attach(Permission::where('slug', 'upload-media')->first()->id); $user2 = User::factory()->create(); $user2->roles()->attach($role2); $response = $this->actingAs($user2)->get('/' . $adminPath . '/media'); $response->assertStatus(200); $response->assertSee('"upload-media":true', false); $response->assertSee('"delete-media":false', false); } public function test_page_editor_passes_media_permissions_to_picker(): void { $this->seed(\Database\Seeders\PermissionSeeder::class); $role = Role::create([ 'name' => 'Page Editor Limited', 'slug' => 'page-editor-limited', ]); $role->permissions()->attach(Permission::where('slug', 'view-pages')->first()->id); $role->permissions()->attach(Permission::where('slug', 'create-pages')->first()->id); $role->permissions()->attach(Permission::where('slug', 'edit-pages')->first()->id); // NO media permissions $user = User::factory()->create(); $user->roles()->attach($role); $adminPath = env('ADMIN_PATH', 'loom'); $response = $this->actingAs($user)->get('/' . $adminPath . '/pages/create'); $response->assertStatus(200); // Verify "upload-media" is false in data-permissions $response->assertSee('data-permissions'); $response->assertSee('"upload-media":false', false); // Grant upload-media $role->permissions()->attach(Permission::where('slug', 'upload-media')->first()->id); $response = $this->actingAs($user)->get('/' . $adminPath . '/pages/create'); $response->assertStatus(200); $response->assertSee('"upload-media":true', false); } }