Files
michaelschiemer/tests/Framework/Admin/CrudServiceTest.php
Michael Schiemer 5050c7d73a docs: consolidate documentation into organized structure
- Move 12 markdown files from root to docs/ subdirectories
- Organize documentation by category:
  • docs/troubleshooting/ (1 file)  - Technical troubleshooting guides
  • docs/deployment/      (4 files) - Deployment and security documentation
  • docs/guides/          (3 files) - Feature-specific guides
  • docs/planning/        (4 files) - Planning and improvement proposals

Root directory cleanup:
- Reduced from 16 to 4 markdown files in root
- Only essential project files remain:
  • CLAUDE.md (AI instructions)
  • README.md (Main project readme)
  • CLEANUP_PLAN.md (Current cleanup plan)
  • SRC_STRUCTURE_IMPROVEMENTS.md (Structure improvements)

This improves:
 Documentation discoverability
 Logical organization by purpose
 Clean root directory
 Better maintainability
2025-10-05 11:05:04 +02:00

279 lines
9.4 KiB
PHP

<?php
declare(strict_types=1);
use App\Framework\Admin\Factories\AdminFormFactory;
use App\Framework\Admin\Services\CrudService;
use App\Framework\Admin\ValueObjects\CrudConfig;
use App\Framework\Http\HttpRequest;
use App\Framework\Http\Method;
use App\Framework\Http\Responses\Redirect;
use App\Framework\Http\Responses\ViewResult;
use App\Framework\View\TemplateRenderer;
beforeEach(function () {
$this->renderer = Mockery::mock(TemplateRenderer::class);
$this->formFactory = Mockery::mock(AdminFormFactory::class);
$this->service = new CrudService($this->renderer, $this->formFactory);
$this->config = CrudConfig::forResource(
resource: 'campaigns',
resourceName: 'Campaign',
title: 'Campaigns'
)->withColumns([
['field' => 'name', 'label' => 'Name'],
['field' => 'status', 'label' => 'Status'],
]);
});
afterEach(function () {
Mockery::close();
});
describe('CrudService', function () {
describe('renderIndex', function () {
it('renders index view with items and pagination', function () {
$items = [
['id' => '1', 'name' => 'Campaign 1', 'status' => 'active'],
['id' => '2', 'name' => 'Campaign 2', 'status' => 'draft'],
];
$pagination = [
'current_page' => 1,
'total_pages' => 5,
'per_page' => 10,
];
$request = Mockery::mock(HttpRequest::class);
$request->shouldReceive('uri')->andReturn('/admin/campaigns');
$result = $this->service->renderIndex(
$this->config,
$items,
$request,
$pagination
);
expect($result)->toBeInstanceOf(ViewResult::class);
expect($result->template)->toBe('crud-index');
expect($result->data['items'])->toBe($items);
expect($result->data['pagination'])->toBe($pagination);
expect($result->data['resource'])->toBe('campaigns');
expect($result->data['createUrl'])->toBe('/admin/campaigns/create');
});
});
describe('renderCreate', function () {
it('renders create form with default configuration', function () {
$formFields = [
['type' => 'text', 'name' => 'name', 'label' => 'Name'],
];
$mockForm = Mockery::mock();
$mockForm->shouldReceive('build')->andReturn('<form>...</form>');
$mockForm->shouldReceive('getId')->andReturn('campaign-form');
$this->formFactory->shouldReceive('create')
->once()
->andReturn($mockForm);
$result = $this->service->renderCreate(
$this->config,
$formFields
);
expect($result)->toBeInstanceOf(ViewResult::class);
expect($result->template)->toBe('crud-create');
expect($result->data['title'])->toBe('Create Campaign');
expect($result->data['formId'])->toBe('campaign-form');
expect($result->data['backUrl'])->toBe('/admin/campaigns');
});
it('renders create form with help text', function () {
$formFields = [];
$helpText = 'Fill in the campaign details carefully.';
$mockForm = Mockery::mock();
$mockForm->shouldReceive('build')->andReturn('');
$mockForm->shouldReceive('getId')->andReturn('form-id');
$this->formFactory->shouldReceive('create')->andReturn($mockForm);
$result = $this->service->renderCreate(
$this->config,
$formFields,
null,
$helpText
);
expect($result->data['helpText'])->toBe($helpText);
});
});
describe('renderEdit', function () {
it('renders edit form with item data and metadata', function () {
$formFields = [
['type' => 'text', 'name' => 'name', 'label' => 'Name'],
];
$itemData = [
'id' => '123',
'name' => 'Test Campaign',
'status' => 'active',
];
$metadata = [
'id' => '123',
'createdAt' => '2024-01-01 10:00:00',
'updatedAt' => '2024-01-02 15:30:00',
];
$mockForm = Mockery::mock();
$mockForm->shouldReceive('build')->andReturn('<form>...</form>');
$mockForm->shouldReceive('getId')->andReturn('edit-form');
$this->formFactory->shouldReceive('create')
->once()
->andReturn($mockForm);
$result = $this->service->renderEdit(
$this->config,
'123',
$formFields,
$itemData,
$metadata
);
expect($result)->toBeInstanceOf(ViewResult::class);
expect($result->template)->toBe('crud-edit');
expect($result->data['title'])->toBe('Edit Campaign');
expect($result->data['metadata'])->toBe($metadata);
expect($result->data['deleteUrl'])->toBe('/admin/campaigns/delete/123');
});
});
describe('renderShow', function () {
it('renders show view with fields and metadata', function () {
$fields = [
['label' => 'Name', 'value' => 'Test Campaign', 'type' => 'text'],
['label' => 'Status', 'value' => 'Active', 'type' => 'badge', 'color' => 'success'],
];
$metadata = [
'id' => '123',
'createdAt' => '2024-01-01',
];
$result = $this->service->renderShow(
$this->config,
'123',
$fields,
$metadata
);
expect($result)->toBeInstanceOf(ViewResult::class);
expect($result->template)->toBe('crud-show');
expect($result->data['fields'])->toBe($fields);
expect($result->data['metadata'])->toBe($metadata);
expect($result->data['editUrl'])->toBe('/admin/campaigns/edit/123');
});
});
describe('redirectAfterCreate', function () {
it('redirects to index after successful create', function () {
$request = Mockery::mock(HttpRequest::class);
$request->parsedBody = Mockery::mock();
$request->parsedBody->shouldReceive('get')
->with('action')
->andReturn(null);
$result = $this->service->redirectAfterCreate(
$this->config,
$request,
'123'
);
expect($result)->toBeInstanceOf(Redirect::class);
expect($result->url)->toBe('/admin/campaigns');
});
it('redirects to create form when save-and-continue is requested', function () {
$request = Mockery::mock(HttpRequest::class);
$request->parsedBody = Mockery::mock();
$request->parsedBody->shouldReceive('get')
->with('action')
->andReturn('save-and-continue');
$result = $this->service->redirectAfterCreate(
$this->config,
$request,
'123'
);
expect($result->url)->toBe('/admin/campaigns/create');
});
});
describe('redirectAfterUpdate', function () {
it('redirects to index after successful update', function () {
$request = Mockery::mock(HttpRequest::class);
$request->parsedBody = Mockery::mock();
$request->parsedBody->shouldReceive('get')
->with('action')
->andReturn(null);
$result = $this->service->redirectAfterUpdate(
$this->config,
$request,
'123'
);
expect($result->url)->toBe('/admin/campaigns');
});
it('redirects to show view when save-and-view is requested', function () {
$request = Mockery::mock(HttpRequest::class);
$request->parsedBody = Mockery::mock();
$request->parsedBody->shouldReceive('get')
->with('action')
->andReturn('save-and-view');
$result = $this->service->redirectAfterUpdate(
$this->config,
$request,
'123'
);
expect($result->url)->toBe('/admin/campaigns/view/123');
});
});
describe('redirectAfterDelete', function () {
it('redirects to index after successful delete', function () {
$result = $this->service->redirectAfterDelete($this->config);
expect($result)->toBeInstanceOf(Redirect::class);
expect($result->url)->toBe('/admin/campaigns');
});
});
describe('redirectWithError', function () {
it('redirects back with error message', function () {
$result = $this->service->redirectWithError('Something went wrong');
expect($result)->toBeInstanceOf(Redirect::class);
});
it('redirects with error message and input data', function () {
$inputData = ['name' => 'Test', 'email' => 'test@example.com'];
$result = $this->service->redirectWithError(
'Validation failed',
$inputData
);
expect($result)->toBeInstanceOf(Redirect::class);
});
});
});