feat: complete user authentication, admin guard, customer account dashboard and branded HTML emails
This commit is contained in:
@@ -6,6 +6,7 @@ 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 Tests\TestCase;
|
||||
|
||||
@@ -13,10 +14,46 @@ class AdminContentTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_admin_content_editor_loads_successfully(): void
|
||||
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);
|
||||
@@ -35,7 +72,7 @@ class AdminContentTest extends TestCase
|
||||
'announcement_text' => 'Tijdelijke actie: gratis verzending!',
|
||||
];
|
||||
|
||||
$response = $this->post(route('admin.content.update'), $payload);
|
||||
$response = $this->actingAs($this->admin)->post(route('admin.content.update'), $payload);
|
||||
|
||||
$response->assertRedirect(route('admin.content.index'));
|
||||
$response->assertSessionHas('success');
|
||||
@@ -60,7 +97,7 @@ class AdminContentTest extends TestCase
|
||||
Setting::set('hero_title', 'Tijdelijke Titel');
|
||||
$this->assertSame('Tijdelijke Titel', Setting::get('hero_title'));
|
||||
|
||||
$response = $this->post(route('admin.content.reset'));
|
||||
$response = $this->actingAs($this->admin)->post(route('admin.content.reset'));
|
||||
$response->assertRedirect(route('admin.content.index'));
|
||||
|
||||
$this->assertNull(Setting::get('hero_title'));
|
||||
@@ -84,17 +121,17 @@ class AdminContentTest extends TestCase
|
||||
]);
|
||||
|
||||
// Products index
|
||||
$indexResponse = $this->get(route('admin.products.index'));
|
||||
$indexResponse = $this->actingAs($this->admin)->get(route('admin.products.index'));
|
||||
$indexResponse->assertStatus(200);
|
||||
$indexResponse->assertSee('Test Fidget Draak');
|
||||
|
||||
// Edit page
|
||||
$editResponse = $this->get(route('admin.products.edit', $product));
|
||||
$editResponse = $this->actingAs($this->admin)->get(route('admin.products.edit', $product));
|
||||
$editResponse->assertStatus(200);
|
||||
$editResponse->assertSee('Test Fidget Draak');
|
||||
|
||||
// Update product
|
||||
$updateResponse = $this->put(route('admin.products.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,
|
||||
@@ -128,12 +165,12 @@ class AdminContentTest extends TestCase
|
||||
'status' => 'pending',
|
||||
]);
|
||||
|
||||
$response = $this->get(route('admin.orders.index'));
|
||||
$response = $this->actingAs($this->admin)->get(route('admin.orders.index'));
|
||||
$response->assertStatus(200);
|
||||
$response->assertSee('ORD-TEST-999');
|
||||
$response->assertSee('Jan Jansen');
|
||||
|
||||
$showResponse = $this->get(route('admin.orders.show', $order));
|
||||
$showResponse = $this->actingAs($this->admin)->get(route('admin.orders.show', $order));
|
||||
$showResponse->assertStatus(200);
|
||||
$showResponse->assertSee('ORD-TEST-999');
|
||||
}
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Mail\OrderConfirmationMail;
|
||||
use App\Mail\PasswordResetMail;
|
||||
use App\Mail\WelcomeMail;
|
||||
use App\Models\Category;
|
||||
use App\Models\Material;
|
||||
use App\Models\Product;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AuthAndEmailTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_customer_can_register_and_receives_welcome_email(): void
|
||||
{
|
||||
Mail::fake();
|
||||
|
||||
$response = $this->post(route('register.submit'), [
|
||||
'name' => 'Sophie de Vries',
|
||||
'email' => 'sophie@example.com',
|
||||
'password' => 'VeiligWachtwoord123!',
|
||||
'password_confirmation' => 'VeiligWachtwoord123!',
|
||||
]);
|
||||
|
||||
$response->assertRedirect(route('account.index'));
|
||||
$this->assertAuthenticated();
|
||||
|
||||
$this->assertDatabaseHas('users', [
|
||||
'email' => 'sophie@example.com',
|
||||
'name' => 'Sophie de Vries',
|
||||
'is_admin' => false,
|
||||
]);
|
||||
|
||||
Mail::assertSent(WelcomeMail::class, function ($mail) {
|
||||
return $mail->hasTo('sophie@example.com')
|
||||
&& str_contains($mail->envelope()->subject, 'Welkom bij Jouwdriedee.nl');
|
||||
});
|
||||
}
|
||||
|
||||
public function test_customer_can_login_with_valid_credentials(): void
|
||||
{
|
||||
$user = User::create([
|
||||
'name' => 'Lars Bakker',
|
||||
'email' => 'lars@example.com',
|
||||
'password' => Hash::make('MijnGeheimeWachtwoord'),
|
||||
'is_admin' => false,
|
||||
]);
|
||||
|
||||
$response = $this->post(route('login.submit'), [
|
||||
'email' => 'lars@example.com',
|
||||
'password' => 'MijnGeheimeWachtwoord',
|
||||
]);
|
||||
|
||||
$response->assertRedirect(route('account.index'));
|
||||
$this->assertAuthenticatedAs($user);
|
||||
}
|
||||
|
||||
public function test_admin_login_redirects_to_admin_content_dashboard(): void
|
||||
{
|
||||
$admin = User::create([
|
||||
'name' => 'Jouwdriedee Beheer',
|
||||
'email' => 'info@jouwdriedee.nl',
|
||||
'password' => Hash::make('Jw3D!x9#QmK7$vR2'),
|
||||
'is_admin' => true,
|
||||
]);
|
||||
|
||||
$response = $this->post(route('login.submit'), [
|
||||
'email' => 'info@jouwdriedee.nl',
|
||||
'password' => 'Jw3D!x9#QmK7$vR2',
|
||||
]);
|
||||
|
||||
$response->assertRedirect(route('admin.content.index'));
|
||||
$this->assertAuthenticatedAs($admin);
|
||||
}
|
||||
|
||||
public function test_login_fails_with_invalid_credentials(): void
|
||||
{
|
||||
User::create([
|
||||
'name' => 'Lars Bakker',
|
||||
'email' => 'lars@example.com',
|
||||
'password' => Hash::make('MijnGeheimeWachtwoord'),
|
||||
]);
|
||||
|
||||
$response = $this->post(route('login.submit'), [
|
||||
'email' => 'lars@example.com',
|
||||
'password' => 'FoutWachtwoord',
|
||||
]);
|
||||
|
||||
$response->assertSessionHasErrors('email');
|
||||
$this->assertGuest();
|
||||
}
|
||||
|
||||
public function test_customer_can_request_password_reset_and_receives_email(): void
|
||||
{
|
||||
Mail::fake();
|
||||
|
||||
$user = User::create([
|
||||
'name' => 'Emma Visser',
|
||||
'email' => 'emma@example.com',
|
||||
'password' => Hash::make('Wachtwoord123'),
|
||||
]);
|
||||
|
||||
$response = $this->post(route('password.email'), [
|
||||
'email' => 'emma@example.com',
|
||||
]);
|
||||
|
||||
$response->assertSessionHas('success');
|
||||
|
||||
Mail::assertSent(PasswordResetMail::class, function ($mail) {
|
||||
return $mail->hasTo('emma@example.com')
|
||||
&& str_contains($mail->envelope()->subject, 'Wachtwoord opnieuw instellen');
|
||||
});
|
||||
|
||||
$this->assertDatabaseHas('password_reset_tokens', [
|
||||
'email' => 'emma@example.com',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_customer_can_reset_password_with_valid_token(): void
|
||||
{
|
||||
$user = User::create([
|
||||
'name' => 'Emma Visser',
|
||||
'email' => 'emma@example.com',
|
||||
'password' => Hash::make('OudWachtwoord123'),
|
||||
]);
|
||||
|
||||
$rawToken = 'test-secret-token-1234567890';
|
||||
DB::table('password_reset_tokens')->insert([
|
||||
'email' => 'emma@example.com',
|
||||
'token' => Hash::make($rawToken),
|
||||
'created_at' => now(),
|
||||
]);
|
||||
|
||||
$response = $this->post(route('password.update'), [
|
||||
'token' => $rawToken,
|
||||
'email' => 'emma@example.com',
|
||||
'password' => 'GloednieuwWachtwoord123!',
|
||||
'password_confirmation' => 'GloednieuwWachtwoord123!',
|
||||
]);
|
||||
|
||||
$response->assertRedirect(route('account.index'));
|
||||
$this->assertAuthenticatedAs($user);
|
||||
|
||||
$user->refresh();
|
||||
$this->assertTrue(Hash::check('GloednieuwWachtwoord123!', $user->password));
|
||||
|
||||
$this->assertDatabaseMissing('password_reset_tokens', [
|
||||
'email' => 'emma@example.com',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_checkout_sends_order_confirmation_email(): void
|
||||
{
|
||||
Mail::fake();
|
||||
|
||||
Material::updateOrCreate(['code' => 'pla'], [
|
||||
'name' => 'Bio-PLA+',
|
||||
'code' => 'pla',
|
||||
'price_multiplier' => 1.0,
|
||||
'is_active' => true,
|
||||
]);
|
||||
|
||||
$category = Category::create([
|
||||
'name' => 'Fidgets',
|
||||
'slug' => 'fidgets',
|
||||
]);
|
||||
|
||||
$product = Product::create([
|
||||
'name' => 'Kristaldraak Mini',
|
||||
'slug' => 'kristaldraak-mini',
|
||||
'category_id' => $category->id,
|
||||
'base_price' => 15.00,
|
||||
'description' => 'Test draakje',
|
||||
'is_active' => true,
|
||||
]);
|
||||
|
||||
// Put item in cart
|
||||
session()->put('cart', [
|
||||
'kristaldraak-mini-pla-rood' => [
|
||||
'id' => $product->id,
|
||||
'name' => 'Kristaldraak Mini',
|
||||
'slug' => 'kristaldraak-mini',
|
||||
'price' => 15.00,
|
||||
'quantity' => 2,
|
||||
'material' => 'pla',
|
||||
'color' => 'Vurig Rood',
|
||||
'scale' => '100%',
|
||||
'infill' => '20%',
|
||||
],
|
||||
]);
|
||||
|
||||
$response = $this->post(route('checkout.store'), [
|
||||
'customer_name' => 'Klant Tester',
|
||||
'customer_email' => 'klant@test.nl',
|
||||
'customer_phone' => '0612345678',
|
||||
'shipping_street' => 'Hoofdstraat',
|
||||
'shipping_number' => '42',
|
||||
'shipping_postal_code' => '1000AA',
|
||||
'shipping_city' => 'Utrecht',
|
||||
'payment_method' => 'ideal',
|
||||
]);
|
||||
|
||||
$response->assertRedirect();
|
||||
|
||||
Mail::assertSent(OrderConfirmationMail::class, function ($mail) {
|
||||
return $mail->hasTo('klant@test.nl')
|
||||
&& str_contains($mail->envelope()->subject, 'Bestelbevestiging');
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ namespace Tests\Feature;
|
||||
use App\Models\Category;
|
||||
use App\Models\Product;
|
||||
use App\Models\Setting;
|
||||
use App\Models\User;
|
||||
use App\Services\MakerWorldService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
@@ -14,6 +15,20 @@ class MakerWorldImporterTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$admin = User::create([
|
||||
'name' => 'Admin Jouwdriedee',
|
||||
'email' => 'info@jouwdriedee.nl',
|
||||
'password' => bcrypt('Jw3D!x9#QmK7$vR2'),
|
||||
'is_admin' => true,
|
||||
]);
|
||||
|
||||
$this->actingAs($admin);
|
||||
}
|
||||
|
||||
protected function fakeMakerWorldApi(): void
|
||||
{
|
||||
Http::fake([
|
||||
|
||||
Reference in New Issue
Block a user