Skip to content

Commit

Permalink
Merge pull request #15 from CodeWithDennis/generate-tests-lines-to-stub
Browse files Browse the repository at this point in the history
[WIP] Generate tests from columns
  • Loading branch information
CodeWithDennis authored Mar 16, 2024
2 parents 0039a65 + 9d30c5e commit 0bad7d4
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 93 deletions.
145 changes: 57 additions & 88 deletions src/Commands/FilamentResourceTestsCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,13 @@
use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\Collection;

use function Laravel\Prompts\select;
use function Laravel\Prompts\multiselect;

class FilamentResourceTestsCommand extends Command
{
protected $signature = 'make:filament-resource-test {name?}';
protected $signature = 'make:filament-resource-test';

protected $description = 'Create a new test for a Filament resource.';

protected ?string $resourceName = '';
protected $description = 'Create tests for a Filament components';

protected Filesystem $files;

Expand All @@ -34,28 +32,35 @@ protected function getStubPath(): string
return __DIR__.'/../../stubs/Resource.stub';
}

protected function getStubVariables(): array
protected function convertDoubleQuotedArrayString(string $string): array|string
{
return str_replace('"', '\'', str_replace(',', ', ', $string));
}

protected function getStubVariables(Resource $resource): array
{
$name = $this->resourceName;
$singularName = str($name)->singular()->remove('resource', false);
$pluralName = str($name)->plural()->remove('resource', false);
$model = $resource->getModel();
$columns = collect($this->getResourceTable($resource)->getColumns());

return [
'resource' => $this->getResourceName(),
'model' => $this->getModel(),
'singular_name' => $singularName,
'singular_name_lowercase' => $singularName->lower(),
'plural_name' => $pluralName,
'plural_name_lowercase' => $pluralName->lower(),
'resource' => str($resource::class)->afterLast('\\'),
'model' => $model,
'modelSingularName' => str($model)->afterLast('\\'),
'modelPluralName' => str($model)->afterLast('\\')->plural(),
'resourceTableColumns' => $this->convertDoubleQuotedArrayString($columns->keys()),
'resourceTableColumnsWithoutHidden' => $this->convertDoubleQuotedArrayString($columns->filter(fn ($column) => ! $column->isToggledHiddenByDefault())->keys()),
'resourceTableToggleableColumns' => $this->convertDoubleQuotedArrayString($columns->filter(fn ($column) => $column->isToggleable())->keys()),
'resourceTableSortableColumns' => $this->convertDoubleQuotedArrayString($columns->filter(fn ($column) => $column->isSortable())->keys()),
'resourceTableSearchableColumns' => $this->convertDoubleQuotedArrayString($columns->filter(fn ($column) => $column->isSearchable())->keys()),
];
}

protected function getSourceFile(): array|bool|string
protected function getSourceFile(Resource $resource): array|bool|string
{
return $this->getStubContents($this->getStubPath(), $this->getStubVariables());
return $this->getStubContents($this->getStubPath(), $this->getStubVariables($resource));
}

protected function getStubContents($stub, $stubVariables = []): array|bool|string
protected function getStubContents(string $stub, array $stubVariables = []): array|bool|string
{
$contents = file_get_contents($stub);

Expand All @@ -66,15 +71,15 @@ protected function getStubContents($stub, $stubVariables = []): array|bool|strin
return $contents;
}

protected function getSourceFilePath(): string
protected function getSourceFilePath(string $name): string
{
$directory = trim(config('filament-resource-tests.directory_name'), '/');

if (config('filament-resource-tests.separate_tests_into_folders')) {
$directory .= DIRECTORY_SEPARATOR.$this->resourceName;
$directory .= DIRECTORY_SEPARATOR.$name;
}

return $directory.DIRECTORY_SEPARATOR.$this->getResourceName().'Test.php';
return $directory.DIRECTORY_SEPARATOR.$name.'Test.php';
}

protected function makeDirectory($path): string
Expand All @@ -86,22 +91,10 @@ protected function makeDirectory($path): string
return $path;
}

protected function getModel(): ?string
{
return $this->getResourceClass()?->getModel();
}

protected function getResourceName(): ?string
{
return str($this->resourceName)->endsWith('Resource') ?
$this->resourceName :
$this->resourceName.'Resource';
}

protected function getResourceClass(): ?Resource
protected function getResourceClass(string $resource): ?Resource
{
$match = $this->getResources()
->first(fn ($resource): bool => str_contains($resource, $this->getResourceName()) && class_exists($resource));
->first(fn ($value): bool => str_contains($value, $resource) && class_exists($value));

return $match ? app()->make($match) : null;
}
Expand All @@ -111,88 +104,64 @@ protected function getResources(): Collection
return collect(Filament::getResources());
}

protected function getTable(): Table
protected function getResourceTable(Resource $resource): Table
{
$livewire = app('livewire')->new(ListRecords::class);

return $this->getResourceClass()::table(new Table($livewire));
return $resource::table(new Table($livewire));
}

