Skip to content

Commit

Permalink
Add more tests; Add filter in filament resource; Added options for us…
Browse files Browse the repository at this point in the history
…er create command
  • Loading branch information
korridor committed Feb 6, 2025
1 parent 84c9cfe commit dce608e
Show file tree
Hide file tree
Showing 20 changed files with 413 additions and 12 deletions.
8 changes: 7 additions & 1 deletion app/Console/Commands/Admin/UserCreateCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ class UserCreateCommand extends Command
protected $signature = 'admin:user:create
{ name : The name of the user }
{ email : The email of the user }
{ --ask-for-password : Ask for the password, otherwise the command will generate a random one }';
{ --ask-for-password : Ask for the password, otherwise the command will generate a random one }
{ --verify-email : Verify the email address of the user }';

/**
* The console command description.
Expand All @@ -39,6 +40,7 @@ public function handle(): int
$name = $this->argument('name');
$email = $this->argument('email');
$askForPassword = (bool) $this->option('ask-for-password');
$verifyEmail = (bool) $this->option('verify-email');

if (User::query()->where('email', $email)->where('is_placeholder', '=', false)->exists()) {
$this->error('User with email "'.$email.'" already exists.');
Expand Down Expand Up @@ -71,6 +73,10 @@ public function handle(): int
throw new LogicException('User does not have an organization');
}

if ($verifyEmail) {
$user->markEmailAsVerified();
}

$this->info('Created user "'.$name.'" ("'.$email.'")');
$this->line('ID: '.$user->getKey());
$this->line('Name: '.$name);
Expand Down
5 changes: 5 additions & 0 deletions app/Filament/Resources/ClientResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,13 @@ public static function table(Table $table): Table
->defaultSort('created_at', 'desc')
->filters([
SelectFilter::make('organization')
->label('Organization')
->relationship('organization', 'name')
->searchable(),
SelectFilter::make('organization_id')
->label('Organization ID')
->relationship('organization', 'id')
->searchable(),
])
->actions([
Tables\Actions\EditAction::make(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace App\Filament\Resources\OrganizationInvitationResource\Pages;

use App\Filament\Resources\OrganizationInvitationResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;

class EditOrganizationInvitation extends EditRecord
Expand All @@ -14,6 +15,8 @@ class EditOrganizationInvitation extends EditRecord
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make()
->icon('heroicon-m-trash'),
];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ public function table(Table $table): Table
])
->headerActions([
Tables\Actions\AttachAction::make()
->recordTitle(fn (User $record): string => "{$record->name} ({$record->email})")
->form(fn (AttachAction $action): array => [
$action->getRecordSelect(),
Select::make('role')
Expand Down
5 changes: 5 additions & 0 deletions app/Filament/Resources/ProjectResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,13 @@ public static function table(Table $table): Table
])
->filters([
SelectFilter::make('organization')
->label('Organization')
->relationship('organization', 'name')
->searchable(),
SelectFilter::make('organization_id')
->label('Organization ID')
->relationship('organization', 'id')
->searchable(),
])
->defaultSort('created_at', 'desc')
->actions([
Expand Down
5 changes: 5 additions & 0 deletions app/Filament/Resources/ReportResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,13 @@ public static function table(Table $table): Table
->defaultSort('created_at', 'desc')
->filters([
SelectFilter::make('organization')
->label('Organization')
->relationship('organization', 'name')
->searchable(),
SelectFilter::make('organization_id')
->label('Organization ID')
->relationship('organization', 'id')
->searchable(),
])
->actions([
Action::make('public-view')
Expand Down
5 changes: 5 additions & 0 deletions app/Filament/Resources/TagResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,13 @@ public static function table(Table $table): Table
->defaultSort('created_at', 'desc')
->filters([
SelectFilter::make('organization')
->label('Organization')
->relationship('organization', 'name')
->searchable(),
SelectFilter::make('organization_id')
->label('Organization ID')
->relationship('organization', 'id')
->searchable(),
])
->actions([
Tables\Actions\EditAction::make(),
Expand Down
5 changes: 5 additions & 0 deletions app/Filament/Resources/TaskResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,13 @@ public static function table(Table $table): Table
])
->filters([
SelectFilter::make('organization')
->label('Organization')
->relationship('organization', 'name')
->searchable(),
SelectFilter::make('organization_id')
->label('Organization ID')
->relationship('organization', 'id')
->searchable(),
])
->defaultSort('created_at', 'desc')
->actions([
Expand Down
5 changes: 5 additions & 0 deletions app/Filament/Resources/TimeEntryResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,13 @@ public static function table(Table $table): Table
])
->filters([
SelectFilter::make('organization')
->label('Organization')
->relationship('organization', 'name')
->searchable(),
SelectFilter::make('organization_id')
->label('Organization ID')
->relationship('organization', 'id')
->searchable(),
])
->defaultSort('created_at', 'desc')
->actions([
Expand Down
1 change: 1 addition & 0 deletions app/Service/Import/ImportDatabaseHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ public function getCachedModels(): array
if ($this->mapKeyToModel === null) {
return [];
}

return array_values($this->mapKeyToModel);
}

Expand Down
4 changes: 2 additions & 2 deletions config/excel.php
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,8 @@
*/
'cells' => [
'middleware' => [
//\Maatwebsite\Excel\Middleware\TrimCellValue::class,
//\Maatwebsite\Excel\Middleware\ConvertEmptyCellValuesToNull::class,
// \Maatwebsite\Excel\Middleware\TrimCellValue::class,
// \Maatwebsite\Excel\Middleware\ConvertEmptyCellValuesToNull::class,
],
],

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ public function test_it_calls_the_deletion_service_with_the_organization(): void
});

