510 lines
17 KiB
PHP
510 lines
17 KiB
PHP
<?php
|
|
|
|
use App\Enums\UserStatus;
|
|
use App\Enums\UserType;
|
|
use App\Models\AdminLog;
|
|
use App\Models\User;
|
|
use Livewire\Volt\Volt;
|
|
|
|
beforeEach(function () {
|
|
$this->admin = User::factory()->admin()->create();
|
|
});
|
|
|
|
// ===========================================
|
|
// Create Client Tests
|
|
// ===========================================
|
|
|
|
test('admin can access individual clients index page', function () {
|
|
$this->actingAs($this->admin)
|
|
->get(route('admin.clients.individual.index'))
|
|
->assertOk();
|
|
});
|
|
|
|
test('admin can access create individual client page', function () {
|
|
$this->actingAs($this->admin)
|
|
->get(route('admin.clients.individual.create'))
|
|
->assertOk();
|
|
});
|
|
|
|
test('admin can create individual client with all valid data', function () {
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.clients.individual.create')
|
|
->set('full_name', 'Test Client')
|
|
->set('email', 'testclient@example.com')
|
|
->set('national_id', '123456789')
|
|
->set('phone', '+970599123456')
|
|
->set('password', 'password123')
|
|
->set('preferred_language', 'ar')
|
|
->call('create')
|
|
->assertHasNoErrors()
|
|
->assertRedirect(route('admin.clients.individual.index'));
|
|
|
|
expect(User::where('email', 'testclient@example.com')->exists())->toBeTrue();
|
|
|
|
$client = User::where('email', 'testclient@example.com')->first();
|
|
expect($client->user_type)->toBe(UserType::Individual);
|
|
expect($client->status)->toBe(UserStatus::Active);
|
|
});
|
|
|
|
test('created client has user_type set to individual', function () {
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.clients.individual.create')
|
|
->set('full_name', 'Test Client')
|
|
->set('email', 'testclient@example.com')
|
|
->set('national_id', '123456789')
|
|
->set('phone', '+970599123456')
|
|
->set('password', 'password123')
|
|
->set('preferred_language', 'ar')
|
|
->call('create')
|
|
->assertHasNoErrors();
|
|
|
|
$client = User::where('email', 'testclient@example.com')->first();
|
|
expect($client->user_type)->toBe(UserType::Individual);
|
|
});
|
|
|
|
test('admin log entry created on successful creation', function () {
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.clients.individual.create')
|
|
->set('full_name', 'Test Client')
|
|
->set('email', 'testclient@example.com')
|
|
->set('national_id', '123456789')
|
|
->set('phone', '+970599123456')
|
|
->set('password', 'password123')
|
|
->set('preferred_language', 'ar')
|
|
->call('create')
|
|
->assertHasNoErrors();
|
|
|
|
expect(AdminLog::where('action', 'create')
|
|
->where('target_type', 'user')
|
|
->where('admin_id', $this->admin->id)
|
|
->exists())->toBeTrue();
|
|
});
|
|
|
|
test('cannot create client without required name field', function () {
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.clients.individual.create')
|
|
->set('full_name', '')
|
|
->set('email', 'testclient@example.com')
|
|
->set('national_id', '123456789')
|
|
->set('phone', '+970599123456')
|
|
->set('password', 'password123')
|
|
->set('preferred_language', 'ar')
|
|
->call('create')
|
|
->assertHasErrors(['full_name' => 'required']);
|
|
});
|
|
|
|
test('cannot create client without required email field', function () {
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.clients.individual.create')
|
|
->set('full_name', 'Test Client')
|
|
->set('email', '')
|
|
->set('national_id', '123456789')
|
|
->set('phone', '+970599123456')
|
|
->set('password', 'password123')
|
|
->set('preferred_language', 'ar')
|
|
->call('create')
|
|
->assertHasErrors(['email' => 'required']);
|
|
});
|
|
|
|
test('cannot create client without required national_id field', function () {
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.clients.individual.create')
|
|
->set('full_name', 'Test Client')
|
|
->set('email', 'testclient@example.com')
|
|
->set('national_id', '')
|
|
->set('phone', '+970599123456')
|
|
->set('password', 'password123')
|
|
->set('preferred_language', 'ar')
|
|
->call('create')
|
|
->assertHasErrors(['national_id' => 'required']);
|
|
});
|
|
|
|
test('cannot create client without required phone field', function () {
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.clients.individual.create')
|
|
->set('full_name', 'Test Client')
|
|
->set('email', 'testclient@example.com')
|
|
->set('national_id', '123456789')
|
|
->set('phone', '')
|
|
->set('password', 'password123')
|
|
->set('preferred_language', 'ar')
|
|
->call('create')
|
|
->assertHasErrors(['phone' => 'required']);
|
|
});
|
|
|
|
test('cannot create client with invalid email format', function () {
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.clients.individual.create')
|
|
->set('full_name', 'Test Client')
|
|
->set('email', 'invalid-email')
|
|
->set('national_id', '123456789')
|
|
->set('phone', '+970599123456')
|
|
->set('password', 'password123')
|
|
->set('preferred_language', 'ar')
|
|
->call('create')
|
|
->assertHasErrors(['email' => 'email']);
|
|
});
|
|
|
|
test('cannot create client with duplicate email', function () {
|
|
User::factory()->individual()->create(['email' => 'existing@example.com']);
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.clients.individual.create')
|
|
->set('full_name', 'Test Client')
|
|
->set('email', 'existing@example.com')
|
|
->set('national_id', '123456789')
|
|
->set('phone', '+970599123456')
|
|
->set('password', 'password123')
|
|
->set('preferred_language', 'ar')
|
|
->call('create')
|
|
->assertHasErrors(['email' => 'unique']);
|
|
});
|
|
|
|
test('cannot create client with duplicate national_id', function () {
|
|
User::factory()->individual()->create(['national_id' => '123456789']);
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.clients.individual.create')
|
|
->set('full_name', 'Test Client')
|
|
->set('email', 'testclient@example.com')
|
|
->set('national_id', '123456789')
|
|
->set('phone', '+970599123456')
|
|
->set('password', 'password123')
|
|
->set('preferred_language', 'ar')
|
|
->call('create')
|
|
->assertHasErrors(['national_id' => 'unique']);
|
|
});
|
|
|
|
test('cannot create client with password less than 8 characters', function () {
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.clients.individual.create')
|
|
->set('full_name', 'Test Client')
|
|
->set('email', 'testclient@example.com')
|
|
->set('national_id', '123456789')
|
|
->set('phone', '+970599123456')
|
|
->set('password', 'short')
|
|
->set('preferred_language', 'ar')
|
|
->call('create')
|
|
->assertHasErrors(['password' => 'min']);
|
|
});
|
|
|
|
// ===========================================
|
|
// List View Tests
|
|
// ===========================================
|
|
|
|
test('index page displays only individual clients', function () {
|
|
// Create different types of users
|
|
$individualClient = User::factory()->individual()->create(['full_name' => 'Individual Test']);
|
|
$companyClient = User::factory()->company()->create(['full_name' => 'Company Test']);
|
|
$adminUser = User::factory()->admin()->create(['full_name' => 'Admin Test']);
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.clients.individual.index')
|
|
->assertSee('Individual Test')
|
|
->assertDontSee('Company Test')
|
|
->assertDontSee('Admin Test');
|
|
});
|
|
|
|
test('clients sorted by created_at desc by default', function () {
|
|
$oldClient = User::factory()->individual()->create([
|
|
'full_name' => 'Old Client',
|
|
'created_at' => now()->subDays(10),
|
|
]);
|
|
|
|
$newClient = User::factory()->individual()->create([
|
|
'full_name' => 'New Client',
|
|
'created_at' => now(),
|
|
]);
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
$response = Volt::test('admin.clients.individual.index');
|
|
|
|
// The new client should appear before the old client
|
|
$response->assertSeeInOrder(['New Client', 'Old Client']);
|
|
});
|
|
|
|
// ===========================================
|
|
// Search & Filter Tests
|
|
// ===========================================
|
|
|
|
test('can search clients by name (partial match)', function () {
|
|
User::factory()->individual()->create(['full_name' => 'John Doe']);
|
|
User::factory()->individual()->create(['full_name' => 'Jane Smith']);
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.clients.individual.index')
|
|
->set('search', 'John')
|
|
->assertSee('John Doe')
|
|
->assertDontSee('Jane Smith');
|
|
});
|
|
|
|
test('can search clients by email (partial match)', function () {
|
|
User::factory()->individual()->create([
|
|
'full_name' => 'John Doe',
|
|
'email' => 'john@example.com',
|
|
]);
|
|
User::factory()->individual()->create([
|
|
'full_name' => 'Jane Smith',
|
|
'email' => 'jane@example.com',
|
|
]);
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.clients.individual.index')
|
|
->set('search', 'john@')
|
|
->assertSee('John Doe')
|
|
->assertDontSee('Jane Smith');
|
|
});
|
|
|
|
test('can search clients by national_id (partial match)', function () {
|
|
User::factory()->individual()->create([
|
|
'full_name' => 'John Doe',
|
|
'national_id' => '111222333',
|
|
]);
|
|
User::factory()->individual()->create([
|
|
'full_name' => 'Jane Smith',
|
|
'national_id' => '444555666',
|
|
]);
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.clients.individual.index')
|
|
->set('search', '111222')
|
|
->assertSee('John Doe')
|
|
->assertDontSee('Jane Smith');
|
|
});
|
|
|
|
test('can filter clients by active status', function () {
|
|
User::factory()->individual()->create([
|
|
'full_name' => 'Active Client',
|
|
'status' => UserStatus::Active,
|
|
]);
|
|
User::factory()->individual()->deactivated()->create([
|
|
'full_name' => 'Deactivated Client',
|
|
]);
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.clients.individual.index')
|
|
->set('statusFilter', 'active')
|
|
->assertSee('Active Client')
|
|
->assertDontSee('Deactivated Client');
|
|
});
|
|
|
|
test('can filter clients by deactivated status', function () {
|
|
User::factory()->individual()->create([
|
|
'full_name' => 'Active Client',
|
|
'status' => UserStatus::Active,
|
|
]);
|
|
User::factory()->individual()->deactivated()->create([
|
|
'full_name' => 'Deactivated Client',
|
|
]);
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.clients.individual.index')
|
|
->set('statusFilter', 'deactivated')
|
|
->assertDontSee('Active Client')
|
|
->assertSee('Deactivated Client');
|
|
});
|
|
|
|
test('clear filters resets search and filter', function () {
|
|
User::factory()->individual()->create(['full_name' => 'Test Client']);
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
$component = Volt::test('admin.clients.individual.index')
|
|
->set('search', 'something')
|
|
->set('statusFilter', 'active')
|
|
->call('clearFilters');
|
|
|
|
expect($component->get('search'))->toBe('');
|
|
expect($component->get('statusFilter'))->toBe('');
|
|
});
|
|
|
|
// ===========================================
|
|
// Edit Client Tests
|
|
// ===========================================
|
|
|
|
test('admin can access edit individual client page', function () {
|
|
$client = User::factory()->individual()->create();
|
|
|
|
$this->actingAs($this->admin)
|
|
->get(route('admin.clients.individual.edit', $client))
|
|
->assertOk();
|
|
});
|
|
|
|
test('edit form pre-populates with current values', function () {
|
|
$client = User::factory()->individual()->create([
|
|
'full_name' => 'Original Name',
|
|
'email' => 'original@example.com',
|
|
'national_id' => '987654321',
|
|
'phone' => '+970599000000',
|
|
'preferred_language' => 'en',
|
|
]);
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
$component = Volt::test('admin.clients.individual.edit', ['client' => $client]);
|
|
|
|
expect($component->get('full_name'))->toBe('Original Name');
|
|
expect($component->get('email'))->toBe('original@example.com');
|
|
expect($component->get('national_id'))->toBe('987654321');
|
|
expect($component->get('phone'))->toBe('+970599000000');
|
|
expect($component->get('preferred_language'))->toBe('en');
|
|
});
|
|
|
|
test('can edit existing client information', function () {
|
|
$client = User::factory()->individual()->create();
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.clients.individual.edit', ['client' => $client])
|
|
->set('full_name', 'Updated Name')
|
|
->set('email', 'updated@example.com')
|
|
->set('national_id', '111111111')
|
|
->set('phone', '+970599111111')
|
|
->set('preferred_language', 'en')
|
|
->set('status', 'active')
|
|
->call('update')
|
|
->assertHasNoErrors()
|
|
->assertRedirect(route('admin.clients.individual.index'));
|
|
|
|
$client->refresh();
|
|
|
|
expect($client->full_name)->toBe('Updated Name');
|
|
expect($client->email)->toBe('updated@example.com');
|
|
expect($client->national_id)->toBe('111111111');
|
|
});
|
|
|
|
test('validation rules apply on edit (except unique for own record)', function () {
|
|
$client = User::factory()->individual()->create([
|
|
'email' => 'client@example.com',
|
|
'national_id' => '123456789',
|
|
]);
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
// Should not error when keeping same email
|
|
Volt::test('admin.clients.individual.edit', ['client' => $client])
|
|
->set('full_name', 'Updated Name')
|
|
->set('email', 'client@example.com')
|
|
->set('national_id', '123456789')
|
|
->set('phone', '+970599111111')
|
|
->set('preferred_language', 'en')
|
|
->set('status', 'active')
|
|
->call('update')
|
|
->assertHasNoErrors();
|
|
});
|
|
|
|
test('admin log entry created on successful update', function () {
|
|
$client = User::factory()->individual()->create();
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.clients.individual.edit', ['client' => $client])
|
|
->set('full_name', 'Updated Name')
|
|
->set('email', 'updated@example.com')
|
|
->set('national_id', '111111111')
|
|
->set('phone', '+970599111111')
|
|
->set('preferred_language', 'en')
|
|
->set('status', 'active')
|
|
->call('update')
|
|
->assertHasNoErrors();
|
|
|
|
expect(AdminLog::where('action', 'update')
|
|
->where('target_type', 'user')
|
|
->where('target_id', $client->id)
|
|
->where('admin_id', $this->admin->id)
|
|
->exists())->toBeTrue();
|
|
});
|
|
|
|
// ===========================================
|
|
// View Profile Tests
|
|
// ===========================================
|
|
|
|
test('admin can access view individual client page', function () {
|
|
$client = User::factory()->individual()->create();
|
|
|
|
$this->actingAs($this->admin)
|
|
->get(route('admin.clients.individual.show', $client))
|
|
->assertOk();
|
|
});
|
|
|
|
test('profile page displays all client information', function () {
|
|
$client = User::factory()->individual()->create([
|
|
'full_name' => 'John Doe',
|
|
'email' => 'john@example.com',
|
|
'national_id' => '123456789',
|
|
'phone' => '+970599123456',
|
|
]);
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
Volt::test('admin.clients.individual.show', ['client' => $client])
|
|
->assertSee('John Doe')
|
|
->assertSee('john@example.com')
|
|
->assertSee('123456789')
|
|
->assertSee('+970599123456');
|
|
});
|
|
|
|
test('profile shows consultation count', function () {
|
|
$client = User::factory()->individual()->create();
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
$component = Volt::test('admin.clients.individual.show', ['client' => $client]);
|
|
|
|
// The component should load consultation counts
|
|
expect($component->get('client')->consultations_count)->toBe(0);
|
|
});
|
|
|
|
test('profile shows timeline count', function () {
|
|
$client = User::factory()->individual()->create();
|
|
|
|
$this->actingAs($this->admin);
|
|
|
|
$component = Volt::test('admin.clients.individual.show', ['client' => $client]);
|
|
|
|
// The component should load timeline counts
|
|
expect($component->get('client')->timelines_count)->toBe(0);
|
|
});
|
|
|
|
// ===========================================
|
|
// Authorization Tests
|
|
// ===========================================
|
|
|
|
test('non-admin cannot access individual clients pages', function () {
|
|
$client = User::factory()->individual()->create();
|
|
|
|
$this->actingAs($client);
|
|
|
|
$this->get(route('admin.clients.individual.index'))->assertForbidden();
|
|
$this->get(route('admin.clients.individual.create'))->assertForbidden();
|
|
$this->get(route('admin.clients.individual.show', $client))->assertForbidden();
|
|
$this->get(route('admin.clients.individual.edit', $client))->assertForbidden();
|
|
});
|
|
|
|
test('unauthenticated user cannot access individual clients pages', function () {
|
|
$client = User::factory()->individual()->create();
|
|
|
|
$this->get(route('admin.clients.individual.index'))->assertRedirect(route('login'));
|
|
$this->get(route('admin.clients.individual.create'))->assertRedirect(route('login'));
|
|
$this->get(route('admin.clients.individual.show', $client))->assertRedirect(route('login'));
|
|
$this->get(route('admin.clients.individual.edit', $client))->assertRedirect(route('login'));
|
|
});
|