Files
michaelschiemer/tests/Framework/Admin/CrudServiceTest.php
Michael Schiemer fc3d7e6357 feat(Production): Complete production deployment infrastructure
- Add comprehensive health check system with multiple endpoints
- Add Prometheus metrics endpoint
- Add production logging configurations (5 strategies)
- Add complete deployment documentation suite:
  * QUICKSTART.md - 30-minute deployment guide
  * DEPLOYMENT_CHECKLIST.md - Printable verification checklist
  * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle
  * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference
  * production-logging.md - Logging configuration guide
  * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation
  * README.md - Navigation hub
  * DEPLOYMENT_SUMMARY.md - Executive summary
- Add deployment scripts and automation
- Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment
- Update README with production-ready features

All production infrastructure is now complete and ready for deployment.
2025-10-25 19:18:37 +02:00

278 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\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);
});
});
});