// Act
$this->artisan('admin:organization:delete', ['organization' => $organization->getKey()])
->expectsOutput("Deleting organization with ID {$organization->getKey()}")
$command = $this->artisan('admin:organization:delete', ['organization' => $organization->getKey()]);

// Assert
$command->expectsOutput("Deleting organization with ID {$organization->getKey()}")
->expectsOutput("Organization with ID {$organization->getKey()} has been deleted.")
->assertExitCode(0);
}
Expand All @@ -40,9 +42,11 @@ public function test_it_fails_if_organization_does_not_exist(): void
$organizationId = Str::uuid()->toString();

// Act
$this->artisan('admin:organization:delete', ['organization' => $organizationId])
->expectsOutput('Organization with ID '.$organizationId.' not found.')
->assertExitCode(1);
$command = $this->artisan('admin:organization:delete', ['organization' => $organizationId]);

// Assert
$command->expectsOutput('Organization with ID '.$organizationId.' not found.');
$command->assertExitCode(1);
}

public function test_it_fails_if_organization_id_is_not_a_valid_uuid(): void
Expand All @@ -51,8 +55,10 @@ public function test_it_fails_if_organization_id_is_not_a_valid_uuid(): void
$organizationId = 'invalid-uuid';

// Act
$this->artisan('admin:organization:delete', ['organization' => $organizationId])
->expectsOutput('Organization ID must be a valid UUID.')
$command = $this->artisan('admin:organization:delete', ['organization' => $organizationId]);

// Assert
$command->expectsOutput('Organization ID must be a valid UUID.')
->assertExitCode(1);
}
}
114 changes: 114 additions & 0 deletions tests/Unit/Console/Commands/Admin/UserCreateCommandCommandTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<?php

declare(strict_types=1);

namespace Tests\Unit\Console\Commands\Admin;

use App\Console\Commands\Admin\UserCreateCommand;
use App\Models\User;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Hash;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\UsesClass;
use Tests\TestCaseWithDatabase;

