Display CMS Optimierungen 03-06-2026

This commit is contained in:
Kevin Adametz 2026-06-03 15:43:18 +02:00
parent 6c6d683b9a
commit bebfa63e87
17 changed files with 925 additions and 133 deletions

View file

@ -16,6 +16,12 @@ test('page is accessible without login', function () {
->assertSeeLivewire(QuickStatus::class);
});
test('page accepts key query parameter used in admin link', function () {
$this->get('/info/status?key='.VALID_KEY)
->assertSuccessful()
->assertSeeLivewire(QuickStatus::class);
});
test('page shows forbidden when key is missing', function () {
Livewire::test(QuickStatus::class, ['k' => ''])
->assertSet('authorized', false)

View file

@ -176,6 +176,7 @@ test('returns playlist with offers config', function () {
'bullets' => [],
'disclaimer' => '',
'qr_url' => 'https://cabinet-bielefeld.de',
'qr_image_url' => 'https://portal.b2in.test/storage/display-qr-codes/cabinet.png',
'qr_title' => 'Reservieren',
'contact' => "0521 98620100\nTel. oder WhatsApp",
'show_brand_text' => false,
@ -193,6 +194,7 @@ test('returns playlist with offers config', function () {
$response->assertJsonPath('playlist.0.slides.0.title', 'GOYA Sideboard');
$response->assertJsonPath('playlist.0.slides.0.price', '489 €');
$response->assertJsonPath('playlist.0.slides.0.qr_url', 'https://cabinet-bielefeld.de');
$response->assertJsonPath('playlist.0.slides.0.qr_image_url', 'https://portal.b2in.test/storage/display-qr-codes/cabinet.png');
});
test('returns playlist with multiple versions in order', function () {
@ -449,7 +451,25 @@ test('display player keeps previews in a strict 9 by 16 viewport', function () {
->toContain('this.settings.footer_claim')
->toContain('this.settings.footer_url')
->toContain('this.settings.header_logo_url')
->toContain('/_cabinet/assets/b2in-logo-positive.svg')
->toContain("url.startsWith('../assets/')")
->toContain("!url.includes('/') && url.endsWith('.svg')")
->toContain('this.settings.qr_label')
->toContain('function setQrImage')
->toContain('function qrCodeImageUrl')
->toContain('options.imageUrl')
->toContain('content.qr_image_url')
->toContain('this.settings.qr_image_url')
->toContain('slide.qr_image_url')
->toContain("img.loading = 'eager'")
->toContain('maxAttempts')
->toContain('cb=${Date.now()}-${attempt}')
->toContain('offer-slide--no-header')
->toContain('offer-slide--no-bottom')
->toContain('offer-bottom--info-only')
->toContain('offer-bottom--qr-only')
->toContain('offer-info--compact')
->toContain('const showBottom = showInfo || showQrBox')
->toContain('this.settings.show_footer !== false')
->toContain('this.settings.show_logo !== false')
->toContain('this.settings.show_claim !== false')

View file

@ -10,6 +10,8 @@ use App\Models\DisplayPlaylistItem;
use App\Models\DisplayVersion;
use App\Models\DisplayVersionItem;
use App\Models\User;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\URL;
use Livewire\Livewire;
@ -70,6 +72,7 @@ test('can create a display version', function () {
expect($version->settings)->toBeArray();
expect($version->settings)->toHaveKey('theme');
expect($version->settings)->toHaveKey('header_logo_url');
expect($version->settings['header_logo_url'])->toBe('/_cabinet/assets/b2in-logo-positive.svg');
expect($version->settings)->toHaveKey('footer_url');
});
@ -446,6 +449,56 @@ test('can add a slide item to offers version', function () {
expect($item->content['qr_url'])->toBe('https://cabinet-bielefeld.de');
});
test('slide editor generates and stores a qr image when a qr url is saved', function () {
Storage::fake('public');
Http::fake([
'api.qrserver.com/*' => Http::response('fake-png', 200, ['Content-Type' => 'image/png']),
]);
$user = User::factory()->create();
$version = DisplayVersion::factory()->create(['type' => 'offers']);
Livewire::actingAs($user)
->test(DisplayVersionEditor::class, ['displayVersion' => $version])
->call('openItemModal', null, 'slide')
->set('slideTitle', 'QR Slide')
->set('slideQrUrl', 'cabinet-bielefeld.de')
->call('saveItem');
$item = DisplayVersionItem::where('display_version_id', $version->id)->first();
expect($item->content['qr_url'])->toBe('cabinet-bielefeld.de')
->and($item->content['qr_image_path'])->toStartWith('display-qr-codes/')
->and($item->content['qr_image_url'])->toContain('/storage/display-qr-codes/');
expect(Storage::disk('public')->exists($item->content['qr_image_path']))->toBeTrue();
Http::assertSentCount(1);
});
test('b2in settings generate and store a qr image when a qr url is saved', function () {
Storage::fake('public');
Http::fake([
'api.qrserver.com/*' => Http::response('fake-png', 200, ['Content-Type' => 'image/png']),
]);
$user = User::factory()->create();
$version = DisplayVersion::factory()->create(['type' => 'b2in']);
Livewire::actingAs($user)
->test(DisplayVersionEditor::class, ['displayVersion' => $version])
->call('openSettingsModal')
->set('settings.qr_url', 'b2in.eu')
->call('saveSettings');
$settings = $version->fresh()->settings;
expect($settings['qr_image_path'])->toStartWith('display-qr-codes/')
->and($settings['qr_image_url'])->toContain('/storage/display-qr-codes/');
expect(Storage::disk('public')->exists($settings['qr_image_path']))->toBeTrue();
Http::assertSentCount(1);
});
test('can add a slide with bullets to offers version', function () {
$user = User::factory()->create();
$version = DisplayVersion::factory()->create(['type' => 'offers']);

View file

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
use Illuminate\Support\Facades\URL;
beforeEach(function () {
URL::forceRootUrl('https://'.config('domains.domain_portal'));
});
test('portal domain serves flux javascript from laravel route', function () {
$this->get('https://'.config('domains.domain_portal').'/flux/flux.js?id=test')
->assertSuccessful()
->assertHeader('content-type', 'text/javascript; charset=utf-8');
});
test('portal domain serves minified flux javascript route in production mode', function () {
config(['app.debug' => false]);
$this->get('https://'.config('domains.domain_portal').'/flux/flux.min.js?id=test')
->assertSuccessful()
->assertHeader('content-type', 'text/javascript; charset=utf-8');
});
test('flux pro vendor bundle contains alpine components used by the admin ui', function () {
$path = base_path('vendor/livewire/flux-pro/dist/flux.js');
expect(is_file($path))->toBeTrue('Flux Pro must be installed via composer (auth.json on live).');
expect(file_get_contents($path))->toContain('fluxModal');
});

View file

@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
use Illuminate\Support\Facades\File;
test('flux publish assets command copies javascript into public flux directory', function () {
$targetDir = public_path('flux');
if (File::isDirectory($targetDir)) {
File::deleteDirectory($targetDir);
}
$this->artisan('flux:publish-assets')
->assertSuccessful();
expect(is_file(public_path('flux/flux.js')))->toBeTrue();
expect(is_file(public_path('flux/flux.min.js')))->toBeTrue();
expect(filesize(public_path('flux/flux.min.js')))->toBeGreaterThan(1000);
File::deleteDirectory($targetDir);
});
test('composer install and update publish flux assets', function () {
$composer = json_decode((string) file_get_contents(base_path('composer.json')), true, flags: JSON_THROW_ON_ERROR);
$expectedCommand = '@php artisan flux:publish-assets --ansi --force';
expect($composer['scripts']['post-install-cmd'] ?? [])->toContain($expectedCommand);
expect($composer['scripts']['post-update-cmd'] ?? [])->toContain($expectedCommand);
});