10-04-2026
This commit is contained in:
parent
4d6b4930b2
commit
4bb89aad8c
836 changed files with 52961 additions and 5950 deletions
410
tests/Feature/Cms/CmsAdminTest.php
Normal file
410
tests/Feature/Cms/CmsAdminTest.php
Normal file
|
|
@ -0,0 +1,410 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Models\CmsArticle;
|
||||
use App\Models\CmsProject;
|
||||
use App\Models\User;
|
||||
use FluxCms\Core\Models\CmsContent;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Livewire\Volt\Volt;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
beforeEach(function () {
|
||||
$portalDomain = config('domains.domain_portal');
|
||||
url()->forceRootUrl('https://'.$portalDomain);
|
||||
});
|
||||
|
||||
// ========================================
|
||||
// Authentication
|
||||
// ========================================
|
||||
|
||||
test('cms dashboard requires authentication', function () {
|
||||
$this->get(route('cms.dashboard'))->assertRedirect('/login');
|
||||
});
|
||||
|
||||
test('cms content index requires authentication', function () {
|
||||
$this->get(route('cms.content.index'))->assertRedirect('/login');
|
||||
});
|
||||
|
||||
test('cms projects index requires authentication', function () {
|
||||
$this->get(route('cms.projects.index'))->assertRedirect('/login');
|
||||
});
|
||||
|
||||
test('cms media index requires authentication', function () {
|
||||
$this->get(route('cms.media.index'))->assertRedirect('/login');
|
||||
});
|
||||
|
||||
// ========================================
|
||||
// Dashboard
|
||||
// ========================================
|
||||
|
||||
test('cms dashboard renders for authenticated users', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user)
|
||||
->get(route('cms.dashboard'))
|
||||
->assertSuccessful()
|
||||
->assertSee('So funktioniert das CMS')
|
||||
->assertSee('Medienbibliothek');
|
||||
});
|
||||
|
||||
test('cms dashboard shows correct stats', function () {
|
||||
$user = User::factory()->create();
|
||||
CmsProject::factory()->published()->count(2)->create();
|
||||
CmsProject::factory()->unpublished()->create();
|
||||
|
||||
Volt::actingAs($user)
|
||||
->test('admin.cms.dashboard')
|
||||
->assertSee('3')
|
||||
->assertSee('2 veröffentlicht');
|
||||
});
|
||||
|
||||
// ========================================
|
||||
// Content Index
|
||||
// ========================================
|
||||
|
||||
test('cms content index renders for authenticated users', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user)
|
||||
->get(route('cms.content.index'))
|
||||
->assertSuccessful();
|
||||
});
|
||||
|
||||
test('cms content index shows groups', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
CmsContent::create([
|
||||
'group' => 'home',
|
||||
'key' => 'hero',
|
||||
'type' => 'json',
|
||||
'value' => ['de' => ['title' => 'Test']],
|
||||
]);
|
||||
|
||||
CmsContent::create([
|
||||
'group' => 'home',
|
||||
'key' => 'about',
|
||||
'type' => 'text',
|
||||
'value' => ['de' => 'About text'],
|
||||
]);
|
||||
|
||||
Volt::actingAs($user)
|
||||
->test('admin.cms.content-index')
|
||||
->assertSee('home')
|
||||
->assertSee('2');
|
||||
});
|
||||
|
||||
test('cms content index can select group and show flattened fields', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
CmsContent::create([
|
||||
'group' => 'home',
|
||||
'key' => 'hero',
|
||||
'type' => 'json',
|
||||
'value' => ['de' => ['title' => 'Hero Title', 'subtitle' => 'Hero Sub']],
|
||||
]);
|
||||
|
||||
Volt::actingAs($user)
|
||||
->test('admin.cms.content-index')
|
||||
->call('selectGroup', 'home')
|
||||
->assertSee('hero')
|
||||
->assertSee('title')
|
||||
->assertSee('subtitle')
|
||||
->assertSee('Hero Title')
|
||||
->assertSee('Hero Sub');
|
||||
});
|
||||
|
||||
test('cms content index can edit a flattened field', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$content = CmsContent::create([
|
||||
'group' => 'home',
|
||||
'key' => 'hero',
|
||||
'type' => 'json',
|
||||
'value' => ['de' => ['title' => 'Old Title', 'subtitle' => 'Sub']],
|
||||
]);
|
||||
|
||||
Volt::actingAs($user)
|
||||
->test('admin.cms.content-index')
|
||||
->call('selectGroup', 'home')
|
||||
->call('startFieldEdit', $content->id, 'title')
|
||||
->assertSet('editingId', $content->id)
|
||||
->assertSet('editingField', 'title')
|
||||
->assertSet('editValue', 'Old Title')
|
||||
->set('editValue', 'New Title')
|
||||
->call('saveEdit')
|
||||
->assertSet('editingId', null);
|
||||
|
||||
$content->refresh();
|
||||
$value = $content->getTranslation('value', 'de');
|
||||
expect($value['title'])->toBe('New Title')
|
||||
->and($value['subtitle'])->toBe('Sub');
|
||||
});
|
||||
|
||||
test('cms content index opens json modal for array subfields', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$content = CmsContent::create([
|
||||
'group' => 'home',
|
||||
'key' => 'hero',
|
||||
'type' => 'json',
|
||||
'value' => ['de' => ['title' => 'Title', 'stats' => [['label' => 'Projects', 'value' => '50+']]]],
|
||||
]);
|
||||
|
||||
Volt::actingAs($user)
|
||||
->test('admin.cms.content-index')
|
||||
->call('selectGroup', 'home')
|
||||
->call('startFieldEdit', $content->id, 'stats')
|
||||
->assertSet('showJsonModal', true)
|
||||
->assertSet('jsonEditingKey', 'hero.stats');
|
||||
});
|
||||
|
||||
// ========================================
|
||||
// Projects Index
|
||||
// ========================================
|
||||
|
||||
test('cms projects index renders for authenticated users', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user)
|
||||
->get(route('cms.projects.index'))
|
||||
->assertSuccessful();
|
||||
});
|
||||
|
||||
test('cms projects index lists projects', function () {
|
||||
$user = User::factory()->create();
|
||||
CmsProject::factory()->published()->create(['slug' => 'test-project', 'title' => ['de' => 'Test Projekt']]);
|
||||
|
||||
Volt::actingAs($user)
|
||||
->test('admin.cms.projects-index')
|
||||
->assertSee('Test Projekt');
|
||||
});
|
||||
|
||||
test('cms projects can open create form', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
Volt::actingAs($user)
|
||||
->test('admin.cms.projects-index')
|
||||
->call('openCreate')
|
||||
->assertSet('showForm', true)
|
||||
->assertSet('editingId', null);
|
||||
});
|
||||
|
||||
test('cms projects can save a new project', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
Volt::actingAs($user)
|
||||
->test('admin.cms.projects-index')
|
||||
->call('openCreate')
|
||||
->set('slug', 'new-project')
|
||||
->set('projectTitle', 'New Project')
|
||||
->set('is_published', true)
|
||||
->set('order', 1)
|
||||
->call('save')
|
||||
->assertSet('showForm', false)
|
||||
->assertHasNoErrors();
|
||||
|
||||
expect(CmsProject::where('slug', 'new-project')->exists())->toBeTrue();
|
||||
});
|
||||
|
||||
test('cms projects can save with all detail fields', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
Volt::actingAs($user)
|
||||
->test('admin.cms.projects-index')
|
||||
->call('openCreate')
|
||||
->set('slug', 'full-project')
|
||||
->set('projectTitle', 'Full Project')
|
||||
->set('location', 'Dubai')
|
||||
->set('status', 'NEW LAUNCH')
|
||||
->set('price_from_aed', 1125000)
|
||||
->set('highlights', ['Highlight A', 'Highlight B'])
|
||||
->set('quick_facts', [['icon' => 'home-modern', 'label' => 'Typen', 'value' => '1BR']])
|
||||
->set('investTitle', 'Starkes Investment')
|
||||
->set('investText', 'Beschreibung')
|
||||
->set('investViews', ['Road View'])
|
||||
->set('galleryItems', ['img1.jpg', 'img2.jpg'])
|
||||
->set('locTitle', 'Location: Al Jaddaf')
|
||||
->set('locMapUrl', 'https://maps.google.com')
|
||||
->set('locPoints', ['Punkt 1', 'Punkt 2'])
|
||||
->set('contactTitle', 'Kontakt Titel')
|
||||
->set('contactSubtitle', 'Ihr Ansprechpartner')
|
||||
->set('contactOptions', [['key' => '', 'value' => 'Bitte wählen'], ['key' => '1br', 'value' => '1BR Apt']])
|
||||
->call('save')
|
||||
->assertSet('showForm', false);
|
||||
|
||||
$project = CmsProject::where('slug', 'full-project')->first();
|
||||
expect($project)->not->toBeNull()
|
||||
->and($project->getTranslation('highlights', 'de'))->toHaveCount(2)
|
||||
->and($project->quick_facts)->toHaveCount(1)
|
||||
->and($project->gallery)->toHaveCount(2)
|
||||
->and($project->getTranslation('investment_case', 'de')['title'])->toBe('Starkes Investment')
|
||||
->and($project->getTranslation('location_info', 'de')['points'])->toHaveCount(2)
|
||||
->and($project->getTranslation('contact', 'de')['options'])->toHaveKey('1br');
|
||||
});
|
||||
|
||||
test('cms projects can edit existing project', function () {
|
||||
$user = User::factory()->create();
|
||||
$project = CmsProject::factory()->published()->create(['slug' => 'edit-me', 'title' => ['de' => 'Edit Me']]);
|
||||
|
||||
Volt::actingAs($user)
|
||||
->test('admin.cms.projects-index')
|
||||
->call('openEdit', $project->id)
|
||||
->assertSet('showForm', true)
|
||||
->assertSet('editingId', $project->id)
|
||||
->assertSet('slug', 'edit-me');
|
||||
});
|
||||
|
||||
test('cms projects can duplicate a project', function () {
|
||||
$user = User::factory()->create();
|
||||
$project = CmsProject::factory()->published()->create([
|
||||
'slug' => 'original-project',
|
||||
'title' => ['de' => 'Original Projekt'],
|
||||
]);
|
||||
|
||||
Volt::actingAs($user)
|
||||
->test('admin.cms.projects-index')
|
||||
->call('duplicateProject', $project->id)
|
||||
->assertSet('showForm', true)
|
||||
->assertSet('editingId', null)
|
||||
->assertSet('projectTitle', 'Original Projekt');
|
||||
|
||||
expect($this->slug ?? '')->not->toBe('original-project');
|
||||
});
|
||||
|
||||
test('cms projects can delete a project', function () {
|
||||
$user = User::factory()->create();
|
||||
$project = CmsProject::factory()->create(['slug' => 'delete-me']);
|
||||
|
||||
Volt::actingAs($user)
|
||||
->test('admin.cms.projects-index')
|
||||
->call('deleteProject', $project->id);
|
||||
|
||||
expect(CmsProject::where('slug', 'delete-me')->exists())->toBeFalse();
|
||||
});
|
||||
|
||||
// ========================================
|
||||
// Media Index
|
||||
// ========================================
|
||||
|
||||
test('cms media index renders for authenticated users', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user)
|
||||
->get(route('cms.media.index'))
|
||||
->assertSuccessful();
|
||||
});
|
||||
|
||||
// ========================================
|
||||
// Articles (Magazin)
|
||||
// ========================================
|
||||
|
||||
test('cms articles index requires authentication', function () {
|
||||
$this->get(route('cms.articles.index'))->assertRedirect('/login');
|
||||
});
|
||||
|
||||
test('cms articles index renders for authenticated users', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user)
|
||||
->get(route('cms.articles.index'))
|
||||
->assertSuccessful()
|
||||
->assertSee('Magazin Beiträge');
|
||||
});
|
||||
|
||||
test('cms articles index shows existing articles', function () {
|
||||
$user = User::factory()->create();
|
||||
CmsArticle::factory()->create([
|
||||
'slug' => 'test-magazin-artikel',
|
||||
'title' => ['de' => 'Ein Test Artikel'],
|
||||
'category' => 'Dubai Investment',
|
||||
'author' => ['name' => 'Marcel Scheibe', 'bio' => 'CEO', 'avatar' => 'a.jpg'],
|
||||
]);
|
||||
|
||||
$this->actingAs($user)
|
||||
->get(route('cms.articles.index'))
|
||||
->assertSee('Ein Test Artikel')
|
||||
->assertSee('Dubai Investment')
|
||||
->assertSee('Marcel Scheibe');
|
||||
});
|
||||
|
||||
test('cms articles index can create new article', function () {
|
||||
$user = User::factory()->create();
|
||||
$this->actingAs($user);
|
||||
|
||||
Volt::test('admin.cms.articles-index')
|
||||
->call('openCreate')
|
||||
->assertSet('showForm', true)
|
||||
->assertSet('editingId', null);
|
||||
});
|
||||
|
||||
test('cms articles index can save a new article', function () {
|
||||
$user = User::factory()->create();
|
||||
$this->actingAs($user);
|
||||
|
||||
Volt::test('admin.cms.articles-index')
|
||||
->call('openCreate')
|
||||
->set('slug', 'neuer-test-artikel')
|
||||
->set('articleTitle', 'Neuer Testartikel')
|
||||
->set('subtitle', 'Ein Untertitel')
|
||||
->set('category', 'Test Kategorie')
|
||||
->set('date_label', 'März 23, 2026')
|
||||
->set('read_time', '5 min read')
|
||||
->set('authorName', 'Test Autor')
|
||||
->set('intro', 'Einleitungstext hier.')
|
||||
->set('sections', [['title' => 'Abschnitt 1', 'content' => 'Inhalt 1']])
|
||||
->call('save')
|
||||
->assertSet('showForm', false);
|
||||
|
||||
$article = CmsArticle::where('slug', 'neuer-test-artikel')->first();
|
||||
|
||||
expect($article)->not->toBeNull()
|
||||
->and($article->category)->toBe('Test Kategorie')
|
||||
->and($article->getTranslation('title', 'de'))->toBe('Neuer Testartikel');
|
||||
|
||||
$content = $article->getTranslation('content', 'de');
|
||||
expect($content['intro'])->toBe('Einleitungstext hier.')
|
||||
->and($content['sections'])->toHaveCount(1);
|
||||
});
|
||||
|
||||
test('cms articles index can edit existing article', function () {
|
||||
$user = User::factory()->create();
|
||||
$this->actingAs($user);
|
||||
|
||||
$article = CmsArticle::factory()->create([
|
||||
'slug' => 'edit-test',
|
||||
'title' => ['de' => 'Original Titel'],
|
||||
]);
|
||||
|
||||
Volt::test('admin.cms.articles-index')
|
||||
->call('openEdit', $article->id)
|
||||
->assertSet('editingId', $article->id)
|
||||
->assertSet('slug', 'edit-test')
|
||||
->assertSet('showForm', true);
|
||||
});
|
||||
|
||||
test('cms articles index can delete article', function () {
|
||||
$user = User::factory()->create();
|
||||
$this->actingAs($user);
|
||||
|
||||
$article = CmsArticle::factory()->create();
|
||||
|
||||
Volt::test('admin.cms.articles-index')
|
||||
->call('deleteArticle', $article->id);
|
||||
|
||||
expect(CmsArticle::find($article->id))->toBeNull();
|
||||
});
|
||||
|
||||
test('cms articles index can toggle published status', function () {
|
||||
$user = User::factory()->create();
|
||||
$this->actingAs($user);
|
||||
|
||||
$article = CmsArticle::factory()->published()->create();
|
||||
|
||||
Volt::test('admin.cms.articles-index')
|
||||
->call('togglePublished', $article->id);
|
||||
|
||||
expect($article->refresh()->is_published)->toBeFalse();
|
||||
});
|
||||
112
tests/Feature/Cms/CmsArticleTest.php
Normal file
112
tests/Feature/Cms/CmsArticleTest.php
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Models\CmsArticle;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
test('cms article can be created with factory', function () {
|
||||
$article = CmsArticle::factory()->create();
|
||||
|
||||
expect($article)->toBeInstanceOf(CmsArticle::class)
|
||||
->and($article->slug)->not->toBeEmpty()
|
||||
->and($article->title)->not->toBeEmpty();
|
||||
});
|
||||
|
||||
test('published scope returns only published articles', function () {
|
||||
CmsArticle::factory()->published()->count(2)->create();
|
||||
CmsArticle::factory()->unpublished()->create();
|
||||
|
||||
expect(CmsArticle::published()->count())->toBe(2);
|
||||
});
|
||||
|
||||
test('ordered scope sorts by order then created_at desc', function () {
|
||||
$first = CmsArticle::factory()->create(['order' => 1]);
|
||||
$second = CmsArticle::factory()->create(['order' => 2]);
|
||||
$third = CmsArticle::factory()->create(['order' => 3]);
|
||||
|
||||
$sorted = CmsArticle::ordered()->pluck('id')->toArray();
|
||||
|
||||
expect($sorted)->toBe([$first->id, $second->id, $third->id]);
|
||||
});
|
||||
|
||||
test('toFrontendArray returns compatible structure', function () {
|
||||
$article = CmsArticle::factory()->create([
|
||||
'slug' => 'test-article',
|
||||
'title' => 'Test Article',
|
||||
'subtitle' => 'Test Subtitle',
|
||||
'image' => 'b2in/magazin-1.jpg',
|
||||
'category' => 'Dubai Investment',
|
||||
'date_label' => 'März 10, 2026',
|
||||
'read_time' => '6 min read',
|
||||
'author' => ['name' => 'Marcel', 'bio' => 'CEO', 'avatar' => 'avatar.jpg'],
|
||||
'content' => ['de' => ['intro' => 'Intro text', 'sections' => [['title' => 'S1', 'content' => 'C1']]]],
|
||||
]);
|
||||
|
||||
$array = $article->toFrontendArray();
|
||||
|
||||
expect($array)
|
||||
->toHaveKeys(['id', 'slug', 'title', 'subtitle', 'image', 'category', 'date', 'readTime', 'author', 'content'])
|
||||
->and($array['slug'])->toBe('test-article')
|
||||
->and($array['date'])->toBe('März 10, 2026')
|
||||
->and($array['readTime'])->toBe('6 min read')
|
||||
->and($array['author']['name'])->toBe('Marcel')
|
||||
->and($array['content']['sections'])->toHaveCount(1);
|
||||
});
|
||||
|
||||
test('slug is unique', function () {
|
||||
CmsArticle::factory()->create(['slug' => 'unique-slug']);
|
||||
|
||||
expect(fn () => CmsArticle::factory()->create(['slug' => 'unique-slug']))
|
||||
->toThrow(\Illuminate\Database\QueryException::class);
|
||||
});
|
||||
|
||||
test('author cast returns array', function () {
|
||||
$article = CmsArticle::factory()->create([
|
||||
'author' => ['name' => 'Test Author', 'bio' => 'Bio text', 'avatar' => 'a.jpg'],
|
||||
]);
|
||||
|
||||
$article->refresh();
|
||||
|
||||
expect($article->author)
|
||||
->toBeArray()
|
||||
->toHaveKey('name', 'Test Author')
|
||||
->toHaveKey('bio', 'Bio text');
|
||||
});
|
||||
|
||||
test('translatable fields work correctly', function () {
|
||||
$article = CmsArticle::factory()->create([
|
||||
'title' => ['de' => 'Deutscher Titel', 'en' => 'English Title'],
|
||||
'subtitle' => ['de' => 'Deutsch', 'en' => 'English'],
|
||||
]);
|
||||
|
||||
expect($article->getTranslation('title', 'de'))->toBe('Deutscher Titel')
|
||||
->and($article->getTranslation('title', 'en'))->toBe('English Title');
|
||||
});
|
||||
|
||||
test('seeder creates articles from config data', function () {
|
||||
$this->seed(\Database\Seeders\CmsArticleSeeder::class);
|
||||
|
||||
expect(CmsArticle::count())->toBe(5);
|
||||
|
||||
$article = CmsArticle::where('slug', 'escrow-system-dubai-investoren')->first();
|
||||
|
||||
expect($article)->not->toBeNull()
|
||||
->and($article->category)->toBe('Dubai Investment')
|
||||
->and($article->read_time)->toBe('6 min read')
|
||||
->and($article->author['name'])->toBe('Marcel Scheibe')
|
||||
->and($article->is_published)->toBeTrue();
|
||||
|
||||
$content = $article->getTranslation('content', 'de');
|
||||
expect($content)->toHaveKey('intro')
|
||||
->and($content['sections'])->toHaveCount(3);
|
||||
});
|
||||
|
||||
test('seeder is idempotent', function () {
|
||||
$this->seed(\Database\Seeders\CmsArticleSeeder::class);
|
||||
$this->seed(\Database\Seeders\CmsArticleSeeder::class);
|
||||
|
||||
expect(CmsArticle::count())->toBe(5);
|
||||
});
|
||||
135
tests/Feature/Cms/CmsContentSeederTest.php
Normal file
135
tests/Feature/Cms/CmsContentSeederTest.php
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use FluxCms\Core\Models\CmsContent;
|
||||
use FluxCms\Core\Services\CmsContentService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
test('seeder creates content entries for all mapped sections', function () {
|
||||
$this->seed(\Database\Seeders\CmsContentSeeder::class);
|
||||
|
||||
expect(CmsContent::count())->toBeGreaterThan(0);
|
||||
|
||||
$expectedGroups = ['global', 'home', 'immobilien', 'netzwerk', 'faq', 'contact', 'about', 'magazin'];
|
||||
|
||||
foreach ($expectedGroups as $group) {
|
||||
expect(CmsContent::where('group', $group)->exists())
|
||||
->toBeTrue("Expected group '{$group}' to exist in CmsContent");
|
||||
}
|
||||
});
|
||||
|
||||
test('seeder creates all home sections', function () {
|
||||
$this->seed(\Database\Seeders\CmsContentSeeder::class);
|
||||
|
||||
$homeKeys = CmsContent::where('group', 'home')->pluck('key')->toArray();
|
||||
|
||||
expect($homeKeys)
|
||||
->toContain('hero')
|
||||
->toContain('founder_bar')
|
||||
->toContain('ecosystem_core')
|
||||
->toContain('vision_section');
|
||||
});
|
||||
|
||||
test('seeder stores hero content as translatable json', function () {
|
||||
$this->seed(\Database\Seeders\CmsContentSeeder::class);
|
||||
|
||||
$hero = CmsContent::where('group', 'home')->where('key', 'hero')->first();
|
||||
|
||||
expect($hero)->not->toBeNull()
|
||||
->and($hero->type)->toBe('json');
|
||||
|
||||
$valueDe = $hero->getTranslation('value', 'de');
|
||||
$valueEn = $hero->getTranslation('value', 'en');
|
||||
|
||||
expect($valueDe)->toBeArray()
|
||||
->toHaveKeys(['title', 'subtitle', 'image']);
|
||||
|
||||
expect($valueEn)->toBeArray()
|
||||
->toHaveKeys(['title', 'subtitle', 'image']);
|
||||
});
|
||||
|
||||
test('cms helper returns correct content after seeding', function () {
|
||||
$this->seed(\Database\Seeders\CmsContentSeeder::class);
|
||||
|
||||
$hero = cms('home.hero');
|
||||
|
||||
expect($hero)->toBeArray()
|
||||
->and($hero['title'])->toContain('B2in');
|
||||
});
|
||||
|
||||
test('cms content service getGroup returns all section keys', function () {
|
||||
$this->seed(\Database\Seeders\CmsContentSeeder::class);
|
||||
|
||||
$service = app(CmsContentService::class);
|
||||
$homeGroup = $service->getGroup('home');
|
||||
|
||||
expect($homeGroup)->toBeArray()
|
||||
->toHaveKey('hero')
|
||||
->toHaveKey('founder_bar')
|
||||
->toHaveKey('ecosystem_core');
|
||||
|
||||
expect($homeGroup['hero'])->toBeArray()
|
||||
->toHaveKey('title');
|
||||
});
|
||||
|
||||
test('seeder is idempotent', function () {
|
||||
$this->seed(\Database\Seeders\CmsContentSeeder::class);
|
||||
$countFirst = CmsContent::count();
|
||||
|
||||
$this->seed(\Database\Seeders\CmsContentSeeder::class);
|
||||
$countSecond = CmsContent::count();
|
||||
|
||||
expect($countSecond)->toBe($countFirst);
|
||||
});
|
||||
|
||||
test('immobilien sections are seeded correctly', function () {
|
||||
$this->seed(\Database\Seeders\CmsContentSeeder::class);
|
||||
|
||||
$immoKeys = CmsContent::where('group', 'immobilien')->pluck('key')->toArray();
|
||||
|
||||
expect($immoKeys)
|
||||
->toContain('hero_v2')
|
||||
->toContain('warum_dubai')
|
||||
->toContain('kaufprozess')
|
||||
->toContain('bruecke')
|
||||
->toContain('mindset')
|
||||
->toContain('moebel_vorteil');
|
||||
});
|
||||
|
||||
test('faq content contains questions array', function () {
|
||||
$this->seed(\Database\Seeders\CmsContentSeeder::class);
|
||||
|
||||
$faq = cms('faq.faq');
|
||||
|
||||
expect($faq)->toBeArray()
|
||||
->toHaveKey('questions')
|
||||
->and($faq['questions'])->toBeArray()
|
||||
->not->toBeEmpty();
|
||||
});
|
||||
|
||||
test('cms_theme_section returns CMS content after seeding', function () {
|
||||
$this->seed(\Database\Seeders\CmsContentSeeder::class);
|
||||
|
||||
$hero = cms_theme_section('hero');
|
||||
|
||||
expect($hero)->toBeArray()
|
||||
->and($hero['title'])->toContain('B2in');
|
||||
});
|
||||
|
||||
test('portfolio is stored under immobilien group for CMS', function () {
|
||||
$this->seed(\Database\Seeders\CmsContentSeeder::class);
|
||||
|
||||
$portfolio = CmsContent::where('group', 'immobilien')->where('key', 'portfolio')->first();
|
||||
|
||||
expect($portfolio)->not->toBeNull()
|
||||
->and($portfolio->type)->toBe('json');
|
||||
|
||||
$valueDe = $portfolio->getTranslation('value', 'de');
|
||||
|
||||
expect($valueDe)->toBeArray()
|
||||
->toHaveKey('projects')
|
||||
->and($valueDe['projects'])->toBeArray();
|
||||
});
|
||||
115
tests/Feature/Cms/CmsProjectTest.php
Normal file
115
tests/Feature/Cms/CmsProjectTest.php
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Models\CmsProject;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
test('cms project can be created with factory', function () {
|
||||
$project = CmsProject::factory()->create();
|
||||
|
||||
expect($project)->toBeInstanceOf(CmsProject::class)
|
||||
->and($project->slug)->not->toBeEmpty()
|
||||
->and($project->title)->not->toBeEmpty();
|
||||
});
|
||||
|
||||
test('published scope returns only published projects', function () {
|
||||
CmsProject::factory()->published()->count(2)->create();
|
||||
CmsProject::factory()->unpublished()->create();
|
||||
|
||||
expect(CmsProject::published()->count())->toBe(2);
|
||||
});
|
||||
|
||||
test('ordered scope sorts by order then launch_date desc', function () {
|
||||
$first = CmsProject::factory()->create([
|
||||
'order' => 0,
|
||||
'launch_date' => '2026-06-01',
|
||||
]);
|
||||
$second = CmsProject::factory()->create([
|
||||
'order' => 0,
|
||||
'launch_date' => '2026-01-01',
|
||||
]);
|
||||
$third = CmsProject::factory()->create([
|
||||
'order' => 1,
|
||||
'launch_date' => '2026-12-01',
|
||||
]);
|
||||
|
||||
$sorted = CmsProject::ordered()->pluck('id')->toArray();
|
||||
|
||||
expect($sorted)->toBe([$first->id, $second->id, $third->id]);
|
||||
});
|
||||
|
||||
test('getFormattedPrice returns formatted AED with EUR and USD', function () {
|
||||
$project = CmsProject::factory()->create(['price_from_aed' => 1_125_000]);
|
||||
|
||||
$formatted = $project->getFormattedPrice();
|
||||
|
||||
expect($formatted)
|
||||
->toContain('AED')
|
||||
->toContain('EUR')
|
||||
->toContain('USD')
|
||||
->toContain('1.125.000');
|
||||
});
|
||||
|
||||
test('getFormattedPrice returns empty string when no price', function () {
|
||||
$project = CmsProject::factory()->create(['price_from_aed' => null]);
|
||||
|
||||
expect($project->getFormattedPrice())->toBe('');
|
||||
});
|
||||
|
||||
test('toFrontendArray returns compatible structure', function () {
|
||||
$project = CmsProject::factory()->create([
|
||||
'slug' => 'test-project',
|
||||
'title' => 'Test Project',
|
||||
'location' => 'Dubai',
|
||||
'status' => 'NEW LAUNCH',
|
||||
'launch_date' => '2026-03-03',
|
||||
'price_from_aed' => 1_000_000,
|
||||
'highlights' => ['Highlight 1', 'Highlight 2'],
|
||||
'quick_facts' => [['icon' => 'home', 'label' => 'Type', 'value' => '1BR']],
|
||||
'gallery' => ['img1.jpg', 'img2.jpg'],
|
||||
]);
|
||||
|
||||
$array = $project->toFrontendArray();
|
||||
|
||||
expect($array)
|
||||
->toHaveKeys(['slug', 'title', 'location', 'status', 'launch_date', 'price_from', 'image', 'highlights', 'quick_facts', 'investment_case', 'gallery', 'location_info', 'contact', 'investor_trust', 'furniture_benefit'])
|
||||
->and($array['slug'])->toBe('test-project')
|
||||
->and($array['launch_date'])->toBe('03.03.2026')
|
||||
->and($array['highlights'])->toHaveCount(2)
|
||||
->and($array['gallery'])->toHaveCount(2)
|
||||
->and($array['price_from'])->toContain('AED');
|
||||
});
|
||||
|
||||
test('slug is unique', function () {
|
||||
CmsProject::factory()->create(['slug' => 'unique-slug']);
|
||||
|
||||
expect(fn () => CmsProject::factory()->create(['slug' => 'unique-slug']))
|
||||
->toThrow(\Illuminate\Database\QueryException::class);
|
||||
});
|
||||
|
||||
test('seeder creates project from config data', function () {
|
||||
$this->seed(\Database\Seeders\CmsProjectSeeder::class);
|
||||
|
||||
$project = CmsProject::where('slug', 'azizi-creek-views-4')->first();
|
||||
|
||||
expect($project)->not->toBeNull()
|
||||
->and($project->title)->toBe('Azizi Developments: Creek Views 4')
|
||||
->and($project->price_from_aed)->toBe(1_125_000)
|
||||
->and($project->is_published)->toBeTrue()
|
||||
->and($project->gallery)->toHaveCount(6)
|
||||
->and($project->quick_facts)->toHaveCount(4)
|
||||
->and($project->investor_trust)->toBeArray()
|
||||
->and($project->investor_trust['columns'] ?? [])->toHaveCount(3)
|
||||
->and($project->furniture_benefit)->toBeArray()
|
||||
->and($project->furniture_benefit['button_link'] ?? '')->toBe('/netzwerk');
|
||||
});
|
||||
|
||||
test('seeder is idempotent', function () {
|
||||
$this->seed(\Database\Seeders\CmsProjectSeeder::class);
|
||||
$this->seed(\Database\Seeders\CmsProjectSeeder::class);
|
||||
|
||||
expect(CmsProject::count())->toBe(1);
|
||||
});
|
||||
30
tests/Feature/Cms/HeroiconOutlineListTest.php
Normal file
30
tests/Feature/Cms/HeroiconOutlineListTest.php
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use FluxCms\Core\Services\HeroiconOutlineList;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
test('heroicon outline list returns a sorted string array', function () {
|
||||
$names = HeroiconOutlineList::names();
|
||||
|
||||
expect($names)->toBeArray();
|
||||
|
||||
foreach ($names as $name) {
|
||||
expect($name)->toBeString()->not->toBeEmpty();
|
||||
}
|
||||
|
||||
$sorted = $names;
|
||||
sort($sorted);
|
||||
expect($names)->toEqual($sorted);
|
||||
});
|
||||
|
||||
test('heroicon outline forgetCached allows list to be rebuilt', function () {
|
||||
HeroiconOutlineList::forgetCached();
|
||||
|
||||
$names = HeroiconOutlineList::names();
|
||||
|
||||
expect($names)->toBeArray();
|
||||
});
|
||||
45
tests/Feature/Cms/NetzwerkPageCmsSeederTest.php
Normal file
45
tests/Feature/Cms/NetzwerkPageCmsSeederTest.php
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use FluxCms\Core\Models\CmsContent;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
test('netzwerk page lang blocks exist for de', function () {
|
||||
$cabinet = trans('b2in.themes.b2in.netzwerk_cabinet_partner', [], 'de');
|
||||
$hint = trans('b2in.themes.b2in.netzwerk_immobilien_hint', [], 'de');
|
||||
|
||||
expect($cabinet)->toBeArray()
|
||||
->toHaveKey('badge')
|
||||
->and($cabinet['paragraphs'])->toBeArray();
|
||||
|
||||
expect($hint)->toBeArray()
|
||||
->toHaveKey('title')
|
||||
->toHaveKey('button_text');
|
||||
});
|
||||
|
||||
test('netzwerk page cms seeder creates rows only once', function () {
|
||||
$this->seed(\Database\Seeders\NetzwerkPageCmsSeeder::class);
|
||||
|
||||
expect(CmsContent::where('group', 'netzwerk')->where('key', 'cabinet_partner')->exists())->toBeTrue()
|
||||
->and(CmsContent::where('group', 'netzwerk')->where('key', 'immobilien_hint')->exists())->toBeTrue();
|
||||
|
||||
$count = CmsContent::count();
|
||||
|
||||
$this->seed(\Database\Seeders\NetzwerkPageCmsSeeder::class);
|
||||
|
||||
expect(CmsContent::count())->toBe($count);
|
||||
});
|
||||
|
||||
test('cms_theme_section returns cabinet content from database after netzwerk page seed', function () {
|
||||
$this->seed(\Database\Seeders\NetzwerkPageCmsSeeder::class);
|
||||
|
||||
app()->setLocale('de');
|
||||
|
||||
$cabinet = cms_theme_section('netzwerk_cabinet_partner');
|
||||
|
||||
expect($cabinet)->toBeArray()
|
||||
->and($cabinet['badge'])->toBe('Premiumpartner');
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue