Files
jouwdriedee/tests/Feature/AdminContentTest.php
T

307 lines
12 KiB
PHP

<?php
namespace Tests\Feature;
use App\Models\Category;
use App\Models\Order;
use App\Models\Product;
use App\Models\Setting;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Tests\TestCase;
class AdminContentTest extends TestCase
{
use RefreshDatabase;
protected User $admin;
protected function setUp(): void
{
parent::setUp();
$this->admin = User::create([
'name' => 'Admin Jouwdriedee',
'email' => 'info@jouwdriedee.nl',
'password' => bcrypt('Jw3D!x9#QmK7$vR2'),
'is_admin' => true,
]);
}
public function test_guest_is_redirected_to_login_when_accessing_admin(): void
{
$response = $this->get(route('admin.content.index'));
$response->assertRedirect(route('login'));
}
public function test_regular_customer_cannot_access_admin(): void
{
$customer = User::create([
'name' => 'Klant Piet',
'email' => 'piet@example.com',
'password' => bcrypt('secret1234'),
'is_admin' => false,
]);
$response = $this->actingAs($customer)->get(route('admin.content.index'));
$response->assertRedirect(route('home'));
$response->assertSessionHas('error');
}
public function test_admin_content_editor_loads_successfully(): void
{
$response = $this->actingAs($this->admin)->get(route('admin.content.index'));
$response->assertStatus(200);
$response->assertSee('Homepage Hero');
$response->assertSee('Shop Content & Stijl CMS', false);
}
public function test_admin_can_update_layout_and_texts(): void
{
$payload = [
'site_name' => 'Mega 3D Shop',
'hero_title' => 'Custom 3D Speelgoed & Figuren',
'hero_subtitle' => 'Nieuwe custom introductietekst voor de winkel.',
'hero_primary_btn_text' => 'Direct Winkelen',
'usp_title' => 'Waarom kiezen voor onze prints?',
'footer_email' => 'hallo@mega3d.nl',
'announcement_enabled' => '1',
'announcement_text' => 'Tijdelijke actie: gratis verzending!',
];
$response = $this->actingAs($this->admin)->post(route('admin.content.update'), $payload);
$response->assertRedirect(route('admin.content.index'));
$response->assertSessionHas('success');
$this->assertSame('Mega 3D Shop', Setting::get('site_name'));
$this->assertSame('Custom 3D Speelgoed & Figuren', Setting::get('hero_title'));
$this->assertSame('hallo@mega3d.nl', Setting::get('footer_email'));
// Homepage should now display the updated content!
$homeResponse = $this->get(route('home'));
$homeResponse->assertStatus(200);
$homeResponse->assertSee('Custom 3D Speelgoed & Figuren');
$homeResponse->assertSee('Nieuwe custom introductietekst voor de winkel.');
$homeResponse->assertSee('Direct Winkelen');
$homeResponse->assertSee('Waarom kiezen voor onze prints?');
$homeResponse->assertSee('hallo@mega3d.nl');
$homeResponse->assertSee('Tijdelijke actie: gratis verzending!');
}
public function test_admin_can_reset_content_to_defaults(): void
{
Setting::set('hero_title', 'Tijdelijke Titel');
$this->assertSame('Tijdelijke Titel', Setting::get('hero_title'));
$response = $this->actingAs($this->admin)->post(route('admin.content.reset'));
$response->assertRedirect(route('admin.content.index'));
$this->assertNull(Setting::get('hero_title'));
}
public function test_admin_can_view_and_edit_products(): void
{
$category = Category::create([
'name' => 'Fidgets',
'slug' => 'fidgets',
]);
$product = Product::create([
'name' => 'Test Fidget Draak',
'slug' => 'test-fidget-draak',
'category_id' => $category->id,
'base_price' => 12.50,
'short_description' => 'Korte test',
'description' => 'Uitgebreide test beschrijving',
'is_active' => true,
]);
// Products index
$indexResponse = $this->actingAs($this->admin)->get(route('admin.products.index'));
$indexResponse->assertStatus(200);
$indexResponse->assertSee('Test Fidget Draak');
// Edit page
$editResponse = $this->actingAs($this->admin)->get(route('admin.products.edit', $product));
$editResponse->assertStatus(200);
$editResponse->assertSee('Test Fidget Draak');
// Update product
$updateResponse = $this->actingAs($this->admin)->put(route('admin.products.update', $product), [
'name' => 'Aangepaste Fidget Draak',
'category_id' => $category->id,
'base_price' => 18.00,
'short_description' => 'Geüpdatete korte test',
'description' => 'Nieuwe lange beschrijving',
'is_active' => 1,
'is_featured' => 1,
]);
$updateResponse->assertRedirect(route('admin.products.index'));
$this->assertDatabaseHas('products', [
'id' => $product->id,
'name' => 'Aangepaste Fidget Draak',
'base_price' => 18.00,
]);
}
public function test_admin_can_view_orders(): void
{
$order = Order::create([
'order_number' => 'ORD-TEST-999',
'customer_name' => 'Jan Jansen',
'customer_email' => 'jan@example.com',
'shipping_street' => 'Dorpstraat',
'shipping_number' => '1',
'shipping_postal_code' => '1234AB',
'shipping_city' => 'Amsterdam',
'subtotal' => 25.00,
'shipping_cost' => 0.00,
'total' => 25.00,
'status' => 'pending',
]);
$response = $this->actingAs($this->admin)->get(route('admin.orders.index'));
$response->assertStatus(200);
$response->assertSee('ORD-TEST-999');
$response->assertSee('Jan Jansen');
$showResponse = $this->actingAs($this->admin)->get(route('admin.orders.show', $order));
$showResponse->assertStatus(200);
$showResponse->assertSee('ORD-TEST-999');
}
public function test_admin_can_update_product_images_and_gallery(): void
{
$category = Category::create([
'name' => 'Fidget Gadgets',
'slug' => 'fidget-gadgets-gallery-test',
]);
$product = Product::create([
'category_id' => $category->id,
'name' => 'Multi Foto Draak',
'slug' => 'multi-foto-draak',
'short_description' => 'Test met meerdere fotos',
'description' => 'Test beschrijving met galerij',
'base_price' => 19.95,
'image_url' => 'https://cdn.example.com/cover.jpg',
'gallery_images' => ['https://cdn.example.com/photo1.jpg', 'https://cdn.example.com/photo2.jpg'],
'is_active' => true,
]);
// Edit page loads with visual image gallery
$editResponse = $this->actingAs($this->admin)->get(route('admin.products.edit', $product));
$editResponse->assertStatus(200);
$editResponse->assertSee('Productafbeeldingen & Fotogalerij', false);
$editResponse->assertSee('Hoofdafbeelding (Cover)');
// Update product with new cover and extra gallery images
$updateResponse = $this->actingAs($this->admin)->put(route('admin.products.update', $product), [
'name' => 'Multi Foto Draak Bijgewerkt',
'category_id' => $category->id,
'base_price' => 21.50,
'short_description' => 'Geüpdatet',
'description' => 'Nieuwe omschrijving',
'image_url' => 'https://cdn.example.com/new-cover.jpg',
'gallery_images' => [
'https://cdn.example.com/photo1.jpg',
'https://cdn.example.com/photo2.jpg',
'https://cdn.example.com/photo3.jpg',
'https://cdn.example.com/new-cover.jpg', // Should be excluded because it matches cover
],
'is_active' => 1,
]);
$updateResponse->assertRedirect(route('admin.products.index'));
$product->refresh();
$this->assertEquals('https://cdn.example.com/new-cover.jpg', $product->image_url);
$this->assertCount(3, $product->gallery_images);
$this->assertContains('https://cdn.example.com/photo3.jpg', $product->gallery_images);
$this->assertNotContains('https://cdn.example.com/new-cover.jpg', $product->gallery_images);
// Storefront product details page shows the multi-image gallery
$shopResponse = $this->get(route('product.show', $product->slug));
$shopResponse->assertStatus(200);
$shopResponse->assertSee('https://cdn.example.com/new-cover.jpg');
$shopResponse->assertSee('https://cdn.example.com/photo1.jpg');
$shopResponse->assertSee('https://cdn.example.com/photo3.jpg');
}
public function test_admin_can_upload_product_image(): void
{
Storage::fake('public');
$onePixelJpeg = base64_decode('/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAP//////////////////////////////////////////////////////////////////////////////////////wgALCAABAAEBAREA/8QAFBABAAAAAAAAAAAAAAAAAAAAAP/aAAgBAQABPxA=');
$file = UploadedFile::fake()->createWithContent('test-print-photo.jpg', $onePixelJpeg);
$response = $this->actingAs($this->admin)->postJson(route('admin.products.upload-image'), [
'image' => $file,
]);
$response->assertStatus(200);
$response->assertJson([
'success' => true,
]);
$url = $response->json('url');
$this->assertStringStartsWith('/storage/products/', $url);
$storagePath = str_replace('/storage/', '', $url);
Storage::disk('public')->assertExists($storagePath);
}
public function test_admin_can_toggle_webshop_offline_mode(): void
{
$this->assertEquals('0', Setting::get('shop_offline', '0'));
// Toggle offline via admin button
$response = $this->actingAs($this->admin)->post(route('admin.toggle-offline'));
$response->assertRedirect();
Setting::flushCache();
$this->assertEquals('1', Setting::get('shop_offline'));
// Logout admin so subsequent requests are unauthenticated guest requests
auth()->logout();
$this->flushSession();
// Guest visitor receives 503 with big red offline banner
$guestResponse = $this->get(route('home'));
$guestResponse->assertStatus(503);
$guestResponse->assertSee('Aan deze webshop wordt hard gewerkt', false);
$guestResponse->assertSee('Webshop Tijdelijk Offline');
// Other customer routes are blocked
$catalogResponse = $this->get(route('catalog'));
$catalogResponse->assertStatus(503);
// Login page remains accessible
$loginResponse = $this->get(route('login'));
$loginResponse->assertStatus(200);
// Admin can still view storefront normally with preview banner
$adminShopResponse = $this->actingAs($this->admin)->get(route('home'));
$adminShopResponse->assertStatus(200);
$adminShopResponse->assertSee('OFFLINE BEHEERDERS-PREVIEW');
// Toggle back online
$this->actingAs($this->admin)->post(route('admin.toggle-offline'));
Setting::flushCache();
$this->assertEquals('0', Setting::get('shop_offline'));
// Logout admin and verify guest can visit normally again
auth()->logout();
$this->flushSession();
$guestOnlineResponse = $this->get(route('home'));
$guestOnlineResponse->assertStatus(200);
}
}