#[CoversClass(UserCreateCommand::class)]
#[UsesClass(UserCreateCommand::class)]
class UserCreateCommandCommandTest extends TestCaseWithDatabase
{
public function test_it_creates_user(): void
{
// Arrange
$email = '[email protected]';
$name = 'Test User';

// Act
$exitCode = $this->withoutMockingConsoleOutput()->artisan('admin:user:create', [
'name' => $name,
'email' => $email,
]);

// Assert
$this->assertSame(Command::SUCCESS, $exitCode);
$output = Artisan::output();
$this->assertStringContainsString('Created user "'.$name.'" ("'.$email.'")', $output);
$this->assertDatabaseHas(User::class, [
'name' => $name,
'email' => $email,
'email_verified_at' => null,
]);
}

public function test_created_user_is_verified_if_option_is_set(): void
{
// Arrange
$email = '[email protected]';
$name = 'Test User';

// Act
$exitCode = $this->withoutMockingConsoleOutput()->artisan('admin:user:create', [
'name' => $name,
'email' => $email,
'--verify-email' => true,
]);

// Assert
$this->assertSame(Command::SUCCESS, $exitCode);
$output = Artisan::output();
$this->assertStringContainsString('Created user "'.$name.'" ("'.$email.'")', $output);
$this->assertDatabaseHas(User::class, [
'name' => $name,
'email' => $email,
]);
$user = User::where('email', $email)->first();
$this->assertNotNull($user->email_verified_at);
}

public function test_it_fails_if_user_with_email_already_exists(): void
{
// Arrange
$email = '[email protected]';
$name = 'Test User';

User::factory()->create([
'email' => $email,
]);

// Act
$exitCode = $this->withoutMockingConsoleOutput()->artisan('admin:user:create', [
'name' => $name,
'email' => $email,
]);

// Assert
$this->assertSame(Command::FAILURE, $exitCode);
$output = Artisan::output();
$this->assertStringContainsString('User with email "'.$email.'" already exists.', $output);
}

public function test_it_asks_for_password_if_option_is_set(): void
{
// Arrange
$email = '[email protected]';
$name = 'Test User';

// Act
$this->artisan('admin:user:create', [
'name' => $name,
'email' => $email,
'--ask-for-password' => true,
])
->expectsQuestion('Enter the password', 'password')
->assertExitCode(Command::SUCCESS);

$this->assertDatabaseHas(User::class, [
'name' => $name,
'email' => $email,
'email_verified_at' => null,
]);
$user = User::where('email', $email)->first();
$this->assertNotNull($user->password);
$this->assertTrue(Hash::check('password', $user->password));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ public function test_it_verifies_user_email(): void
$command = $this->artisan('admin:user:verify', ['email' => $user->email]);

// Assert

$command->expectsOutput('Start verifying user with email "'.$user->email.'"')
->expectsOutput('User with email "'.$user->email.'" has been verified.')
->assertExitCode(0);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php

declare(strict_types=1);

namespace Tests\Unit\Filament\Resources;

use App\Filament\Resources\OrganizationInvitationResource;
use App\Models\Organization;
use App\Models\OrganizationInvitation;
use App\Models\User;
use Filament\Actions\DeleteAction;
use Illuminate\Support\Facades\Config;
use Livewire\Livewire;
use PHPUnit\Framework\Attributes\UsesClass;
use Tests\Unit\Filament\FilamentTestCase;

#[UsesClass(OrganizationInvitationResource::class)]
class OrganizationInvitationResourceTest extends FilamentTestCase
{
protected function setUp(): void
{
parent::setUp();
Config::set('auth.super_admins', ['[email protected]']);
$user = User::factory()->withPersonalOrganization()->create([
'email' => '[email protected]',
]);

$this->actingAs($user);
}

public function test_can_list_organization_invitations(): void
{
// Arrange
$user = User::factory()->create();
$organization = Organization::factory()->withOwner($user)->create();
$organizationInvitations = OrganizationInvitation::factory()->forOrganization($organization)->createMany(5);

// Act
$response = Livewire::test(OrganizationInvitationResource\Pages\ListOrganizationInvitations::class);

// Assert
$response->assertSuccessful();
$response->assertCanSeeTableRecords($organizationInvitations);
}

public function test_can_see_edit_page_of_organization_invitation(): void
{
// Arrange
$organization = Organization::factory()->create();
$organizationInvitation = OrganizationInvitation::factory()->forOrganization($organization)->create();

// Act
$response = Livewire::test(OrganizationInvitationResource\Pages\EditOrganizationInvitation::class, [
'record' => $organizationInvitation->getKey(),
]);

// Assert
$response->assertSuccessful();
}

public function test_can_delete_a_organization_invitation(): void
{
// Arrange
$organization = Organization::factory()->create();
$organizationInvitation = OrganizationInvitation::factory()->forOrganization($organization)->create();

// Act
$response = Livewire::test(OrganizationInvitationResource\Pages\EditOrganizationInvitation::class, [
'record' => $organizationInvitation->getKey(),
])->callAction(DeleteAction::class);

// Assert
$response->assertSuccessful();
$this->assertDatabaseMissing(OrganizationInvitation::class, [
'id' => $organizationInvitation->getKey(),
]);
}
}
Loading

0 comments on commit dce608e

Please sign in to comment.