protected function getResourceTableColumns(): array
protected function getResourceTableColumns(Table $table): array
{
return $this->getTable()->getColumns();
return $table->getColumns();
}

protected function getResourceSortableTableColumns(): Collection
protected function getResourceSortableTableColumns(array $columns): Collection
{
return collect($this->getResourceTableColumns())->filter(fn ($column) => $column->isSortable());
return collect($columns)->filter(fn ($column) => $column->isSortable());
}

protected function getResourceSearchableTableColumns(): Collection
protected function getResourceSearchableTableColumns(array $columns): Collection
{
return collect($this->getResourceTableColumns())->filter(fn ($column) => $column->isSearchable());
return collect($columns)->filter(fn ($column) => $column->isSearchable());
}

protected function getResourceTableFilters(): array
protected function getResourceTableFilters(Table $table): array
{
return $this->getTable()->getFilters();
return $table->getFilters();
}

public function handle(): void
public function handle(): int
{
// Get the resource name from the command argument
$this->resourceName = $this->argument('name');

// Get all available resources
$availableResources = $this->getResources()
->map(fn ($resource): string => str($resource)->afterLast('Resources\\'));

// Ask the user for the resource
$this->resourceName = (string) str(
$this->resourceName ?? select(
label: 'What is the resource you would like to create this test for?',
options: $availableResources->flatten(),
required: true,
),
)
->studly()
->trim('/')
->trim('\\')
->trim(' ')
->replace('/', '\\');

// If the resource does not end with 'Resource', append it
if (! str($this->resourceName)->endsWith('Resource')) {
$this->resourceName .= 'Resource';
}
$selectedResources = multiselect(
label: 'What is the resource you would like to create this test for?',
options: $availableResources->flatten(),
required: true,
);

// Check if the resource exists
if (! $this->getResourceClass()) {
$this->warn("The filament resource {$this->resourceName} does not exist.");
foreach ($selectedResources as $selectedResource) {
$resource = $this->getResourceClass($selectedResource);

return;
}
$path = $this->getSourceFilePath($selectedResource);

// Get the source file path
$path = $this->getSourceFilePath();
$this->makeDirectory(dirname($path));

// Make the directory if it does not exist
$this->makeDirectory(dirname($path));
$contents = $this->getSourceFile($resource);

// Get the source file contents
$contents = $this->getSourceFile();
if ($this->files->exists($path)) {
$this->warn("Test for {$selectedResource} already exists.");

// Check if the test already exists
if ($this->files->exists($path)) {
$this->warn("Test for {$this->getResourceName()} already exists.");
break;
}

return;
}
$this->files->put($path, $contents);

// Write the file
$this->files->put($path, $contents);
$this->info("Test for {$selectedResource} created successfully.");
}

// Output success message
$this->info("Test for {$this->getResourceName()} created successfully.");
return self::SUCCESS;
}
}
54 changes: 49 additions & 5 deletions stubs/Resource.stub
Original file line number Diff line number Diff line change
@@ -1,9 +1,53 @@
<?php

use function Pest\Livewire\livewire;
use App\Filament\Resources\$resource$\Pages\List$plural_name$;
use App\Filament\Resources\$resource$\Pages\List$modelPluralName$;
use $model$;
use App\Models\User;
use Illuminate\Support\Facades\Hash;

use function Pest\Livewire\livewire;

beforeEach(function () {
$this->actingAs(User::factory()->create([
'password' => Hash::make('password'),
]));
});

it('can render page', function () {
livewire(List$modelPluralName$::class)->assertSuccessful();
});

it('can render column', function (string $column) {
$modelSingularName$::factory()->count(3)->create();

livewire(List$modelPluralName$::class)->assertCanRenderTableColumn($column);
})->with($resourceTableColumnsWithoutHidden$);

it('has column', function (string $column) {
livewire(List$modelPluralName$::class)
->assertTableColumnExists($column);
})->with($resourceTableColumns$);

it('can sort column', function (string $column) {
$records = $modelSingularName$::factory()->count(3)->create();

livewire(List$modelPluralName$::class)
->sortTable($column)
->assertCanSeeTableRecords($records->sortBy($column), inOrder: true)
->sortTable($column, 'desc')
->assertCanSeeTableRecords($records->sortByDesc($column), inOrder: true);
})->with($resourceTableSortableColumns$);

it('can search column', function (string $column) {
$records = $modelSingularName$::factory()->count(3)->create();

$search = $records->first()->{$column};

livewire(List$modelPluralName$::class)
->searchTable($search)
->assertCanSeeTableRecords($records->where($column, $search))
->assertCanNotSeeTableRecords($records->where($column, '!=', $search));
})->with($resourceTableSearchableColumns$);



it('can render the $singular_name_lowercase$ list page', function () {
livewire(List$plural_name$::class)->assertSuccessful();
});

0 comments on commit 0bad7d4

Please sign in to comment.